diff --git a/packages/@vue/cli-ui/package.json b/packages/@vue/cli-ui/package.json
index bb288957b6..53bc00bfa6 100644
--- a/packages/@vue/cli-ui/package.json
+++ b/packages/@vue/cli-ui/package.json
@@ -25,6 +25,7 @@
"lru-cache": "^4.1.2",
"mkdirp": "^0.5.1",
"rimraf": "^2.6.2",
+ "semver": "^5.5.0",
"shortid": "^2.2.8",
"subscriptions-transport-ws": "^0.9.5",
"vue": "^2.5.13",
diff --git a/packages/@vue/cli-ui/src/components/ContentView.vue b/packages/@vue/cli-ui/src/components/ContentView.vue
index b096fd3e07..92fc3355f0 100644
--- a/packages/@vue/cli-ui/src/components/ContentView.vue
+++ b/packages/@vue/cli-ui/src/components/ContentView.vue
@@ -1,12 +1,16 @@
@@ -32,12 +36,19 @@ export default {
grid-template-rows auto 1fr
grid-template-areas "header" "content"
+ .wrapper
+ width 100%
+ height 100%
+ box-sizing border-box
+
.header
grid-area header
- h-box()
- box-center()
- background $vue-ui-color-light-neutral
- padding $padding-item
+ background darken($vue-ui-color-light-neutral, 3%)
+ .wrapper
+ background $vue-ui-color-light-neutral
+ h-box()
+ box-center()
+ padding $padding-item
.title
flex 100% 1 1
@@ -49,7 +60,14 @@ export default {
.content
grid-area content
- position relative
- overflow-x hidden
- overflow-y auto
+ background darken($color-light-background, 3%)
+ .wrapper
+ background $color-light-background
+ position relative
+ overflow-x hidden
+ overflow-y auto
+
+ &.limit-width
+ .wrapper
+ max-width 1200px
diff --git a/packages/@vue/cli-ui/src/components/ProjectPluginItem.vue b/packages/@vue/cli-ui/src/components/ProjectPluginItem.vue
index ce8e900d21..88432a7d6c 100644
--- a/packages/@vue/cli-ui/src/components/ProjectPluginItem.vue
+++ b/packages/@vue/cli-ui/src/components/ProjectPluginItem.vue
@@ -1,59 +1,122 @@
-
-
-
-
-
- {{ $t('components.project-plugin-item.version') }}
- {{ plugin.version.current }}
-
+
+
-
- {{ $t('components.project-plugin-item.latest') }}
-
- {{ plugin.version.latest }}
-
+
+
+
+
+ {{ $t('components.project-plugin-item.version') }}
+ {{ pluginDetails.version.current }}
+
-
-
- {{ $t('components.project-plugin-item.official') }}
-
+
+ {{ $t('components.project-plugin-item.latest') }}
+
+ {{ pluginDetails.version.latest }}
+
+
-
-
- {{ $t('components.project-plugin-item.installed') }}
-
+
+
+ {{ $t('components.project-plugin-item.official') }}
+
-
- {{ plugin.description }}
+
+
+ {{ $t('components.project-plugin-item.installed') }}
+
+
+
+ {{ pluginDetails.description }}
+
-
-
+
+
+
+
@@ -63,8 +126,10 @@ export default {
.project-plugin-item
padding $padding-item
- h-box()
- box-center()
+
+ .content
+ h-box()
+ box-center()
.list-item-info
flex 100% 1 1
diff --git a/packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js b/packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js
index 7d7f8fcf80..c2d6f4725b 100644
--- a/packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js
+++ b/packages/@vue/cli-ui/src/graphql-api/connectors/plugins.js
@@ -1,6 +1,7 @@
const path = require('path')
const fs = require('fs')
const LRU = require('lru-cache')
+const semver = require('semver')
const {
isPlugin,
isOfficialPlugin,
@@ -11,7 +12,8 @@ const getPackageVersion = require('@vue/cli/lib/util/getPackageVersion')
const {
progress: installProgress,
installPackage,
- uninstallPackage
+ uninstallPackage,
+ updatePackage
} = require('@vue/cli/lib/util/installDeps')
const { loadOptions } = require('@vue/cli/lib/options')
const invoke = require('@vue/cli/lib/invoke')
@@ -20,6 +22,7 @@ const cwd = require('./cwd')
const folders = require('./folders')
const prompts = require('./prompts')
const progress = require('./progress')
+const logs = require('./logs')
const metadataCache = new LRU({
max: 200,
@@ -34,9 +37,12 @@ const PROGRESS_ID = 'plugin-installation'
let currentPluginId
let eventsInstalled = false
+let plugins = []
function getPath (id) {
- return path.join(cwd.get(), 'node_modules', id)
+ return path.dirname(require.resolve(id, {
+ paths: [cwd.get()]
+ }))
}
function findPlugins (deps) {
@@ -55,12 +61,18 @@ function findPlugins (deps) {
function list (file, context) {
const pkg = folders.readPackage(file, context)
- let plugins = []
+ plugins = []
plugins = plugins.concat(findPlugins(pkg.dependencies || {}))
plugins = plugins.concat(findPlugins(pkg.devDependencies || {}))
return plugins
}
+function findOne (id, context) {
+ return plugins.find(
+ p => p.id === id
+ )
+}
+
function readPackage (id, context) {
return folders.readPackage(getPath(id), context)
}
@@ -70,18 +82,10 @@ async function getMetadata (id, context) {
if (metadata) {
return metadata
}
- if (isOfficialPlugin(id)) {
- const res = await getPackageVersion('vue-cli-version-marker', 'latest')
- if (res.statusCode === 200) {
- metadata = res.body
- }
- const pkg = folders.readPackage(path.dirname(require.resolve(id)), context)
- metadata.description = pkg.description
- } else {
- const res = await getPackageVersion(id, id.indexOf('@') === -1 ? 'latest' : '')
- if (res.statusCode === 200) {
- metadata = res.body
- }
+
+ const res = await getPackageVersion(id)
+ if (res.statusCode === 200) {
+ metadata = res.body
}
if (metadata) {
@@ -98,20 +102,22 @@ async function getVersion ({ id, installed, versionRange }, context) {
} else {
current = null
}
- let latest
+ let latest, wanted
const metadata = await getMetadata(id, context)
if (metadata) {
- latest = (metadata['dist-tags'] && metadata['dist-tags'].latest) || metadata.version
- }
+ latest = metadata['dist-tags'].latest
- if (!latest) {
- // fallback to local version
- latest = current
+ const versions = Object.keys(metadata.versions)
+ wanted = semver.maxSatisfying(versions, versionRange)
}
+ if (!latest) latest = current
+ if (!wanted) wanted = current
+
return {
current,
latest,
+ wanted,
range: versionRange
}
}
@@ -230,13 +236,41 @@ async function initPrompts (id, context) {
prompts.start()
}
+function update (id, context) {
+ return progress.wrap('plugin-update', context, async setProgress => {
+ setProgress({
+ status: 'plugin-update',
+ args: [id]
+ })
+
+ currentPluginId = id
+
+ const plugin = findOne(id, context)
+ const { current, wanted } = await getVersion(plugin, context)
+
+ const packageManager = loadOptions().packageManager || (hasYarn() ? 'yarn' : 'npm')
+ await updatePackage(cwd.get(), packageManager, null, id)
+
+ logs.add({
+ message: `Plugin ${id} updated from ${current} to ${wanted}`,
+ type: 'info'
+ }, context)
+
+ currentPluginId = null
+
+ return findOne(id)
+ })
+}
+
module.exports = {
list,
+ findOne,
getVersion,
getDescription,
getLogo,
getInstallation,
install,
uninstall,
+ update,
runInvoke
}
diff --git a/packages/@vue/cli-ui/src/graphql-api/resolvers.js b/packages/@vue/cli-ui/src/graphql-api/resolvers.js
index f643d4c70b..baf0dfafb9 100644
--- a/packages/@vue/cli-ui/src/graphql-api/resolvers.js
+++ b/packages/@vue/cli-ui/src/graphql-api/resolvers.js
@@ -43,7 +43,8 @@ module.exports = {
projects: (root, args, context) => projects.list(context),
projectCurrent: (root, args, context) => projects.getCurrent(context),
projectCreation: (root, args, context) => projects.getCreation(context),
- pluginInstallation: (root, args, context) => plugins.getInstallation(context)
+ pluginInstallation: (root, args, context) => plugins.getInstallation(context),
+ plugin: (root, { id }, context) => plugins.findOne(id, context)
},
Mutation: {
@@ -64,7 +65,8 @@ module.exports = {
projectCwdReset: (root, args, context) => projects.resetCwd(context),
pluginInstall: (root, { id }, context) => plugins.install(id, context),
pluginUninstall: (root, { id }, context) => plugins.uninstall(id, context),
- pluginInvoke: (root, { id }, context) => plugins.runInvoke(id, context)
+ pluginInvoke: (root, { id }, context) => plugins.runInvoke(id, context),
+ pluginUpdate: (root, { id }, context) => plugins.update(id, context)
},
Subscription: {
diff --git a/packages/@vue/cli-ui/src/graphql-api/type-defs.js b/packages/@vue/cli-ui/src/graphql-api/type-defs.js
index cf144e259c..ea62d4121a 100644
--- a/packages/@vue/cli-ui/src/graphql-api/type-defs.js
+++ b/packages/@vue/cli-ui/src/graphql-api/type-defs.js
@@ -69,6 +69,7 @@ type ProjectCreation {
type Version {
current: String
latest: String
+ wanted: String
range: String
}
@@ -164,6 +165,7 @@ type Query {
projectCurrent: Project
projectCreation: ProjectCreation
pluginInstallation: PluginInstallation
+ plugin (id: ID!): Plugin
}
type Mutation {
@@ -183,6 +185,7 @@ type Mutation {
pluginInstall (id: ID!): PluginInstallation
pluginUninstall (id: ID!): PluginInstallation
pluginInvoke (id: ID!): PluginInstallation
+ pluginUpdate (id: ID!): Plugin
}
type Subscription {
diff --git a/packages/@vue/cli-ui/src/graphql/pluginDetails.gql b/packages/@vue/cli-ui/src/graphql/pluginDetails.gql
new file mode 100644
index 0000000000..1b99bd8cdd
--- /dev/null
+++ b/packages/@vue/cli-ui/src/graphql/pluginDetails.gql
@@ -0,0 +1,11 @@
+#import "./versionFragment.gql"
+
+query pluginDetails ($id: ID!) {
+ pluginDetails: plugin (id: $id) {
+ id
+ version {
+ ...version
+ }
+ description
+ }
+}
diff --git a/packages/@vue/cli-ui/src/graphql/pluginFragment.gql b/packages/@vue/cli-ui/src/graphql/pluginFragment.gql
index 8a7b2a6bcb..69b8f6f7d2 100644
--- a/packages/@vue/cli-ui/src/graphql/pluginFragment.gql
+++ b/packages/@vue/cli-ui/src/graphql/pluginFragment.gql
@@ -1,13 +1,6 @@
fragment plugin on Plugin {
id
- version {
- current
- latest
- range
- }
official
installed
website
- description
- logo
}
diff --git a/packages/@vue/cli-ui/src/graphql/pluginLogo.gql b/packages/@vue/cli-ui/src/graphql/pluginLogo.gql
new file mode 100644
index 0000000000..73accce4b6
--- /dev/null
+++ b/packages/@vue/cli-ui/src/graphql/pluginLogo.gql
@@ -0,0 +1,6 @@
+query pluginLogo ($id: ID!) {
+ pluginLogo: plugin (id: $id) {
+ id
+ logo
+ }
+}
diff --git a/packages/@vue/cli-ui/src/graphql/pluginUpdate.gql b/packages/@vue/cli-ui/src/graphql/pluginUpdate.gql
new file mode 100644
index 0000000000..875a970b51
--- /dev/null
+++ b/packages/@vue/cli-ui/src/graphql/pluginUpdate.gql
@@ -0,0 +1,10 @@
+#import "./versionFragment.gql"
+
+mutation pluginUpdate ($id: ID!) {
+ pluginUpdate (id: $id) {
+ id
+ version {
+ ...version
+ }
+ }
+}
diff --git a/packages/@vue/cli-ui/src/graphql/versionFragment.gql b/packages/@vue/cli-ui/src/graphql/versionFragment.gql
new file mode 100644
index 0000000000..2ef072d187
--- /dev/null
+++ b/packages/@vue/cli-ui/src/graphql/versionFragment.gql
@@ -0,0 +1,6 @@
+fragment version on Version {
+ current
+ latest
+ wanted
+ range
+}
diff --git a/packages/@vue/cli-ui/src/locales/en.json b/packages/@vue/cli-ui/src/locales/en.json
index 2f37501994..cd5906bb4d 100644
--- a/packages/@vue/cli-ui/src/locales/en.json
+++ b/packages/@vue/cli-ui/src/locales/en.json
@@ -48,7 +48,10 @@
"version": "version",
"latest": "latest",
"official": "Official",
- "installed": "Installed"
+ "installed": "Installed",
+ "actions": {
+ "update": "Update {target}"
+ }
},
"prompts-list": {
"empty": "No configuration"
@@ -79,7 +82,8 @@
"done": "Successfully created project",
"plugin-install": "Installing {arg0}...",
"plugin-uninstall": "Uninstalling {arg0}...",
- "plugin-invoke": "Invoking {arg0}..."
+ "plugin-invoke": "Invoking {arg0}...",
+ "plugin-update": "Updating {arg0}..."
}
},
"views": {
diff --git a/packages/@vue/cli-ui/src/locales/fr.json b/packages/@vue/cli-ui/src/locales/fr.json
index 6e470af071..9394e65b77 100644
--- a/packages/@vue/cli-ui/src/locales/fr.json
+++ b/packages/@vue/cli-ui/src/locales/fr.json
@@ -48,7 +48,10 @@
"version": "version",
"latest": "dernière version",
"official": "Officiel",
- "installed": "Installé"
+ "installed": "Installé",
+ "actions": {
+ "update": "Mettre à jour {target}"
+ }
},
"prompts-list": {
"empty": "Pas de configuration"
@@ -79,7 +82,8 @@
"done": "Projet créé avec succès",
"plugin-install": "Installation de {arg0}...",
"plugin-uninstall": "Désinstallation de {arg0}...",
- "plugin-invoke": "Invocation de {arg0}..."
+ "plugin-invoke": "Invocation de {arg0}...",
+ "plugin-update": "Mise à jour de {arg0}..."
}
},
"views": {
diff --git a/packages/@vue/cli-ui/src/views/ProjectPlugins.vue b/packages/@vue/cli-ui/src/views/ProjectPlugins.vue
index 6230a3d384..708d3f0a4d 100644
--- a/packages/@vue/cli-ui/src/views/ProjectPlugins.vue
+++ b/packages/@vue/cli-ui/src/views/ProjectPlugins.vue
@@ -2,6 +2,7 @@
diff --git a/packages/@vue/cli/lib/util/installDeps.js b/packages/@vue/cli/lib/util/installDeps.js
index 3de10cda33..4a9e76c6ea 100644
--- a/packages/@vue/cli/lib/util/installDeps.js
+++ b/packages/@vue/cli/lib/util/installDeps.js
@@ -288,3 +288,23 @@ exports.uninstallPackage = async function (targetDir, command, cliRegistry, pack
await executeCommand(command, args, targetDir)
}
+
+exports.updatePackage = async function (targetDir, command, cliRegistry, packageName) {
+ const args = []
+ if (command === 'npm') {
+ args.push('update', '--loglevel', 'error')
+ } else if (command === 'yarn') {
+ args.push('upgrade')
+ } else {
+ throw new Error(`Unknown package manager: ${command}`)
+ }
+
+ await addRegistryToArgs(command, args, cliRegistry)
+
+ args.push(packageName)
+
+ debug(`command: `, command)
+ debug(`args: `, args)
+
+ await executeCommand(command, args, targetDir)
+}