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
path: root/doc
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-04-29 15:10:00 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-04-29 15:10:00 +0300
commit4233d3aa86fe94e6288279aa55d42ed95bfe753c (patch)
tree7b97b519371f6df1fa6a0f2ffe69535207a73754 /doc
parente357d4951c53a3ce4f696cf533ce24a4c6350a7e (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc')
-rw-r--r--doc/api/branches.md5
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql135
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json351
-rw-r--r--doc/api/graphql/reference/index.md15
-rw-r--r--doc/api/projects.md4
-rw-r--r--doc/development/fe_guide/vue.md13
-rw-r--r--doc/development/fe_guide/vue3_migration.md109
-rw-r--r--doc/development/geo/framework.md223
-rw-r--r--doc/user/project/settings/index.md2
9 files changed, 807 insertions, 50 deletions
diff --git a/doc/api/branches.md b/doc/api/branches.md
index 2f9ca62ced6..f9c87222f9a 100644
--- a/doc/api/branches.md
+++ b/doc/api/branches.md
@@ -41,6 +41,7 @@ Example response:
"developers_can_push": false,
"developers_can_merge": false,
"can_push": true,
+ "web_url": "http://gitlab.example.com/my-group/my-project/-/tree/master",
"commit": {
"author_email": "john@example.com",
"author_name": "John Smith",
@@ -96,6 +97,7 @@ Example response:
"developers_can_push": false,
"developers_can_merge": false,
"can_push": true,
+ "web_url": "http://gitlab.example.com/my-group/my-project/-/tree/master",
"commit": {
"author_email": "john@example.com",
"author_name": "John Smith",
@@ -171,7 +173,8 @@ Example response:
"default": false,
"developers_can_push": false,
"developers_can_merge": false,
- "can_push": true
+ "can_push": true,
+ "web_url": "http://gitlab.example.com/my-group/my-project/-/tree/newbranch"
}
```
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 0a56eb9197c..604322bf5a4 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -3451,6 +3451,36 @@ type GeoNode {
name: String
"""
+ Package file registries of the GeoNode. Available only when feature flag `geo_self_service_framework` is enabled
+ """
+ packageFileRegistries(
+ """
+ Returns the elements in the list that come after the specified cursor.
+ """
+ after: String
+
+ """
+ Returns the elements in the list that come before the specified cursor.
+ """
+ before: String
+
+ """
+ Returns the first _n_ elements from the list.
+ """
+ first: Int
+
+ """
+ Filters registries by their ID
+ """
+ ids: [ID!]
+
+ """
+ Returns the last _n_ elements from the list.
+ """
+ last: Int
+ ): PackageFileRegistryConnection
+
+ """
Indicates whether this Geo node is the primary
"""
primary: Boolean
@@ -6330,6 +6360,86 @@ interface Noteable {
}
"""
+Represents the sync and verification state of a package file
+"""
+type PackageFileRegistry {
+ """
+ Timestamp when the PackageFileRegistry was created
+ """
+ createdAt: Time
+
+ """
+ ID of the PackageFileRegistry
+ """
+ id: ID!
+
+ """
+ Error message during sync of the PackageFileRegistry
+ """
+ lastSyncFailure: String
+
+ """
+ Timestamp of the most recent successful sync of the PackageFileRegistry
+ """
+ lastSyncedAt: Time
+
+ """
+ ID of the PackageFile
+ """
+ packageFileId: ID!
+
+ """
+ Timestamp after which the PackageFileRegistry should be resynced
+ """
+ retryAt: Time
+
+ """
+ Number of consecutive failed sync attempts of the PackageFileRegistry
+ """
+ retryCount: Int
+
+ """
+ Sync state of the PackageFileRegistry
+ """
+ state: RegistryState
+}
+
+"""
+The connection type for PackageFileRegistry.
+"""
+type PackageFileRegistryConnection {
+ """
+ A list of edges.
+ """
+ edges: [PackageFileRegistryEdge]
+
+ """
+ A list of nodes.
+ """
+ nodes: [PackageFileRegistry]
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+"""
+An edge in a connection.
+"""
+type PackageFileRegistryEdge {
+ """
+ A cursor for use in pagination.
+ """
+ cursor: String!
+
+ """
+ The item at the end of the edge.
+ """
+ node: PackageFileRegistry
+}
+
+"""
Information about pagination in a connection.
"""
type PageInfo {
@@ -7806,6 +7916,31 @@ type Query {
}
"""
+State of a Geo registry.
+"""
+enum RegistryState {
+ """
+ Registry that failed to sync
+ """
+ FAILED
+
+ """
+ Registry waiting to be synced
+ """
+ PENDING
+
+ """
+ Registry currently syncing
+ """
+ STARTED
+
+ """
+ Registry that is synced
+ """
+ SYNCED
+}
+
+"""
Autogenerated input type of RemoveAwardEmoji
"""
input RemoveAwardEmojiInput {
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index b422258171f..d41088e051d 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -9927,6 +9927,77 @@
"deprecationReason": null
},
{
+ "name": "packageFileRegistries",
+ "description": "Package file registries of the GeoNode. Available only when feature flag `geo_self_service_framework` is enabled",
+ "args": [
+ {
+ "name": "ids",
+ "description": "Filters registries by their ID",
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ }
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "after",
+ "description": "Returns the elements in the list that come after the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "before",
+ "description": "Returns the elements in the list that come before the specified cursor.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "first",
+ "description": "Returns the first _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ },
+ {
+ "name": "last",
+ "description": "Returns the last _n_ elements from the list.",
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "defaultValue": null
+ }
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "PackageFileRegistryConnection",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
"name": "primary",
"description": "Indicates whether this Geo node is the primary",
"args": [
@@ -19093,6 +19164,251 @@
},
{
"kind": "OBJECT",
+ "name": "PackageFileRegistry",
+ "description": "Represents the sync and verification state of a package file",
+ "fields": [
+ {
+ "name": "createdAt",
+ "description": "Timestamp when the PackageFileRegistry was created",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "id",
+ "description": "ID of the PackageFileRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lastSyncFailure",
+ "description": "Error message during sync of the PackageFileRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "lastSyncedAt",
+ "description": "Timestamp of the most recent successful sync of the PackageFileRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "packageFileId",
+ "description": "ID of the PackageFile",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "ID",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "retryAt",
+ "description": "Timestamp after which the PackageFileRegistry should be resynced",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Time",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "retryCount",
+ "description": "Number of consecutive failed sync attempts of the PackageFileRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "SCALAR",
+ "name": "Int",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "state",
+ "description": "Sync state of the PackageFileRegistry",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "ENUM",
+ "name": "RegistryState",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "PackageFileRegistryConnection",
+ "description": "The connection type for PackageFileRegistry.",
+ "fields": [
+ {
+ "name": "edges",
+ "description": "A list of edges.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PackageFileRegistryEdge",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "nodes",
+ "description": "A list of nodes.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "LIST",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PackageFileRegistry",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "pageInfo",
+ "description": "Information to aid in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "OBJECT",
+ "name": "PageInfo",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
+ "name": "PackageFileRegistryEdge",
+ "description": "An edge in a connection.",
+ "fields": [
+ {
+ "name": "cursor",
+ "description": "A cursor for use in pagination.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "NON_NULL",
+ "name": null,
+ "ofType": {
+ "kind": "SCALAR",
+ "name": "String",
+ "ofType": null
+ }
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "node",
+ "description": "The item at the end of the edge.",
+ "args": [
+
+ ],
+ "type": {
+ "kind": "OBJECT",
+ "name": "PackageFileRegistry",
+ "ofType": null
+ },
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "inputFields": null,
+ "interfaces": [
+
+ ],
+ "enumValues": null,
+ "possibleTypes": null
+ },
+ {
+ "kind": "OBJECT",
"name": "PageInfo",
"description": "Information about pagination in a connection.",
"fields": [
@@ -23240,6 +23556,41 @@
"possibleTypes": null
},
{
+ "kind": "ENUM",
+ "name": "RegistryState",
+ "description": "State of a Geo registry.",
+ "fields": null,
+ "inputFields": null,
+ "interfaces": null,
+ "enumValues": [
+ {
+ "name": "PENDING",
+ "description": "Registry waiting to be synced",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "STARTED",
+ "description": "Registry currently syncing",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "SYNCED",
+ "description": "Registry that is synced",
+ "isDeprecated": false,
+ "deprecationReason": null
+ },
+ {
+ "name": "FAILED",
+ "description": "Registry that failed to sync",
+ "isDeprecated": false,
+ "deprecationReason": null
+ }
+ ],
+ "possibleTypes": null
+ },
+ {
"kind": "INPUT_OBJECT",
"name": "RemoveAwardEmojiInput",
"description": "Autogenerated input type of RemoveAwardEmoji",
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index a974278f04f..82f5bd1e000 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -962,6 +962,21 @@ Represents a milestone.
| `readNote` | Boolean! | Indicates the user can perform `read_note` on this resource |
| `resolveNote` | Boolean! | Indicates the user can perform `resolve_note` on this resource |
+## PackageFileRegistry
+
+Represents the sync and verification state of a package file
+
+| Name | Type | Description |
+| --- | ---- | ---------- |
+| `createdAt` | Time | Timestamp when the PackageFileRegistry was created |
+| `id` | ID! | ID of the PackageFileRegistry |
+| `lastSyncFailure` | String | Error message during sync of the PackageFileRegistry |
+| `lastSyncedAt` | Time | Timestamp of the most recent successful sync of the PackageFileRegistry |
+| `packageFileId` | ID! | ID of the PackageFile |
+| `retryAt` | Time | Timestamp after which the PackageFileRegistry should be resynced |
+| `retryCount` | Int | Number of consecutive failed sync attempts of the PackageFileRegistry |
+| `state` | RegistryState | Sync state of the PackageFileRegistry |
+
## PageInfo
Information about pagination in a connection.
diff --git a/doc/api/projects.md b/doc/api/projects.md
index b9513cc767e..aa5e9ef6e43 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -312,8 +312,8 @@ GET /projects?custom_attributes[key]=value&custom_attributes[other_key]=other_va
### Pagination limits
-From GitLab 12.10, [offset-based pagination](README.md#offset-based-pagination) will be
-[limited to 10,000 records](https://gitlab.com/gitlab-org/gitlab/issues/34565).
+From GitLab 13.0, [offset-based pagination](README.md#offset-based-pagination) will be
+[limited to 50,000 records](https://gitlab.com/gitlab-org/gitlab/issues/34565).
[Keyset pagination](README.md#keyset-based-pagination) will be required to retrieve projects
beyond this limit.
diff --git a/doc/development/fe_guide/vue.md b/doc/development/fe_guide/vue.md
index c8aec5601a2..7e2d4b08767 100644
--- a/doc/development/fe_guide/vue.md
+++ b/doc/development/fe_guide/vue.md
@@ -289,3 +289,16 @@ One should apply to be a Vue.js expert by opening an MR when the Merge Request's
- Full understanding of testing a Vue and Vuex application
- Vuex code follows the [documented pattern](vuex.md#actions-pattern-request-and-receive-namespaces)
- Knowledge about the existing Vue and Vuex applications and existing reusable components
+
+## Vue 2 -> Vue 3 Migration
+
+> This section is added temporarily to support the efforts to migrate the codebase from Vue 2.x to Vue 3.x
+
+Currently, we recommend to minimize adding certain features to the codebase to prevent increasing the tech debt for the eventual migration:
+
+- filters;
+- event buses;
+- functional templated
+- `slot` attributes
+
+You can find more details on [Migration to Vue 3](vue3_migration.md)
diff --git a/doc/development/fe_guide/vue3_migration.md b/doc/development/fe_guide/vue3_migration.md
new file mode 100644
index 00000000000..1292926d951
--- /dev/null
+++ b/doc/development/fe_guide/vue3_migration.md
@@ -0,0 +1,109 @@
+# Migration to Vue 3
+
+In order to prepare for the eventual migration to Vue 3.x, we should be wary about adding the following features to the codebase:
+
+## Vue filters
+
+**Why?**
+
+Filters [are removed](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0015-remove-filters.md) from the Vue 3 API completely.
+
+**What to use instead**
+
+Component's computed properties / methods or external helpers.
+
+## Event bus
+
+**Why?**
+
+`$on` and `$off` methods [are removed](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0020-events-api-change.md) from the Vue instance, so in Vue 3 it can't be used to create an event bus.
+
+**What to use instead**
+
+Vue docs recommend using [mitt](https://github.com/developit/mitt) library. It's relatively small (200 bytes gzipped) and has a simple API:
+
+```javascript
+import mitt from 'mitt'
+
+const emitter = mitt()
+
+// listen to an event
+emitter.on('foo', e => console.log('foo', e) )
+
+// listen to all events
+emitter.on('*', (type, e) => console.log(type, e) )
+
+// fire an event
+emitter.emit('foo', { a: 'b' })
+
+// working with handler references:
+function onFoo() {}
+
+emitter.on('foo', onFoo) // listen
+emitter.off('foo', onFoo) // unlisten
+```
+
+## <template functional>
+
+**Why?**
+
+In Vue 3, `{ functional: true }` option [is removed](https://github.com/vuejs/rfcs/blob/functional-async-api-change/active-rfcs/0007-functional-async-api-change.md) and `<template functional>` is no longer supported.
+
+**What to use instead**
+
+Functional components must be written as plain functions:
+
+```javascript
+import { h } from 'vue'
+
+const FunctionalComp = (props, slots) => {
+ return h('div', `Hello! ${props.name}`)
+}
+```
+
+## Old slots syntax with `slot` attribute
+
+**Why?**
+
+In Vue 2.6 `slot` attribute was already deprecated in favor of `v-slot` directive but its usage is still allowed and sometimes we prefer using them because it simplifies unit tests (with old syntax, slots are rendered on `shallowMount`). However, in Vue 3 we can't use old syntax anymore.
+
+**What to use instead**
+
+The syntax with `v-slot` directive. To fix rendering slots in `shallowMount`, we need to stub a child component with slots explicitly.
+
+```html
+<!-- MyAwesomeComponent.vue -->
+<script>
+import SomeChildComponent from './some_child_component.vue'
+
+export default {
+ components: {
+ SomeChildComponent
+ }
+}
+
+</script>
+
+<template>
+ <div>
+ <h1>Hello GitLab!</h1>
+ <some-child-component>
+ <template #header>
+ Header content
+ </template>
+ </some-child-component>
+ </div>
+</template>
+```
+
+```js
+// MyAwesomeComponent.spec.js
+
+import SomeChildComponent from '~/some_child_component.vue'
+
+shallowMount(MyAwesomeComponent, {
+ stubs: {
+ SomeChildComponent
+ }
+})
+```
diff --git a/doc/development/geo/framework.md b/doc/development/geo/framework.md
index 83809d1fd3d..a2ee52cbc7c 100644
--- a/doc/development/geo/framework.md
+++ b/doc/development/geo/framework.md
@@ -161,49 +161,7 @@ state.
For example, to add support for files referenced by a `Widget` model with a
`widgets` table, you would perform the following steps:
-1. Add verification state fields to the `widgets` table so the Geo primary can
- track verification state:
-
- ```ruby
- # frozen_string_literal: true
-
- class AddVerificationStateToWidgets < ActiveRecord::Migration[6.0]
- DOWNTIME = false
-
- def change
- add_column :widgets, :verification_retry_at, :datetime_with_timezone
- add_column :widgets, :verified_at, :datetime_with_timezone
- add_column :widgets, :verification_checksum, :string
- add_column :widgets, :verification_failure, :string
- add_column :widgets, :verification_retry_count, :integer
- end
- end
- ```
-
-1. Add a partial index on `verification_failure` and `verification_checksum` to ensure
- re-verification can be performed efficiently:
-
- ```ruby
- # frozen_string_literal: true
-
- class AddVerificationFailureIndexToWidgets < ActiveRecord::Migration[6.0]
- include Gitlab::Database::MigrationHelpers
-
- DOWNTIME = false
-
- disable_ddl_transaction!
-
- def up
- add_concurrent_index :widgets, :verification_failure, where: "(verification_failure IS NOT NULL)", name: "widgets_verification_failure_partial"
- add_concurrent_index :widgets, :verification_checksum, where: "(verification_checksum IS NOT NULL)", name: "widgets_verification_checksum_partial"
- end
-
- def down
- remove_concurrent_index :widgets, :verification_failure
- remove_concurrent_index :widgets, :verification_checksum
- end
- end
- ```
+#### Replication
1. Include `Gitlab::Geo::ReplicableModel` in the `Widget` class, and specify
the Replicator class `with_replicator Geo::WidgetReplicator`.
@@ -350,11 +308,53 @@ For example, to add support for files referenced by a `Widget` model with a
end
```
-Widget files should now be replicated and verified by Geo!
+Widgets should now be replicated by Geo!
+
+#### Verification
+
+1. Add verification state fields to the `widgets` table so the Geo primary can
+ track verification state:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class AddVerificationStateToWidgets < ActiveRecord::Migration[6.0]
+ DOWNTIME = false
-### Verification statistics with Blob Replicator Strategy
+ def change
+ add_column :widgets, :verification_retry_at, :datetime_with_timezone
+ add_column :widgets, :verified_at, :datetime_with_timezone
+ add_column :widgets, :verification_checksum, :string
+ add_column :widgets, :verification_failure, :string
+ add_column :widgets, :verification_retry_count, :integer
+ end
+ end
+ ```
-GitLab Geo stores statistic data in the `geo_node_statuses` table.
+1. Add a partial index on `verification_failure` and `verification_checksum` to ensure
+ re-verification can be performed efficiently:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ class AddVerificationFailureIndexToWidgets < ActiveRecord::Migration[6.0]
+ include Gitlab::Database::MigrationHelpers
+
+ DOWNTIME = false
+
+ disable_ddl_transaction!
+
+ def up
+ add_concurrent_index :widgets, :verification_failure, where: "(verification_failure IS NOT NULL)", name: "widgets_verification_failure_partial"
+ add_concurrent_index :widgets, :verification_checksum, where: "(verification_checksum IS NOT NULL)", name: "widgets_verification_checksum_partial"
+ end
+
+ def down
+ remove_concurrent_index :widgets, :verification_failure
+ remove_concurrent_index :widgets, :verification_checksum
+ end
+ end
+ ```
1. Add fields `widget_count`, `widget_checksummed_count`, and `widget_checksum_failed_count`
to `GeoNodeStatus#RESOURCE_STATUS_FIELDS` array in `ee/app/models/geo_node_status.rb`.
@@ -378,3 +378,134 @@ GitLab Geo stores statistic data in the `geo_node_statuses` table.
1. Update `Sidekiq metrics` table in `doc/administration/monitoring/prometheus/gitlab_metrics.md` with new fields.
1. Update `GET /geo_nodes/status` example response in `doc/api/geo_nodes.md` with new fields.
1. Update `ee/spec/models/geo_node_status_spec.rb` and `ee/spec/factories/geo_node_statuses.rb` with new fields.
+
+To do: Add verification on secondaries.
+
+Widgets should now be verified by Geo!
+
+#### GraphQL API
+
+1. Add a new field to `GeoNodeType` in
+ `ee/app/graphql/types/geo/geo_node_type.rb`:
+
+ ```ruby
+ field :widget_registries, ::Types::Geo::WidgetRegistryType.connection_type,
+ null: true,
+ resolver: ::Resolvers::Geo::WidgetRegistriesResolver,
+ description: 'Find widget registries on this Geo node',
+ feature_flag: :geo_self_service_framework
+ ```
+
+1. Add the new `widget_registries` field name to the `expected_fields` array in
+ `ee/spec/graphql/types/geo/geo_node_type_spec.rb`.
+
+1. Create `ee/app/graphql/resolvers/geo/widget_registries_resolver.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Resolvers
+ module Geo
+ class WidgetRegistriesResolver < BaseResolver
+ include RegistriesResolver
+ end
+ end
+ end
+ ```
+
+1. Create `ee/spec/graphql/resolvers/geo/widget_registries_resolver_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ describe Resolvers::Geo::WidgetRegistriesResolver do
+ it_behaves_like 'a Geo registries resolver', :widget_registry
+ end
+ ```
+
+1. Create `ee/app/finders/geo/widget_registry_finder.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Geo
+ class WidgetRegistryFinder
+ include FrameworkRegistryFinder
+ end
+ end
+ ```
+
+1. Create `ee/spec/finders/geo/widget_registry_finder_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ describe Geo::WidgetRegistryFinder do
+ it_behaves_like 'a framework registry finder', :widget_registry
+ end
+ ```
+
+1. Create `ee/app/graphql/types/geo/package_file_registry_type.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ module Types
+ module Geo
+ # rubocop:disable Graphql/AuthorizeTypes because it is included
+ class WidgetRegistryType < BaseObject
+ include ::Types::Geo::RegistryType
+
+ graphql_name 'WidgetRegistry'
+ description 'Represents the sync and verification state of a widget'
+
+ field :widget_id, GraphQL::ID_TYPE, null: false, description: 'ID of the Widget'
+ end
+ end
+ end
+ ```
+
+1. Create `ee/spec/graphql/types/geo/widget_registry_type_spec.rb`:
+
+ ```ruby
+ # frozen_string_literal: true
+
+ require 'spec_helper'
+
+ describe GitlabSchema.types['WidgetRegistry'] do
+ it_behaves_like 'a Geo registry type'
+
+ it 'has the expected fields (other than those included in RegistryType)' do
+ expected_fields = %i[widget_id]
+
+ expect(described_class).to have_graphql_fields(*expected_fields).at_least
+ end
+ end
+ ```
+
+1. Add integration tests for providing Widget registry data to the frontend via
+ the GraphQL API, by duplicating and modifying the following shared examples
+ in `ee/spec/requests/api/graphql/geo/registries_spec.rb`:
+
+ ```ruby
+ it_behaves_like 'gets registries for', {
+ field_name: 'widgetRegistries',
+ registry_class_name: 'WidgetRegistry',
+ registry_factory: :widget_registry,
+ registry_foreign_key_field_name: 'widgetId'
+ }
+ ```
+
+Individual widget synchronization and verification data should now be available
+via the GraphQL API!
+
+#### Admin UI
+
+To do.
+
+Widget sync and verification data (aggregate and individual) should now be
+available in the Admin UI!
diff --git a/doc/user/project/settings/index.md b/doc/user/project/settings/index.md
index 6cb97e2e2a8..ae87945c684 100644
--- a/doc/user/project/settings/index.md
+++ b/doc/user/project/settings/index.md
@@ -257,7 +257,7 @@ To do so:
1. Confirm the action by typing the project's path as instructed.
NOTE: **Note:**
-Only project maintainers have the [permissions](../../permissions.md#project-members-permissions)
+Only project owners have the [permissions](../../permissions.md#project-members-permissions)
to remove a fork relationship.
## Operations settings