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 @@ @@ -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) +}