Skip to content

Commit 172cf41

Browse files
author
Emil Andersson
committed
Autorun deeplinked play commands
1 parent 726f20f commit 172cf41

File tree

12 files changed

+135
-22
lines changed

12 files changed

+135
-22
lines changed

src/browser/modules/App/App.jsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {
4343
getActiveConnectionData,
4444
isConnected,
4545
getConnectionData,
46+
INITIAL_SWITCH_CONNECTION_FAILED,
4647
SWITCH_CONNECTION_FAILED,
4748
SWITCH_CONNECTION,
4849
SILENT_DISCONNECT,
@@ -140,7 +141,7 @@ export function App(props) {
140141
onMount={(...args) => {
141142
buildConnectionCreds(...args, { defaultConnectionData })
142143
.then(creds => props.bus.send(INJECTED_DISCOVERY, creds))
143-
.catch(() => props.bus.send(SWITCH_CONNECTION_FAILED))
144+
.catch(() => props.bus.send(INITIAL_SWITCH_CONNECTION_FAILED))
144145
getDesktopTheme(...args)
145146
.then(theme => setEnvironmentTheme(theme))
146147
.catch(setEnvironmentTheme(null))

src/browser/modules/Stream/Auth/ConnectionForm.jsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,10 @@ import {
2929
CONNECT,
3030
VERIFY_CREDENTIALS
3131
} from 'shared/modules/connections/connectionsDuck'
32-
import { getInitCmd } from 'shared/modules/settings/settingsDuck'
32+
import {
33+
getInitCmd,
34+
getPlayImplicitInitCommands
35+
} from 'shared/modules/settings/settingsDuck'
3336
import { executeSystemCommand } from 'shared/modules/commands/commandsDuck'
3437
import { shouldRetainConnectionCredentials } from 'shared/modules/dbMeta/dbMetaDuck'
3538
import { FORCE_CHANGE_PASSWORD } from 'shared/modules/cypher/cypherDuck'
@@ -196,7 +199,9 @@ export class ConnectionForm extends Component {
196199
this.state.successCallback()
197200
this.saveCredentials()
198201
this.props.setActiveConnection(this.state.id)
199-
this.props.executeInitCmd()
202+
if (this.props.playImplicitInitCommands) {
203+
this.props.executeInitCmd()
204+
}
200205
}
201206

202207
saveCredentials() {
@@ -277,6 +282,7 @@ const mapStateToProps = state => {
277282
initCmd: getInitCmd(state),
278283
activeConnection: getActiveConnection(state),
279284
activeConnectionData: getActiveConnectionData(state),
285+
playImplicitInitCommands: getPlayImplicitInitCommands(state),
280286
storeCredentials: shouldRetainConnectionCredentials(state)
281287
}
282288
}
@@ -293,6 +299,7 @@ const mapDispatchToProps = dispatch => {
293299

294300
const mergeProps = (stateProps, dispatchProps, ownProps) => {
295301
return {
302+
playImplicitInitCommands: stateProps.playImplicitInitCommands,
296303
activeConnection: stateProps.activeConnection,
297304
activeConnectionData: stateProps.activeConnectionData,
298305
storeCredentials: stateProps.storeCredentials,

src/shared/modules/commands/commandsDuck.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ import { addHistory } from '../history/historyDuck'
3838
import {
3939
getCmdChar,
4040
getMaxHistory,
41+
getPlayImplicitInitCommands,
4142
shouldEnableMultiStatementMode
4243
} from '../settings/settingsDuck'
4344
import { fetchRemoteGuide } from './helpers/play'
@@ -257,7 +258,10 @@ export const postConnectCmdEpic = (some$, store) =>
257258
const cmds = extractPostConnectCommandsFromServerConfig(
258259
serverSettings['browser.post_connect_cmd']
259260
)
260-
if (cmds !== undefined) {
261+
const playImplicitInitCommands = getPlayImplicitInitCommands(
262+
store.getState()
263+
)
264+
if (playImplicitInitCommands && cmds !== undefined) {
261265
cmds.forEach(cmd => {
262266
store.dispatch(executeSystemCommand(`${cmdchar}${cmd}`))
263267
})

src/shared/modules/commands/postConnectCmdEpic.test.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ describe('postConnectCmdEpic', () => {
4040
const command = 'play hello'
4141
const store = mockStoreLocal({
4242
settings: {
43-
cmdchar: ':'
43+
cmdchar: ':',
44+
playImplicitInitCommands: true
4445
},
4546
meta: {
4647
settings: {
@@ -80,7 +81,8 @@ describe('postConnectCmdEpic', () => {
8081
])
8182
const store = mockStoreLocal({
8283
settings: {
83-
cmdchar: ':'
84+
cmdchar: ':',
85+
playImplicitInitCommands: true
8486
},
8587
meta: {
8688
settings: {

src/shared/modules/connections/connectionsDuck.js

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
import { executeSystemCommand } from 'shared/modules/commands/commandsDuck'
3030
import {
3131
getInitCmd,
32+
getPlayImplicitInitCommands,
3233
getSettings,
3334
getCmdChar,
3435
getConnectionTimeout
@@ -56,6 +57,8 @@ export const UPDATE_AUTH_ENABLED = NAME + '/UPDATE_AUTH_ENABLED'
5657
export const SWITCH_CONNECTION = NAME + '/SWITCH_CONNECTION'
5758
export const SWITCH_CONNECTION_SUCCESS = NAME + '/SWITCH_CONNECTION_SUCCESS'
5859
export const SWITCH_CONNECTION_FAILED = NAME + '/SWITCH_CONNECTION_FAILED'
60+
export const INITIAL_SWITCH_CONNECTION_FAILED =
61+
NAME + '/INITIAL_SWITCH_CONNECTION_FAILED'
5962
export const VERIFY_CREDENTIALS = NAME + '/VERIFY_CREDENTIALS'
6063
export const USE_DB = NAME + '/USE_DB'
6164

@@ -429,19 +432,27 @@ export const startupConnectEpic = (action$, store) => {
429432
export const startupConnectionSuccessEpic = (action$, store) => {
430433
return action$
431434
.ofType(STARTUP_CONNECTION_SUCCESS)
432-
.do(() =>
433-
store.dispatch(
434-
executeSystemCommand(getCmdChar(store.getState()) + 'server status')
435-
)
436-
)
437-
.mapTo(executeSystemCommand(getInitCmd(store.getState()))) // execute initCmd from settings
435+
.do(() => {
436+
if (getPlayImplicitInitCommands(store.getState())) {
437+
store.dispatch(
438+
executeSystemCommand(getCmdChar(store.getState()) + 'server status')
439+
)
440+
store.dispatch(executeSystemCommand(getInitCmd(store.getState())))
441+
}
442+
})
443+
.mapTo({ type: 'NOOP' })
438444
}
439445
export const startupConnectionFailEpic = (action$, store) => {
440446
return action$
441447
.ofType(STARTUP_CONNECTION_FAILED)
442-
.mapTo(
443-
executeSystemCommand(getCmdChar(store.getState()) + 'server connect')
444-
)
448+
.do(() => {
449+
if (getPlayImplicitInitCommands(store.getState())) {
450+
store.dispatch(
451+
executeSystemCommand(getCmdChar(store.getState()) + 'server connect')
452+
)
453+
}
454+
})
455+
.mapTo({ type: 'NOOP' })
445456
}
446457

447458
let lastActiveConnectionId = null
@@ -624,6 +635,21 @@ export const switchConnectionFailEpic = (action$, store) => {
624635
executeSystemCommand(getCmdChar(store.getState()) + 'server switch fail')
625636
)
626637
}
638+
export const initialSwitchConnectionFailEpic = (action$, store) => {
639+
return action$
640+
.ofType(INITIAL_SWITCH_CONNECTION_FAILED)
641+
.do(() => {
642+
store.dispatch(updateConnectionState(DISCONNECTED_STATE))
643+
if (getPlayImplicitInitCommands(store.getState())) {
644+
store.dispatch(
645+
executeSystemCommand(
646+
getCmdChar(store.getState()) + 'server switch fail'
647+
)
648+
)
649+
}
650+
})
651+
.mapTo({ type: 'NOOP' })
652+
}
627653

628654
export const retainCredentialsSettingsEpic = (action$, store) => {
629655
return action$

src/shared/modules/editor/editorDuck.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@
2020

2121
import Rx from 'rxjs/Rx'
2222
import { getUrlParamValue } from 'services/utils'
23-
import { getSettings } from 'shared/modules/settings/settingsDuck'
23+
import {
24+
getSettings,
25+
DISABLE_IMPLICIT_INIT_COMMANDS
26+
} from 'shared/modules/settings/settingsDuck'
2427
import { APP_START, URL_ARGUMENTS_CHANGE } from 'shared/modules/app/appDuck'
28+
import { executeCommand } from 'shared/modules/commands/commandsDuck'
2529

2630
const NAME = 'editor'
2731
export const SET_CONTENT = NAME + '/SET_CONTENT'
@@ -83,6 +87,15 @@ export const populateEditorFromUrlEpic = (some$, store) => {
8387
) || []
8488
const fullCommand = validCommandTypes[commandType](cmdchar, cmdArgs)
8589

90+
// Play command is considered safe and can run automatically
91+
// When running the explicit command, also set flag to skip any implicit init commands
92+
if (commandType === 'play') {
93+
return [
94+
executeCommand(fullCommand),
95+
{ type: DISABLE_IMPLICIT_INIT_COMMANDS }
96+
]
97+
}
98+
8699
return Rx.Observable.of({ type: SET_CONTENT, ...setContent(fullCommand) })
87100
})
88101
}

src/shared/modules/editor/editorDuck.test.js

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import {
2727
NOT_SUPPORTED_URL_PARAM_COMMAND
2828
} from './editorDuck'
2929
import { APP_START, URL_ARGUMENTS_CHANGE } from '../app/appDuck'
30+
import { COMMAND_QUEUED, executeCommand } from '../commands/commandsDuck'
3031

3132
describe('editorDuck Epics', () => {
3233
let store
@@ -47,19 +48,39 @@ describe('editorDuck Epics', () => {
4748
bus.reset()
4849
store.clearActions()
4950
})
50-
test('Sends a SET_CONTENT event on initial url arguments', done => {
51+
test('Sends a COMMAND_QUEUED event if cmd is "play"', done => {
5152
const cmd = 'play'
5253
const arg = 'test-guide'
5354
const action = {
5455
type: APP_START,
5556
url: `http://url.com?cmd=${cmd}&arg=${arg}`
5657
}
5758

59+
bus.take(COMMAND_QUEUED, () => {
60+
// Then
61+
expect(store.getActions()).toEqual([
62+
action,
63+
executeCommand(`:${cmd} ${arg}`)
64+
])
65+
done()
66+
})
67+
68+
// When
69+
store.dispatch(action)
70+
})
71+
test('Sends a SET_CONTENT event on initial url arguments', done => {
72+
const cmd = 'edit'
73+
const arg = 'RETURN 1'
74+
const action = {
75+
type: APP_START,
76+
url: `http://url.com?cmd=${cmd}&arg=${arg}`
77+
}
78+
5879
bus.take(SET_CONTENT, currentAction => {
5980
// Then
6081
expect(store.getActions()).toEqual([
6182
action,
62-
{ type: SET_CONTENT, message: `:${cmd} ${arg}` }
83+
{ type: SET_CONTENT, message: arg }
6384
])
6485
done()
6586
})
@@ -68,8 +89,8 @@ describe('editorDuck Epics', () => {
6889
store.dispatch(action)
6990
})
7091
test('Sends a SET_CONTENT event on url arguments change', done => {
71-
const cmd = 'play'
72-
const arg = 'test-guide'
92+
const cmd = 'edit'
93+
const arg = 'RETURN 1'
7394
const action = {
7495
type: URL_ARGUMENTS_CHANGE,
7596
url: `?cmd=${cmd}&arg=${arg}`
@@ -79,7 +100,7 @@ describe('editorDuck Epics', () => {
79100
// Then
80101
expect(store.getActions()).toEqual([
81102
action,
82-
{ type: SET_CONTENT, message: `:${cmd} ${arg}` }
103+
{ type: SET_CONTENT, message: arg }
83104
])
84105
done()
85106
})

src/shared/modules/settings/__snapshots__/settingsDuck.test.js.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Object {
1717
"maxNeighbours": 100,
1818
"maxRows": 1000,
1919
"new": "conf",
20+
"playImplicitInitCommands": true,
2021
"scrollToTop": true,
2122
"shouldReportUdc": true,
2223
"showSampleScripts": true,

src/shared/modules/settings/settingsDuck.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ import { APP_START, USER_CLEAR } from 'shared/modules/app/appDuck'
2323
export const NAME = 'settings'
2424
export const UPDATE = 'settings/UPDATE'
2525
export const REPLACE = 'settings/REPLACE'
26+
export const DISABLE_IMPLICIT_INIT_COMMANDS =
27+
'settings/DISABLE_IMPLICIT_INIT_COMMANDS'
2628

2729
export const AUTO_THEME = 'auto'
2830
export const LIGHT_THEME = 'normal'
@@ -35,6 +37,8 @@ export const getSettings = state => state[NAME]
3537
export const getMaxHistory = state =>
3638
state[NAME].maxHistory || initialState.maxHistory
3739
export const getInitCmd = state => (state[NAME].initCmd || '').trim()
40+
export const getPlayImplicitInitCommands = state =>
41+
state[NAME].playImplicitInitCommands
3842
export const getTheme = state => state[NAME].theme || initialState.theme
3943
export const getUseBoltRouting = state =>
4044
state[NAME].useBoltRouting || initialState.useBoltRouting
@@ -79,6 +83,7 @@ const initialState = {
7983
maxHistory: 30,
8084
theme: AUTO_THEME,
8185
initCmd: ':play start',
86+
playImplicitInitCommands: true,
8287
initialNodeDisplay: 300,
8388
maxNeighbours: 100,
8489
showSampleScripts: true,
@@ -108,6 +113,8 @@ export default function settings(state = initialState, action) {
108113
return Object.assign({}, { ...initialState }, action.state)
109114
case USER_CLEAR:
110115
return initialState
116+
case DISABLE_IMPLICIT_INIT_COMMANDS:
117+
return { ...state, playImplicitInitCommands: false }
111118
default:
112119
return state
113120
}

src/shared/modules/settings/settingsDuck.test.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
*/
2020

2121
import reducer, {
22+
DISABLE_IMPLICIT_INIT_COMMANDS,
2223
NAME,
2324
UPDATE,
2425
REPLACE,
@@ -71,6 +72,18 @@ describe('settings reducer', () => {
7172
expect(nextState.type).toBeUndefined()
7273
expect(nextState).toMatchSnapshot()
7374
})
75+
76+
it('defaults playImplicitInitCommands to true', () => {
77+
expect(reducer(undefined, { type: 'dummy action' })).toEqual(
78+
expect.objectContaining({ playImplicitInitCommands: true })
79+
)
80+
})
81+
82+
it('sets playImplicitInitCommands to false on DISABLE_IMPLICIT_INIT_COMMANDS', () => {
83+
expect(
84+
reducer(undefined, { type: DISABLE_IMPLICIT_INIT_COMMANDS })
85+
).toEqual(expect.objectContaining({ playImplicitInitCommands: false }))
86+
})
7487
})
7588

7689
describe('Selectors', () => {

0 commit comments

Comments
 (0)