diff options
Diffstat (limited to 'doc/development/fe_guide')
-rw-r--r-- | doc/development/fe_guide/axios.md | 16 | ||||
-rw-r--r-- | doc/development/fe_guide/dependencies.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/development_process.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/droplab/plugins/ajax.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/droplab/plugins/filter.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/droplab/plugins/input_setter.md | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/emojis.md | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/frontend_faq.md | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/graphql.md | 107 | ||||
-rw-r--r-- | doc/development/fe_guide/icons.md | 8 | ||||
-rw-r--r-- | doc/development/fe_guide/performance.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/style/vue.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/vue.md | 10 |
13 files changed, 114 insertions, 51 deletions
diff --git a/doc/development/fe_guide/axios.md b/doc/development/fe_guide/axios.md index f8d301dac5e..38a8c8f1086 100644 --- a/doc/development/fe_guide/axios.md +++ b/doc/development/fe_guide/axios.md @@ -1,15 +1,15 @@ # Axios -We use [axios](https://github.com/axios/axios) to communicate with the server in Vue applications and most new code. +We use [Axios](https://github.com/axios/axios) to communicate with the server in Vue applications and most new code. -In order to guarantee all defaults are set you *should not use `axios` directly*, you should import `axios` from `axios_utils`. +In order to guarantee all defaults are set you *should not use Axios directly*, you should import Axios from `axios_utils`. ## CSRF token -All our request require a CSRF token. -To guarantee this token is set, we are importing [axios](https://github.com/axios/axios), setting the token, and exporting `axios` . +All our requests require a CSRF token. +To guarantee this token is set, we are importing [Axios](https://github.com/axios/axios), setting the token, and exporting `axios` . -This exported module should be used instead of directly using `axios` to ensure the token is set. +This exported module should be used instead of directly using Axios to ensure the token is set. ## Usage @@ -30,7 +30,7 @@ This exported module should be used instead of directly using `axios` to ensure }); ``` -## Mock axios response in tests +## Mock Axios response in tests To help us mock the responses we are using [axios-mock-adapter](https://github.com/ctimmerm/axios-mock-adapter). @@ -41,7 +41,7 @@ Advantages over [`spyOn()`](https://jasmine.github.io/api/edge/global.html#spyOn - simple API to test error cases - provides `replyOnce()` to allow for different responses -We have also decided against using [axios interceptors](https://github.com/axios/axios#interceptors) because they are not suitable for mocking. +We have also decided against using [Axios interceptors](https://github.com/axios/axios#interceptors) because they are not suitable for mocking. ### Example @@ -67,7 +67,7 @@ We have also decided against using [axios interceptors](https://github.com/axios }); ``` -### Mock poll requests in tests with axios +### Mock poll requests in tests with Axios Because polling function requires a header object, we need to always include an object as the third argument: diff --git a/doc/development/fe_guide/dependencies.md b/doc/development/fe_guide/dependencies.md index 0f5825992e9..7f078df887d 100644 --- a/doc/development/fe_guide/dependencies.md +++ b/doc/development/fe_guide/dependencies.md @@ -32,7 +32,7 @@ because they can create conflicts in the dependency tree. Blocked dependencies a ### BootstrapVue -[BootstrapVue](https://bootstrap-vue.js.org/) is a component library built with Vue.js and Bootstrap. +[BootstrapVue](https://bootstrap-vue.org/) is a component library built with Vue.js and Bootstrap. We wrap BootstrapVue components in [GitLab UI](https://gitlab.com/gitlab-org/gitlab-ui/) with the purpose of applying visual styles and usage guidelines specified in the [Pajamas Design System](https://design.gitlab.com/). For this reason, we recommend not installing diff --git a/doc/development/fe_guide/development_process.md b/doc/development/fe_guide/development_process.md index 6e078f097cd..892e931bf5b 100644 --- a/doc/development/fe_guide/development_process.md +++ b/doc/development/fe_guide/development_process.md @@ -23,7 +23,7 @@ Please use your best judgment when to use it and please contribute new points th - [ ] Are all necessary UX specifications available that you will need in order to implement? Are there new UX components/patterns in the designs? Then contact the UI component team early on. How should error messages or validation be handled? - [ ] **Library usage** Use Vuex as soon as you have even a medium state to manage, use Vue router if you need to have different views internally and want to link from the outside. Check what libraries we already have for which occasions. - [ ] **Plan your implementation:** - - [ ] **Architecture plan:** Create a plan aligned with GitLab's architecture, how you are going to do the implementation, for example Vue application setup and its components (through [onion skinning](https://gitlab.com/gitlab-org/gitlab-foss/issues/35873#note_39994091)), Store structure and data flow, which existing Vue components can you reuse. It's a good idea to go through your plan with another engineer to refine it. + - [ ] **Architecture plan:** Create a plan aligned with GitLab's architecture, how you are going to do the implementation, for example Vue application setup and its components (through [onion skinning](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/35873#note_39994091)), Store structure and data flow, which existing Vue components can you reuse. It's a good idea to go through your plan with another engineer to refine it. - [ ] **Backend:** The best way is to kickoff the implementation in a call and discuss with the assigned Backend engineer what you will need from the backend and also when. Can you reuse existing API's? How is the performance with the planned architecture? Maybe create together a JSON mock object to already start with development. - [ ] **Communication:** It also makes sense to have for bigger features an own slack channel (normally called #f_{feature_name}) and even weekly demo calls with all people involved. - [ ] **Dependency Plan:** Are there big dependencies in the plan between you and others, then maybe create an execution diagram to show what is blocking which part and the order of the different parts. diff --git a/doc/development/fe_guide/droplab/plugins/ajax.md b/doc/development/fe_guide/droplab/plugins/ajax.md index abc208e7568..f22d95064dd 100644 --- a/doc/development/fe_guide/droplab/plugins/ajax.md +++ b/doc/development/fe_guide/droplab/plugins/ajax.md @@ -6,7 +6,7 @@ Add the `Ajax` object to the plugins array of a `DropLab.prototype.init` or `DropLab.prototype.addHook` call. -`Ajax` requires 2 config values, the `endpoint` and `method`. +`Ajax` requires 2 configuration values, the `endpoint` and `method`. - `endpoint` should be a URL to the request endpoint. - `method` should be `setData` or `addData`. diff --git a/doc/development/fe_guide/droplab/plugins/filter.md b/doc/development/fe_guide/droplab/plugins/filter.md index 876149e4872..e8194e45a41 100644 --- a/doc/development/fe_guide/droplab/plugins/filter.md +++ b/doc/development/fe_guide/droplab/plugins/filter.md @@ -7,7 +7,7 @@ to the dropdown using a simple fuzzy string search of an input value. Add the `Filter` object to the plugins array of a `DropLab.prototype.init` or `DropLab.prototype.addHook` call. -- `Filter` requires a config value for `template`. +- `Filter` requires a configuration value for `template`. - `template` should be the key of the objects within your data array that you want to compare to the user input string, for filtering. diff --git a/doc/development/fe_guide/droplab/plugins/input_setter.md b/doc/development/fe_guide/droplab/plugins/input_setter.md index 9b2e1e8faab..b873b7a14ee 100644 --- a/doc/development/fe_guide/droplab/plugins/input_setter.md +++ b/doc/development/fe_guide/droplab/plugins/input_setter.md @@ -6,12 +6,12 @@ Add the `InputSetter` object to the plugins array of a `DropLab.prototype.init` or `DropLab.prototype.addHook` call. -- `InputSetter` requires a config value for `input` and `valueAttribute`. +- `InputSetter` requires a configuration value for `input` and `valueAttribute`. - `input` should be the DOM element that you want to manipulate. - `valueAttribute` should be a string that is the name of an attribute on your list items that is used to get the value to update the `input` element with. -You can also set the `InputSetter` config to an array of objects, which will allow you to update multiple elements. +You can also set the `InputSetter` configuration to an array of objects, which will allow you to update multiple elements. ```html <input id="input" value=""> diff --git a/doc/development/fe_guide/emojis.md b/doc/development/fe_guide/emojis.md index 6d324d4c4a0..3cd14c0dfd3 100644 --- a/doc/development/fe_guide/emojis.md +++ b/doc/development/fe_guide/emojis.md @@ -1,6 +1,6 @@ # Emojis -GitLab supports native unicode emojis and fallsback to image-based emojis selectively +GitLab supports native Unicode emojis and falls back to image-based emojis selectively when your platform does not support it. ## How to update Emojis @@ -21,7 +21,7 @@ when your platform does not support it. 1. Ensure you see new individual images copied into `app/assets/images/emoji/` 1. Ensure you can see the new emojis and their aliases in the GFM Autocomplete 1. Ensure you can see the new emojis and their aliases in the award emoji menu - 1. You might need to add new emoji unicode support checks and rules for platforms + 1. You might need to add new emoji Unicode support checks and rules for platforms that do not support a certain emoji and we need to fallback to an image. See `app/assets/javascripts/emoji/support/is_emoji_unicode_supported.js` and `app/assets/javascripts/emoji/support/unicode_support_map.js` diff --git a/doc/development/fe_guide/frontend_faq.md b/doc/development/fe_guide/frontend_faq.md index 8f8f162609a..4f814f3cdde 100644 --- a/doc/development/fe_guide/frontend_faq.md +++ b/doc/development/fe_guide/frontend_faq.md @@ -82,7 +82,7 @@ To avoid this behavior, add the class `js-no-auto-disable` to the button. ### 5. Should I use a full URL (i.e. `gon.gitlab_url`) or a full path (i.e. `gon.relative_url_root`) when referencing backend endpoints? It's preferred to use a **full path** over a **full URL** because the URL will use the hostname configured with -GitLab which may not match the request. This will cause [CORS issues like this Web IDE one](https://gitlab.com/gitlab-org/gitlab/issues/36810). +GitLab which may not match the request. This will cause [CORS issues like this Web IDE one](https://gitlab.com/gitlab-org/gitlab/-/issues/36810). Example: @@ -141,7 +141,7 @@ function initFoo() { }); } -// Vuex action can now reference the path from it's state :) +// Vuex action can now reference the path from its state :) export const fetchFoos = ({ state }) => { return axios.get(state.settings.fooPath); }; diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index caf84d04490..191ebd2ff58 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -1,7 +1,69 @@ # GraphQL +## Getting Started + +### Helpful Resources + +**General resources**: + +- [📚 Official Introduction to GraphQL](https://graphql.org/learn/) +- [📚 Official Introduction to Apollo](https://www.apollographql.com/docs/tutorial/introduction/) + +**GraphQL at GitLab**: + +- [🎬 GitLab Unfiltered GraphQL playlist](https://www.youtube.com/watch?v=wHPKZBDMfxE&list=PL05JrBw4t0KpcjeHjaRMB7IGB2oDWyJzv) +- [🎬 GraphQL at GitLab: Deep Dive](../api_graphql_styleguide.md#deep-dive) (video) by Nick Thomas + - An overview of the history of GraphQL at GitLab (not frontend-specific) +- [🎬 GitLab Feature Walkthrough with GraphQL and Vue Apollo](https://www.youtube.com/watch?v=6yYp2zB7FrM) (video) by Natalia Tepluhina + - A real-life example of implementing a frontend feature in GitLab using GraphQL +- [🎬 History of client-side GraphQL at GitLab](https://www.youtube.com/watch?v=mCKRJxvMnf0) (video) Illya Klymov and Natalia Tepluhina +- [🎬 From Vuex to Apollo](https://www.youtube.com/watch?v=9knwu87IfU8) (video) by Natalia Tepluhina + - A useful overview of when Apollo might be a better choice than Vuex, and how one could go about the transition +- [🛠Vuex -> Apollo Migration: a proof-of-concept project](https://gitlab.com/ntepluhina/vuex-to-apollo/blob/master/README.md) + - A collection of examples that show the possible approaches for state management with Vue+GraphQL+(Vuex or Apollo) apps + +### Libraries + +We use [Apollo](https://www.apollographql.com/) (specifically [Apollo Client](https://www.apollographql.com/docs/react/)) and [Vue Apollo](https://github.com/vuejs/vue-apollo) +when using GraphQL for frontend development. + +If you are using GraphQL within a Vue application, the [Usage in Vue](#usage-in-vue) section +can help you learn how to integrate Vue Apollo. + +For other use cases, check out the [Usage outside of Vue](#usage-outside-of-vue) section. + +### Tooling + +- [Apollo Client Devtools](https://github.com/apollographql/apollo-client-devtools) + +#### [Apollo GraphQL VS Code extension](https://marketplace.visualstudio.com/items?itemName=apollographql.vscode-apollo) + +If you use VS Code, the Apollo GraphQL extension supports autocompletion in `.graphql` files. To set up +the GraphQL extension, follow these steps: + +1. Add an `apollo.config.js` file to the root of your `gitlab` local directory. +1. Populate the file with the following content: + + ```javascript + module.exports = { + client: { + includes: ['./app/assets/javascripts/**/*.graphql', './ee/app/assets/javascripts/**/*.graphql'], + service: { + name: 'GitLab', + localSchemaFile: './doc/api/graphql/reference/gitlab_schema.graphql', + }, + }, + }; + ``` + +1. Restart VS Code. + +### Exploring the GraphQL API + Our GraphQL API can be explored via GraphiQL at your instance's -`/-/graphql-explorer` or at [GitLab.com](https://gitlab.com/-/graphql-explorer). +`/-/graphql-explorer` or at [GitLab.com](https://gitlab.com/-/graphql-explorer). Consult the +[GitLab GraphQL API Reference documentation](../../api/graphql/reference) +where needed. You can check all existing queries and mutations on the right side of GraphiQL in its **Documentation explorer**. It's also possible to @@ -10,9 +72,6 @@ their execution by clicking **Execute query** button on the top left: ![GraphiQL interface](img/graphiql_explorer_v12_4.png) -We use [Apollo](https://www.apollographql.com/) and [Vue Apollo](https://github.com/vuejs/vue-apollo) for working with GraphQL -on the frontend. - ## Apollo Client To save duplicated clients getting created in different apps, we have a @@ -30,7 +89,7 @@ Default client accepts two parameters: `resolvers` and `config`. ## GraphQL Queries To save query compilation at runtime, webpack can directly import `.graphql` -files. This allows webpack to preprocess the query at compile time instead +files. This allows webpack to pre-process the query at compile time instead of the client doing compilation of queries. To distinguish queries from mutations and fragments, the following naming convention is recommended: @@ -41,7 +100,7 @@ To distinguish queries from mutations and fragments, the following naming conven ### Fragments -Fragments are a way to make your complex GraphQL queries more readable and re-usable. Here is an example of GraphQL fragment: +[Fragments](https://graphql.org/learn/queries/#fragments) are a way to make your complex GraphQL queries more readable and re-usable. Here is an example of GraphQL fragment: ```javascript fragment DesignListItem on Design { @@ -94,7 +153,7 @@ new Vue({ }); ``` -Read more about [Vue Apollo](https://github.com/vuejs/vue-apollo) in the [Vue Apollo documentation](https://vue-apollo.netlify.com/guide/). +Read more about [Vue Apollo](https://github.com/vuejs/vue-apollo) in the [Vue Apollo documentation](https://vue-apollo.netlify.app/guide/). ### Local state with Apollo @@ -206,11 +265,11 @@ const defaultClient = createDefaultClient( Now every single time on attempt to fetch a version, our client will fetch `id` and `sha` from the remote API endpoint and will assign our hardcoded values to `author` and `createdAt` version properties. With this data, frontend developers are able to work on UI part without being blocked by backend. When actual response is added to the API, a custom local resolver can be removed fast and the only change to query/fragment is `@client` directive removal. -Read more about local state management with Apollo in the [Vue Apollo documentation](https://vue-apollo.netlify.com/guide/local-state.html#local-state). +Read more about local state management with Apollo in the [Vue Apollo documentation](https://vue-apollo.netlify.app/guide/local-state.html#local-state). ### Using with Vuex -When Apollo Client is used within Vuex and fetched data is stored in the Vuex store, there is no need in keeping Apollo Client cache enabled. Otherwise we would have data from the API stored in two places - Vuex store and Apollo Client cache. More to say, with Apollo default settings, a subsequent fetch from the GraphQL API could result in fetching data from Apollo cache (in the case where we have the same query and variables). To prevent this behavior, we need to disable Apollo Client cache passing a valid `fetchPolicy` option to its constructor: +When Apollo Client is used within Vuex and fetched data is stored in the Vuex store, there is no need in keeping Apollo Client cache enabled. Otherwise we would have data from the API stored in two places - Vuex store and Apollo Client cache. More to say, with Apollo's default settings, a subsequent fetch from the GraphQL API could result in fetching data from Apollo cache (in the case where we have the same query and variables). To prevent this behavior, we need to disable Apollo Client cache passing a valid `fetchPolicy` option to its constructor: ```javascript import fetchPolicies from '~/graphql_shared/fetch_policy_constants'; @@ -411,18 +470,6 @@ fetchNextPage() { Please note we don't have to save `pageInfo` one more time; `fetchMore` triggers a query `result` hook as well. -#### Limitations - -Currently, bidirectional pagination doesn't work: - -- `hasNextPage` returns a correct value only when we paginate forward using `endCursor` - and `first` parameters. -- `hasPreviousPage` returns a correct value only when we paginate backward using - `startCursor` and `last` parameters. - -This should be resolved in the scope of the issue -[Bi-directional Pagination in GraphQL doesn't work as expected](https://gitlab.com/gitlab-org/gitlab/-/issues/208301). - ### Testing #### Mocking response as component data @@ -599,4 +646,20 @@ defaultClient.query({ query }) .then(result => console.log(result)); ``` -Read more about the [Apollo](https://www.apollographql.com/) client in the [Apollo documentation](https://www.apollographql.com/docs/tutorial/client/). +When [using Vuex](#Using-with-Vuex), disable the cache when: + +- The data is being cached elsewhere +- The use case does not need caching +if the data is being cached elsewhere, or if there is simply no need for it for the given use case. + +```javascript +import createDefaultClient from '~/lib/graphql'; +import fetchPolicies from '~/graphql_shared/fetch_policy_constants'; + +const defaultClient = createDefaultClient( + {}, + { + fetchPolicy: fetchPolicies.NO_CACHE, + }, +); +``` diff --git a/doc/development/fe_guide/icons.md b/doc/development/fe_guide/icons.md index 4fb738f5466..131324e6479 100644 --- a/doc/development/fe_guide/icons.md +++ b/doc/development/fe_guide/icons.md @@ -24,7 +24,7 @@ sprite_icon(icon_name, size: nil, css_class: '') - **icon_name** Use the icon_name that you can find in the SVG Sprite ([Overview is available here](https://gitlab-org.gitlab.io/gitlab-svgs)). - **size (optional)** Use one of the following sizes : 16, 24, 32, 48, 72 (this will be translated into a `s16` class) -- **css_class (optional)** If you want to add additional css classes +- **css_class (optional)** If you want to add additional CSS classes **Example** @@ -67,8 +67,8 @@ export default { - **name** Name of the Icon in the SVG Sprite ([Overview is available here](https://gitlab-org.gitlab.io/gitlab-svgs)). - **size (optional)** Number value for the size which is then mapped to a specific CSS class - (Available Sizes: 8, 12, 16, 18, 24, 32, 48, 72 are mapped to `sXX` css classes) -- **css-classes (optional)** Additional CSS Classes to add to the svg tag. + (Available Sizes: 8, 12, 16, 18, 24, 32, 48, 72 are mapped to `sXX` CSS classes) +- **css-classes (optional)** Additional CSS Classes to add to the SVG tag. ### Usage in HTML/JS @@ -91,7 +91,7 @@ Please use the class `svg-content` around it to ensure nice rendering. ### Usage in Vue -To use an SVG illustrations in a template provide the path as a property and display it through a standard img tag. +To use an SVG illustrations in a template provide the path as a property and display it through a standard `img` tag. Component: diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index aaa6bb16fab..5d2b699c40d 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -65,7 +65,7 @@ within the `pages` directory correspond to Rails controllers and actions. These auto-generated bundles will be automatically included on the corresponding pages. -For example, if you were to visit <https://gitlab.com/gitlab-org/gitlab/issues>, +For example, if you were to visit <https://gitlab.com/gitlab-org/gitlab/-/issues>, you would be accessing the `app/controllers/projects/issues_controller.rb` controller with the `index` action. If a corresponding file exists at `pages/projects/issues/index/index.js`, it will be compiled into a webpack diff --git a/doc/development/fe_guide/style/vue.md b/doc/development/fe_guide/style/vue.md index 46305cc7217..1a64db443bc 100644 --- a/doc/development/fe_guide/style/vue.md +++ b/doc/development/fe_guide/style/vue.md @@ -53,7 +53,7 @@ Please check this [rules](https://github.com/vuejs/eslint-plugin-vue#bulb-rules) ## Naming -1. **Extensions**: Use `.vue` extension for Vue components. Do not use `.js` as file extension ([#34371](https://gitlab.com/gitlab-org/gitlab-foss/issues/34371)). +1. **Extensions**: Use `.vue` extension for Vue components. Do not use `.js` as file extension ([#34371](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/34371)). 1. **Reference Naming**: Use PascalCase for their instances: ```javascript diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 972c2ded9c9..0d77e4d129b 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -6,9 +6,9 @@ To get started with Vue, read through [their documentation](https://vuejs.org/v2 What is described in the following sections can be found in these examples: -- web ide: <https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/assets/javascripts/ide/stores> -- security products: <https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports> -- registry: <https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/assets/javascripts/registry/stores> +- [Web IDE](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/assets/javascripts/ide/stores) +- [Security products](https://gitlab.com/gitlab-org/gitlab/tree/master/ee/app/assets/javascripts/vue_shared/security_reports) +- [Registry](https://gitlab.com/gitlab-org/gitlab-foss/tree/master/app/assets/javascripts/registry/stores) ## Vue architecture @@ -16,7 +16,7 @@ All new features built with Vue.js must follow a [Flux architecture](https://fac 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](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch) +You can also read about this architecture in Vue docs about [state management](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch) and about [one way data flow](https://vuejs.org/v2/guide/components.html#One-Way-Data-Flow). ### Components and Store @@ -59,7 +59,7 @@ To do that, provide the data through `data` attributes in the HTML element and q _Note:_ You should only do this while initializing the application, because the mounted element will be replaced with Vue-generated DOM. The advantage of providing data from the DOM to the Vue instance through `props` in the `render` function -instead of querying the DOM inside the main vue component is that makes tests easier by avoiding the need to +instead of querying the DOM inside the main Vue component is that makes tests easier by avoiding the need to create a fixture or an HTML element in the unit test. See the following example: ```javascript |