mirror of
https://github.com/vuejs/vue-cli.git
synced 2026-05-04 02:50:03 -05:00
feat(ui): plugins update
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
<template>
|
||||
<div class="content-view">
|
||||
<div class="header">
|
||||
<h2 v-if="title" class="title">{{ title }}</h2>
|
||||
<slot name="header"/>
|
||||
<div class="wrapper">
|
||||
<h2 v-if="title" class="title">{{ title }}</h2>
|
||||
<slot name="header"/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="content">
|
||||
<slot/>
|
||||
<div class="wrapper">
|
||||
<slot/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -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
|
||||
</style>
|
||||
|
||||
@@ -1,59 +1,122 @@
|
||||
<template>
|
||||
<div class="project-plugin-item list-item">
|
||||
<ItemLogo :image="plugin.logo"/>
|
||||
<div class="content">
|
||||
<ItemLogo :image="pluginLogo && pluginLogo.logo"/>
|
||||
|
||||
<ListItemInfo
|
||||
:name="plugin.id"
|
||||
:link="plugin.website"
|
||||
show-description
|
||||
>
|
||||
<span slot="description" class="plugin-description">
|
||||
<span class="info version">
|
||||
<span class="label">{{ $t('components.project-plugin-item.version') }}</span>
|
||||
<span class="value">{{ plugin.version.current }}</span>
|
||||
</span>
|
||||
<ListItemInfo
|
||||
:name="plugin.id"
|
||||
:link="plugin.website"
|
||||
show-description
|
||||
>
|
||||
<span slot="description" class="plugin-description">
|
||||
<template v-if="pluginDetails">
|
||||
<span class="info version">
|
||||
<span class="label">{{ $t('components.project-plugin-item.version') }}</span>
|
||||
<span class="value">{{ pluginDetails.version.current }}</span>
|
||||
</span>
|
||||
|
||||
<span class="info latest">
|
||||
<span class="label">{{ $t('components.project-plugin-item.latest') }}</span>
|
||||
<VueIcon
|
||||
v-if="plugin.version.current !== plugin.version.latest"
|
||||
icon="warning"
|
||||
class="top medium"
|
||||
/>
|
||||
<span class="value">{{ plugin.version.latest }}</span>
|
||||
</span>
|
||||
<span class="info latest">
|
||||
<span class="label">{{ $t('components.project-plugin-item.latest') }}</span>
|
||||
<VueIcon
|
||||
v-if="pluginDetails.version.current !== pluginDetails.version.latest"
|
||||
icon="warning"
|
||||
class="top medium"
|
||||
/>
|
||||
<span class="value">{{ pluginDetails.version.latest }}</span>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<span v-if="plugin.official" class="info">
|
||||
<VueIcon
|
||||
icon="star"
|
||||
class="top medium"
|
||||
/>
|
||||
{{ $t('components.project-plugin-item.official') }}
|
||||
</span>
|
||||
<span v-if="plugin.official" class="info">
|
||||
<VueIcon
|
||||
icon="star"
|
||||
class="top medium"
|
||||
/>
|
||||
{{ $t('components.project-plugin-item.official') }}
|
||||
</span>
|
||||
|
||||
<span v-if="plugin.installed" class="info">
|
||||
<VueIcon
|
||||
icon="check_circle"
|
||||
class="top medium"
|
||||
/>
|
||||
{{ $t('components.project-plugin-item.installed') }}
|
||||
</span>
|
||||
<span v-if="plugin.installed" class="info">
|
||||
<VueIcon
|
||||
icon="check_circle"
|
||||
class="top medium"
|
||||
/>
|
||||
{{ $t('components.project-plugin-item.installed') }}
|
||||
</span>
|
||||
|
||||
<span v-if="plugin.description" class="package-description">
|
||||
{{ plugin.description }}
|
||||
<span v-if="pluginDetails && pluginDetails.description" class="package-description">
|
||||
{{ pluginDetails.description }}
|
||||
</span>
|
||||
</span>
|
||||
</span>
|
||||
</ListItemInfo>
|
||||
</ListItemInfo>
|
||||
|
||||
<VueButton
|
||||
v-if="pluginDetails && pluginDetails.version.current !== pluginDetails.version.wanted"
|
||||
icon-left="file_download"
|
||||
class="icon-button"
|
||||
v-tooltip="$t('components.project-plugin-item.actions.update', { target: plugin.id })"
|
||||
:loading-left="updating"
|
||||
@click="updatePlugin()"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import PLUGIN_DETAILS from '../graphql/pluginDetails.gql'
|
||||
import PLUGIN_LOGO from '../graphql/pluginLogo.gql'
|
||||
import PLUGIN_UPDATE from '../graphql/pluginUpdate.gql'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
plugin: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
pluginDetails: null,
|
||||
pluginLogo:! null,
|
||||
updating: false
|
||||
}
|
||||
},
|
||||
|
||||
apollo: {
|
||||
pluginDetails: {
|
||||
query: PLUGIN_DETAILS,
|
||||
variables () {
|
||||
return {
|
||||
id: this.plugin.id
|
||||
}
|
||||
},
|
||||
fetchPolicy: 'cache-and-network'
|
||||
},
|
||||
|
||||
pluginLogo: {
|
||||
query: PLUGIN_LOGO,
|
||||
variables () {
|
||||
return {
|
||||
id: this.plugin.id
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
async updatePlugin () {
|
||||
this.updating = true
|
||||
try {
|
||||
this.$apollo.mutate({
|
||||
mutation: PLUGIN_UPDATE,
|
||||
variables: {
|
||||
id: this.plugin.id
|
||||
}
|
||||
})
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
}
|
||||
this.updating = false
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
const versions = Object.keys(metadata.versions)
|
||||
wanted = semver.maxSatisfying(versions, versionRange)
|
||||
}
|
||||
|
||||
if (!latest) {
|
||||
// fallback to local version
|
||||
latest = current
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
#import "./versionFragment.gql"
|
||||
|
||||
query pluginDetails ($id: ID!) {
|
||||
pluginDetails: plugin (id: $id) {
|
||||
id
|
||||
version {
|
||||
...version
|
||||
}
|
||||
description
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,6 @@
|
||||
fragment plugin on Plugin {
|
||||
id
|
||||
version {
|
||||
current
|
||||
latest
|
||||
range
|
||||
}
|
||||
official
|
||||
installed
|
||||
website
|
||||
description
|
||||
logo
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
query pluginLogo ($id: ID!) {
|
||||
pluginLogo: plugin (id: $id) {
|
||||
id
|
||||
logo
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#import "./versionFragment.gql"
|
||||
|
||||
mutation pluginUpdate ($id: ID!) {
|
||||
pluginUpdate (id: $id) {
|
||||
id
|
||||
version {
|
||||
...version
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
fragment version on Version {
|
||||
current
|
||||
latest
|
||||
wanted
|
||||
range
|
||||
}
|
||||
@@ -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": {
|
||||
|
||||
@@ -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": {
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<div class="project-plugins page">
|
||||
<ContentView
|
||||
:title="$t('views.project-plugins.title')"
|
||||
class="limit-width"
|
||||
>
|
||||
<template slot="header">
|
||||
<VueButton
|
||||
@@ -34,6 +35,10 @@
|
||||
</template>
|
||||
</ApolloQuery>
|
||||
</ContentView>
|
||||
|
||||
<ProgressScreen
|
||||
progress-id="plugin-update"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user