feat(ui): ProjectNav plugin support

This commit is contained in:
Guillaume Chau
2018-04-21 18:01:40 +02:00
parent 9fbe07cf13
commit 9d8dc0be6e
12 changed files with 120 additions and 57 deletions

View File

@@ -0,0 +1,11 @@
<template>
<div class="test-view">
<h1>I'm a custom view</h1>
<p>A vue-cli plugin created me! I am a dynamically loaded component paired with a custom route.</p>
</div>
</template>
<style lang="stylus" scoped>
.test-view
padding 42px
</style>

View File

@@ -1,8 +1,13 @@
import VueProgress from 'vue-progress-path'
import WebpackDashboard from './components/WebpackDashboard.vue'
import TestView from './components/TestView.vue'
Vue.use(VueProgress, {
defaultShape: 'circle'
})
ClientAddonApi.component('vue-webpack-dashboard', WebpackDashboard)
ClientAddonApi.addRoutes('vue-webpack', [
{ path: '', name: 'test-webpack-route', component: TestView }
])

View File

@@ -1,24 +1,31 @@
// Connectors
const logs = require('../connectors/logs')
const plugins = require('../connectors/plugins')
const sharedData = require('../connectors/shared-data')
const routes = require('../connectors/routes')
// Utils
const ipc = require('../utils/ipc')
const { validate: validateConfig } = require('./configuration')
const { validate: validateTask } = require('./task')
const { validate: validateClientAddon } = require('./client-addon')
// Validators
const { validateConfiguration } = require('./configuration')
const { validateTask } = require('./task')
const { validateClientAddon } = require('./client-addon')
const { validateRoute, validateBadge } = require('./route')
class PluginApi {
constructor (context) {
this.context = context
this.pluginId = null
// Data
this.configurations = []
this.tasks = []
this.clientAddons = []
this.routes = []
this.actions = new Map()
this.pluginId = null
}
describeConfig (options) {
try {
validateConfig(options)
validateConfiguration(options)
this.configurations.push(options)
} catch (e) {
logs.add({
@@ -64,6 +71,42 @@ class PluginApi {
}
}
/* Routes */
addRoute (options) {
try {
validateRoute(options)
this.routes.push(options)
} catch (e) {
logs.add({
type: 'error',
tag: 'PluginApi',
message: `(${this.pluginId || 'unknown plugin'}) 'addRoute' options are invalid\n${e.message}`
}, this.context)
console.error(new Error(`Invalid options: ${e.message}`))
}
}
addRouteBadge (routeId, options) {
try {
validateBadge(options)
routes.addBadge({ routeId, badge: options }, this.context)
} catch (e) {
logs.add({
type: 'error',
tag: 'PluginApi',
message: `(${this.pluginId || 'unknown plugin'}) 'addRouteBadge' options are invalid\n${e.message}`
}, this.context)
console.error(new Error(`Invalid options: ${e.message}`))
}
}
removeRouteBadge (routeId, badgeId) {
routes.removeBadge({ routeId, badgeId }, this.context)
}
/* IPC */
ipcOn (cb) {
return ipc.on(cb)
}

View File

@@ -6,6 +6,6 @@ const schema = createSchema(joi => ({
url: joi.string()
}))
exports.validate = (options) => {
exports.validateClientAddon = (options) => {
validateSync(options, schema)
}

View File

@@ -16,6 +16,6 @@ const schema = createSchema(joi => ({
onWrite: joi.func().required()
}))
exports.validate = (options) => {
exports.validateConfiguration = (options) => {
validateSync(options, schema)
}

View File

@@ -0,0 +1,25 @@
const { createSchema, validateSync } = require('@vue/cli-shared-utils')
const routeSchema = createSchema(joi => ({
id: joi.string().required(),
name: joi.string().required().description('route name (vue-router)'),
icon: joi.string().required(),
tooltip: joi.string().required()
}))
const badgeSchema = createSchema(joi => ({
id: joi.string().required(),
type: joi.string(),
label: joi.string().required(),
count: joi.number().integer(),
priority: joi.number().integer(),
hidden: joi.boolean()
}))
exports.validateRoute = (options) => {
validateSync(options, routeSchema)
}
exports.validateBadge = (options) => {
validateSync(options, badgeSchema)
}

View File

@@ -17,6 +17,6 @@ const schema = createSchema(joi => ({
onExit: joi.func()
}))
exports.validate = (options) => {
exports.validateTask = (options) => {
validateSync(options, schema)
}

View File

@@ -8,8 +8,6 @@ module.exports = {
ROUTE_ADDED: 'route_added',
ROUTE_REMOVED: 'route_removed',
ROUTE_CHANGED: 'route_changed',
VUE_ROUTER_DEFINITION_ADDED: 'vue_router_definition_added',
VUE_ROUTER_DEFINITION_REMOVED: 'vue_router_definition_removed',
CLIENT_ADDON_ADDED: 'client_addon_added',
SHARED_DATA_UPDATED: 'shared_data_updated',
PLUGIN_ACTION_CALLED: 'plugin_action_called',

View File

@@ -26,6 +26,7 @@ const prompts = require('./prompts')
const progress = require('./progress')
const logs = require('./logs')
const clientAddons = require('./client-addons')
const routes = require('./routes')
// Api
const PluginApi = require('../api/PluginApi')
// Utils
@@ -77,6 +78,11 @@ function list (file, context) {
}
function resetPluginApi (context) {
// Clean up
if (pluginApi) {
pluginApi.routes.forEach(r => routes.remove(r.id, context))
}
pluginApi = new PluginApi(context)
// Run Plugin API
runPluginApi('@vue/cli-service', context)
@@ -84,6 +90,8 @@ function resetPluginApi (context) {
runPluginApi('.', context, 'vue-cli-ui')
// Add client addons
pluginApi.clientAddons.forEach(options => clientAddons.add(options, context))
// Add routes
pluginApi.routes.forEach(route => routes.add(route, context))
}
function runPluginApi (id, context, fileName = 'ui') {

View File

@@ -26,8 +26,6 @@ let routes = [
...BUILTIN_ROUTES
]
let vueRouterDefinitions = []
function list (context) {
return routes
}
@@ -64,29 +62,6 @@ function update (route, context) {
}
}
function listVueRouterDefinitions (context) {
return vueRouterDefinitions
}
function addVueRouterDefinition ({ id, routes }, context) {
const def = { id, routes }
vueRouterDefinitions.push(def)
context.pubsub.publish(channels.VUE_ROUTER_DEFINITION_ADDED, {
vueRouterDEfinitionAdded: def
})
}
function removeVueRouterDefinition (id, context) {
const index = vueRouterDefinitions.findIndex(d => d.id === id)
if (index !== -1) {
const def = vueRouterDefinitions[index]
vueRouterDefinitions.splice(index, 1)
context.pubsub.publish(channels.VUE_ROUTER_DEFINITION_REMOVED, {
vueRouterDefinitionRemoved: def
})
}
}
function addBadge ({ routeId, badge }, context) {
const route = findOne(routeId)
if (route) {
@@ -94,12 +69,12 @@ function addBadge ({ routeId, badge }, context) {
const existingBadge = route.badges.find(b => b.id === badge.id)
if (existingBadge) {
Object.assign(existingBadge, badge, {
count: existingBadge.count + 1
count: existingBadge.count + (badge.count || 1)
})
} else {
route.badges.push({
type: 'dim',
count: 1,
count: (badge.count || 1),
priority: 0,
hidden: false,
...badge
@@ -130,9 +105,6 @@ module.exports = {
add,
remove,
update,
listVueRouterDefinitions,
addVueRouterDefinition,
removeVueRouterDefinition,
addBadge,
removeBadge
}

View File

@@ -7,15 +7,12 @@ const routes = require('../connectors/routes')
exports.types = gql`
extend type Query {
routes: [Route]
vueRouterDefinitions: [VueRouterDefinition]
}
extend type Subscription {
routeAdded: Route
routeRemoved: Route
routeChanged: Route
vueRouterDefinitionAdded: VueRouterDefinition
vueRouterDefinitionRemoved: VueRouterDefinition
}
type Route {
@@ -43,17 +40,11 @@ enum RouteBadgeType {
accent
dim
}
type VueRouterDefinition {
id: ID!
routes: JSON
}
`
exports.resolvers = {
Query: {
routes: (root, args, context) => routes.list(context),
vueRouterDefinitions: (root, args, context) => routes.listVueRouterDefinitions(context)
routes: (root, args, context) => routes.list(context)
},
Subscription: {
@@ -65,12 +56,6 @@ exports.resolvers = {
},
routeRemoved: {
subscribe: (parent, args, { pubsub }) => pubsub.asyncIterator(channels.ROUTE_REMOVED)
},
vueRouterDefinitionAdded: {
subscribe: (parent, args, { pubsub }) => pubsub.asyncIterator(channels.VUE_ROUTER_DEFINITION_ADDED)
},
vueRouterDefinitionRemoved: {
subscribe: (parent, args, { pubsub }) => pubsub.asyncIterator(channels.VUE_ROUTER_DEFINITION_REMOVED)
}
}
}

View File

@@ -1,7 +1,9 @@
import Vue from 'vue'
import router from '../router'
import ProjectHome from '../views/ProjectHome.vue'
export default class ClientAddonApi {
constructor (addonId) {
constructor () {
this.components = new Map()
this.componentListeners = new Map()
}
@@ -42,6 +44,20 @@ export default class ClientAddonApi {
}
})
}
addRoutes (id, routes) {
router.addRoutes([
{
path: `/addon/${id}`,
component: ProjectHome,
meta: {
needProject: true,
restore: true
},
children: routes
}
])
}
}
export function toComponentId (id) {