Skip to content
This repository was archived by the owner on Dec 17, 2024. It is now read-only.

Commit 6ef6443

Browse files
committed
add unlock mode button to action create/update
Fixes #680
1 parent 62246d5 commit 6ef6443

File tree

6 files changed

+106
-88
lines changed

6 files changed

+106
-88
lines changed

.travis.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ jobs:
5656
env: EXECUTING=01:08:02:05
5757
- script: (cd tests && ./bin/runLocal.sh 07)
5858
env: EXECUTING=07
59-
- script: (cd tests && ./bin/runLocal.sh 02 03)
60-
env: EXECUTING=02:03
59+
- script: (cd tests && ./bin/runLocal.sh 03)
60+
env: EXECUTING=03
6161
- script: (cd tests && ./bin/runLocal.sh 04)
6262
env: EXECUTING=04

app/content/js/repl.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ const unflag = opt => opt.replace(/^[-]+/,'')
523523
*/
524524
self.exec = (commandUntrimmed, execOptions) => {
525525
//debug(`repl::exec ${new Date()}`)
526+
debug('exec', commandUntrimmed)
526527

527528
const echo = !execOptions || execOptions.echo !== false
528529
const nested = execOptions && execOptions.noHistory

app/plugins/openwhisk-extensions/actions/let.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -626,13 +626,10 @@ module.exports = (commandTree, prequire) => {
626626
(annotators[letType] || []).forEach(annotator => annotator(action))
627627
if (annotators[extension]) annotators[extension].forEach(annotator => annotator(action))
628628

629-
const owOpts = wsk.owOpts({ name: name, action: action })
630-
debug('inline-function::create', owOpts, code)
631-
return preflight(update, owOpts)
632-
.then(owOpts => wsk.ow.actions[update](owOpts)) // dangit, the openwhisk npm uses classes, so we have to do this
633-
.then(wsk.addPrettyType('actions', 'create'))
634-
.then(action => execOptions && execOptions.nested ? action : commandTree.changeContext(`/wsk/actions`, action.name)(action))
629+
debug('inline-function::create', name)
630+
return repl.qexec(`wsk action update "${name}"`, undefined, undefined, { entity: { action } })
635631
.catch(packageAutoCreate(name))
632+
636633
} else {
637634
// maybe a sequence?
638635
debug('sequenceMatch', sequenceMatch, components)

app/plugins/ui/commands/openwhisk-core.js

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -486,26 +486,30 @@ const specials = {}
486486

487487
/** for parametrizable entity types, e.g. actions, packages, the standard view modes */
488488
const standardViewModes = (defaultMode, fn) => {
489-
let modes = [{ mode: 'parameters', label: 'params', command: () => 'parameters' },
490-
{ mode: 'annotations', command: () => 'annotations' },
491-
{ mode: 'raw', command: () => 'raw' }]
492-
493-
if (defaultMode) {
494-
if (!Array.isArray(defaultMode)) {
495-
if (!modes.find(_ => _.mode === defaultMode)) {
496-
// only add the defaultMode if it isn't already in the list
497-
const mode = defaultMode.mode || defaultMode
498-
modes.splice(0, 0, { mode, defaultMode: typeof mode === 'string' || mode.default, command: () => mode })
489+
const makeModes = () => {
490+
let modes = [{ mode: 'parameters', label: 'params', command: () => 'parameters' },
491+
{ mode: 'annotations', command: () => 'annotations' },
492+
{ mode: 'raw', command: () => 'raw' }]
493+
494+
if (defaultMode) {
495+
if (!Array.isArray(defaultMode)) {
496+
if (!modes.find(_ => _.mode === defaultMode)) {
497+
// only add the defaultMode if it isn't already in the list
498+
const mode = defaultMode.mode || defaultMode
499+
modes.splice(0, 0, { mode, defaultMode: typeof mode === 'string' || mode.default, command: () => mode })
500+
}
501+
} else {
502+
modes = defaultMode.concat(modes)
499503
}
500-
} else {
501-
modes = defaultMode.concat(modes)
502504
}
505+
506+
return modes
503507
}
504508

505509
if (fn) {
506-
return (options, argv, verb) => Object.assign(fn(options, argv, verb) || {}, { modes: entity => modes })
510+
return (options, argv, verb) => Object.assign(fn(options, argv, verb) || {}, { modes: entity => makeModes() })
507511
} else {
508-
return (options, argv) => ({ modes: entity => modes })
512+
return (options, argv) => ({ modes: entity => makeModes() })
509513
}
510514
}
511515

@@ -774,7 +778,7 @@ const executor = (_entity, _verb, verbSynonym, commandTree, preflight) => (block
774778
let options = Object.assign({}, regularOptions, pair.kvOptions)
775779
delete options._
776780

777-
debug('exec', entity, verb, argv, options)
781+
debug('exec', entity, verb, argv, options, execOptions)
778782

779783
const verbIndex = argv.findIndex(arg => arg === verbSynonym),
780784
nameIndex = verbIndex + 1,
@@ -846,6 +850,13 @@ const executor = (_entity, _verb, verbSynonym, commandTree, preflight) => (block
846850
}
847851
}*/
848852

853+
const kind = toOpenWhiskKind(entity)
854+
if (execOptions && execOptions.entity && execOptions.entity[kind]) {
855+
// passing entity options programatically rather than via the command line
856+
options[kind] = Object.assign({}, options[entity]||{}, execOptions.entity[kind])
857+
debug('programmatic entity', execOptions.entity[kind], options[entity])
858+
}
859+
849860
if (!options.then) options = Promise.resolve(options)
850861

851862
return options.then(options => {
@@ -1049,11 +1060,10 @@ module.exports = (commandTree, prequire) => {
10491060
}
10501061
},
10511062

1052-
/** add action modes */
1063+
/** add action modes; where=push|unshift */
10531064
addActionMode: (mode, where='push') => {
10541065
actionSpecificModes[where](mode)
10551066
debug('adding action mode', where, mode, actionSpecificModes)
1056-
specials.actions.get = standardViewModes(actionSpecificModes)
10571067
},
10581068

10591069
owOpts: owOpts,

tests/lib/ui.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const common = require('./common'),
99
},
1010

1111
keys = {
12+
TAB: '\uE004',
1213
ENTER: '\uE007',
1314
ESCAPE: '\uE00C'
1415
}

tests/tests/passes/02/tab-completion.js

Lines changed: 72 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,9 @@ describe('Tab completion', function() {
3838
const tabby = (app, partial, full, expectOK=true) => app.client.waitForExist(ui.selectors.CURRENT_PROMPT_BLOCK)
3939
.then(() => app.client.getAttribute(ui.selectors.CURRENT_PROMPT_BLOCK, 'data-input-count'))
4040
.then(count => parseInt(count))
41-
.then(count => app.client.keys(partial)
41+
.then(count => app.client.setValue(ui.selectors.CURRENT_PROMPT, partial)
4242
.then(() => app.client.waitForValue(ui.selectors.PROMPT_N(count), partial))
43-
.then(() => app.client.keys('Tab'))
43+
.then(() => app.client.setValue(ui.selectors.CURRENT_PROMPT, `${partial}${keys.TAB}`))
4444
.then(() => app.client.waitForValue(ui.selectors.PROMPT_N(count), full)))
4545
.then(() => cli.do('', app))
4646
.then(data => {
@@ -52,65 +52,74 @@ describe('Tab completion', function() {
5252
})
5353
.catch(common.oops(this));
5454

55-
const tabbyWithOptions = (app, partial, expected, full, { click, nTabs, expectOK=true }={}) => app.client.waitForExist(ui.selectors.CURRENT_PROMPT_BLOCK)
56-
.then(() => app.client.getAttribute(ui.selectors.CURRENT_PROMPT_BLOCK, 'data-input-count'))
57-
.then(count => parseInt(count))
58-
.then(count => app.client.keys(partial)
59-
.then(() => app.client.waitForValue(ui.selectors.PROMPT_N(count), partial))
60-
.then(() => app.client.keys('Tab'))
61-
.then(() => {
62-
if (!expected) {
63-
// then we expect non-visibility of the tab-completion popup
64-
// console.error('Expecting non-existence of popup')
65-
return app.client.waitForVisible(`${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .clickable`, 20000, true)
66-
.then(() => {
67-
// great, the tab completion popup does not exist; early exit
68-
const err = new Error()
69-
err.failedAsExpected = true
70-
throw err
71-
})
72-
} else {
73-
const selector = `${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .clickable`
74-
// console.error('Expecting existence of popup', selector)
75-
return app.client.waitForVisible(selector, 20000)
76-
}
77-
})
78-
.then(() => app.client.getText(`${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .clickable`))
79-
.then(ui.expectArray(expected))
80-
// .then(() => { console.error('Got expected options') })
81-
.then(() => {
82-
if (click !== undefined) {
83-
// click on a row
84-
const selector = `${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .tab-completion-option[data-value="${expected[click]}"] .clickable`
85-
console.error('clicking', click, selector)
86-
return app.client.waitForVisible(selector, 20000)
87-
.then(() => app.client.click(selector))
88-
} else {
89-
// otherwise hit tab a number of times, to cycle to the desired entry
90-
console.error('tabbing', nTabs)
91-
return doTimes(nTabs, () => app.client.keys('Tab'))
92-
.then(() => app.client.keys('Enter'))
93-
}
94-
})
95-
.then(() => app.client.waitForVisible(`${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary`, 20000, true)) // wait for non-existence of the temporary
96-
.then(() => app.client.waitForValue(ui.selectors.PROMPT_N(count), full)))
97-
.then(() => cli.do('', app))
98-
.then(data => {
99-
if (expectOK) {
100-
return cli.expectJustOK(data)
101-
} else {
102-
return app
103-
}
104-
})
105-
.catch(err => this.app.client.execute('repl.doCancel()') // clear the line
106-
.then(() => common.oops(this)(err)))
55+
const tabbyWithOptions = (app, partial, expected, full, { click, nTabs, expectOK=true, iter=0 }={}) => {
56+
return app.client.waitForExist(ui.selectors.CURRENT_PROMPT_BLOCK)
57+
.then(() => app.client.getAttribute(ui.selectors.CURRENT_PROMPT_BLOCK, 'data-input-count'))
58+
.then(count => parseInt(count))
59+
.then(count => app.client.setValue(ui.selectors.CURRENT_PROMPT, partial)
60+
.then(() => app.client.waitForValue(ui.selectors.PROMPT_N(count), partial))
61+
.then(() => app.client.setValue(ui.selectors.CURRENT_PROMPT, `${partial}${keys.TAB}`))
62+
.then(() => {
63+
if (!expected) {
64+
// then we expect non-visibility of the tab-completion popup
65+
// console.error('Expecting non-existence of popup')
66+
return app.client.waitForVisible(`${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .clickable`, 10000, true)
67+
.then(() => {
68+
// great, the tab completion popup does not exist; early exit
69+
const err = new Error()
70+
err.failedAsExpected = true
71+
throw err
72+
})
73+
} else {
74+
const selector = `${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .clickable`
75+
// console.error('Expecting existence of popup', selector)
76+
return app.client.waitForVisible(selector, 10000)
77+
}
78+
})
79+
.then(() => app.client.getText(`${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .clickable`))
80+
.then(ui.expectArray(expected))
81+
// .then(() => { console.error('Got expected options') })
82+
.then(() => {
83+
if (click !== undefined) {
84+
// click on a row
85+
const selector = `${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .tab-completion-option[data-value="${expected[click]}"] .clickable`
86+
// console.error('clicking', click, selector)
87+
return app.client.waitForVisible(selector, 10000)
88+
.then(() => app.client.click(selector))
89+
} else {
90+
// otherwise hit tab a number of times, to cycle to the desired entry
91+
// console.error('tabbing', nTabs)
92+
return doTimes(nTabs, () => app.client.keys('Tab'))
93+
.then(() => app.client.keys('Enter'))
94+
}
95+
})
96+
.then(() => app.client.waitForVisible(`${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary`, 8000, true)) // wait for non-existence of the temporary
97+
.then(() => app.client.waitForValue(ui.selectors.PROMPT_N(count), full)))
98+
.then(() => cli.do('', app))
99+
.then(data => {
100+
if (expectOK) {
101+
return cli.expectJustOK(data)
102+
} else {
103+
return app
104+
}
105+
})
106+
.catch(err => this.app.client.execute('repl.doCancel()') // clear the line
107+
.then(() => {
108+
if (iter < 5) {
109+
console.error('retry', iter)
110+
return tabbyWithOptions(app, partial, expected, full, { click, nTabs, expectOK, iter: iter + 1 })
111+
} else {
112+
return common.oops(this)(err)
113+
}
114+
}))
115+
}
107116

108117
const tabbyWithOptionsThenCancel = (app, partial, expected) => app.client.waitForExist(ui.selectors.CURRENT_PROMPT_BLOCK)
109118
.then(() => app.client.getAttribute(ui.selectors.CURRENT_PROMPT_BLOCK, 'data-input-count'))
110119
.then(count => parseInt(count))
111-
.then(count => app.client.keys(partial)
120+
.then(count => app.client.setValue(ui.selectors.CURRENT_PROMPT, partial)
112121
.then(() => app.client.waitForValue(ui.selectors.PROMPT_N(count), partial))
113-
.then(() => app.client.keys('Tab'))
122+
.then(() => app.client.setValue(ui.selectors.CURRENT_PROMPT, `${partial}${keys.TAB}`))
114123
.then(() => app.client.waitForVisible(`${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .clickable`))
115124
.then(() => app.client.getText(`${ui.selectors.PROMPT_BLOCK_N(count)} .tab-completion-temporary .clickable`))
116125
.then(ui.expectArray(expected))
@@ -121,6 +130,13 @@ describe('Tab completion', function() {
121130

122131
it('should have an active repl', () => cli.waitForRepl(this.app))
123132

133+
// tab completion with options, then click on the second (idx=1) entry of the expected cmpletion list
134+
it('should tab complete local file path', () => tabbyWithOptions(this.app,
135+
'lls data/com',
136+
options,
137+
'lls data/composer-source/',
138+
{ click: 1 }))
139+
124140
it('should tab complete the data directory', () => tabby(this.app, 'lls da', 'lls data/'))
125141
it('should tab complete the data/fsm.js file', () => tabby(this.app, 'lls data/fsm.js', 'lls data/fsm.json'))
126142
it('should tab complete the ../app directory', () => tabby(this.app, 'lls ../ap', 'lls ../app/'))
@@ -130,13 +146,6 @@ describe('Tab completion', function() {
130146
'composer-source-expect-errors/',
131147
'composer-wookiechat/']
132148

133-
// tab completion with options, then click on the second (idx=1) entry of the expected cmpletion list
134-
it('should tab complete local file path', () => tabbyWithOptions(this.app,
135-
'lls data/com',
136-
options,
137-
'lls data/composer-source/',
138-
{ click: 1 }))
139-
140149
// same, but this time tab to cycle through the options
141150
it('should tab complete local file path', () => tabbyWithOptions(this.app,
142151
'lls data/com',

0 commit comments

Comments
 (0)