diff options
Diffstat (limited to 'doc/development')
-rw-r--r-- | doc/development/fe_guide/vue.md | 13 | ||||
-rw-r--r-- | doc/development/fe_guide/vue3_migration.md | 109 | ||||
-rw-r--r-- | doc/development/geo/framework.md | 223 |
3 files changed, 299 insertions, 46 deletions
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! |