diff options
Diffstat (limited to 'doc/development/fe_guide')
-rw-r--r-- | doc/development/fe_guide/content_editor.md | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/customizable_dashboards.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/graphql.md | 66 | ||||
-rw-r--r-- | doc/development/fe_guide/index.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/merge_request_widget_extensions.md | 1 | ||||
-rw-r--r-- | doc/development/fe_guide/performance.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/registry_architecture.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/source_editor.md | 12 | ||||
-rw-r--r-- | doc/development/fe_guide/style/javascript.md | 21 | ||||
-rw-r--r-- | doc/development/fe_guide/style/scss.md | 3 | ||||
-rw-r--r-- | doc/development/fe_guide/style/vue.md | 12 | ||||
-rw-r--r-- | doc/development/fe_guide/vue.md | 99 |
12 files changed, 156 insertions, 70 deletions
diff --git a/doc/development/fe_guide/content_editor.md b/doc/development/fe_guide/content_editor.md index 5c7fe68fec5..25140a067ca 100644 --- a/doc/development/fe_guide/content_editor.md +++ b/doc/development/fe_guide/content_editor.md @@ -1,6 +1,6 @@ --- -stage: Create -group: Editor +stage: Plan +group: Knowledge info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments --- diff --git a/doc/development/fe_guide/customizable_dashboards.md b/doc/development/fe_guide/customizable_dashboards.md index 26c73b26126..9e45c660745 100644 --- a/doc/development/fe_guide/customizable_dashboards.md +++ b/doc/development/fe_guide/customizable_dashboards.md @@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Customizable dashboards -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98610) in GitLab 15.5 as an [Alpha feature](../../policy/alpha-beta-support.md#alpha-features). +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/98610) in GitLab 15.5 as an [Experiment](../../policy/alpha-beta-support.md#experiment). Customizable dashboards provide a dashboard structure that allows users to create their own dashboards and commit the structure to a repository. diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index 5f0855d8f91..da3a6eff79d 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -1129,53 +1129,7 @@ We use [subscriptions](https://www.apollographql.com/docs/react/data/subscriptio **NOTE:** We cannot test subscriptions using GraphiQL, because they require an ActionCable client, which GraphiQL does not support at the moment. -Subscriptions don't require any additional configuration of Apollo Client instance, you can use them in the application right away. To distinguish subscriptions from queries and mutations, we recommend naming them with `.subscription.graphql` extension: - -```graphql -// ~/sidebar/queries/issuable_assignees.subscription.graphql - -subscription issuableAssigneesUpdated($issuableId: IssuableID!) { - issuableAssigneesUpdated(issuableId: $issuableId) { - ... on Issue { - assignees { - nodes { - ...User - status { - availability - } - } - } - } - } -} -``` - -When using GraphQL subscriptions in Vue application, we recommend updating existing Apollo query results with [subscribeToMore](https://apollo.vuejs.org/guide/apollo/subscriptions.html#subscribe-to-more) option: - -```javascript -import issuableAssigneesSubscription from '~/sidebar/queries/issuable_assignees.subscription.graphql' - -apollo: { - issuable: { - query() { - return assigneesQueries[this.issuableType].query; - }, - subscribeToMore: { - // Specify the subscription that will update the query - document() { - return issuableAssigneesSubscription; - }, - variables() { - return { - issuableId: convertToGraphQLId(this.issuableClass, this.issuableId), - }; - }, - }, - }, -}, -``` - -We would need also to define a field policy similarly like we do it for the [paginated queries](#defining-field-merge-policy) +Refer to the [Real-time widgets developer guide](../real_time.md) for a comprehensive introduction to subscriptions. ### Best Practices @@ -1446,6 +1400,24 @@ describe('when query times out', () => { }); ``` +Previously, we've used `{ mocks: { $apollo ...}}` on `mount` to test Apollo functionality. This approach is discouraged - proper `$apollo` mocking leaks a lot of implementation details to the tests. Consider replacing it with mocked Apollo provider + +```javascript +wrapper = mount(SomeComponent, { + mocks: { + // avoid! Mock real graphql queries and mutations instead + $apollo: { + mutate: jest.fn(), + queries: { + groups: { + loading, + }, + }, + }, + }, +}); +``` + #### Testing `@client` queries ##### Using mock resolvers diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md index 6403cff549f..ef506f260f7 100644 --- a/doc/development/fe_guide/index.md +++ b/doc/development/fe_guide/index.md @@ -11,7 +11,7 @@ across the GitLab frontend team. ## Overview -GitLab is built on top of [Ruby on Rails](https://rubyonrails.org). It uses [Haml](https://haml.info/) and a JavaScript-based frontend with [Vue.js](https://vuejs.org). +GitLab is built on top of [Ruby on Rails](https://rubyonrails.org). It uses [Haml](https://haml.info/) and a JavaScript-based frontend with [Vue.js](https://vuejs.org). If you are not sure when to use Vue on top of Haml-page, please read [this explanation](vue.md#when-to-add-vue-application). <!-- vale gitlab.Spelling = NO --> diff --git a/doc/development/fe_guide/merge_request_widget_extensions.md b/doc/development/fe_guide/merge_request_widget_extensions.md index 4242dd837f8..07029aec015 100644 --- a/doc/development/fe_guide/merge_request_widget_extensions.md +++ b/doc/development/fe_guide/merge_request_widget_extensions.md @@ -329,7 +329,6 @@ To generate these known events for a single widget: 1. `product_section` = `dev` 1. `product_stage` = `create` 1. `product_group` = `code_review` - 1. `product_category` = `code_review` 1. `introduced_by_url` = `'[your MR]'` 1. `options.events` = (the event in the command from above that generated this file, like `i_code_review_merge_request_widget_test_reports_count_view`) - This value is how the telemetry events are linked to "metrics" so this is probably one of the more important values. diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md index 20609718217..432e66bee33 100644 --- a/doc/development/fe_guide/performance.md +++ b/doc/development/fe_guide/performance.md @@ -474,4 +474,4 @@ General tips: - [WebPage Test](https://www.webpagetest.org) for testing site loading time and size. - [Google PageSpeed Insights](https://pagespeed.web.dev/) grades web pages and provides feedback to improve the page. - [Profiling with Chrome DevTools](https://developer.chrome.com/docs/devtools/) -- [Browser Diet](https://browserdiet.com/) is a community-built guide that catalogues practical tips for improving web page performance. +- [Browser Diet](https://github.com/zenorocha/browser-diet) was a community-built guide that cataloged practical tips for improving web page performance. diff --git a/doc/development/fe_guide/registry_architecture.md b/doc/development/fe_guide/registry_architecture.md index d86f8416db6..cf267e80619 100644 --- a/doc/development/fe_guide/registry_architecture.md +++ b/doc/development/fe_guide/registry_architecture.md @@ -14,7 +14,7 @@ Existing registries: - Package Registry - Container Registry -- Infrastructure Registry +- Terraform Module Registry - Dependency Proxy ## Frontend architecture diff --git a/doc/development/fe_guide/source_editor.md b/doc/development/fe_guide/source_editor.md index 9f52850041d..2c115effcf9 100644 --- a/doc/development/fe_guide/source_editor.md +++ b/doc/development/fe_guide/source_editor.md @@ -17,6 +17,14 @@ GitLab features use it, including: - [Web Editor](../../user/project/repository/web_editor.md) - [Security Policies](../../user/application_security/policies/index.md) +## When to use Source Editor + +Use Source Editor only when users need to edit the file content. +If you only need to display source code, consider using the [`BlobContent`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/blob/components/blob_content.vue) component. + +If the page you're working on is already loading the Source Editor, +displaying read-only content in the Source Editor is still a valid option. + ## How to use Source Editor Source Editor is framework-agnostic and can be used in any application, including both @@ -56,7 +64,7 @@ An instance of Source Editor accepts the following configuration options: | `blobContent` | `false` | `String`: The initial content to render in the editor. | | `extensions` | `false` | `Array`: Extensions to use in this instance. | | `blobGlobalId` | `false` | `String`: An auto-generated property.<br>**Note:** This property may go away in the future. Do not pass `blobGlobalId` unless you know what you're doing.| -| Editor Options | `false` | `Object(s)`: Any property outside of the list above is treated as an Editor Option for this particular instance. Use this field to override global Editor Options on the instance level. A full [index of Editor Options](https://microsoft.github.io/monaco-editor/api/enums/monaco.editor.EditorOption.html) is available. | +| Editor Options | `false` | `Object(s)`: Any property outside of the list above is treated as an Editor Option for this particular instance. Use this field to override global Editor Options on the instance level. A full [index of Editor Options](https://microsoft.github.io/monaco-editor/docs.html#enums/editor.EditorOption.html) is available. | ## API @@ -68,7 +76,7 @@ with additional functions on the instance level: | --------------------- | ----- | ----- | | `updateModelLanguage` | `path`: String | Updates the instance's syntax highlighting to follow the extension of the passed `path`. Available only on the instance level. | | `use` | Array of objects | Array of extensions to apply to the instance. Accepts only an array of **objects**. The extensions' ES6 modules must be fetched and resolved in your views or components before they're passed to `use`. Available on the instance and global editor (all instances) levels. | -| Monaco Editor options | See [documentation](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneCodeEditor.html) | Default Monaco editor options. | +| Monaco Editor options | See [documentation](https://microsoft.github.io/monaco-editor/docs.html#interfaces/editor.IStandaloneCodeEditor.html) | Default Monaco editor options. | ## Tips diff --git a/doc/development/fe_guide/style/javascript.md b/doc/development/fe_guide/style/javascript.md index b35ffdd8669..987543642f0 100644 --- a/doc/development/fe_guide/style/javascript.md +++ b/doc/development/fe_guide/style/javascript.md @@ -2,7 +2,6 @@ stage: none group: unassigned info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments -disqus_identifier: 'https://docs.gitlab.com/ee/development/fe_guide/style_guide_js.html' --- # JavaScript style guide @@ -332,19 +331,23 @@ Only export the constants as a collection (array, or object) when there is a nee ## Error handling -When catching a server-side error you should use the error message +When catching a server-side error, you should use the error message utility function contained in `app/assets/javascripts/lib/utils/error_message.js`. -This utility parses the received error message and checks for a prefix that indicates -whether the message is meant to be user-facing or not. The utility returns -an object with the message, and a boolean indicating whether the message is meant to be user-facing or not. Please make sure that the Backend is aware of the utils usage and is adding the prefix -to the error message accordingly. +This utility accepts two parameters: the error object received from the server response and a +default error message. The utility examines the message in the error object for a prefix that +indicates whether the message is meant to be user-facing or not. If the message is intended +to be user-facing, the utility returns it as is. Otherwise, it returns the default error +message passed as a parameter. ```javascript import { parseErrorMessage } from '~/lib/utils/error_message'; onError(error) { - const { message, userFacing } = parseErrorMessage(error); - - const errorMessage = userFacing ? message : genericErrorText; + const errorMessage = parseErrorMessage(error, genericErrorText); } ``` + +To benefit from this parsing mechanism, the utility user should ensure that the server-side +code is aware of this utility's usage and prefixes the error messages where appropriate +before sending them back to the user. See +[Error handling for API](../../api_styleguide.md#error-handling) for more information. diff --git a/doc/development/fe_guide/style/scss.md b/doc/development/fe_guide/style/scss.md index aed7310e95d..e760b0adaaa 100644 --- a/doc/development/fe_guide/style/scss.md +++ b/doc/development/fe_guide/style/scss.md @@ -2,7 +2,6 @@ stage: none group: unassigned info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments -disqus_identifier: 'https://docs.gitlab.com/ee/development/fe_guide/style_guide_scss.html' --- # SCSS style guide @@ -77,7 +76,7 @@ These mixins should be used to replace _magic values_ in our code. For example a `margin-top: 8px` is a good candidate for the `@include gl-mt-3` mixin replacement. Avoid using utility mixins for [pre-defined CSS keywords](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Values_and_Units#pre-defined_keyword_values). -For example prefer `display: flex` over `@include gl-display-flex`. +For example prefer `display: flex` over `@include gl-display-flex`. Utility mixins are particularly useful for encapsulating our design system but there is no need to encapsulate simple properties. ```scss // Bad diff --git a/doc/development/fe_guide/style/vue.md b/doc/development/fe_guide/style/vue.md index e9d2a724d9d..a3ab1c1af30 100644 --- a/doc/development/fe_guide/style/vue.md +++ b/doc/development/fe_guide/style/vue.md @@ -650,6 +650,18 @@ over [`expect.objectContaining`](https://jestjs.io/docs/expect#expectobjectconta }); ``` +### Testing props validation + +1. When checking component props use `assertProps` helper. Props validation failures will be thrown as errors + +```javascript +import { assertProps } from 'helpers/assert_props' + +// ... + +expect(() => assertProps(SomeComponent, { invalidPropValue: '1', someOtherProp: 2 })).toThrow() +``` + ## The JavaScript/Vue Accord The goal of this accord is to make sure we are all on the same page. diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 119a91e33b5..65ceb9f0220 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -16,11 +16,23 @@ What is described in the following sections can be found in these examples: - [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) +## When to add Vue application + +Sometimes, HAML page is enough to satisfy requirements. This statement is correct primarily for the static pages or pages that have very little logic. How do we know it's worth adding a Vue application to the page? The answer is "when we need to maintain application state and synchronize the rendered page with it". + +To better explain this, let's imagine the page that has one toggle, and toggling it sends an API request. This case does not involve any state we want to maintain, we send the request and switch the toggle. However, if we add ont more toggle that should always be the opposite to the first one, we need a _state_: one toggle should be "aware" about the state of another one. When written in plain JavaScript, this logic usually involves listening to DOM event and reacting with modifying DOM. Cases like this are much easier to handle with Vue.js so we should create a Vue application here. + +### What are some flags signaling that you might need Vue application? + +- when you need to define complex conditionals based on multiple factors and update them on user interaction; +- when you have to maintain any form of application state and share it between tags/elements; +- when you expect complex logic to be added in the future - it's easier to start with basic Vue application than having to rewrite JS/HAML to Vue on the next step. + ## Vue architecture -All new features built with Vue.js must follow a [Flux architecture](https://facebook.github.io/flux/). +All new features built with Vue.js must follow a [Flux architecture](https://facebookarchive.github.io/flux/). The main goal we are trying to achieve is to have only one data flow, and only one data entry. -To achieve this goal we use [Vuex](#vuex). +To achieve this goal we use [Vuex](#vuex) or [Apollo Client](graphql.md#libraries) You can also read about this architecture in Vue documentation about [state management](https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch) @@ -121,7 +133,7 @@ export default { ```javascript //index.js import MyComponent from './my_component.vue' -import initSimpleApp from '~/helpers/init_simple_app_helper' +import { initSimpleApp } from '~/helpers/init_simple_app_helper' initSimpleApp('#js-my-element', MyComponent) ``` @@ -391,6 +403,87 @@ You can read more about components in Vue.js site, [Component System](https://v2 Check this [page](vuex.md) for more details. +### Vue Router + +To add [Vue Router](https://router.vuejs.org/) to a page: + +1. Add a catch-all route to the Rails route file using a wildcard named `*vueroute`: + + ```ruby + # example from ee/config/routes/project.rb + + resources :iteration_cadences, path: 'cadences(/*vueroute)', action: :index + ``` + + The above example serves the `index` page from `iteration_cadences` controller to any route + matching the start of the `path`, for example `groupname/projectname/-/cadences/123/456/`. +1. Pass the base route (everything before `*vueroute`) to the frontend to use as the `base` parameter to initialize Vue Router: + + ```haml + .js-my-app{ data: { base_path: project_iteration_cadences_path(project) } } + ``` + +1. Initialize the router: + + ```javascript + Vue.use(VueRouter); + + export function createRouter(basePath) { + return new VueRouter({ + routes: createRoutes(), + mode: 'history', + base: basePath, + }); + } + ``` + +1. Add a fallback for unrecognised routes with `path: '*'`. Either: + - Add a redirect to the end of your routes array: + + ```javascript + const routes = [ + { + path: '/', + name: 'list-page', + component: ListPage, + }, + { + path: '*', + redirect: '/', + }, + ]; + ``` + + - Add a fallback component to the end of your routes array: + + ```javascript + const routes = [ + { + path: '/', + name: 'list-page', + component: ListPage, + }, + { + path: '*', + component: NotFound, + }, + ]; + ``` + +1. Optional. To also allow using the path helper for child routes, add `controller` and `action` + parameters to use the parent controller. + + ```ruby + resources :iteration_cadences, path: 'cadences(/*vueroute)', action: :index do + resources :iterations, only: [:index, :new, :edit, :show], constraints: { id: /\d+/ }, controller: :iteration_cadences, action: :index + end + ``` + + This means routes like `/cadences/123/iterations/456/edit` can be validated on the backend, + for example to check group or project membership. + It also means we can use the `_path` helper, which means we can load the page in feature specs + without manually building the `*vueroute` part of the path.. + ### Mixing Vue and jQuery - Mixing Vue and jQuery is not recommended. |