Skip to content

Commit

Permalink
feat: improve Commands tab UX (#1041)
Browse files Browse the repository at this point in the history
* feat: improve UX for main Commands screen

* chore: adjust translation key

* chore: replace .keys with .toPairs

* chore: remove leftover methodNames

* chore: write command parameters in multiple lines

* fix: fix argument order for rotateDevice

* chore: store automationName as separate prop

* fix: show some commands only for supported drivers

* feat: support informational notes for commands

* chore: address review comment

* chore: fix eslint warning
  • Loading branch information
eglitise authored Aug 17, 2023
1 parent 24a1c72 commit bc5be87
Show file tree
Hide file tree
Showing 8 changed files with 261 additions and 260 deletions.
14 changes: 0 additions & 14 deletions app/renderer/actions/Inspector.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ export const HIDE_PROMPT_KEEP_ALIVE = 'HIDE_PROMPT_KEEP_ALIVE';

export const SELECT_INTERACTION_MODE = 'SELECT_INTERACTION_MODE';

export const SELECT_COMMAND_GROUP = 'SELECT_COMMAND_GROUP';
export const SELECT_COMMAND_SUB_GROUP = 'SELECT_COMMAND_SUB_GROUP';
export const ENTERING_COMMAND_ARGS = 'ENTERING_COMMAND_ARGS';
export const CANCEL_PENDING_COMMAND = 'CANCEL_PENDING_COMMAND';
export const SET_COMMAND_ARG = 'SET_COMMAND_ARG';
Expand Down Expand Up @@ -668,18 +666,6 @@ export function clearSwipeAction () {
};
}

export function selectCommandGroup (group) {
return (dispatch) => {
dispatch({type: SELECT_COMMAND_GROUP, group});
};
}

export function selectCommandSubGroup (group) {
return (dispatch) => {
dispatch({type: SELECT_COMMAND_SUB_GROUP, group});
};
}

export function selectInteractionMode (interaction) {
return (dispatch) => {
dispatch({type: SELECT_INTERACTION_MODE, interaction});
Expand Down
65 changes: 38 additions & 27 deletions app/renderer/components/Inspector/Commands.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import React from 'react';
import _ from 'lodash';
import { Row, Col, Button, Select, Modal, Input, Switch, notification, } from 'antd';
import { Alert, Row, Col, Button, Collapse, Modal, Input, Switch, Space, notification, Tooltip } from 'antd';
import { COMMAND_DEFINITIONS, COMMAND_ARG_TYPES } from './shared';
import InspectorStyles from './Inspector.css';
import { INPUT } from '../AntdTypes';
import { ALERT, INPUT } from '../AntdTypes';

const Commands = (props) => {
const { selectCommandGroup, selectCommandSubGroup, selectedCommandGroup, selectedCommandSubGroup,
pendingCommand, cancelPendingCommand, setCommandArg, applyClientMethod, t } = props;
const { pendingCommand, cancelPendingCommand, setCommandArg, applyClientMethod, automationName, t } = props;

const startPerformingCommand = (commandName, command) => {
const { startEnteringCommandArgs } = props;
if (_.isEmpty(command.args)) {
applyClientMethod({methodName: command.methodName, args: [], skipRefresh: !command.refresh, ignoreResult: false});
applyClientMethod({methodName: commandName, args: [], skipRefresh: !command.refresh, ignoreResult: false});
} else {
startEnteringCommandArgs(commandName, command);
}
Expand Down Expand Up @@ -66,35 +65,47 @@ const Commands = (props) => {
cancelPendingCommand();
};

const generateCommandNotes = (notes) =>
notes.map((note) =>
_.isArray(note) ? `${t(note[0])}: ${note[1]}` : t(note)
).join('; ');

return <div className={InspectorStyles['commands-container']}>
<Row gutter={16} className={InspectorStyles['arg-row']}>
<Col span={24}>
<Select onChange={(commandGroupName) => selectCommandGroup(commandGroupName)} placeholder={t('Select Command Group')}>
{ _.keys(COMMAND_DEFINITIONS).map((commandGroup) => <Select.Option key={commandGroup}>{t(commandGroup)}</Select.Option>) }
</Select>
</Col>
</Row>
{selectedCommandGroup && <Row>
<Col span={24}>
<Select onChange={(commandGroupName) => selectCommandSubGroup(commandGroupName)} placeholder={t('Select Sub Group')}>
{ _.keys(COMMAND_DEFINITIONS[selectedCommandGroup]).map((commandGroup) => <Select.Option key={commandGroup}>{t(commandGroup)}</Select.Option>) }
</Select>
</Col>
</Row>}
<Row>
{selectedCommandSubGroup && _.toPairs(COMMAND_DEFINITIONS[selectedCommandGroup][selectedCommandSubGroup]).map(([commandName, command], index) => <Col key={index} span={8}>
<div className={InspectorStyles['btn-container']}>
<Button onClick={() => startPerformingCommand(commandName, command)}>{t(commandName)}</Button>
</div>
</Col>)}
</Row>
<Space className={InspectorStyles.spaceContainer} direction='vertical' size='middle'>
{t('commandsDescription')}
<Collapse>
{ _.toPairs(COMMAND_DEFINITIONS).map(([commandGroup, commands]) =>
<Collapse.Panel header={t(commandGroup)} key={commandGroup}>
<Row>
{_.toPairs(commands).map(([commandName, command], index) =>
(!automationName || !command.drivers || command.drivers.includes(_.toLower(automationName))) &&
<Col key={index} xs={12} sm={12} md={12} lg={8} xl={6} xxl={4}>
<div className={InspectorStyles['btn-container']}>
<Tooltip title={(command.notes && !command.args) ? generateCommandNotes(command.notes) : null}>
<Button onClick={() => startPerformingCommand(commandName, command)}>
{commandName}
</Button>
</Tooltip>
</div>
</Col>
)}
</Row>
</Collapse.Panel>
)}
</Collapse>
</Space>
{!!pendingCommand && <Modal
title={t(pendingCommand.commandName)}
title={`${t('Enter Parameters for:')} ${t(pendingCommand.commandName)}`}
okText={t('Execute Command')}
cancelText={t('Cancel')}
open={!!pendingCommand}
onOk={() => executeCommand()}
onCancel={() => cancelPendingCommand()}>
{pendingCommand.command.notes && <Alert
message={generateCommandNotes(pendingCommand.command.notes)}
type={ALERT.INFO}
showIcon/>
}
{
!_.isEmpty(pendingCommand.command.args) && _.map(pendingCommand.command.args, ([argName, argType], index) => <Row key={index} gutter={16}>
<Col span={24} className={InspectorStyles['arg-container']}>
Expand Down
15 changes: 4 additions & 11 deletions app/renderer/components/Inspector/ElementLocator.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ const STRAT_UIAUTOMATOR = ['-android uiautomator', 'UIAutomator'];
const STRAT_DATAMATCHER = ['-android datamatcher', 'DataMatcher'];
const STRAT_VIEWTAG = ['-android viewtag', 'View Tag'];

const locatorStrategies = (driver) => {
const automationName = driver.client.capabilities.automationName;
const locatorStrategies = (automationName) => {
let strategies = [STRAT_ID, STRAT_XPATH, STRAT_NAME, STRAT_CLASS_NAME, STRAT_ACCESSIBILITY_ID];
if (!automationName) { return strategies; }
switch (automationName.toLowerCase()) {
Expand All @@ -33,14 +32,8 @@ const locatorStrategies = (driver) => {
return strategies;
};

const showMissingAutomationNameInfo = (driver, t) => {
if (!driver.client.capabilities.automationName) {
return <Alert message={t('missingAutomationNameForStrategies')} type={ALERT.INFO} showIcon/>;
}
};

const ElementLocator = (props) => {
const { setLocatorTestValue, locatorTestValue, setLocatorTestStrategy, locatorTestStrategy, driver, t } = props;
const { setLocatorTestValue, locatorTestValue, setLocatorTestStrategy, locatorTestStrategy, automationName, t } = props;

return (
<Space className={InspectorStyles.spaceContainer} direction='vertical' size='small'>
Expand All @@ -51,7 +44,7 @@ const ElementLocator = (props) => {
defaultValue={locatorTestStrategy}
>
<Row justify="center">
{locatorStrategies(driver).map(([strategyValue, strategyName]) => (
{locatorStrategies(automationName).map(([strategyValue, strategyName]) => (
<Radio.Button
className={InspectorStyles.locatorStrategyBtn}
value={strategyValue}
Expand All @@ -63,7 +56,7 @@ const ElementLocator = (props) => {
</Row>
</Radio.Group>
</Row>
{showMissingAutomationNameInfo(driver, t)}
{!automationName && <Alert message={t('missingAutomationNameForStrategies')} type={ALERT.INFO} showIcon/>}
{t('selector')}
<Input.TextArea
className={InspectorStyles.locatorSelectorTextArea}
Expand Down
6 changes: 1 addition & 5 deletions app/renderer/components/Inspector/Inspector.css
Original file line number Diff line number Diff line change
Expand Up @@ -590,11 +590,7 @@
}

.commands-container .btn-container {
padding: 16px;
}

.commands-container .arg-row {
margin-bottom: 8px;
padding: 8px;
}

.arg-container {
Expand Down
3 changes: 1 addition & 2 deletions app/renderer/components/Inspector/LocatedElements.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@ const LocatedElements = (props) => {
const sendKeys = useRef(null);

const showIdAutocompleteInfo = () => {
const { locatorTestStrategy, locatorTestValue } = props;
const automationName = driver.client.capabilities.automationName;
const { locatorTestStrategy, locatorTestValue, automationName } = props;
const idLocatorAutocompletionDisabled = driver.client.capabilities.disableIdLocatorAutocompletion;
if (automationName && automationName.toLowerCase() === 'uiautomator2' &&
locatorTestStrategy === 'id' && !locatorTestValue.includes(':id/') && !idLocatorAutocompletionDisabled) {
Expand Down
Loading

0 comments on commit bc5be87

Please sign in to comment.