Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-04-20 13:00:54 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-04-20 13:00:54 +0300
commit3cccd102ba543e02725d247893729e5c73b38295 (patch)
treef36a04ec38517f5deaaacb5acc7d949688d1e187 /doc/development/fe_guide
parent205943281328046ef7b4528031b90fbda70c75ac (diff)
Add latest changes from gitlab-org/gitlab@14-10-stable-eev14.10.0-rc42
Diffstat (limited to 'doc/development/fe_guide')
-rw-r--r--doc/development/fe_guide/accessibility.md2
-rw-r--r--doc/development/fe_guide/emojis.md2
-rw-r--r--doc/development/fe_guide/graphql.md122
-rw-r--r--doc/development/fe_guide/performance.md2
-rw-r--r--doc/development/fe_guide/registry_architecture.md90
-rw-r--r--doc/development/fe_guide/source_editor.md10
-rw-r--r--doc/development/fe_guide/vue.md8
-rw-r--r--doc/development/fe_guide/vue3_migration.md2
8 files changed, 220 insertions, 18 deletions
diff --git a/doc/development/fe_guide/accessibility.md b/doc/development/fe_guide/accessibility.md
index e71e414002a..2a1083d031f 100644
--- a/doc/development/fe_guide/accessibility.md
+++ b/doc/development/fe_guide/accessibility.md
@@ -32,7 +32,7 @@ By default, macOS limits the <kbd>tab</kbd> key to **Text boxes and lists only**
1. Open the **Shortcuts** tab.
1. Enable the setting **Use keyboard navigation to move focus between controls**.
-You can read more about enabling browser-specific keyboard navigation on [a11yproject](https://www.a11yproject.com/posts/2017-12-29-macos-browser-keyboard-navigation/).
+You can read more about enabling browser-specific keyboard navigation on [a11yproject](https://www.a11yproject.com/posts/macos-browser-keyboard-navigation/).
## Quick checklist
diff --git a/doc/development/fe_guide/emojis.md b/doc/development/fe_guide/emojis.md
index 2dedbc8f19d..7ef88c5ca19 100644
--- a/doc/development/fe_guide/emojis.md
+++ b/doc/development/fe_guide/emojis.md
@@ -25,7 +25,7 @@ when your platform does not support it.
- `app/assets/images/emoji.png`
- `app/assets/images/emoji@2x.png`
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 GitLab Flavored Markdown (GFM) Autocomplete
+ 1. Ensure you can see the new emojis and their aliases in the GitLab Flavored Markdown (GLFM) 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
that do not support a certain emoji and we need to fallback to an image.
diff --git a/doc/development/fe_guide/graphql.md b/doc/development/fe_guide/graphql.md
index e79a473df9e..ddd99f3614d 100644
--- a/doc/development/fe_guide/graphql.md
+++ b/doc/development/fe_guide/graphql.md
@@ -264,9 +264,15 @@ Read more about [Vue Apollo](https://github.com/vuejs/vue-apollo) in the [Vue Ap
### Local state with Apollo
-It is possible to manage an application state with Apollo by passing
-in a resolvers object when creating the default client. The default state can be set by writing
-to the cache after setting up the default client. In the example below, we are using query with `@client` Apollo directive to write the initial data to Apollo cache and then get this state in the Vue component:
+It is possible to manage an application state with Apollo by using [client-site resolvers](#using-client-side-resolvers)
+or [type policies with reactive variables](#using-type-policies-with-reactive-variables) when creating your default
+client.
+
+#### Using client-side resolvers
+
+The default state can be set by writing to the cache after setting up the default client. In the
+example below, we are using query with `@client` Apollo directive to write the initial data to
+Apollo cache and then get this state in the Vue component:
```javascript
// user.query.graphql
@@ -322,7 +328,7 @@ export default {
Along with creating local data, we can also extend existing GraphQL types with `@client` fields. This is extremely helpful when we need to mock an API response for fields not yet added to our GraphQL API.
-#### Mocking API response with local Apollo cache
+##### Mocking API response with local Apollo cache
Using local Apollo Cache is helpful when we have a need to mock some GraphQL API responses, queries, or mutations locally (such as when they're still not added to our actual API).
@@ -384,6 +390,108 @@ For each attempt to fetch a version, our client fetches `id` and `sha` from the
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 type policies with reactive variables
+
+Apollo Client 3 offers an alternative to [client-side resolvers](#using-client-side-resolvers) by using
+[reactive variables to store client state](https://www.apollographql.com/docs/react/local-state/reactive-variables/).
+
+**NOTE:**
+We are still learning the best practices for both **type policies** and **reactive vars**.
+Take a moment to improve this guide or [leave a comment](https://gitlab.com/gitlab-org/frontend/rfcs/-/issues/100)
+if you use it!
+
+In the example below we define a `@client` query and its `typedefs`:
+
+```javascript
+// ./graphql/typedefs.graphql
+extend type Query {
+ localData: String!
+}
+```
+
+```javascript
+// ./graphql/get_local_data.query.graphql
+query getLocalData {
+ localData @client
+}
+```
+
+Similar to resolvers, your `typePolicies` will execute when the `@client` query is used. However,
+using `makeVar` will trigger every relevant active Apollo query to reactively update when the state
+mutates.
+
+```javascript
+// ./graphql/local_state.js
+
+import { makeVar } from '@apollo/client/core';
+import typeDefs from './typedefs.graphql';
+
+export const createLocalState = () => {
+ // set an initial value
+ const localDataVar = makeVar('');
+
+ const cacheConfig = {
+ typePolicies: {
+ Query: {
+ fields: {
+ localData() {
+ // obtain current value
+ // triggers when `localDataVar` is updated
+ return localDataVar();
+ },
+ },
+ },
+ },
+ };
+
+ // methods that update local state
+ const localMutations = {
+ setLocalData(newData) {
+ localDataVar(newData);
+ },
+ clearData() {
+ localDataVar('');
+ },
+ };
+
+ return {
+ cacheConfig,
+ typeDefs,
+ localMutations,
+ };
+};
+```
+
+Pass the cache config to your Apollo Client:
+
+```javascript
+// index.js
+
+// ...
+import createDefaultClient from '~/lib/graphql';
+import { createLocalState } from './graphql/local_state';
+
+const { cacheConfig, typeDefs, localMutations } = createLocalState();
+
+const apolloProvider = new VueApollo({
+ defaultClient: createDefaultClient({}, { cacheConfig, typeDefs }),
+});
+
+return new Vue({
+ el,
+ apolloProvider,
+ provide: {
+ // inject local state mutations to your app
+ localMutations,
+ },
+ render(h) {
+ return h(MyApp);
+ },
+});
+```
+
+Wherever used, the local query will update as the state updates thanks to the **reactive variable**.
+
### Using with Vuex
When the Apollo Client is used in Vuex and fetched data is stored in the Vuex store, the Apollo Client cache does not need to be enabled. Otherwise we would have data from the API stored in two places - Vuex store and Apollo Client cache. 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 by passing a valid `fetchPolicy` option to its constructor:
@@ -583,7 +691,7 @@ we want to fetch after or before a given endpoint.
For example, here we're fetching 10 designs after a cursor (let us call this `projectQuery`):
```javascript
-#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
+#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query {
project(fullPath: "root/my-project") {
@@ -606,7 +714,7 @@ query {
}
```
-Note that we are using the [`pageInfo.fragment.graphql`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/graphql_shared/fragments/pageInfo.fragment.graphql) to populate the `pageInfo` information.
+Note that we are using the [`page_info.fragment.graphql`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/graphql_shared/fragments/page_info.fragment.graphql) to populate the `pageInfo` information.
#### Using `fetchMore` method in components
@@ -869,7 +977,7 @@ You'd then be able to retrieve the data without providing any pagination-specifi
Here's an example of a query using the `@connection` directive:
```graphql
-#import "~/graphql_shared/fragments/pageInfo.fragment.graphql"
+#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query DastSiteProfiles($fullPath: ID!, $after: String, $before: String, $first: Int, $last: Int) {
project(fullPath: $fullPath) {
diff --git a/doc/development/fe_guide/performance.md b/doc/development/fe_guide/performance.md
index 94beecf6168..bcdc49a1070 100644
--- a/doc/development/fe_guide/performance.md
+++ b/doc/development/fe_guide/performance.md
@@ -457,6 +457,6 @@ General tips:
## Additional Resources
- [WebPage Test](https://www.webpagetest.org) for testing site loading time and size.
-- [Google PageSpeed Insights](https://developers.google.com/speed/pagespeed/insights/) grades web pages and provides feedback to improve the page.
+- [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.
diff --git a/doc/development/fe_guide/registry_architecture.md b/doc/development/fe_guide/registry_architecture.md
new file mode 100644
index 00000000000..47a6dc40e19
--- /dev/null
+++ b/doc/development/fe_guide/registry_architecture.md
@@ -0,0 +1,90 @@
+---
+stage: Package
+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
+---
+
+# Registry architecture
+
+GitLab has several registry applications. Given that they all leverage similar UI, UX, and business
+logic, they are all built with the same architecture. In addition, a set of shared components
+already exists to unify the user and developer experiences.
+
+Existing registries:
+
+- Package Registry
+- Container Registry
+- Infrastructure Registry
+- Dependency Proxy
+
+## Frontend architecture
+
+### Component classification
+
+All the registries follow an architecture pattern that includes four component types:
+
+- Pages: represent an entire app, or for the registries using [vue-router](https://v3.router.vuejs.org/) they represent one router
+ route.
+- Containers: represent a single piece of functionality. They contain complex logic and may
+ connect to the API.
+- Presentationals: represent a portion of the UI. They receive all their data with `props` or through
+ `inject`, and do not connect to the API.
+- Shared components: presentational components that accept a various array of configurations and are
+ shared across all of the registries.
+
+### Communicating with the API
+
+The complexity and communication with the API should be concentrated in the pages components, and
+in the container components when needed. This makes it easier to:
+
+- Handle concurrent requests, loading states, and user messages.
+- Maintain the code, especially to estimate work. If it touches a page or functional component,
+ expect it to be more complex.
+- Write fast and consistent unit tests.
+
+### Best practices
+
+- Use [`provide` or `inject`](https://v2.vuejs.org/v2/api/?redirect=true#provide-inject)
+ to pass static, non-reactive values coming from the app initialization.
+- When passing data, prefer `props` over nested queries or Vuex bindings. Only pages and
+ container components should be aware of the state and API communication.
+- Don't repeat yourself. If one registry receives functionality, the likelihood of the rest needing
+ it in the future is high. If something seems reusable and isn't bound to the state, create a
+ shared component.
+- Try to express functionality and logic with dedicated components. It's much easier to deal with
+ events and properties than callbacks and asynchronous code (see
+ [`delete_package.vue`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/app/assets/javascripts/packages_and_registries/package_registry/components/functional/delete_package.vue)).
+- Leverage [startup for GraphQL calls](graphql.md#making-initial-queries-early-with-graphql-startup-calls).
+
+## Shared compoenents library
+
+Inside `vue_shared/components/registry` and `packages_and_registries/shared`, there's a set of
+shared components that you can use to implement registry functionality. These components build the
+main pieces of the desired UI and UX of a registry page. The most important components are:
+
+- `code-instruction`: represents a copyable box containing code. Supports multiline and single line
+ code boxes. Snowplow tracks the code copy event.
+- `details-row`: represents a row of details. Used to add additional info in the details area of
+ the `list-item` component.
+- `history-item`: represents a history list item used to build a timeline.
+- `list-item`: represents a list element in the registry. It supports: left action, left primary and
+ secondary content, right primary and secondary content, right action, and details slots.
+- `metadata-item`: represents one piece of metadata, with an icon or a link. Used primarily in the
+ title area.
+- `persisted-dropdown-selection`: represents a dropdown menu that stores the user selection in the
+ `localStorage`.
+- `registry-search`: implements `gl-filtered-search` with a sorting section on the right.
+- `title-area`: implements the top title area of the registry. Includes: a main title, an avatar, a
+ subtitle, a metadata row, and a right actions slot.
+
+## Adding a new registry page
+
+When adding a new registry:
+
+- Leverage the shared components that already exist. It's good to look at how the components are
+ structured and used in the more mature registries (for example, the Package Registry).
+- If it's in line with the backend requirements, we suggest using GraphQL for the API. This helps in
+ dealing with the innate performance issue of registries.
+- If possible, we recommend using [Vue Router](https://v3.router.vuejs.org/)
+ and frontend routing. Coupled with Apollo, the caching layer helps with the perceived page
+ performance.
diff --git a/doc/development/fe_guide/source_editor.md b/doc/development/fe_guide/source_editor.md
index 2ff0bacfc3a..b06e341630f 100644
--- a/doc/development/fe_guide/source_editor.md
+++ b/doc/development/fe_guide/source_editor.md
@@ -35,7 +35,7 @@ Vue component, but the integration of Source Editor is generally straightforward
const editor = new SourceEditor({
// Editor Options.
// The list of all accepted options can be found at
- // https://microsoft.github.io/monaco-editor/api/enums/monaco.editor.editoroption.html
+ // https://microsoft.github.io/monaco-editor/api/enums/monaco.editor.EditorOption.html
});
```
@@ -56,19 +56,19 @@ 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/api/enums/monaco.editor.EditorOption.html) is available. |
## API
The editor uses the same public API as
-[provided by Monaco editor](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandalonecodeeditor.html)
+[provided by Monaco editor](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneCodeEditor.html)
with additional functions on the instance level:
| Function | Arguments | Description
| --------------------- | ----- | ----- |
| `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 the array of _objects_. You must fetch the extensions' ES6 modules must be fetched and resolved in your views or components before they are passed to `use`. This property is available on _instance_ (applies extension to this particular instance) and _global editor_ (applies the same extension to 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/api/interfaces/monaco.editor.IStandaloneCodeEditor.html) | Default Monaco editor options |
## Tips
@@ -202,7 +202,7 @@ export default {
In the code example, `this` refers to the instance. By referring to the instance,
we can access the complete underlying
-[Monaco editor API](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.istandalonecodeeditor.html),
+[Monaco editor API](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IStandaloneCodeEditor.html),
which includes functions like `getValue()`.
Now let's use our extension:
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index b947d90cc11..fecb0af936d 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -123,6 +123,10 @@ Using dependency injection to provide values from HAML is ideal when:
prop-drilling becomes an inconvenience. Prop-drilling when the same prop is passed
through all components in the hierarchy until the component that is genuinely using it.
+Dependency injection can potentially break a child component (either an immediate child or multiple levels deep) if the value declared in the `inject` configuration doesn't have defaults defined and the parent component has not provided the value using the `provide` configuration.
+
+- A [default value](https://vuejs.org/guide/components/provide-inject.html#injection-default-values) might be useful in contexts where it makes sense.
+
##### props
If the value from HAML doesn't fit the criteria of dependency injection, use `props`.
@@ -499,7 +503,7 @@ component under test, with the `computed` property, for example). Remember to us
We should test for events emitted in response to an action in our component. This is used to
verify the correct events are being fired with the correct arguments.
-For any DOM events we should use [`trigger`](https://vue-test-utils.vuejs.org/api/wrapper/#trigger)
+For any DOM events we should use [`trigger`](https://v1.test-utils.vuejs.org/api/wrapper/#trigger)
to fire out event.
```javascript
@@ -530,7 +534,7 @@ it('should fire the itemClicked event', () => {
```
We should verify an event has been fired by asserting against the result of the
-[`emitted()`](https://vue-test-utils.vuejs.org/api/wrapper/#emitted) method.
+[`emitted()`](https://v1.test-utils.vuejs.org/api/wrapper/#emitted) method.
## Vue.js Expert Role
diff --git a/doc/development/fe_guide/vue3_migration.md b/doc/development/fe_guide/vue3_migration.md
index f174408c946..8c8bb36d962 100644
--- a/doc/development/fe_guide/vue3_migration.md
+++ b/doc/development/fe_guide/vue3_migration.md
@@ -156,6 +156,6 @@ export default {
</template>
```
-[In Vue 3](https://v3.vuejs.org/guide/migration/props-default-this.html#props-default-function-this-access),
+[In Vue 3](https://v3-migration.vuejs.org/breaking-changes/props-default-this.html),
the props default value factory is passed the raw props as an argument, and can
also access injections.