diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-10-18 18:10:37 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-10-18 18:10:37 +0300 |
commit | b556d0fab74a7ef460d868e508ea5ca72d0e5eed (patch) | |
tree | d0e0dce2c15d056b37e0fdd9495d754cffe2f7ef /doc/development | |
parent | a300f4d5c7fdd5d557288ee526986e0adb683b35 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'doc/development')
-rw-r--r-- | doc/development/database/foreign_keys.md | 98 | ||||
-rw-r--r-- | doc/development/fe_guide/customizable_dashboards.md | 99 | ||||
-rw-r--r-- | doc/development/feature_development.md | 1 | ||||
-rw-r--r-- | doc/development/json.md | 46 |
4 files changed, 195 insertions, 49 deletions
diff --git a/doc/development/database/foreign_keys.md b/doc/development/database/foreign_keys.md index dd0fc6f8446..d9506ae614a 100644 --- a/doc/development/database/foreign_keys.md +++ b/doc/development/database/foreign_keys.md @@ -4,7 +4,7 @@ group: Database 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 --- -# Foreign Keys & Associations +# Foreign keys and associations When adding an association to a model you must also add a foreign key. For example, say you have the following model: @@ -20,7 +20,7 @@ that data consistency is enforced on database level. Foreign keys also mean that the database can very quickly remove associated data (for example, when removing a user), instead of Rails having to do this. -## Adding Foreign Keys In Migrations +## Adding foreign keys in migrations Foreign keys can be added concurrently using `add_concurrent_foreign_key` as defined in `Gitlab::Database::MigrationHelpers`. See the @@ -31,7 +31,7 @@ you have removed any orphaned rows. The method `add_concurrent_foreign_key` does not take care of this so you must do so manually. See [adding foreign key constraint to an existing column](add_foreign_key_to_existing_column.md). -## Updating Foreign Keys In Migrations +## Updating foreign keys in migrations Sometimes a foreign key constraint must be changed, preserving the column but updating the constraint condition. For example, moving from @@ -45,64 +45,64 @@ To replace a foreign key: 1. [Add the new foreign key without validation](add_foreign_key_to_existing_column.md#prevent-invalid-records) - The name of the foreign key constraint must be changed to add a new - foreign key before removing the old one. + The name of the foreign key constraint must be changed to add a new + foreign key before removing the old one. - ```ruby - class ReplaceFkOnPackagesPackagesProjectId < Gitlab::Database::Migration[2.0] - disable_ddl_transaction! + ```ruby + class ReplaceFkOnPackagesPackagesProjectId < Gitlab::Database::Migration[2.0] + disable_ddl_transaction! - NEW_CONSTRAINT_NAME = 'fk_new' + NEW_CONSTRAINT_NAME = 'fk_new' - def up - add_concurrent_foreign_key(:packages_packages, :projects, column: :project_id, on_delete: :nullify, validate: false, name: NEW_CONSTRAINT_NAME) - end + def up + add_concurrent_foreign_key(:packages_packages, :projects, column: :project_id, on_delete: :nullify, validate: false, name: NEW_CONSTRAINT_NAME) + end - def down - with_lock_retries do - remove_foreign_key_if_exists(:packages_packages, column: :project_id, on_delete: :nullify, name: NEW_CONSTRAINT_NAME) - end - end - end - ``` + def down + with_lock_retries do + remove_foreign_key_if_exists(:packages_packages, column: :project_id, on_delete: :nullify, name: NEW_CONSTRAINT_NAME) + end + end + end + ``` 1. [Validate the new foreign key](add_foreign_key_to_existing_column.md#validate-the-foreign-key) - ```ruby - class ValidateFkNew < Gitlab::Database::Migration[2.0] - NEW_CONSTRAINT_NAME = 'fk_new' + ```ruby + class ValidateFkNew < Gitlab::Database::Migration[2.0] + NEW_CONSTRAINT_NAME = 'fk_new' - # foreign key added in <link to MR or path to migration adding new FK> - def up - validate_foreign_key(:packages_packages, name: NEW_CONSTRAINT_NAME) - end + # foreign key added in <link to MR or path to migration adding new FK> + def up + validate_foreign_key(:packages_packages, name: NEW_CONSTRAINT_NAME) + end - def down - # no-op - end - end - ``` + def down + # no-op + end + end + ``` 1. Remove the old foreign key: - ```ruby - class RemoveFkOld < Gitlab::Database::Migration[2.0] - OLD_CONSTRAINT_NAME = 'fk_old' + ```ruby + class RemoveFkOld < Gitlab::Database::Migration[2.0] + OLD_CONSTRAINT_NAME = 'fk_old' - # new foreign key added in <link to MR or path to migration adding new FK> - # and validated in <link to MR or path to migration validating new FK> - def up - remove_foreign_key_if_exists(:packages_packages, column: :project_id, on_delete: :cascade, name: OLD_CONSTRAINT_NAME) - end + # new foreign key added in <link to MR or path to migration adding new FK> + # and validated in <link to MR or path to migration validating new FK> + def up + remove_foreign_key_if_exists(:packages_packages, column: :project_id, on_delete: :cascade, name: OLD_CONSTRAINT_NAME) + end - def down - # Validation is skipped here, so if rolled back, this will need to be revalidated in a separate migration - add_concurrent_foreign_key(:packages_packages, :projects, column: :project_id, on_delete: :cascade, validate: false, name: OLD_CONSTRAINT_NAME) - end - end - ``` + def down + # Validation is skipped here, so if rolled back, this will need to be revalidated in a separate migration + add_concurrent_foreign_key(:packages_packages, :projects, column: :project_id, on_delete: :cascade, validate: false, name: OLD_CONSTRAINT_NAME) + end + end + ``` -## Cascading Deletes +## Cascading deletes Every foreign key must define an `ON DELETE` clause, and in 99% of the cases this should be set to `CASCADE`. @@ -124,7 +124,7 @@ have a foreign key constraint. So if that spec fails, don't add the column to `IGNORED_FK_COLUMNS`, but instead add the FK constraint, or consider naming it differently. -## Dependent Removals +## Dependent removals Don't define options such as `dependent: :destroy` or `dependent: :delete` when defining an association. Defining these options means Rails handles the @@ -182,9 +182,9 @@ create_table :user_configs, id: false do |t| end ``` -Setting `default: nil` ensures a primary key sequence is not created, and since the primary key +Setting `default: nil` ensures a primary key sequence is not created, and because the primary key automatically gets an index, we set `index: false` to avoid creating a duplicate. -You also need to add the new primary key to the model: +You must also add the new primary key to the model: ```ruby class UserConfig < ActiveRecord::Base diff --git a/doc/development/fe_guide/customizable_dashboards.md b/doc/development/fe_guide/customizable_dashboards.md new file mode 100644 index 00000000000..38ee750d421 --- /dev/null +++ b/doc/development/fe_guide/customizable_dashboards.md @@ -0,0 +1,99 @@ +--- +stage: Analytics +group: Product Analytics +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 +--- + +# Customizable dashboards **(PREMIUM)** + +> [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). + +Customizable dashboards provide a dashboard structure that allows users to create +their own dashboards and commit the structure to a repository. + +## Usage + +To use customizable dashboards: + +1. Create your dashboard component. +1. Render an instance of `CustomizableDashboard`. +1. Pass a list of widgets to render. + +For example, a customizable dashboard for users over time: + +```vue +<script> +import CustomizableDashboard from 'ee/vue_shared/components/customizable_dashboard/customizable_dashboard.vue'; +import { s__ } from '~/locale'; + +export default { + name: 'AnalyticsDashboard', + components: { + CustomizableDashboard, + }, + data() { + return { + widgets: [ + { + component: 'CubeLineChart', // The name of the widget component. + title: s__('ProductAnalytics|Users / Time'), // The title shown on the widget component. + // Gridstack settings based upon https://github.com/gridstack/gridstack.js/tree/master/doc#item-options. + // All values are grid row/column numbers up to 12. + // We use the default 12 column grid https://github.com/gridstack/gridstack.js#change-grid-columns. + gridAttributes: { + size: { + height: 4, + width: 6, + minHeight: 4, + minWidth: 6, + }, + position: { + xPos: 0, + yPos: 0, + }, + }, + // Options that are used to set bespoke values for each widget. + // Available customizations are determined by the widget itself. + customizations: {}, + // Chart options defined by the charting library being used by the widget. + chartOptions: { + xAxis: { name: __('Time'), type: 'time' }, + yAxis: { name: __('Counts') }, + }, + // The data for the widget. + // This could be imported or in this case, a query passed to be used by the widgets API. + // Each widget type determines how it handles this property. + data: { + query: { + users: { + measures: ['Jitsu.count'], + dimensions: ['Jitsu.eventType'], + }, + }, + }, + }, + ] + }; + }, +}; +</script> + +<template> + <h1>{{ s__('ProductAnalytics|Analytics dashboard') }}</h1> + <customizable-dashboard :widgets="widgets" /> +</template> +``` + +The widgets data can be retrieved from a file or API request, or imported through HTML data attributes. + +For each widget, a `component` is defined. Each `component` is a component declaration and should be included in +[`vue_shared/components/customizable_dashboard/widgets_base.vue`](https://gitlab.com/gitlab-org/gitlab/blob/master/ee/app/assets/javascripts/vue_shared/components/customizable_dashboard/widgets_base.vue) +as a dynamic import, to keep the memory usage down until it is used. + +For example: + +```javascript +components: { + CubeLineChart: () => import('ee/product_analytics/dashboards/components/widgets/cube_line_chart.vue') +} +``` diff --git a/doc/development/feature_development.md b/doc/development/feature_development.md index 32ed54f6fd8..760ba033633 100644 --- a/doc/development/feature_development.md +++ b/doc/development/feature_development.md @@ -114,6 +114,7 @@ Consult these topics for information on contributing to specific GitLab features - [Cached queries guidelines](cached_queries.md), for tracking down N+1 queries masked by query caching, memory profiling and why should we avoid cached queries. +- [JSON guidelines](json.md) for how to handle JSON in a performant manner. ## Database guides diff --git a/doc/development/json.md b/doc/development/json.md new file mode 100644 index 00000000000..8a2575401fb --- /dev/null +++ b/doc/development/json.md @@ -0,0 +1,46 @@ +--- +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 +--- + +# JSON Guidelines + +At GitLab we handle a lot of JSON data. To best ensure we remain performant +when handling large JSON encodes or decodes, we use our own JSON class +instead of the default methods. + +## `Gitlab::Json` + +This class should be used in place of any calls to the default `JSON` class, +`.to_json` calls, and the like. It implements the majority of the public +methods provided by `JSON`, such as `.parse`, `.generate`, `.dump`, etc, and +should be entirely identical in its response. + +The difference being that by sending all JSON handling through `Gitlab::Json` +we can change the gem being used in the background. We use `oj` +instead of the `json` gem, which uses C extensions and is therefore notably +faster. + +This class came into existence because, due to the age of the GitLab application, +it was proving impossible to just replace the `json` gem with `oj` by default because: + +- The number of tests with exact expectations of the responses. +- The subtle variances between different JSON processors, particularly + around formatting. + +The `Gitlab::Json` class takes this into account and can +vary the adapter based on the use case, and account for outdated formatting +expectations. + +## `Gitlab::Json::PrecompiledJson` + +This class is used by our hooks into the Grape framework to ensure that +already-generated JSON is not then run through JSON generation +a second time when returning the response. + +## `Gitlab::Json::LimitedEncoder` + +This class can be used to generate JSON but fail with an error if the +resulting JSON would be too large. The default limit for the `.encode` +method is 25 MB, but this can be customized when using the method. |