diff options
Diffstat (limited to 'doc/development')
-rw-r--r-- | doc/development/architecture.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/img/vue_arch.png | bin | 9848 -> 0 bytes | |||
-rw-r--r-- | doc/development/fe_guide/vue.md | 239 | ||||
-rw-r--r-- | doc/development/what_requires_downtime.md | 4 |
4 files changed, 14 insertions, 231 deletions
diff --git a/doc/development/architecture.md b/doc/development/architecture.md index e6cf5e01f46..3e417a44ec1 100644 --- a/doc/development/architecture.md +++ b/doc/development/architecture.md @@ -197,4 +197,4 @@ Note: It is recommended to log into the `git` user using `sudo -i -u git` or `su ## GitLab.com -CONFLICT! +We've also detailed [our architecture of GitLab.com](https://about.gitlab.com/handbook/engineering/infrastructure/production-architecture/) but this is probably over the top unless you have millions of users. diff --git a/doc/development/fe_guide/img/vue_arch.png b/doc/development/fe_guide/img/vue_arch.png Binary files differdeleted file mode 100644 index a67706c7c1e..00000000000 --- a/doc/development/fe_guide/img/vue_arch.png +++ /dev/null diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 219b98ac696..f6cbd11042c 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -2,27 +2,24 @@ To get started with Vue, read through [their documentation][vue-docs]. -## Vue architecture +## Examples -All new features built with Vue.js must follow a [Flux architecture][flux]. -The main goal we are trying to achieve is to have only one data flow and only one data entry. -In order to achieve this goal, you can either use [vuex](#vuex) or use the [store pattern][state-management], explained below: +What is described in the following sections can be found in these examples: -Each Vue bundle needs a Store - where we keep all the data -, a Service - that we use to communicate with the server - and a main Vue component. +- web ide: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/ide/stores +- security products: https://gitlab.com/gitlab-org/gitlab-ee/tree/master/ee/app/assets/javascripts/vue_shared/security_reports +- registry: https://gitlab.com/gitlab-org/gitlab-ce/tree/master/app/assets/javascripts/registry/stores -Think of the Main Vue Component as the entry point of your application. This is the only smart -component that should exist in each Vue feature. -This component is responsible for: -1. Calling the Service to get data from the server -1. Calling the Store to store the data received -1. Mounting all the other components +## Vue architecture -![Vue Architecture](img/vue_arch.png) +All new features built with Vue.js must follow a [Flux architecture][flux]. +The main goal we are trying to achieve is to have only one data flow and only one data entry. +In order to achieve this goal we use [vuex](#vuex). You can also read about this architecture in vue docs about [state management][state-management] and about [one way data flow][one-way-data-flow]. -### Components, Stores and Services +### Components and Store In some features implemented with Vue.js, like the [issue board][issue-boards] or [environments table][environments-table] @@ -33,10 +30,8 @@ new_feature ├── components │ └── component.vue │ └── ... -├── stores +├── store │ └── new_feature_store.js -├── services # only when not using vuex -│ └── new_feature_service.js ├── index.js ``` _For consistency purposes, we recommend you to follow the same structure._ @@ -125,217 +120,6 @@ You can read more about components in Vue.js site, [Component System][component- #### Vuex Check this [page](vuex.md) for more details. -#### Flux like state management -The Store is a class that allows us to manage the state in a single -source of truth. It is not aware of the service or the components. - -The concept we are trying to follow is better explained by Vue documentation -itself, please read this guide: [State Management][state-management] - -### A folder for the Service - -**If you are using Vuex you won't need this step** - -The Service is a class used only to communicate with the server. -It does not store or manipulate any data. It is not aware of the store or the components. -We use [axios][axios] to communicate with the server. -Refer to [axios](axios.md) for more details. - -Axios instance should only be imported in the service file. - -```javascript -import axios from '~/lib/utils/axios_utils'; -``` - -### End Result - -The following example shows an application: - -```javascript -// store.js -export default class Store { - - /** - * This is where we will iniatialize the state of our data. - * Usually in a small SPA you don't need any options when starting the store. - * In that case you do need guarantee it's an Object and it's documented. - * - * @param {Object} options - */ - constructor(options) { - this.options = options; - - // Create a state object to handle all our data in the same place - this.todos = []; - } - - setTodos(todos = []) { - this.todos = todos; - } - - addTodo(todo) { - this.todos.push(todo); - } - - removeTodo(todoID) { - const state = this.todos; - - const newState = state.filter((element) => {element.id !== todoID}); - - this.todos = newState; - } -} - -// service.js -import axios from '~/lib/utils/axios_utils' - -export default class Service { - constructor(options) { - this.todos = axios.create({ - baseURL: endpoint.todosEndpoint - }); - - } - - getTodos() { - return this.todos.get(); - } - - addTodo(todo) { - return this.todos.put(todo); - } -} -// todo_component.vue -<script> -export default { - props: { - data: { - type: Object, - required: true, - }, - }, -}; -</script> -<template> - <div> - <h1> - Title: {{data.title}} - </h1> - <p> - {{data.text}} - </p> - </div> -</template> - -// todos_main_component.vue -<script> -import Store from 'store'; -import Service from 'service'; -import TodoComponent from 'todoComponent'; -export default { - components: { - todo: TodoComponent, - }, - /** - * Although most data belongs in the store, each component it's own state. - * We want to show a loading spinner while we are fetching the todos, this state belong - * in the component. - * - * We need to access the store methods through all methods of our component. - * We need to access the state of our store. - */ - data() { - const store = new Store(); - - return { - isLoading: false, - store: store, - todos: store.todos, - }; - }, - - created() { - this.service = new Service('/todos'); - - this.getTodos(); - }, - - methods: { - getTodos() { - this.isLoading = true; - - this.service - .getTodos() - .then(response => { - this.store.setTodos(response); - this.isLoading = false; - }) - .catch(() => { - this.isLoading = false; - // Show an error - }); - }, - - addTodo(event) { - this.service - .addTodo({ - title: 'New entry', - text: `You clicked on ${event.target.tagName}`, - }) - .then(response => { - this.store.addTodo(response); - }) - .catch(() => { - // Show an error - }); - }, - }, -}; -</script> -<template> - <div class="container"> - <div v-if="isLoading"> - <i - class="fa fa-spin fa-spinner" - aria-hidden="true" /> - </div> - - <div - v-if="!isLoading" - class="js-todo-list"> - <template v-for='todo in todos'> - <todo :data="todo" /> - </template> - - <button - @click="addTodo" - class="js-add-todo"> - Add Todo - </button> - </div> - <div> -</template> - -// index.js -import todoComponent from 'todos_main_component.vue'; - -new Vue({ - el: '.js-todo-app', - components: { - todoComponent, - }, - render: createElement => createElement('todo-component' { - props: { - someProp: [], - } - }), -}); - -``` - -The [issue boards service][issue-boards-service] -is a good example of this pattern. - ## Style guide Please refer to the Vue section of our [style guide](style_guide_js.md#vue-js) @@ -446,6 +230,5 @@ need to test the rendered output. [Vue][vue-test] guide's to unit test show us e [state-management]: https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch [one-way-data-flow]: https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow [vue-test]: https://vuejs.org/v2/guide/unit-testing.html -[issue-boards-service]: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/app/assets/javascripts/boards/services/board_service.js.es6 [flux]: https://facebook.github.io/flux [axios]: https://github.com/axios/axios diff --git a/doc/development/what_requires_downtime.md b/doc/development/what_requires_downtime.md index 47396666879..b668c9de6a0 100644 --- a/doc/development/what_requires_downtime.md +++ b/doc/development/what_requires_downtime.md @@ -198,14 +198,14 @@ And that's it, we're done! ## Changing The Schema For Large Tables While `change_column_type_concurrently` and `rename_column_concurrently` can be -used for changing the schema of a table without downtime it doesn't work very +used for changing the schema of a table without downtime, it doesn't work very well for large tables. Because all of the work happens in sequence the migration can take a very long time to complete, preventing a deployment from proceeding. They can also produce a lot of pressure on the database due to it rapidly updating many rows in sequence. To reduce database pressure you should instead use -`change_column_type_using_background_migration` or `rename_column_concurrently` +`change_column_type_using_background_migration` or `rename_column_using_background_migration` when migrating a column in a large table (e.g. `issues`). These methods work similarly to the concurrent counterparts but uses background migration to spread the work / load over a longer time period, without slowing down deployments. |