From 73545252e0acc1c58061396a2d1f67f21ef1601b Mon Sep 17 00:00:00 2001 From: Guillaume Chau Date: Thu, 31 May 2018 20:10:05 +0200 Subject: [PATCH] feat: ui tweaks & fixes (#1409) * refactor(ui): use fetchPolic: 'cache-and-network' by default * feat(ui): don't display loader if cached data * fix(ui): eslint errors * feat(ui): new top bar design * fix(ui): remove work icon in top bar * fix(ui): logger view item hover background * feat(ui): Projects list show open project * feat(ui): top bar: responsive + no favorites message * fix(ui): Cannot set property consoleLogLast of # which has only a getter * fix(ui): loading prompts folder when installing plugin * feat(ui): help translating button + docs * docs(ui): fix local. docs * fix(ui): Help translate button * docs(ui): plugin ui dev docs improvements * docs(ui): typo * docs(ui): typo * docs(ui): typo * feat(ui): auto locale now tries full code + short code * docs(ui): fix missing ref locale link --- docs/localization.md | 19 +++ docs/plugin-dev-ui.md | 160 +++++++++++++++--- packages/@vue/cli-ui/locales/en.json | 6 +- packages/@vue/cli-ui/package.json | 5 +- .../@vue/cli-ui/src/components/AppLoading.vue | 23 +++ .../src/components/ConnectionStatus.vue | 1 + .../cli-ui/src/components/ContentView.vue | 33 +--- .../@vue/cli-ui/src/components/LoggerView.vue | 11 +- .../@vue/cli-ui/src/components/ProjectNav.vue | 1 - .../cli-ui/src/components/ProjectNavMore.vue | 2 +- .../src/components/ProjectPluginItem.vue | 3 +- .../src/components/ProjectSelectList.vue | 22 ++- .../src/components/ProjectSelectListItem.vue | 5 + .../@vue/cli-ui/src/components/StatusBar.vue | 37 ++-- .../@vue/cli-ui/src/components/TopBar.vue | 105 ++++++++++++ .../src/graphql-api/connectors/plugins.js | 2 +- packages/@vue/cli-ui/src/graphql/loading.gql | 3 + .../@vue/cli-ui/src/graphql/loadingChange.gql | 3 + packages/@vue/cli-ui/src/i18n.js | 31 +++- packages/@vue/cli-ui/src/main.js | 4 +- .../@vue/cli-ui/src/register-components.js | 40 ++--- packages/@vue/cli-ui/src/state/defaults.js | 3 +- packages/@vue/cli-ui/src/state/resolvers.js | 11 ++ packages/@vue/cli-ui/src/style/main.styl | 5 + packages/@vue/cli-ui/src/util/shared-data.js | 1 - .../src/views/ProjectConfigurationDetails.vue | 3 +- .../src/views/ProjectConfigurations.vue | 3 +- .../@vue/cli-ui/src/views/ProjectHome.vue | 8 +- .../@vue/cli-ui/src/views/ProjectPlugins.vue | 7 +- .../cli-ui/src/views/ProjectPluginsAdd.vue | 2 +- .../cli-ui/src/views/ProjectTaskDetails.vue | 1 - .../@vue/cli-ui/src/views/ProjectTasks.vue | 3 +- packages/@vue/cli-ui/src/vue-apollo.js | 26 ++- yarn.lock | 16 +- 34 files changed, 460 insertions(+), 145 deletions(-) create mode 100644 docs/localization.md create mode 100644 packages/@vue/cli-ui/src/components/AppLoading.vue create mode 100644 packages/@vue/cli-ui/src/components/TopBar.vue create mode 100644 packages/@vue/cli-ui/src/graphql/loading.gql create mode 100644 packages/@vue/cli-ui/src/graphql/loadingChange.gql diff --git a/docs/localization.md b/docs/localization.md new file mode 100644 index 0000000000..dbf87822e5 --- /dev/null +++ b/docs/localization.md @@ -0,0 +1,19 @@ +# Localization + +# Translate the UI + +Follow those simple steps to propose a new language for the CLI UI! + +1. Run `navigator.languages` or `navigator.language` to get the language code for the new locale. *For example: `'fr'`.* + +2. Search NPM to see if a package called `vue-cli-locale-` doesn't already exist. If it does, please contribute to it by submitting PRs! If you don't find any, create a new package called `vue-cli-locale-`. *For example: `vue-cli-locale-fr`* + +3. Put the locale JSON file in a `locales` folder and give it the name of the language code. *For example: `locales/fr.json`* + +4. In the `package.json` file, set the `unpkg` field to the path to the locale file. *For example: `"unpkg": "./locales/fr.json"`* + +5. Publish the package on NPM. + +The English reference locale is [here](https://github.com/vuejs/vue-cli/blob/dev/packages/%40vue/cli-ui/locales/en.json). + +Take a look at [the french localization package](https://github.com/Akryum/vue-cli-locale-fr) as an example. diff --git a/docs/plugin-dev-ui.md b/docs/plugin-dev-ui.md index 178a922d77..d650f9e641 100644 --- a/docs/plugin-dev-ui.md +++ b/docs/plugin-dev-ui.md @@ -10,6 +10,7 @@ This guide will walk you through the development of cli-ui specific features for - [Dev mode](#dev-mode) - [Project configurations](#project-configurations) - [Project tasks](#project-tasks) + - [Prompts](#prompts) - [Client addon](#client-addon) - [Custom views](#custom-views) - [Shared data](#shared-data) @@ -111,6 +112,8 @@ api.describeConfig({ }) ``` +#### Config icon + Specify an icon with either a file type (like `'json'`) or a file name (like `.babelrc` to get the babel icon). This is powered by file-icons. ```js @@ -121,7 +124,11 @@ api.describeConfig({ }) ``` -Then you can specify which files will be read when loading the configuration and then written to: +#### Config file + +By default, a configuration UI might read and write to a configuration file, for example `.eslintrc.js`. + +You can provide what are the possible files to be detected in the user project: ```js api.describeConfig({ @@ -138,6 +145,10 @@ api.describeConfig({ Supported types: `json`, `yaml`, `js`, `package`. +**⚠️ Currently, only 1 file can be read and written to at a time.** + +#### Display config prompts + Use the `onRead` hook to return a list of prompts to be displayed for the configuration: ```js @@ -151,25 +162,13 @@ api.describeConfig({ }) ``` -The prompt objects must be valid [inquirer](https://github.com/SBoudrias/Inquirer.js) prompts with the following additional fields (which are optional): - -```js -{ - /* ... */ - // Used to group the prompts into sections - group: 'Strongly recommended', - // Additional description - description: 'Enforce attribute naming style in template (`my-prop` or `myProp`)', - // "More info" link - link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attribute-hyphenation.md', -} -``` +Those prompts will be displayed in the configuration details pane. -Supported inquirer types: `checkbox`, `confirm`, `input`, `password`, `list`, `rawlist`. +See [Prompts](#prompts) for more info. -In addition to those, the UI supports special types that only works with it: `color`. +#### Save config changes -Use the `onWrite` hook to write the data to the configuration file (or execute any node code): +Use the `onWrite` hook to write the data to the configuration file (or execute any nodejs code): ```js api.describeConfig({ @@ -182,12 +181,12 @@ api.describeConfig({ Arguments: -- `prompts`: current prompts runtime objects +- `prompts`: current prompts runtime objects (see below) - `answers`: answers data from the user inputs - `data`: read-only initial data read from the file - `file`: descriptor of the found file (`{ type: 'json', path: '...' }`) - `cwd`: current working directory -- `api`: onWrite API +- `api`: `onWrite API` (see below) Prompts runtime objects: @@ -213,11 +212,28 @@ Prompts runtime objects: } ``` -onWrite API: +`onWrite` API: - `assignData(newData)`: use `Object.assign` to update the config data before writing. - `setData(newData)`: each key of `newData` will be deeply set (or removed if `undefined` value) to the config data before writing. -- `async getAnswer(id, mapper)`: retrieve answer for a given prompt id and map it through `mapper` function if provide (for example `JSON.parse`). +- `async getAnswer(id, mapper)`: retrieve answer for a given prompt id and map it through `mapper` function if provided (for example `JSON.parse`). + +Example (from the ESLint plugin): + +```js +api.describeConfig({ + // ... + + onWrite: async ({ api, prompts }) => { + // Update ESLint rules + const result = {} + for (const prompt of prompts) { + result[`rules.${prompt.id}`] = await api.getAnswer(prompt.id, JSON.parse) + } + api.setData(result) + } +}) +``` ### Project tasks @@ -233,7 +249,20 @@ api.describeTask({ match: /vue-cli-service serve/, description: 'Compiles and hot-reloads for development', // "More info" link - link: 'https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#serve', + link: 'https://github.com/vuejs/vue-cli/blob/dev/docs/cli-service.md#serve' +}) +``` + +#### Tasks parameters + +You can add prompts to modify the command arguments. They will be displayed in a 'Parameters' modal. + +Example: + +```js +api.describeTask({ + // ... + // Optional parameters (inquirer prompts) prompts: [ { @@ -262,7 +291,26 @@ api.describeTask({ ], description: 'Specify env mode' } - ], + ] +}) +``` + +See [Prompts](#prompts) for more info. + +#### Task hooks + +Several hooks are available: + +- `onBeforeRun` +- `onRun` +- `onExit` + +For example, you can use the answers to the prompts (see above) to add new arguments to the command: + +```js +api.describeTask({ + // ... + // Hooks // Modify arguments here onBeforeRun: async ({ answers, args }) => { @@ -279,7 +327,18 @@ api.describeTask({ onExit: async ({ args, child, cwd, code, signal }) => { // code: exit code // signal: kill signal used if any - }, + } +}) +``` + +#### Task views + +You can display custom views in the task details pane using the `ClientAddon` API: + +```js +api.describeTask({ + // ... + // Additional views (for example the webpack dashboard) // By default, there is the 'output' view which displays the terminal output views: [ @@ -299,9 +358,16 @@ api.describeTask({ }) ``` +See [Client addon](#client-addon) for more info. + + #### Add new tasks -You can also add entirely new tasks which aren't in the `package.json` scripts. Those tasks will only appear in the cli UI: +You can also add entirely new tasks which aren't in the `package.json` scripts with `api.addTask` instead of `api.describeTask`. Those tasks will only appear in the cli UI. + +**You need to provide a `command` option instead of `match`.** + +Example: ```js api.addTask({ @@ -323,6 +389,36 @@ api.addTask({ **⚠️ The `command` will run a node context. This means you can call node bin commands like you would normally do in the `package.json` scripts.** +### Prompts + +The prompt objects must be valid [inquirer](https://github.com/SBoudrias/Inquirer.js) objects. + +However, you can add the following additional fields (which are optional and only used by the UI): + +```js +{ + /* ... */ + // Used to group the prompts into sections + group: 'Strongly recommended', + // Additional description + description: 'Enforce attribute naming style in template (`my-prop` or `myProp`)', + // "More info" link + link: 'https://github.com/vuejs/eslint-plugin-vue/blob/master/docs/rules/attribute-hyphenation.md', +} +``` + +Supported inquirer types: `checkbox`, `confirm`, `input`, `password`, `list`, `rawlist`. + +In addition to those, the UI supports special types that only works with it: + +- `color`: displays a color picker. + +#### Prompts for invocation + +In your vue-cli plugin, you may already have a `prompts.js` file which asks the user a few questions when installing the plugin (with the CLI or the UI). You can add the additional UI-only fields (see above) to those prompt objects as well so they will provide more information if the user is using the UI. + +**⚠️ Currently, the inquirer types which aren't supported (see above) whill not work properly in the UI.** + ### Client addon A Client addon is a JS bundle which is dynamically loaded into the cli-ui. It is useful to load custom components and routes. @@ -518,7 +614,9 @@ ClientAddonApi.addRoutes('vue-webpack', [ Use Shared data to communicate info with custom components in an easy way. -In the plugin `ui.js`: +> For example, the Webpack dashboard shares the build stats between the UI client and the UI server using this API. + +In the plugin `ui.js` (nodejs): ```js // Set or update @@ -554,7 +652,8 @@ const { In the custom component: ```js -{ +// Vue component +export default { // Sync Shared data sharedData () { return { @@ -605,6 +704,8 @@ This is very usefull if you create a settings component for example. Plugin actions are calls sent between the cli-ui (browser) and plugins (nodejs). +> For example, you might have a button in a custom component (see [Client addon](#client-addon)) which calls some nodejs code on the server using this API. + In the `ui.js` file in the plugin (nodejs), you can use two methods from `PluginApi`: ```js @@ -632,6 +733,7 @@ const { onAction, callAction } = api.namespace('vue-webpack-') In the client addon components (browser), you have access to `$onPluginActionCalled`, `$onPluginActionResolved` and `$callPluginAction`: ```js +// Vue component export default { created () { this.$onPluginActionCalled(action => { @@ -780,6 +882,10 @@ locales.keys().forEach(key => { }) ``` +#### Help translate the main UI! + +See [how to help translating the main UI](./localization.md). + ### Hooks Hooks allows to react to certain cli-ui events. diff --git a/packages/@vue/cli-ui/locales/en.json b/packages/@vue/cli-ui/locales/en.json index a201d001b6..8ef7c12e00 100644 --- a/packages/@vue/cli-ui/locales/en.json +++ b/packages/@vue/cli-ui/locales/en.json @@ -110,7 +110,8 @@ "tooltip": "Logs
Click to toggle Vue CLI logs", "empty": "No logs yet" }, - "report-bug": "Report bug" + "report-bug": "Report bug", + "translate": "Help translate" }, "terminal-view": { "buttons": { @@ -118,6 +119,9 @@ "scroll": "Scroll to bottom" } }, + "top-bar": { + "no-favorites": "No favorite projects" + }, "view-badge": { "labels": { "tasks": { diff --git a/packages/@vue/cli-ui/package.json b/packages/@vue/cli-ui/package.json index a2ec547750..7516dab65b 100644 --- a/packages/@vue/cli-ui/package.json +++ b/packages/@vue/cli-ui/package.json @@ -39,7 +39,7 @@ "semver": "^5.5.0", "shortid": "^2.2.8", "terminate": "^2.1.0", - "vue-cli-plugin-apollo": "^0.13.0", + "vue-cli-plugin-apollo": "^0.13.4", "watch": "^1.0.2" }, "devDependencies": { @@ -55,11 +55,12 @@ "eslint-plugin-graphql": "^2.1.1", "file-icons-js": "^1.0.3", "lint-staged": "^6.0.0", + "portal-vue": "^1.3.0", "start-server-and-test": "^1.4.1", "stylus": "^0.54.5", "stylus-loader": "^3.0.1", "vue": "^2.5.16", - "vue-apollo": "^3.0.0-beta.5", + "vue-apollo": "^3.0.0-beta.16", "vue-color": "^2.4.6", "vue-i18n": "^7.6.0", "vue-instantsearch": "^1.5.1", diff --git a/packages/@vue/cli-ui/src/components/AppLoading.vue b/packages/@vue/cli-ui/src/components/AppLoading.vue new file mode 100644 index 0000000000..fa365ae490 --- /dev/null +++ b/packages/@vue/cli-ui/src/components/AppLoading.vue @@ -0,0 +1,23 @@ + + + diff --git a/packages/@vue/cli-ui/src/components/ConnectionStatus.vue b/packages/@vue/cli-ui/src/components/ConnectionStatus.vue index 81a1cb0f05..675cffef01 100644 --- a/packages/@vue/cli-ui/src/components/ConnectionStatus.vue +++ b/packages/@vue/cli-ui/src/components/ConnectionStatus.vue @@ -1,6 +1,7 @@