Skip to content

Commit 7571e80

Browse files
author
Guillaume Chau
committedMar 16, 2018
feat(ui): plugins update
1 parent 1441c02 commit 7571e80

15 files changed

+267
-85
lines changed
 

‎packages/@vue/cli-ui/package.json

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"lru-cache": "^4.1.2",
2626
"mkdirp": "^0.5.1",
2727
"rimraf": "^2.6.2",
28+
"semver": "^5.5.0",
2829
"shortid": "^2.2.8",
2930
"subscriptions-transport-ws": "^0.9.5",
3031
"vue": "^2.5.13",

‎packages/@vue/cli-ui/src/components/ContentView.vue

+28-10
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
11
<template>
22
<div class="content-view">
33
<div class="header">
4-
<h2 v-if="title" class="title">{{ title }}</h2>
5-
<slot name="header"/>
4+
<div class="wrapper">
5+
<h2 v-if="title" class="title">{{ title }}</h2>
6+
<slot name="header"/>
7+
</div>
68
</div>
79

810
<div class="content">
9-
<slot/>
11+
<div class="wrapper">
12+
<slot/>
13+
</div>
1014
</div>
1115
</div>
1216
</template>
@@ -32,12 +36,19 @@ export default {
3236
grid-template-rows auto 1fr
3337
grid-template-areas "header" "content"
3438
39+
.wrapper
40+
width 100%
41+
height 100%
42+
box-sizing border-box
43+
3544
.header
3645
grid-area header
37-
h-box()
38-
box-center()
39-
background $vue-ui-color-light-neutral
40-
padding $padding-item
46+
background darken($vue-ui-color-light-neutral, 3%)
47+
.wrapper
48+
background $vue-ui-color-light-neutral
49+
h-box()
50+
box-center()
51+
padding $padding-item
4152
4253
.title
4354
flex 100% 1 1
@@ -49,7 +60,14 @@ export default {
4960
5061
.content
5162
grid-area content
52-
position relative
53-
overflow-x hidden
54-
overflow-y auto
63+
background darken($color-light-background, 3%)
64+
.wrapper
65+
background $color-light-background
66+
position relative
67+
overflow-x hidden
68+
overflow-y auto
69+
70+
&.limit-width
71+
.wrapper
72+
max-width 1200px
5573
</style>

‎packages/@vue/cli-ui/src/components/ProjectPluginItem.vue

+106-41
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,122 @@
11
<template>
22
<div class="project-plugin-item list-item">
3-
<ItemLogo :image="plugin.logo"/>
4-
5-
<ListItemInfo
6-
:name="plugin.id"
7-
:link="plugin.website"
8-
show-description
9-
>
10-
<span slot="description" class="plugin-description">
11-
<span class="info version">
12-
<span class="label">{{ $t('components.project-plugin-item.version') }}</span>
13-
<span class="value">{{ plugin.version.current }}</span>
14-
</span>
3+
<div class="content">
4+
<ItemLogo :image="pluginLogo && pluginLogo.logo"/>
155

16-
<span class="info latest">
17-
<span class="label">{{ $t('components.project-plugin-item.latest') }}</span>
18-
<VueIcon
19-
v-if="plugin.version.current !== plugin.version.latest"
20-
icon="warning"
21-
class="top medium"
22-
/>
23-
<span class="value">{{ plugin.version.latest }}</span>
24-
</span>
6+
<ListItemInfo
7+
:name="plugin.id"
8+
:link="plugin.website"
9+
show-description
10+
>
11+
<span slot="description" class="plugin-description">
12+
<template v-if="pluginDetails">
13+
<span class="info version">
14+
<span class="label">{{ $t('components.project-plugin-item.version') }}</span>
15+
<span class="value">{{ pluginDetails.version.current }}</span>
16+
</span>
2517

26-
<span v-if="plugin.official" class="info">
27-
<VueIcon
28-
icon="star"
29-
class="top medium"
30-
/>
31-
{{ $t('components.project-plugin-item.official') }}
32-
</span>
18+
<span class="info latest">
19+
<span class="label">{{ $t('components.project-plugin-item.latest') }}</span>
20+
<VueIcon
21+
v-if="pluginDetails.version.current !== pluginDetails.version.latest"
22+
icon="warning"
23+
class="top medium"
24+
/>
25+
<span class="value">{{ pluginDetails.version.latest }}</span>
26+
</span>
27+
</template>
3328

34-
<span v-if="plugin.installed" class="info">
35-
<VueIcon
36-
icon="check_circle"
37-
class="top medium"
38-
/>
39-
{{ $t('components.project-plugin-item.installed') }}
40-
</span>
29+
<span v-if="plugin.official" class="info">
30+
<VueIcon
31+
icon="star"
32+
class="top medium"
33+
/>
34+
{{ $t('components.project-plugin-item.official') }}
35+
</span>
4136

42-
<span v-if="plugin.description" class="package-description">
43-
{{ plugin.description }}
37+
<span v-if="plugin.installed" class="info">
38+
<VueIcon
39+
icon="check_circle"
40+
class="top medium"
41+
/>
42+
{{ $t('components.project-plugin-item.installed') }}
43+
</span>
44+
45+
<span v-if="pluginDetails && pluginDetails.description" class="package-description">
46+
{{ pluginDetails.description }}
47+
</span>
4448
</span>
45-
</span>
46-
</ListItemInfo>
49+
</ListItemInfo>
50+
51+
<VueButton
52+
v-if="pluginDetails && pluginDetails.version.current !== pluginDetails.version.wanted"
53+
icon-left="file_download"
54+
class="icon-button"
55+
v-tooltip="$t('components.project-plugin-item.actions.update', { target: plugin.id })"
56+
:loading-left="updating"
57+
@click="updatePlugin()"
58+
/>
59+
</div>
4760
</div>
4861
</template>
4962

5063
<script>
64+
import PLUGIN_DETAILS from '../graphql/pluginDetails.gql'
65+
import PLUGIN_LOGO from '../graphql/pluginLogo.gql'
66+
import PLUGIN_UPDATE from '../graphql/pluginUpdate.gql'
67+
5168
export default {
5269
props: {
5370
plugin: {
5471
type: Object,
5572
required: true
5673
}
74+
},
75+
76+
data () {
77+
return {
78+
pluginDetails: null,
79+
pluginLogo:! null,
80+
updating: false
81+
}
82+
},
83+
84+
apollo: {
85+
pluginDetails: {
86+
query: PLUGIN_DETAILS,
87+
variables () {
88+
return {
89+
id: this.plugin.id
90+
}
91+
},
92+
fetchPolicy: 'cache-and-network'
93+
},
94+
95+
pluginLogo: {
96+
query: PLUGIN_LOGO,
97+
variables () {
98+
return {
99+
id: this.plugin.id
100+
}
101+
}
102+
}
103+
},
104+
105+
methods: {
106+
async updatePlugin () {
107+
this.updating = true
108+
try {
109+
this.$apollo.mutate({
110+
mutation: PLUGIN_UPDATE,
111+
variables: {
112+
id: this.plugin.id
113+
}
114+
})
115+
} catch (e) {
116+
console.error(e)
117+
}
118+
this.updating = false
119+
}
57120
}
58121
}
59122
</script>
@@ -63,8 +126,10 @@ export default {
63126
64127
.project-plugin-item
65128
padding $padding-item
66-
h-box()
67-
box-center()
129+
130+
.content
131+
h-box()
132+
box-center()
68133
69134
.list-item-info
70135
flex 100% 1 1

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

+55-21
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const path = require('path')
22
const fs = require('fs')
33
const LRU = require('lru-cache')
4+
const semver = require('semver')
45
const {
56
isPlugin,
67
isOfficialPlugin,
@@ -11,7 +12,8 @@ const getPackageVersion = require('@vue/cli/lib/util/getPackageVersion')
1112
const {
1213
progress: installProgress,
1314
installPackage,
14-
uninstallPackage
15+
uninstallPackage,
16+
updatePackage
1517
} = require('@vue/cli/lib/util/installDeps')
1618
const { loadOptions } = require('@vue/cli/lib/options')
1719
const invoke = require('@vue/cli/lib/invoke')
@@ -20,6 +22,7 @@ const cwd = require('./cwd')
2022
const folders = require('./folders')
2123
const prompts = require('./prompts')
2224
const progress = require('./progress')
25+
const logs = require('./logs')
2326

2427
const metadataCache = new LRU({
2528
max: 200,
@@ -34,9 +37,12 @@ const PROGRESS_ID = 'plugin-installation'
3437

3538
let currentPluginId
3639
let eventsInstalled = false
40+
let plugins = []
3741

3842
function getPath (id) {
39-
return path.join(cwd.get(), 'node_modules', id)
43+
return path.dirname(require.resolve(id, {
44+
paths: [cwd.get()]
45+
}))
4046
}
4147

4248
function findPlugins (deps) {
@@ -55,12 +61,18 @@ function findPlugins (deps) {
5561

5662
function list (file, context) {
5763
const pkg = folders.readPackage(file, context)
58-
let plugins = []
64+
plugins = []
5965
plugins = plugins.concat(findPlugins(pkg.dependencies || {}))
6066
plugins = plugins.concat(findPlugins(pkg.devDependencies || {}))
6167
return plugins
6268
}
6369

70+
function findOne (id, context) {
71+
return plugins.find(
72+
p => p.id === id
73+
)
74+
}
75+
6476
function readPackage (id, context) {
6577
return folders.readPackage(getPath(id), context)
6678
}
@@ -70,18 +82,10 @@ async function getMetadata (id, context) {
7082
if (metadata) {
7183
return metadata
7284
}
73-
if (isOfficialPlugin(id)) {
74-
const res = await getPackageVersion('vue-cli-version-marker', 'latest')
75-
if (res.statusCode === 200) {
76-
metadata = res.body
77-
}
78-
const pkg = folders.readPackage(path.dirname(require.resolve(id)), context)
79-
metadata.description = pkg.description
80-
} else {
81-
const res = await getPackageVersion(id, id.indexOf('@') === -1 ? 'latest' : '')
82-
if (res.statusCode === 200) {
83-
metadata = res.body
84-
}
85+
86+
const res = await getPackageVersion(id)
87+
if (res.statusCode === 200) {
88+
metadata = res.body
8589
}
8690

8791
if (metadata) {
@@ -98,20 +102,22 @@ async function getVersion ({ id, installed, versionRange }, context) {
98102
} else {
99103
current = null
100104
}
101-
let latest
105+
let latest, wanted
102106
const metadata = await getMetadata(id, context)
103107
if (metadata) {
104-
latest = (metadata['dist-tags'] && metadata['dist-tags'].latest) || metadata.version
105-
}
108+
latest = metadata['dist-tags'].latest
106109

107-
if (!latest) {
108-
// fallback to local version
109-
latest = current
110+
const versions = Object.keys(metadata.versions)
111+
wanted = semver.maxSatisfying(versions, versionRange)
110112
}
111113

114+
if (!latest) latest = current
115+
if (!wanted) wanted = current
116+
112117
return {
113118
current,
114119
latest,
120+
wanted,
115121
range: versionRange
116122
}
117123
}
@@ -230,13 +236,41 @@ async function initPrompts (id, context) {
230236
prompts.start()
231237
}
232238

239+
function update (id, context) {
240+
return progress.wrap('plugin-update', context, async setProgress => {
241+
setProgress({
242+
status: 'plugin-update',
243+
args: [id]
244+
})
245+
246+
currentPluginId = id
247+
248+
const plugin = findOne(id, context)
249+
const { current, wanted } = await getVersion(plugin, context)
250+
251+
const packageManager = loadOptions().packageManager || (hasYarn() ? 'yarn' : 'npm')
252+
await updatePackage(cwd.get(), packageManager, null, id)
253+
254+
logs.add({
255+
message: `Plugin ${id} updated from ${current} to ${wanted}`,
256+
type: 'info'
257+
}, context)
258+
259+
currentPluginId = null
260+
261+
return findOne(id)
262+
})
263+
}
264+
233265
module.exports = {
234266
list,
267+
findOne,
235268
getVersion,
236269
getDescription,
237270
getLogo,
238271
getInstallation,
239272
install,
240273
uninstall,
274+
update,
241275
runInvoke
242276
}

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

+4-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ module.exports = {
4343
projects: (root, args, context) => projects.list(context),
4444
projectCurrent: (root, args, context) => projects.getCurrent(context),
4545
projectCreation: (root, args, context) => projects.getCreation(context),
46-
pluginInstallation: (root, args, context) => plugins.getInstallation(context)
46+
pluginInstallation: (root, args, context) => plugins.getInstallation(context),
47+
plugin: (root, { id }, context) => plugins.findOne(id, context)
4748
},
4849

4950
Mutation: {
@@ -64,7 +65,8 @@ module.exports = {
6465
projectCwdReset: (root, args, context) => projects.resetCwd(context),
6566
pluginInstall: (root, { id }, context) => plugins.install(id, context),
6667
pluginUninstall: (root, { id }, context) => plugins.uninstall(id, context),
67-
pluginInvoke: (root, { id }, context) => plugins.runInvoke(id, context)
68+
pluginInvoke: (root, { id }, context) => plugins.runInvoke(id, context),
69+
pluginUpdate: (root, { id }, context) => plugins.update(id, context)
6870
},
6971

7072
Subscription: {

‎packages/@vue/cli-ui/src/graphql-api/type-defs.js

+3
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ type ProjectCreation {
6969
type Version {
7070
current: String
7171
latest: String
72+
wanted: String
7273
range: String
7374
}
7475
@@ -164,6 +165,7 @@ type Query {
164165
projectCurrent: Project
165166
projectCreation: ProjectCreation
166167
pluginInstallation: PluginInstallation
168+
plugin (id: ID!): Plugin
167169
}
168170
169171
type Mutation {
@@ -183,6 +185,7 @@ type Mutation {
183185
pluginInstall (id: ID!): PluginInstallation
184186
pluginUninstall (id: ID!): PluginInstallation
185187
pluginInvoke (id: ID!): PluginInstallation
188+
pluginUpdate (id: ID!): Plugin
186189
}
187190
188191
type Subscription {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#import "./versionFragment.gql"
2+
3+
query pluginDetails ($id: ID!) {
4+
pluginDetails: plugin (id: $id) {
5+
id
6+
version {
7+
...version
8+
}
9+
description
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
fragment plugin on Plugin {
22
id
3-
version {
4-
current
5-
latest
6-
range
7-
}
83
official
94
installed
105
website
11-
description
12-
logo
136
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
query pluginLogo ($id: ID!) {
2+
pluginLogo: plugin (id: $id) {
3+
id
4+
logo
5+
}
6+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#import "./versionFragment.gql"
2+
3+
mutation pluginUpdate ($id: ID!) {
4+
pluginUpdate (id: $id) {
5+
id
6+
version {
7+
...version
8+
}
9+
}
10+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
fragment version on Version {
2+
current
3+
latest
4+
wanted
5+
range
6+
}

‎packages/@vue/cli-ui/src/locales/en.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@
4848
"version": "version",
4949
"latest": "latest",
5050
"official": "Official",
51-
"installed": "Installed"
51+
"installed": "Installed",
52+
"actions": {
53+
"update": "Update {target}"
54+
}
5255
},
5356
"prompts-list": {
5457
"empty": "No configuration"
@@ -79,7 +82,8 @@
7982
"done": "Successfully created project",
8083
"plugin-install": "Installing {arg0}...",
8184
"plugin-uninstall": "Uninstalling {arg0}...",
82-
"plugin-invoke": "Invoking {arg0}..."
85+
"plugin-invoke": "Invoking {arg0}...",
86+
"plugin-update": "Updating {arg0}..."
8387
}
8488
},
8589
"views": {

‎packages/@vue/cli-ui/src/locales/fr.json

+6-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,10 @@
4848
"version": "version",
4949
"latest": "dernière version",
5050
"official": "Officiel",
51-
"installed": "Installé"
51+
"installed": "Installé",
52+
"actions": {
53+
"update": "Mettre à jour {target}"
54+
}
5255
},
5356
"prompts-list": {
5457
"empty": "Pas de configuration"
@@ -79,7 +82,8 @@
7982
"done": "Projet créé avec succès",
8083
"plugin-install": "Installation de {arg0}...",
8184
"plugin-uninstall": "Désinstallation de {arg0}...",
82-
"plugin-invoke": "Invocation de {arg0}..."
85+
"plugin-invoke": "Invocation de {arg0}...",
86+
"plugin-update": "Mise à jour de {arg0}..."
8387
}
8488
},
8589
"views": {

‎packages/@vue/cli-ui/src/views/ProjectPlugins.vue

+5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
<div class="project-plugins page">
33
<ContentView
44
:title="$t('views.project-plugins.title')"
5+
class="limit-width"
56
>
67
<template slot="header">
78
<VueButton
@@ -34,6 +35,10 @@
3435
</template>
3536
</ApolloQuery>
3637
</ContentView>
38+
39+
<ProgressScreen
40+
progress-id="plugin-update"
41+
/>
3742
</div>
3843
</template>
3944

‎packages/@vue/cli/lib/util/installDeps.js

+20
Original file line numberDiff line numberDiff line change
@@ -288,3 +288,23 @@ exports.uninstallPackage = async function (targetDir, command, cliRegistry, pack
288288

289289
await executeCommand(command, args, targetDir)
290290
}
291+
292+
exports.updatePackage = async function (targetDir, command, cliRegistry, packageName) {
293+
const args = []
294+
if (command === 'npm') {
295+
args.push('update', '--loglevel', 'error')
296+
} else if (command === 'yarn') {
297+
args.push('upgrade')
298+
} else {
299+
throw new Error(`Unknown package manager: ${command}`)
300+
}
301+
302+
await addRegistryToArgs(command, args, cliRegistry)
303+
304+
args.push(packageName)
305+
306+
debug(`command: `, command)
307+
debug(`args: `, args)
308+
309+
await executeCommand(command, args, targetDir)
310+
}

0 commit comments

Comments
 (0)
Please sign in to comment.