Skip to content

Commit

Permalink
feat: ui tweaks & fixes (#1409)
Browse files Browse the repository at this point in the history
* 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 #<a> 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
  • Loading branch information
Akryum authored and yyx990803 committed May 31, 2018
1 parent af1151a commit 7354525
Show file tree
Hide file tree
Showing 34 changed files with 460 additions and 145 deletions.
19 changes: 19 additions & 0 deletions docs/localization.md
Original file line number Diff line number Diff line change
@@ -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-<language code>` 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-<language code>`. *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.
160 changes: 133 additions & 27 deletions docs/plugin-dev-ui.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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({
Expand All @@ -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
Expand All @@ -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({
Expand All @@ -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:

Expand All @@ -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

Expand All @@ -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: [
{
Expand Down Expand Up @@ -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 }) => {
Expand All @@ -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: [
Expand All @@ -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({
Expand All @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -554,7 +652,8 @@ const {
In the custom component:

```js
{
// Vue component
export default {
// Sync Shared data
sharedData () {
return {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 => {
Expand Down Expand Up @@ -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.
Expand Down
6 changes: 5 additions & 1 deletion packages/@vue/cli-ui/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -110,14 +110,18 @@
"tooltip": "Logs<br><i>Click to toggle Vue CLI logs</i>",
"empty": "No logs yet"
},
"report-bug": "Report bug"
"report-bug": "Report bug",
"translate": "Help translate"
},
"terminal-view": {
"buttons": {
"clear": "Clear console",
"scroll": "Scroll to bottom"
}
},
"top-bar": {
"no-favorites": "No favorite projects"
},
"view-badge": {
"labels": {
"tasks": {
Expand Down
5 changes: 3 additions & 2 deletions packages/@vue/cli-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": {
Expand All @@ -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",
Expand Down
23 changes: 23 additions & 0 deletions packages/@vue/cli-ui/src/components/AppLoading.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<template>
<div class="app-loading">
<transition name="vue-ui-fade">
<VueLoadingIndicator
v-if="loading"
class="primary"
/>
</transition>
</div>
</template>

<script>
import LOADING from '../graphql/loading.gql'
export default {
apollo: {
loading: {
query: LOADING,
fetchPolicy: 'cache-only'
}
}
}
</script>
1 change: 1 addition & 0 deletions packages/@vue/cli-ui/src/components/ConnectionStatus.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<template>
<ApolloQuery
:query="require('../graphql/connected.gql')"
fetch-policy="cache-only"
class="connection-status"
>
<template slot-scope="{ result: { data: { connected } } }">
Expand Down
Loading

0 comments on commit 7354525

Please sign in to comment.