Skip to content

Commit

Permalink
Multiselect, allow users to select multiple commands with shift key
Browse files Browse the repository at this point in the history
  • Loading branch information
david califf committed Apr 8, 2019
1 parent 7125817 commit 7e133ec
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 28 deletions.
61 changes: 53 additions & 8 deletions packages/selenium-ide/src/neo/components/TestRow/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ class TestRow extends React.Component {
static propTypes = {
index: PropTypes.number,
selected: PropTypes.bool,
lastSelected: PropTypes.bool,
className: PropTypes.string,
status: PropTypes.string,
readOnly: PropTypes.bool,
Expand All @@ -133,17 +134,23 @@ class TestRow extends React.Component {
setContextMenu: PropTypes.func,
level: PropTypes.number,
scrollToLastPos: PropTypes.func,
selectCommandByRange: PropTypes.func,
}
componentDidMount() {
if (this.props.selected) {
this.node.focus()
this.props.scrollToLastPos()
this.props.setSectionFocus('editor', () => {
this.node.focus()
})
}
}
componentDidUpdate(prevProps) {
if (this.props.selected && !prevProps.selected) {
if (
this.props.selected &&
!prevProps.lastSelected &&
this.props.lastSelected
) {
this.scrollToRowIfNeeded(this.node)
this.node.focus()
this.props.setSectionFocus('editor', () => {
Expand All @@ -170,7 +177,7 @@ class TestRow extends React.Component {
noModifiers &&
(e.key === 'Delete' || e.key == 'Backspace')
) {
this.remove()
this.remove(this.props.index)
} else if (!this.props.isPristine && noModifiers && key === 'B') {
this.props.command.toggleBreakpoint()
} else if (!this.props.isPristine && noModifiers && key === 'S') {
Expand All @@ -185,13 +192,19 @@ class TestRow extends React.Component {
this.props.executeCommand(this.props.command)
} else if (this.props.moveSelection && noModifiers && e.key === 'ArrowUp') {
e.preventDefault()
if (!e.shiftKey) {
this.props.clearAllSelectedCommands()
}
this.props.moveSelection(this.props.index - 1)
} else if (
this.props.moveSelection &&
noModifiers &&
e.key === 'ArrowDown'
) {
e.preventDefault()
if (!e.shiftKey) {
this.props.clearAllSelectedCommands()
}
this.props.moveSelection(this.props.index + 1)
} else if (!this.props.isPristine && onlyPrimary && key === 'X') {
this.cut()
Expand Down Expand Up @@ -219,20 +232,46 @@ class TestRow extends React.Component {
cut() {
if (!this.props.readOnly) {
this.props.copyToClipboard(this.props.command)
this.props.remove(this.props.index, this.props.command)
this.props.remove()
}
}
paste() {
if (!this.props.readOnly) {
this.props.pasteFromClipboard(this.props.index)
}
}
select() {
select(e) {
if (
(e.type == 'contextmenu' || e.type == 'mousedown') &&
this.props.selected
) {
return
}

if (e.type == 'click' && (e.shiftKey || this.props.lastSelected)) {
if (!e.shiftKey) {
this.props.clearAllSelectedCommands()
this.props.select(this.props.command)
}
return
}

if (e && e.shiftKey === false) {
this.props.clearAllSelectedCommands()
}
if (this.props.isPristine) {
this.props.clearAllSelectedCommands()
}
if (e && e.shiftKey && !this.props.isPristine) {
this.props.selectCommandByRange(this.props.index)
}

this.props.select(this.props.command)
}
remove() {

remove(index) {
if (!this.props.readOnly) {
this.props.remove(this.props.index, this.props.command)
this.props.remove(index)
}
}
async clearAll() {
Expand Down Expand Up @@ -278,7 +317,12 @@ class TestRow extends React.Component {
>
Paste
</ListMenuItem>
<ListMenuItem label="Del" onClick={this.remove}>
<ListMenuItem
label="Del"
onClick={() => {
this.remove(this.props.index)
}}
>
Delete
</ListMenuItem>
<ListMenuSeparator />
Expand Down Expand Up @@ -363,13 +407,14 @@ class TestRow extends React.Component {
: null
}
onClick={this.select}
onFocus={this.select}
onMouseDown={this.select}
onDoubleClick={() => {
this.props.executeCommand && this.props.singleCommandExecutionEnabled
? this.props.executeCommand(this.props.command)
: undefined
}}
onKeyDown={this.handleKeyDown.bind(this)}
onFocus={this.select}
style={{
opacity: this.props.isDragging ? '0' : '1',
}}
Expand Down
36 changes: 33 additions & 3 deletions packages/selenium-ide/src/neo/components/TestTable/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,19 @@ export default class TestTable extends React.Component {
)
this.commandLevels = []
this.node = null
this.selectCommandByRange = this.selectCommandByRange.bind(this)
}
static propTypes = {
commands: MobxPropTypes.arrayOrObservableArray,
callstackIndex: PropTypes.number,
selectedCommand: PropTypes.string,
selectedCommands: MobxPropTypes.arrayOrObservableArray,
selectCommand: PropTypes.func,
addCommand: PropTypes.func,
removeCommand: PropTypes.func,
removeSelectedCommands: PropTypes.func,
swapCommands: PropTypes.func,
clearAllCommands: PropTypes.func,
clearAllSelectedCommand: PropTypes.func,
}
detectNewCommand(change) {
this.newCommand = change.added[0]
Expand All @@ -77,6 +80,20 @@ export default class TestTable extends React.Component {
}
}
}
selectCommandByRange(index) {
if (this.props.selectedCommands.length > 0) {
let fromIndex = this.props.commands.indexOf(
this.props.selectedCommands[0]
)
fromIndex = fromIndex == -1 ? index : fromIndex
const toIndex = index
const from = fromIndex > toIndex ? toIndex : fromIndex
const to = fromIndex > toIndex ? fromIndex : toIndex
for (let i = from; i <= to; i++) {
UiState.addToSelectedCommands(this.props.commands[i])
}
}
}
handleScroll() {
UiState.selectedTest.test.scrollY = this.node.scrollTop
}
Expand Down Expand Up @@ -130,7 +147,13 @@ export default class TestTable extends React.Component {
).state
: ''
)}
selected={this.props.selectedCommand === command.id}
selected={
this.props.selectedCommand === command.id ||
!!this.props.selectedCommands.find(
cmd => cmd.id === command.id
)
}
lastSelected={this.props.selectedCommand === command.id}
readOnly={PlaybackState.isPlaying}
singleCommandExecutionEnabled={
PlaybackState.isSingleCommandExecutionEnabled
Expand All @@ -145,15 +168,19 @@ export default class TestTable extends React.Component {
scrollToLastPos={this.scrollToLastPos}
isPristine={false}
select={this.props.selectCommand}
selectCommandByRange={this.selectCommandByRange}
startPlayingHere={PlaybackState.startPlaying}
executeCommand={PlaybackState.playCommand}
moveSelection={UiState.selectCommandByIndex}
addCommand={this.props.addCommand}
remove={this.props.removeCommand}
remove={this.props.removeSelectedCommands}
swapCommands={this.props.swapCommands}
copyToClipboard={UiState.copyToClipboard}
pasteFromClipboard={UiState.pasteFromClipboard}
clearAllCommands={this.props.clearAllCommands}
clearAllSelectedCommands={
this.props.clearAllSelectedCommands
}
setSectionFocus={UiState.setSectionFocus}
level={this.commandLevels[index]}
/>
Expand All @@ -174,6 +201,9 @@ export default class TestTable extends React.Component {
moveSelection={UiState.selectCommandByIndex}
pasteFromClipboard={UiState.pasteFromClipboard}
setSectionFocus={UiState.setSectionFocus}
clearAllSelectedCommands={
this.props.clearAllSelectedCommands
}
/>
)
: null}
Expand Down
27 changes: 15 additions & 12 deletions packages/selenium-ide/src/neo/containers/Editor/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ export default class Editor extends React.Component {
constructor(props) {
super(props)
this.addCommand = this.addCommand.bind(this)
this.removeCommand = this.removeCommand.bind(this)
this.removeSelectedCommands = this.removeSelectedCommands.bind(this)
}
addCommand(index, command) {
if (command) {
Expand All @@ -50,17 +50,18 @@ export default class Editor extends React.Component {
return newCommand
}
}
removeCommand(index, command) {
removeSelectedCommands(index) {
const { test } = this.props
test.removeCommand(command)
if (UiState.selectedCommand === command) {
if (test.commands.length > index) {
UiState.selectCommand(test.commands[index])
} else if (test.commands.length) {
UiState.selectCommand(test.commands[test.commands.length - 1])
} else {
UiState.selectCommand(UiState.pristineCommand)
}
index = index - (UiState.selectedCommands.length - 1)
index = Math.max(index, 0)
UiState.selectedCommands.forEach(command => test.removeCommand(command))
UiState.clearAllSelectedCommands()
if (test.commands.length > index) {
UiState.selectCommand(test.commands[index])
} else if (test.commands.length) {
UiState.selectCommand(test.commands[test.commands.length - 1])
} else {
UiState.selectCommand(UiState.pristineCommand)
}
}
handleKeyDown(event) {
Expand Down Expand Up @@ -94,12 +95,14 @@ export default class Editor extends React.Component {
selectedCommand={
UiState.selectedCommand ? UiState.selectedCommand.id : null
}
selectedCommands={UiState.selectedCommands}
selectCommand={UiState.selectCommand}
addCommand={this.addCommand}
removeCommand={this.removeCommand}
removeSelectedCommands={this.removeSelectedCommands}
clearAllCommands={
this.props.test ? this.props.test.clearAllCommands : null
}
clearAllSelectedCommands={UiState.clearAllSelectedCommands}
swapCommands={this.props.test ? this.props.test.swapCommands : null}
/>
<CommandForm
Expand Down
2 changes: 2 additions & 0 deletions packages/selenium-ide/src/neo/models/TestCase.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ export default class TestCase {
@observable
selectedCommand = null
@observable
selectedCommands = []
@observable
scrollY = null

constructor(id = uuidv4(), name = 'Untitled Test') {
Expand Down
58 changes: 53 additions & 5 deletions packages/selenium-ide/src/neo/stores/view/UiState.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class UiState {
@observable
selectedCommand = null
@observable
selectedCommands = []
@observable
filterTerm = ''
@observable
clipboard = null
Expand Down Expand Up @@ -168,15 +170,22 @@ class UiState {
}
@action.bound
copyToClipboard(item) {
this.clipboard = item
copyToClipboard() {
// sorting by index
this.clipboard = this.selectedCommands.sort((c1, c2) => {
let c1Index = this.displayedTest.commands.indexOf(c1)
let c2Index = this.displayedTest.commands.indexOf(c2)
return c1Index - c2Index
})
}
@action.bound
pasteFromClipboard(index) {
if (this.clipboard && this.displayedTest) {
const newCommand = this.clipboard.clone()
this.displayedTest.insertCommandAt(newCommand, index)
if (this.clipboard.length && this.displayedTest) {
this.clipboard.forEach((command, idx) => {
const newCommand = command.clone()
this.displayedTest.insertCommandAt(newCommand, index + idx + 1)
})
}
}
Expand All @@ -200,11 +209,18 @@ class UiState {
_test &&
(_test !== this.displayedTest || suite !== this.selectedTest.suite)
) {
if (this.selectedTest.test) {
this.selectedTest.test.selectedCommands = this.selectedCommands.slice(
0
)
}
this.selectedCommands.clear()
this.selectedTest = {
test,
suite,
stack: stack >= 0 ? stack : undefined,
}
this.selectedCommands = this.selectedTest.test.selectedCommands.slice(0)
if (PlaybackState.isPlaying && !PlaybackState.paused) {
this.selectCommand(undefined)
} else if (_test && _test.commands.length) {
Expand Down Expand Up @@ -295,6 +311,7 @@ class UiState {
if (this.selectedTest.test) {
this.selectedTest.test.selectedCommand = command
this.selectedCommand = command
this.addToSelectedCommands(command)
} else {
this.selectedCommand = undefined
}
Expand All @@ -307,10 +324,41 @@ class UiState {
if (index >= 0 && index < test.commands.length) {
this.selectCommand(test.commands[index], opts)
} else if (index === test.commands.length) {
this.clearAllSelectedCommands()
this.selectCommand(this.pristineCommand, opts)
}
}
@action.bound
clearAllSelectedCommands() {
if (this.selectedTest.test) {
this.selectedTest.test.selectedCommand = undefined
this.selectedTest.test.selectedCommands.clear()
this.selectedCommands.clear()
this.selectedCommand = undefined
} else {
this.selectedCommand = undefined
this.selectedCommands.clear()
}
}
@action.bound
addToSelectedCommands(command) {
if (!PlaybackState.isPlaying || PlaybackState.paused) {
if (command) {
if (
this.selectTest &&
this.selectedTest.test.commands.find(c => c === command)
) {
if (
this.selectedCommands.findIndex(c => c.id === command.id) === -1
) {
this.selectedCommands.push(command)
}
}
}
}
}
@action.bound
selectNextCommand(opts = { from: undefined, isCommandTarget: false }) {
this.selectCommandByIndex(this.nextCommandIndex(opts.from), opts)
Expand Down

0 comments on commit 7e133ec

Please sign in to comment.