Skip to content

Commit 8ba6bcf

Browse files
committed
feat(ui): new hooks for plugins
1 parent 8fae98e commit 8ba6bcf

File tree

16 files changed

+297
-25
lines changed

16 files changed

+297
-25
lines changed

docs/dev-guide/ui-api.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,66 @@ api.onPluginReload((project) => {
10751075
})
10761076
```
10771077

1078+
### onConfigRead
1079+
1080+
Called when a configuration screen is open or refreshed.
1081+
1082+
```js
1083+
api.onConfigRead(({ config, data, onReadData, tabs, cwd }) => {
1084+
console.log(config.id)
1085+
})
1086+
```
1087+
1088+
### onConfigWrite
1089+
1090+
Called when the user saves in a configuration screen.
1091+
1092+
```js
1093+
api.onConfigWrite(({ config, data, changedFields, cwd }) => {
1094+
// ...
1095+
})
1096+
```
1097+
1098+
### onTaskOpen
1099+
1100+
Called when the user open a task details pane.
1101+
1102+
```js
1103+
api.onTaskOpen(({ task, cwd }) => {
1104+
console.log(task.id)
1105+
})
1106+
```
1107+
1108+
### onTaskRun
1109+
1110+
Called when the user run a task.
1111+
1112+
```js
1113+
api.onTaskRun(({ task, args, child, cwd }) => {
1114+
// ...
1115+
})
1116+
```
1117+
1118+
### onTaskExit
1119+
1120+
Called when a task exists. It can be called both called on success or failure.
1121+
1122+
```js
1123+
api.onTaskExit(({ task, args, child, signal, code, cwd }) => {
1124+
// ...
1125+
})
1126+
```
1127+
1128+
### onViewOpen
1129+
1130+
Called when the users open a view (like 'Plugins', 'Configurations' or 'Tasks').
1131+
1132+
```js
1133+
api.onViewOpen(({ view, cwd }) => {
1134+
console.log(view.id)
1135+
})
1136+
```
1137+
10781138
## Public static files
10791139

10801140
You may need to expose some static files over the cli-ui builtin HTTP server (typically if you want to specify an icon to a custom view).

packages/@vue/cli-ui/.eslintrc.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,20 @@
11
module.exports = {
22
root: true,
3+
34
extends: [
45
'plugin:vue/essential',
56
'@vue/standard'
67
],
8+
79
globals: {
810
ClientAddonApi: false
911
},
12+
1013
plugins: [
1114
'graphql'
12-
]
15+
],
16+
17+
rules: {
18+
'vue/html-self-closing': 'error'
19+
}
1320
}

packages/@vue/cli-ui/src/components/ProjectNav.vue

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
>
88
<div class="content">
99
<VueGroup
10-
v-model="currentView"
10+
v-model="currentViewName"
1111
class="vertical small-indicator left-indicator primary"
1212
indicator
1313
>
@@ -30,6 +30,7 @@ import VIEWS from '../graphql/views.gql'
3030
import VIEW_ADDED from '../graphql/viewAdded.gql'
3131
import VIEW_REMOVED from '../graphql/viewRemoved.gql'
3232
import VIEW_CHANGED from '../graphql/viewChanged.gql'
33+
import VIEW_OPEN from '../graphql/viewOpen.gql'
3334
3435
export default {
3536
data () {
@@ -90,12 +91,16 @@ export default {
9091
},
9192
9293
computed: {
93-
currentView: {
94+
currentView () {
95+
const currentRoute = this.$route
96+
return this.views.find(
97+
item => isIncludedRoute(currentRoute, this.$router.resolve({ name: item.name }).route)
98+
)
99+
},
100+
101+
currentViewName: {
94102
get () {
95-
const currentRoute = this.$route
96-
const view = this.views.find(
97-
item => isIncludedRoute(currentRoute, this.$router.resolve({ name: item.name }).route)
98-
)
103+
const view = this.currentView
99104
return view && view.name
100105
},
101106
set (name) {
@@ -104,6 +109,22 @@ export default {
104109
}
105110
}
106111
}
112+
},
113+
114+
watch: {
115+
currentView: {
116+
handler (value, oldValue) {
117+
if (!value) return
118+
if (oldValue && value.id === oldValue.id) return
119+
this.$apollo.mutate({
120+
mutation: VIEW_OPEN,
121+
variables: {
122+
id: value.id
123+
}
124+
})
125+
},
126+
immediate: true
127+
}
107128
}
108129
}
109130
</script>

packages/@vue/cli-ui/src/components/TerminalView.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
</div>
2525

2626
<div class="view">
27-
<div ref="render" class="xterm-render"></div>
27+
<div ref="render" class="xterm-render"/>
2828
</div>
2929

3030
<resize-observer v-if="autoSize" @notify="fit"/>

packages/@vue/cli-ui/src/graphql-api/api/PluginApi.js

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,16 @@ class PluginApi {
2121
this.project = null
2222
this.plugins = plugins
2323
// Hooks
24-
this.projectOpenHooks = []
25-
this.pluginReloadHooks = []
24+
this.hooks = {
25+
projectOpen: [],
26+
pluginReload: [],
27+
configRead: [],
28+
configWrite: [],
29+
taskRun: [],
30+
taskExit: [],
31+
taskOpen: [],
32+
viewOpen: []
33+
}
2634
// Data
2735
this.configurations = []
2836
this.describedTasks = []
@@ -43,7 +51,7 @@ class PluginApi {
4351
cb(this.project)
4452
return
4553
}
46-
this.projectOpenHooks.push(cb)
54+
this.hooks.projectOpen.push(cb)
4755
}
4856

4957
/**
@@ -52,7 +60,61 @@ class PluginApi {
5260
* @param {function} cb Handler
5361
*/
5462
onPluginReload (cb) {
55-
this.pluginReloadHooks.push(cb)
63+
this.hooks.pluginReload.push(cb)
64+
}
65+
66+
/**
67+
* Register an handler called when a config is red.
68+
*
69+
* @param {function} cb Handler
70+
*/
71+
onConfigRead (cb) {
72+
this.hooks.configRead.push(cb)
73+
}
74+
75+
/**
76+
* Register an handler called when a config is written.
77+
*
78+
* @param {function} cb Handler
79+
*/
80+
onConfigWrite (cb) {
81+
this.hooks.configWrite.push(cb)
82+
}
83+
84+
/**
85+
* Register an handler called when a task is run.
86+
*
87+
* @param {function} cb Handler
88+
*/
89+
onTaskRun (cb) {
90+
this.hooks.taskRun.push(cb)
91+
}
92+
93+
/**
94+
* Register an handler called when a task has exited.
95+
*
96+
* @param {function} cb Handler
97+
*/
98+
onTaskExit (cb) {
99+
this.hooks.taskExit.push(cb)
100+
}
101+
102+
/**
103+
* Register an handler called when the user opens one task details.
104+
*
105+
* @param {function} cb Handler
106+
*/
107+
onTaskOpen (cb) {
108+
this.hooks.taskOpen.push(cb)
109+
}
110+
111+
/**
112+
* Register an handler called when a view is open.
113+
*
114+
* @param {function} cb Handler
115+
*/
116+
onViewOpen (cb) {
117+
this.hooks.viewOpen.push(cb)
56118
}
57119

58120
/**

packages/@vue/cli-ui/src/graphql-api/connectors/configurations.js

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -156,18 +156,18 @@ async function getPromptTabs (id, context) {
156156
}
157157

158158
// API
159-
const configData = await config.onRead({
159+
const onReadData = await config.onRead({
160160
cwd: cwd.get(),
161161
data
162162
})
163163

164-
let tabs = configData.tabs
164+
let tabs = onReadData.tabs
165165
if (!tabs) {
166166
tabs = [
167167
{
168168
id: '__default',
169169
label: 'Default',
170-
prompts: configData.prompts
170+
prompts: onReadData.prompts
171171
}
172172
]
173173
}
@@ -178,10 +178,19 @@ async function getPromptTabs (id, context) {
178178
tabId: tab.id
179179
}))
180180
}
181-
if (configData.answers) {
182-
await prompts.setAnswers(configData.answers)
181+
if (onReadData.answers) {
182+
await prompts.setAnswers(onReadData.answers)
183183
}
184184
await prompts.start()
185+
186+
plugins.callHook('configRead', [{
187+
config,
188+
data,
189+
onReadData,
190+
tabs,
191+
cwd: cwd.get()
192+
}], context)
193+
185194
return tabs
186195
}
187196
return []
@@ -242,6 +251,14 @@ async function save (id, context) {
242251
})
243252

244253
writeData({ config, data, changedFields }, context)
254+
255+
plugins.callHook('configWrite', [{
256+
config,
257+
data,
258+
changedFields,
259+
cwd: cwd.get()
260+
}], context)
261+
245262
current = {}
246263
}
247264
}

packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,14 @@ function resetPluginApi (context) {
118118
if (!project) return
119119
if (projectId !== project.id) {
120120
projectId = project.id
121-
log('Hook onProjectOpen', pluginApi.projectOpenHooks.length, 'handlers')
122-
pluginApi.projectOpenHooks.forEach(fn => fn(project, projects.getLast(context)))
121+
callHook('projectOpen', [project, projects.getLast(context)], context)
123122
pluginApi.project = project
124123
} else {
125-
log('Hook onPluginReload', pluginApi.pluginReloadHooks.length, 'handlers')
126-
pluginApi.pluginReloadHooks.forEach(fn => fn(project))
124+
callHook('pluginReload', [project], context)
125+
126+
// View open hook
127+
const currentView = views.getCurrent()
128+
if (currentView) views.open(currentView.id)
127129
}
128130
})
129131
}
@@ -147,6 +149,12 @@ function runPluginApi (id, context, fileName = 'ui') {
147149
} catch (e) {}
148150
}
149151

152+
function callHook (id, args, context) {
153+
const fns = pluginApi.hooks[id]
154+
log(`Hook ${id}`, fns.length, 'handlers')
155+
fns.forEach(fn => fn(...args))
156+
}
157+
150158
function findOne (id, context) {
151159
return plugins.find(
152160
p => p.id === id
@@ -472,5 +480,6 @@ module.exports = {
472480
getApi,
473481
finishInstall,
474482
callAction,
483+
callHook,
475484
serve
476485
}

0 commit comments

Comments
 (0)