Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit b0b95cf

Browse files
myan9starpit
authored andcommitted
feat: execute the command in url query when the browser app is loaded
Fixes #5879
1 parent 10e40a9 commit b0b95cf

File tree

5 files changed

+85
-58
lines changed

5 files changed

+85
-58
lines changed

packages/core/src/webapp/bootstrap/boot.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ const domReady = (inSandbox: boolean, client?: Client) => async () => {
3737
const initializer = import('./init')
3838
const plugins = import('../../plugins/plugins')
3939
const events = import('../../core/events')
40-
// const query = import('../query')
4140

4241
try {
4342
const waitForThese: Promise<void>[] = []

packages/core/src/webapp/query.ts

Lines changed: 0 additions & 45 deletions
This file was deleted.

packages/test/src/api/common.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,11 @@ export const remoteIt = (msg: string, func: Func) => {
499499
if (process.env.MOCHA_RUN_TARGET === 'webpack') return it(msg, func)
500500
}
501501

502+
/** only execute the test suite in proxy+browser clients */
503+
export const proxyDescribe = (msg: string, suite: (this: Suite) => void) => {
504+
if (process.env.MOCHA_RUN_TARGET === 'webpack' && process.env.KUI_USE_PROXY === 'true') return describe(msg, suite)
505+
}
506+
502507
/** only execute the test suite in electron or proxy+browser clients */
503508
export const pDescribe = (msg: string, suite: (this: Suite) => void) => {
504509
if (process.env.MOCHA_RUN_TARGET !== 'webpack' || process.env.KUI_USE_PROXY === 'true') return describe(msg, suite)

plugins/plugin-client-common/src/components/Client/Kui.tsx

Lines changed: 40 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,17 @@ export type Props = Partial<KuiConfiguration> & {
6666
/** If in popup mode, execute the given command line */
6767
commandLine?: string[]
6868

69+
/** do not echo the command? */
70+
quietExecCommand?: boolean
71+
6972
/** initial tab title */
7073
initialTabTitle?: string
7174
}
7275

7376
type State = KuiConfiguration & {
7477
isBootstrapped: boolean
78+
commandLine?: string[]
79+
quietExecCommand?: boolean
7580
}
7681

7782
/**
@@ -112,17 +117,39 @@ export class Kui extends React.PureComponent<Props, State> {
112117
})
113118
}
114119

120+
let commandLine = this.props.commandLine
121+
let quietExecCommand = this.props.quietExecCommand !== undefined ? this.props.quietExecCommand : !this.props.isPopup
122+
123+
if (inBrowser()) {
124+
const windowQuery = window.location.search
125+
if (windowQuery) {
126+
// parse and extract the question mark in window.location.search
127+
// e.g. query = { command: 'replay /kui/welcome.json' }
128+
const query = require('querystring').parse(windowQuery.substring(1))
129+
130+
// To avoid SQL injection attacks, users can only query with `replay` command
131+
if (query.command && /^replay/.test(query.command)) {
132+
commandLine = query.command.split(' ')
133+
quietExecCommand = false
134+
}
135+
}
136+
}
137+
115138
try {
116139
this.state = Object.assign({}, this.defaultSessionBehavior(), this.defaultFeatureFlag(), props, {
117-
isBootstrapped: !!props.noBootstrap
140+
isBootstrapped: !!props.noBootstrap,
141+
commandLine,
142+
quietExecCommand
118143
})
119144
debug('initial state:inBrowser?', inBrowser())
120145
debug('initial state:given properties', props)
121146
debug('initial state:final value', this.state)
122147
} catch (err) {
123148
console.log('using default configuration')
124149
this.state = {
125-
isBootstrapped: !!props.noBootstrap
150+
isBootstrapped: !!props.noBootstrap,
151+
commandLine,
152+
quietExecCommand
126153
}
127154
}
128155
}
@@ -220,8 +247,8 @@ export class Kui extends React.PureComponent<Props, State> {
220247
*
221248
*/
222249
private statusStripeProps(): StatusStripeProps {
223-
if (this.props.commandLine) {
224-
const statusStripeIdx = this.props.commandLine.findIndex(_ => _ === '--status-stripe')
250+
if (this.state.commandLine) {
251+
const statusStripeIdx = this.state.commandLine.findIndex(_ => _ === '--status-stripe')
225252
if (statusStripeIdx >= 0) {
226253
return { type: this.props.commandLine[statusStripeIdx + 1] as StatusStripeProps['type'] }
227254
}
@@ -234,13 +261,14 @@ export class Kui extends React.PureComponent<Props, State> {
234261

235262
private firstTab = true
236263
private onTabReady() {
237-
if (this.props.commandLine && this.firstTab) {
264+
if (this.state.commandLine && this.firstTab) {
238265
this.firstTab = false
239266

240-
// do not echo the command?
241-
const quiet = !this.props.isPopup
242-
243-
pexecInCurrentTab(this.props.commandLine.map(_ => encodeComponent(_)).join(' '), undefined, quiet)
267+
pexecInCurrentTab(
268+
this.state.commandLine.map(_ => encodeComponent(_)).join(' '),
269+
undefined,
270+
this.state.quietExecCommand
271+
)
244272
}
245273
}
246274

@@ -251,11 +279,11 @@ export class Kui extends React.PureComponent<Props, State> {
251279
return <Loading />
252280
}
253281

254-
if (this.props.isPopup && this.props.commandLine) {
282+
if (this.props.isPopup && this.state.commandLine) {
255283
return (
256284
<KuiContext.Provider value={this.state}>
257285
<React.Suspense fallback={<div />}>
258-
<Popup commandLine={this.props.commandLine}>{this.props.children}</Popup>
286+
<Popup commandLine={this.state.commandLine}>{this.props.children}</Popup>
259287
</React.Suspense>
260288
</KuiContext.Provider>
261289
)
@@ -268,7 +296,7 @@ export class Kui extends React.PureComponent<Props, State> {
268296
noActiveInput={!!this.props.bottomInput}
269297
bottom={bottom}
270298
title={this.props.initialTabTitle}
271-
onTabReady={this.props.commandLine && this._onTabReady}
299+
onTabReady={this.state.commandLine && this._onTabReady}
272300
>
273301
<ComboSidecar />
274302
</TabContainer>

plugins/plugin-core-support/src/test/core-support/replay.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,3 +209,43 @@ describe(`split-snapshot-replay ${process.env.MOCHA_RUN_TARGET || ''}`, async fu
209209
}
210210
})
211211
})
212+
213+
Common.proxyDescribe(`core snapshot and replay by query ${process.env.MOCHA_RUN_TARGET || ''}`, function(
214+
this: Common.ISuite
215+
) {
216+
before(Common.before(this))
217+
after(Common.after(this))
218+
219+
it(`should base64 ${base64Input}`, () =>
220+
CLI.command(`base64 ${base64Input}`, this.app)
221+
.then(ReplExpect.okWithString(base64Output))
222+
.catch(Common.oops(this, true)))
223+
224+
it('should snapshot', () =>
225+
CLI.command('snapshot /tmp/test.kui', this.app)
226+
.then(ReplExpect.justOK)
227+
.catch(Common.oops(this, true)))
228+
229+
it('should refresh', () => Common.refresh(this))
230+
231+
it('should replay by query', async () => {
232+
try {
233+
await this.app.client.url(`${process.env.WEBPACK_CLIENT_URL}?command=replay /tmp/test.kui`)
234+
235+
// verify the base64 command replay
236+
let idx = 0
237+
await this.app.client.waitUntil(async () => {
238+
const txt = await this.app.client.getText(Selectors.OUTPUT_LAST)
239+
if (++idx > 5) {
240+
console.error(`still waiting for expected=${base64Output}; actual=${txt}`)
241+
}
242+
return txt === base64Output
243+
}, CLI.waitTimeout)
244+
245+
// back to the original url, without this line, the following tests will fail at `before` state
246+
await this.app.client.url(process.env.WEBPACK_CLIENT_URL)
247+
} catch (err) {
248+
await Common.oops(this, true)(err)
249+
}
250+
})
251+
})

0 commit comments

Comments
 (0)