diff options
Diffstat (limited to 'doc/development/fe_guide')
-rw-r--r-- | doc/development/fe_guide/graphql.md | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/index.md | 3 | ||||
-rw-r--r-- | doc/development/fe_guide/storybook.md | 10 | ||||
-rw-r--r-- | doc/development/fe_guide/style/vue.md | 12 | ||||
-rw-r--r-- | doc/development/fe_guide/tooling.md | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/troubleshooting.md | 2 | ||||
-rw-r--r-- | doc/development/fe_guide/view_component.md | 39 | ||||
-rw-r--r-- | doc/development/fe_guide/vue.md | 16 | ||||
-rw-r--r-- | doc/development/fe_guide/vuex.md | 4 | ||||
-rw-r--r-- | doc/development/fe_guide/widgets.md | 6 |
10 files changed, 63 insertions, 37 deletions
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md index 442dda20d23..6dcc57b0ff5 100644 --- a/doc/development/fe_guide/graphql.md +++ b/doc/development/fe_guide/graphql.md @@ -729,8 +729,8 @@ In this case, we can either: - Skip passing a cursor. - Pass `null` explicitly to `after`. -After data is fetched, we can use the `update`-hook as an opportunity -[to customize the data that is set in the Vue component property](https://apollo.vuejs.org/api/smart-query.html#options). +After data is fetched, we can use the `update`-hook as an opportunity +[to customize the data that is set in the Vue component property](https://apollo.vuejs.org/api/smart-query.html#options). This allows us to get a hold of the `pageInfo` object among other data. In the `result`-hook, we can inspect the `pageInfo` object to see if we need to fetch diff --git a/doc/development/fe_guide/index.md b/doc/development/fe_guide/index.md index 02086ec5f1b..d90c270153e 100644 --- a/doc/development/fe_guide/index.md +++ b/doc/development/fe_guide/index.md @@ -36,7 +36,8 @@ Sign in to BrowserStack with the credentials saved in the **Engineering** vault ## Initiatives -Current high-level frontend goals are listed on [Frontend Epics](https://gitlab.com/groups/gitlab-org/-/epics?label_name%5B%5D=frontend). +You can find current frontend initiatives with a cross-functional impact on epics +with the label [frontend-initiative](https://gitlab.com/groups/gitlab-org/-/epics?state=opened&page=1&sort=UPDATED_AT_DESC&label_name[]=frontend-initiative). ## Principles diff --git a/doc/development/fe_guide/storybook.md b/doc/development/fe_guide/storybook.md index 45342eb6d72..a3a1fa2160f 100644 --- a/doc/development/fe_guide/storybook.md +++ b/doc/development/fe_guide/storybook.md @@ -46,10 +46,12 @@ To add a story: 1. Write the story as per the [official Storybook instructions](https://storybook.js.org/docs/vue/writing-stories/introduction/) - Notes: - - Specify the `title` field of the story as the component's file path from the `javascripts/` directory. - - For example, if the component is located at `app/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.vue`, specify the story `title` as `vue_shared/components/sidebar/todo_toggle/todo_button`. This will ensure the Storybook navigation maps closely to our internal directory structure. + NOTE: + Specify the `title` field of the story as the component's file path from the `javascripts/` directory, without the `/components` part. + For example, if the component is located at `app/assets/javascripts/vue_shared/components/sidebar/todo_toggle/todo_button.vue`, + specify the story `title` as `vue_shared/sidebar/todo_toggle/todo_button`. + If the component is located in the `ee/` directory, make sure to prefix the story's title with `ee/` as well. + This will ensure the Storybook navigation maps closely to our internal directory structure. ## Mock backend APIs diff --git a/doc/development/fe_guide/style/vue.md b/doc/development/fe_guide/style/vue.md index c9bd0e1b35a..39dc9cc9c4e 100644 --- a/doc/development/fe_guide/style/vue.md +++ b/doc/development/fe_guide/style/vue.md @@ -121,7 +121,7 @@ Check the [rules](https://github.com/vuejs/eslint-plugin-vue#bulb-rules) for mor 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: +1. **Reference Naming**: Use PascalCase for their default imports: ```javascript // bad @@ -431,7 +431,7 @@ must be unique. It's advised to use `kebab-case` namespaces. Useful links: -1. [`key`](https://vuejs.org/v2/guide/list.html#key) +1. [Maintaining State](https://v2.vuejs.org/v2/guide/list.html#Maintaining-State) 1. [Vue Style Guide: Keyed v-for](https://vuejs.org/v2/style-guide/#Keyed-v-for-essential) ## Vue testing @@ -448,10 +448,8 @@ Typically, when testing a Vue component, the component should be "re-mounted" in To achieve this: 1. Create a mutable `wrapper` variable inside the top-level `describe` block. -1. Mount the component using [`mount`](https://v1.test-utils.vuejs.org/api/#mount)/ -[`shallowMount`](https://v1.test-utils.vuejs.org/api/#shallowMount). -1. Reassign the resulting [`Wrapper`](https://v1.test-utils.vuejs.org/api/wrapper/#wrapper) -instance to our `wrapper` variable. +1. Mount the component using [`mount`](https://v1.test-utils.vuejs.org/api/#mount) or [`shallowMount`](https://v1.test-utils.vuejs.org/api/#shallowMount). +1. Reassign the resulting [`Wrapper`](https://v1.test-utils.vuejs.org/api/wrapper/#wrapper) instance to our `wrapper` variable. Creating a global, mutable wrapper provides a number of advantages, including the ability to: @@ -671,6 +669,6 @@ In the coming months you should fix that tech debt, with its priority to be dete not be rewritten. For example, jQuery tests rewritten to Vue tests. 1. You may choose to use VueX as a centralized state management. If you choose not to use VueX, you must use the *store pattern* which can be found in the -[Vue.js documentation](https://vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch). +[Vue.js documentation](https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch). 1. Once you have chosen a centralized state-management solution you must use it for your entire application. Don't mix and match your state-management solutions. diff --git a/doc/development/fe_guide/tooling.md b/doc/development/fe_guide/tooling.md index 2bb6cbfaf7a..4b55580c33c 100644 --- a/doc/development/fe_guide/tooling.md +++ b/doc/development/fe_guide/tooling.md @@ -63,8 +63,8 @@ disabled due to legacy compatibility reasons but they are in the process of bein Do not disable specific ESLint rules. To avoid introducing technical debt, you may disable the following rules only if you are invoking/instantiating existing code modules. -- [`no-new`](https://eslint.org/docs/rules/no-new) -- [`class-method-use-this`](https://eslint.org/docs/rules/class-methods-use-this) +- [`no-new`](https://eslint.org/docs/latest/rules/no-new) +- [`class-method-use-this`](https://eslint.org/docs/latest/rules/class-methods-use-this) Disable these rules on a per-line basis. This makes it easier to refactor in the future. For example, use `eslint-disable-next-line` or `eslint-disable-line`. diff --git a/doc/development/fe_guide/troubleshooting.md b/doc/development/fe_guide/troubleshooting.md index c0894621ed1..ab10c5bf988 100644 --- a/doc/development/fe_guide/troubleshooting.md +++ b/doc/development/fe_guide/troubleshooting.md @@ -4,7 +4,7 @@ group: unassigned info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments --- -# Troubleshooting +# Troubleshooting frontend development issues Running into a problem? Maybe this will help ¯\_(ツ)_/¯. diff --git a/doc/development/fe_guide/view_component.md b/doc/development/fe_guide/view_component.md index 2e373e6933b..7ddce609ee7 100644 --- a/doc/development/fe_guide/view_component.md +++ b/doc/development/fe_guide/view_component.md @@ -33,7 +33,7 @@ Consider this list a best effort. The full list can be found in [`app/components #### Alert -The `Pajamas::AlertComponent` follows the [Pajamas Alert](https://design.gitlab.com/components/alert) specification. +The `Pajamas::AlertComponent` follows the [Pajamas Alert](https://design.gitlab.com/components/alert/) specification. **Examples:** @@ -57,7 +57,7 @@ For the full list of options, see its #### Banner -The `Pajamas::BannerComponent` follows the [Pajamas Banner](https://design.gitlab.com/components/banner) specification. +The `Pajamas::BannerComponent` follows the [Pajamas Banner](https://design.gitlab.com/components/banner/) specification. **Examples:** @@ -88,7 +88,7 @@ For the full list of options, see its #### Button -The `Pajamas::ButtonComponent` follows the [Pajamas Button](https://design.gitlab.com/components/button) specification. +The `Pajamas::ButtonComponent` follows the [Pajamas Button](https://design.gitlab.com/components/button/) specification. **Examples:** @@ -125,7 +125,7 @@ For the full list of options, see its #### Card -The `Pajamas::CardComponent` follows the [Pajamas Card](https://design.gitlab.com/components/card) specification. +The `Pajamas::CardComponent` follows the [Pajamas Card](https://design.gitlab.com/components/card/) specification. **Examples:** @@ -188,7 +188,7 @@ For the full list of options, see its #### Toggle -The `Pajamas::ToggleComponent` follows the [Pajamas Toggle](https://design.gitlab.com/components/toggle) specification. +The `Pajamas::ToggleComponent` follows the [Pajamas Toggle](https://design.gitlab.com/components/toggle/) specification. ```haml = render Pajamas::ToggleComponent.new(classes: 'js-force-push-toggle', @@ -205,7 +205,34 @@ To actually initialize this component, make sure to call the `initToggle` helper For the full list of options, see its [source](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/components/pajamas/toggle_component.rb). -### Best practices +## Layouts + +Layout components can be used to create common layout patterns used in GitLab. + +### Available components + +#### Horizontal section + +Many of the settings pages use a layout where the title and description are on the left and the settings fields are on the right. The `Layouts::HorizontalSectionComponent` can be used to create this layout. + +**Example:** + +```haml += render ::Layouts::HorizontalSectionComponent.new(options: { class: 'gl-mb-6' }) do |c| + = c.title { _('Naming, visibility') } + = c.description do + = _('Update your group name, description, avatar, and visibility.') + = link_to _('Learn more about groups.'), help_page_path('user/group/index') + = c.body do + .form-group.gl-form-group + = f.label :name, _('New group name') + = f.text_field :name +``` + +For the full list of options, see its +[source](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/components/layouts/horizontal_section_component.rb). + +## Best practices - If you are about to create a new view in Haml, use the available components over creating plain Haml tags with CSS classes. diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md index 27660c0f5f7..5cb461c8ca0 100644 --- a/doc/development/fe_guide/vue.md +++ b/doc/development/fe_guide/vue.md @@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w # Vue -To get started with Vue, read through [their documentation](https://vuejs.org/v2/guide/). +To get started with Vue, read through [their documentation](https://v2.vuejs.org/v2/guide/index.html). ## Examples @@ -23,8 +23,8 @@ The main goal we are trying to achieve is to have only one data flow, and only o To achieve this goal we use [Vuex](#vuex). You can also read about this architecture in Vue documentation 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). +[state management](https://v2.vuejs.org/v2/guide/state-management.html#Simple-State-Management-from-Scratch) +and about [one way data flow](https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow). ### Components and Store @@ -322,7 +322,7 @@ For example, tables are used in a quite amount of places across GitLab, a table would be a good fit for a component. On the other hand, a table cell used only in one table would not be a good use of this pattern. -You can read more about components in Vue.js site, [Component System](https://vuejs.org/v2/guide/#Composing-with-Components). +You can read more about components in Vue.js site, [Component System](https://v2.vuejs.org/v2/guide/#Composing-with-Components). ### A folder for the Store @@ -348,8 +348,7 @@ recommended to observe objects with their own stateful behavior. Based on the Vue guidance: -- **Do not** use or create a JavaScript class in your [data function](https://v2.vuejs.org/v2/api/#data), -such as `user: new User()`. +- **Do not** use or create a JavaScript class in your [data function](https://v2.vuejs.org/v2/api/#data). - **Do not** add new JavaScript class implementations. - **Do** use [GraphQL](../api_graphql_styleguide.md), [Vuex](vuex.md) or a set of components if cannot use primitives or objects. @@ -531,8 +530,7 @@ Each Vue component has a unique output. This output is always present in the ren Although each method of a Vue component can be tested individually, our goal is to test the output of the render function, which represents the state at all times. -Visit the [Vue testing guide](https://v2.vuejs.org/v2/guide/testing.html#Unit-Testing) for help -testing the rendered output. +Visit the [Vue testing guide](https://v2.vuejs.org/v2/guide/testing.html#Unit-Testing) for help. Here's an example of a well structured unit test for [this Vue component](#appendix---vue-component-subject-under-test): @@ -671,7 +669,7 @@ it('should fire the click event', () => { }) ``` -When firing a Vue event, use [`emit`](https://vuejs.org/v2/guide/components-custom-events.html). +When firing a Vue event, use [`emit`](https://v2.vuejs.org/v2/guide/components-custom-events.html). ```javascript wrapper = shallowMount(DropdownItem); diff --git a/doc/development/fe_guide/vuex.md b/doc/development/fe_guide/vuex.md index 8bfb912161a..2d1569b7812 100644 --- a/doc/development/fe_guide/vuex.md +++ b/doc/development/fe_guide/vuex.md @@ -245,7 +245,7 @@ A mutation written like this is easier to maintain. In addition, we avoid errors ### `getters.js` Sometimes we may need to get derived state based on store state, like filtering for a specific prop. -Using a getter also caches the result based on dependencies due to [how computed props work](https://vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods) +Using a getter also caches the result based on dependencies due to [how computed props work](https://v2.vuejs.org/v2/guide/computed.html#Computed-Caching-vs-Methods) This can be done through the `getters`: ```javascript @@ -364,7 +364,7 @@ export default initialState => ({ We made the conscious decision to avoid this pattern to improve the ability to discover and search our frontend codebase. The same applies -when [providing data to a Vue app](vue.md#providing-data-from-haml-to-javascript). The reasoning for this is described in +when [providing data to a Vue app](vue.md#providing-data-from-haml-to-javascript). The reasoning for this is described in [this discussion](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/56#note_302514865): > Consider a `someStateKey` is being used in the store state. You _may_ not be diff --git a/doc/development/fe_guide/widgets.md b/doc/development/fe_guide/widgets.md index b54f9add97d..c6bb89d1fe8 100644 --- a/doc/development/fe_guide/widgets.md +++ b/doc/development/fe_guide/widgets.md @@ -18,11 +18,11 @@ When building a widget, we should follow a few principles described below. All widgets should use the same stack (Vue + Apollo Client). To make it happen, we must add Vue Apollo to the application root (if we use a widget as a component) or provide it directly to a widget. For sidebar widgets, use the -[sidebar Apollo Client and Apollo Provider](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/sidebar/graphql.js): +[issuable Apollo Client and Apollo Provider](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/graphql_shared/issuable_client.js): ```javascript import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue'; -import { apolloProvider } from '~/sidebar/graphql'; +import { apolloProvider } from '~/graphql_shared/issuable_client'; function mountConfidentialComponent() { new Vue({ @@ -118,7 +118,7 @@ In this case, we can use a renderless component that imports a client and listen ```javascript import { fetchPolicies } from '~/lib/graphql'; import { confidentialityQueries } from '~/sidebar/constants'; -import { defaultClient as gqlClient } from '~/sidebar/graphql'; +import { defaultClient as gqlClient } from '~/graphql_shared/issuable_client'; created() { if (this.issuableType !== IssuableType.Issue) { |