Skip to content

Commit 7571e80

Browse files
author
Guillaume Chau
committed
feat(ui): plugins update
1 parent 1441c02 commit 7571e80

File tree

15 files changed

+267
-85
lines changed

15 files changed

+267
-85
lines changed

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

Lines changed: 1 addition & 0 deletions
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

Lines changed: 28 additions & 10 deletions
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

Lines changed: 106 additions & 41 deletions
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

Lines changed: 55 additions & 21 deletions
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
}

0 commit comments

Comments
 (0)