diff options
43 files changed, 595 insertions, 321 deletions
diff --git a/app/assets/javascripts/search/store/getters.js b/app/assets/javascripts/search/store/getters.js new file mode 100644 index 00000000000..650af5fa55a --- /dev/null +++ b/app/assets/javascripts/search/store/getters.js @@ -0,0 +1,9 @@ +import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants'; + +export const frequentGroups = (state) => { + return state.frequentItems[GROUPS_LOCAL_STORAGE_KEY]; +}; + +export const frequentProjects = (state) => { + return state.frequentItems[PROJECTS_LOCAL_STORAGE_KEY]; +}; diff --git a/app/assets/javascripts/search/store/index.js b/app/assets/javascripts/search/store/index.js index 1923c8b96ab..4fa88822722 100644 --- a/app/assets/javascripts/search/store/index.js +++ b/app/assets/javascripts/search/store/index.js @@ -1,6 +1,7 @@ import Vue from 'vue'; import Vuex from 'vuex'; import * as actions from './actions'; +import * as getters from './getters'; import mutations from './mutations'; import createState from './state'; @@ -8,6 +9,7 @@ Vue.use(Vuex); export const getStoreConfig = ({ query }) => ({ actions, + getters, mutations, state: createState({ query }), }); diff --git a/app/assets/javascripts/search/store/utils.js b/app/assets/javascripts/search/store/utils.js index 9f058efeaa7..60c09221ca9 100644 --- a/app/assets/javascripts/search/store/utils.js +++ b/app/assets/javascripts/search/store/utils.js @@ -24,7 +24,15 @@ export const setFrequentItemToLS = (key, data, itemData) => { return; } - const keyList = ['id', 'avatar_url', 'name', 'full_name', 'name_with_namespace', 'frequency']; + const keyList = [ + 'id', + 'avatar_url', + 'name', + 'full_name', + 'name_with_namespace', + 'frequency', + 'lastUsed', + ]; try { const frequentItems = data[key].map((obj) => extractKeys(obj, keyList)); @@ -35,17 +43,25 @@ export const setFrequentItemToLS = (key, data, itemData) => { // Up the frequency (Max 5) const currentFrequency = frequentItems[existingItemIndex].frequency; frequentItems[existingItemIndex].frequency = Math.min(currentFrequency + 1, MAX_FREQUENCY); + frequentItems[existingItemIndex].lastUsed = new Date().getTime(); } else { // Only store a max of 5 items if (frequentItems.length >= MAX_FREQUENT_ITEMS) { frequentItems.pop(); } - frequentItems.push({ ...item, frequency: 1 }); + frequentItems.push({ ...item, frequency: 1, lastUsed: new Date().getTime() }); } - // Sort by frequency - frequentItems.sort((a, b) => b.frequency - a.frequency); + // Sort by frequency and lastUsed + frequentItems.sort((a, b) => { + if (a.frequency > b.frequency) { + return -1; + } else if (a.frequency < b.frequency) { + return 1; + } + return b.lastUsed - a.lastUsed; + }); // Note we do not need to commit a mutation here as immediately after this we refresh the page to // update the search results. diff --git a/app/assets/javascripts/search/topbar/components/group_filter.vue b/app/assets/javascripts/search/topbar/components/group_filter.vue index 2040d2ca173..45a6ae73fac 100644 --- a/app/assets/javascripts/search/topbar/components/group_filter.vue +++ b/app/assets/javascripts/search/topbar/components/group_filter.vue @@ -1,6 +1,6 @@ <script> import { isEmpty } from 'lodash'; -import { mapState, mapActions } from 'vuex'; +import { mapState, mapActions, mapGetters } from 'vuex'; import { visitUrl, setUrlParams } from '~/lib/utils/url_utility'; import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '../constants'; import SearchableDropdown from './searchable_dropdown.vue'; @@ -19,6 +19,7 @@ export default { }, computed: { ...mapState(['groups', 'fetchingGroups']), + ...mapGetters(['frequentGroups']), selectedGroup() { return isEmpty(this.initialData) ? ANY_OPTION : this.initialData; }, @@ -49,6 +50,7 @@ export default { :loading="fetchingGroups" :selected-item="selectedGroup" :items="groups" + :frequent-items="frequentGroups" @first-open="loadFrequentGroups" @search="fetchGroups" @change="handleGroupChange" diff --git a/app/assets/javascripts/search/topbar/components/project_filter.vue b/app/assets/javascripts/search/topbar/components/project_filter.vue index 8589276e9f3..1ca31db61e5 100644 --- a/app/assets/javascripts/search/topbar/components/project_filter.vue +++ b/app/assets/javascripts/search/topbar/components/project_filter.vue @@ -1,5 +1,5 @@ <script> -import { mapState, mapActions } from 'vuex'; +import { mapState, mapActions, mapGetters } from 'vuex'; import { visitUrl, setUrlParams } from '~/lib/utils/url_utility'; import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '../constants'; import SearchableDropdown from './searchable_dropdown.vue'; @@ -18,6 +18,7 @@ export default { }, computed: { ...mapState(['projects', 'fetchingProjects']), + ...mapGetters(['frequentProjects']), selectedProject() { return this.initialData ? this.initialData : ANY_OPTION; }, @@ -52,6 +53,7 @@ export default { :loading="fetchingProjects" :selected-item="selectedProject" :items="projects" + :frequent-items="frequentProjects" @first-open="loadFrequentProjects" @search="fetchProjects" @change="handleProjectChange" diff --git a/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue b/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue index 488fee90fca..5653cddda60 100644 --- a/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue +++ b/app/assets/javascripts/search/topbar/components/searchable_dropdown.vue @@ -2,6 +2,7 @@ import { GlDropdown, GlDropdownItem, + GlDropdownSectionHeader, GlSearchBoxByType, GlLoadingIcon, GlIcon, @@ -16,11 +17,13 @@ import SearchableDropdownItem from './searchable_dropdown_item.vue'; export default { i18n: { clearLabel: __('Clear'), + frequentlySearched: __('Frequently searched'), }, name: 'SearchableDropdown', components: { GlDropdown, GlDropdownItem, + GlDropdownSectionHeader, GlSearchBoxByType, GlLoadingIcon, GlIcon, @@ -61,6 +64,11 @@ export default { required: false, default: () => [], }, + frequentItems: { + type: Array, + required: false, + default: () => [], + }, }, data() { return { @@ -68,6 +76,11 @@ export default { hasBeenOpened: false, }; }, + computed: { + showFrequentItems() { + return !this.searchText && this.frequentItems.length > 0; + }, + }, methods: { isSelected(selected) { return selected.id === this.selectedItem.id; @@ -139,6 +152,25 @@ export default { <span data-testid="item-title">{{ $options.ANY_OPTION.name }}</span> </gl-dropdown-item> </div> + <div + v-if="showFrequentItems" + class="gl-border-b-solid gl-border-b-gray-100 gl-border-b-1 gl-pb-2 gl-mb-2" + > + <gl-dropdown-section-header>{{ + $options.i18n.frequentlySearched + }}</gl-dropdown-section-header> + <searchable-dropdown-item + v-for="item in frequentItems" + :key="item.id" + :item="item" + :selected-item="selectedItem" + :search-text="searchText" + :name="name" + :full-name="fullName" + data-testid="frequent-items" + @change="updateDropdown" + /> + </div> <div v-if="!loading"> <searchable-dropdown-item v-for="item in items" @@ -148,6 +180,7 @@ export default { :search-text="searchText" :name="name" :full-name="fullName" + data-testid="searchable-items" @change="updateDropdown" /> </div> diff --git a/app/controllers/profiles/gpg_keys_controller.rb b/app/controllers/profiles/gpg_keys_controller.rb index 7f04927f517..9e16d195b00 100644 --- a/app/controllers/profiles/gpg_keys_controller.rb +++ b/app/controllers/profiles/gpg_keys_controller.rb @@ -22,7 +22,7 @@ class Profiles::GpgKeysController < Profiles::ApplicationController end def destroy - @gpg_key.destroy + GpgKeys::DestroyService.new(current_user).execute(@gpg_key) respond_to do |format| format.html { redirect_to profile_gpg_keys_url, status: :found } diff --git a/app/graphql/types/ci/build_need_type.rb b/app/graphql/types/ci/build_need_type.rb index 3bd81f8fa8f..19ff758ad1d 100644 --- a/app/graphql/types/ci/build_need_type.rb +++ b/app/graphql/types/ci/build_need_type.rb @@ -7,6 +7,8 @@ module Types class BuildNeedType < BaseObject graphql_name 'CiBuildNeed' + field :id, GraphQL::ID_TYPE, null: false, + description: 'ID of the job we need to complete.' field :name, GraphQL::STRING_TYPE, null: true, description: 'Name of the job we need to complete.' end diff --git a/app/graphql/types/ci/detailed_status_type.rb b/app/graphql/types/ci/detailed_status_type.rb index 0b643a6b676..6310a62a103 100644 --- a/app/graphql/types/ci/detailed_status_type.rb +++ b/app/graphql/types/ci/detailed_status_type.rb @@ -6,6 +6,9 @@ module Types class DetailedStatusType < BaseObject graphql_name 'DetailedStatus' + field :id, GraphQL::STRING_TYPE, null: false, + description: 'ID for a detailed status.', + extras: [:parent] field :group, GraphQL::STRING_TYPE, null: true, description: 'Group of the status.' field :icon, GraphQL::STRING_TYPE, null: true, @@ -29,6 +32,10 @@ module Types calls_gitaly: true, description: 'Action information for the status. This includes method, button title, icon, path, and title.' + def id(parent:) + "#{object.id}-#{parent.object.object.id}" + end + def action if object.has_action? { diff --git a/app/graphql/types/ci/group_type.rb b/app/graphql/types/ci/group_type.rb index d6d4252e8d7..3da183cb842 100644 --- a/app/graphql/types/ci/group_type.rb +++ b/app/graphql/types/ci/group_type.rb @@ -6,12 +6,14 @@ module Types class GroupType < BaseObject graphql_name 'CiGroup' + field :id, GraphQL::STRING_TYPE, null: false, + description: 'ID for a group.' field :name, GraphQL::STRING_TYPE, null: true, - description: 'Name of the job group.' + description: 'Name of the job group.' field :size, GraphQL::INT_TYPE, null: true, - description: 'Size of the group.' + description: 'Size of the group.' field :jobs, Ci::JobType.connection_type, null: true, - description: 'Jobs in group.' + description: 'Jobs in group.' field :detailed_status, Types::Ci::DetailedStatusType, null: true, description: 'Detailed status of the group.' diff --git a/app/graphql/types/ci/stage_type.rb b/app/graphql/types/ci/stage_type.rb index a9499e51124..ce3edb6c54f 100644 --- a/app/graphql/types/ci/stage_type.rb +++ b/app/graphql/types/ci/stage_type.rb @@ -6,20 +6,16 @@ module Types graphql_name 'CiStage' authorize :read_commit_status - field :name, - type: GraphQL::STRING_TYPE, - null: true, + field :id, GraphQL::ID_TYPE, null: false, + description: 'ID of the stage.' + field :name, type: GraphQL::STRING_TYPE, null: true, description: 'Name of the stage.' - field :groups, - type: Ci::GroupType.connection_type, - null: true, + field :groups, type: Ci::GroupType.connection_type, null: true, extras: [:lookahead], description: 'Group of jobs for the stage.' - field :detailed_status, Types::Ci::DetailedStatusType, - null: true, + field :detailed_status, Types::Ci::DetailedStatusType, null: true, description: 'Detailed status of the stage.' - field :jobs, Ci::JobType.connection_type, - null: true, + field :jobs, Ci::JobType.connection_type, null: true, description: 'Jobs for the stage.', method: 'latest_statuses' field :status, GraphQL::STRING_TYPE, diff --git a/app/graphql/types/ci/status_action_type.rb b/app/graphql/types/ci/status_action_type.rb index 9f7299c0270..a06b09735b3 100644 --- a/app/graphql/types/ci/status_action_type.rb +++ b/app/graphql/types/ci/status_action_type.rb @@ -5,6 +5,9 @@ module Types class StatusActionType < BaseObject graphql_name 'StatusAction' + field :id, GraphQL::STRING_TYPE, null: false, + description: 'ID for a status action.', + extras: [:parent] field :button_title, GraphQL::STRING_TYPE, null: true, description: 'Title for the button, for example: Retry this job.' field :icon, GraphQL::STRING_TYPE, null: true, @@ -17,6 +20,10 @@ module Types field :title, GraphQL::STRING_TYPE, null: true, description: 'Title for the action, for example: Retry.' + def id(parent:) + "#{parent.parent.object.object.class.name}-#{parent.object.object.id}" + end + def action_method object[:method] end diff --git a/app/models/ci/group.rb b/app/models/ci/group.rb index 47b91fcf2ce..e5cb2026503 100644 --- a/app/models/ci/group.rb +++ b/app/models/ci/group.rb @@ -10,6 +10,7 @@ module Ci class Group include StaticModel include Gitlab::Utils::StrongMemoize + include GlobalID::Identification attr_reader :project, :stage, :name, :jobs @@ -22,6 +23,10 @@ module Ci @jobs = jobs end + def id + "#{stage.id}-#{name}" + end + def ==(other) other.present? && other.is_a?(self.class) && project == other.project && diff --git a/app/models/namespace_setting.rb b/app/models/namespace_setting.rb index 600abc33471..fc890bf687c 100644 --- a/app/models/namespace_setting.rb +++ b/app/models/namespace_setting.rb @@ -15,7 +15,7 @@ class NamespaceSetting < ApplicationRecord NAMESPACE_SETTINGS_PARAMS = [:default_branch_name, :delayed_project_removal, :lock_delayed_project_removal, :resource_access_token_creation_allowed, - :prevent_sharing_groups_outside_hierarchy].freeze + :prevent_sharing_groups_outside_hierarchy, :new_user_signups_cap].freeze self.primary_key = :namespace_id diff --git a/app/models/user_callout.rb b/app/models/user_callout.rb index 63727e45a5c..e14ba035cc8 100644 --- a/app/models/user_callout.rb +++ b/app/models/user_callout.rb @@ -32,7 +32,9 @@ class UserCallout < ApplicationRecord pipeline_needs_hover_tip: 30, web_ide_ci_environments_guidance: 31, security_configuration_upgrade_banner: 32, - cloud_licensing_subscription_activation_banner: 33 # EE-only + cloud_licensing_subscription_activation_banner: 33, # EE-only + trial_status_reminder_d14: 34, # EE-only + trial_status_reminder_d3: 35 # EE-only } validates :user, presence: true diff --git a/app/policies/group_policy.rb b/app/policies/group_policy.rb index ba06b98e906..0b0edc7c452 100644 --- a/app/policies/group_policy.rb +++ b/app/policies/group_policy.rb @@ -156,6 +156,7 @@ class GroupPolicy < BasePolicy enable :set_note_created_at enable :set_emails_disabled enable :change_prevent_sharing_groups_outside_hierarchy + enable :change_new_user_signups_cap enable :update_default_branch_protection enable :create_deploy_token enable :destroy_deploy_token diff --git a/app/services/gpg_keys/create_service.rb b/app/services/gpg_keys/create_service.rb index e41444b2a82..ab8b12732d7 100644 --- a/app/services/gpg_keys/create_service.rb +++ b/app/services/gpg_keys/create_service.rb @@ -3,9 +3,17 @@ module GpgKeys class CreateService < Keys::BaseService def execute - key = user.gpg_keys.create(params) + key = create(params) notification_service.new_gpg_key(key) if key.persisted? key end + + private + + def create(params) + user.gpg_keys.create(params) + end end end + +GpgKeys::CreateService.prepend_mod diff --git a/app/services/gpg_keys/destroy_service.rb b/app/services/gpg_keys/destroy_service.rb index cecbfe26611..2e82509897e 100644 --- a/app/services/gpg_keys/destroy_service.rb +++ b/app/services/gpg_keys/destroy_service.rb @@ -7,3 +7,5 @@ module GpgKeys end end end + +GpgKeys::DestroyService.prepend_mod diff --git a/app/services/namespace_settings/update_service.rb b/app/services/namespace_settings/update_service.rb index c71f015b9d4..25525265e1c 100644 --- a/app/services/namespace_settings/update_service.rb +++ b/app/services/namespace_settings/update_service.rb @@ -14,7 +14,15 @@ module NamespaceSettings def execute validate_resource_access_token_creation_allowed_param - validate_prevent_sharing_groups_outside_hierarchy_param + + validate_settings_param_for_root_group( + param_key: :prevent_sharing_groups_outside_hierarchy, + user_policy: :change_prevent_sharing_groups_outside_hierarchy + ) + validate_settings_param_for_root_group( + param_key: :new_user_signups_cap, + user_policy: :change_new_user_signups_cap + ) if group.namespace_settings group.namespace_settings.attributes = settings_params @@ -34,17 +42,17 @@ module NamespaceSettings end end - def validate_prevent_sharing_groups_outside_hierarchy_param - return if settings_params[:prevent_sharing_groups_outside_hierarchy].nil? + def validate_settings_param_for_root_group(param_key:, user_policy:) + return if settings_params[param_key].nil? - unless can?(current_user, :change_prevent_sharing_groups_outside_hierarchy, group) - settings_params.delete(:prevent_sharing_groups_outside_hierarchy) - group.namespace_settings.errors.add(:prevent_sharing_groups_outside_hierarchy, _('can only be changed by a group admin.')) + unless can?(current_user, user_policy, group) + settings_params.delete(param_key) + group.namespace_settings.errors.add(param_key, _('can only be changed by a group admin.')) end unless group.root? - settings_params.delete(:prevent_sharing_groups_outside_hierarchy) - group.namespace_settings.errors.add(:prevent_sharing_groups_outside_hierarchy, _('only available on top-level groups.')) + settings_params.delete(param_key) + group.namespace_settings.errors.add(param_key, _('only available on top-level groups.')) end end end diff --git a/app/services/snippets/create_service.rb b/app/services/snippets/create_service.rb index d9a46890c45..6d3b63de9fd 100644 --- a/app/services/snippets/create_service.rb +++ b/app/services/snippets/create_service.rb @@ -20,14 +20,12 @@ module Snippets @snippet.author = current_user - if Feature.enabled?(:snippet_spam) - Spam::SpamActionService.new( - spammable: @snippet, - spam_params: spam_params, - user: current_user, - action: :create - ).execute - end + Spam::SpamActionService.new( + spammable: @snippet, + spam_params: spam_params, + user: current_user, + action: :create + ).execute if save_and_commit UserAgentDetailService.new(spammable: @snippet, spam_params: spam_params).create diff --git a/app/services/snippets/update_service.rb b/app/services/snippets/update_service.rb index f8374cc88bb..d83b21271c0 100644 --- a/app/services/snippets/update_service.rb +++ b/app/services/snippets/update_service.rb @@ -23,14 +23,12 @@ module Snippets update_snippet_attributes(snippet) - if Feature.enabled?(:snippet_spam) - Spam::SpamActionService.new( - spammable: snippet, - spam_params: spam_params, - user: current_user, - action: :update - ).execute - end + Spam::SpamActionService.new( + spammable: snippet, + spam_params: spam_params, + user: current_user, + action: :update + ).execute if save_and_commit(snippet) Gitlab::UsageDataCounters::SnippetCounter.count(:update) diff --git a/config/feature_flags/development/snippet_spam.yml b/config/feature_flags/development/snippet_spam.yml deleted file mode 100644 index 299a69fd68d..00000000000 --- a/config/feature_flags/development/snippet_spam.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: snippet_spam -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/44010 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/262013 -milestone: '13.5' -type: development -group: group::editor -default_enabled: false diff --git a/doc/administration/audit_events.md b/doc/administration/audit_events.md index ae921d4822a..7a871caf658 100644 --- a/doc/administration/audit_events.md +++ b/doc/administration/audit_events.md @@ -166,6 +166,7 @@ The following user actions are recorded: - A failed attempt to create or revoke a user's personal access token ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/276921) in GitLab 13.6) - Administrator added or removed ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/323905) in GitLab 14.1) - Removed SSH key ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220127) in GitLab 14.1) +- Added or removed GPG key ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/220127) in GitLab 14.1) Instance events can also be accessed via the [Instance Audit Events API](../api/audit_events.md#instance-audit-events). diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 305c0bba5e8..39100b25ccf 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -7658,6 +7658,7 @@ Represents the total number of issues and their weights for a particular day. | Name | Type | Description | | ---- | ---- | ----------- | +| <a id="cibuildneedid"></a>`id` | [`ID!`](#id) | ID of the job we need to complete. | | <a id="cibuildneedname"></a>`name` | [`String`](#string) | Name of the job we need to complete. | ### `CiConfig` @@ -7733,6 +7734,7 @@ Represents the total number of issues and their weights for a particular day. | Name | Type | Description | | ---- | ---- | ----------- | | <a id="cigroupdetailedstatus"></a>`detailedStatus` | [`DetailedStatus`](#detailedstatus) | Detailed status of the group. | +| <a id="cigroupid"></a>`id` | [`String!`](#string) | ID for a group. | | <a id="cigroupjobs"></a>`jobs` | [`CiJobConnection`](#cijobconnection) | Jobs in group. (see [Connections](#connections)) | | <a id="cigroupname"></a>`name` | [`String`](#string) | Name of the job group. | | <a id="cigroupsize"></a>`size` | [`Int`](#int) | Size of the group. | @@ -7827,6 +7829,7 @@ Represents the total number of issues and their weights for a particular day. | ---- | ---- | ----------- | | <a id="cistagedetailedstatus"></a>`detailedStatus` | [`DetailedStatus`](#detailedstatus) | Detailed status of the stage. | | <a id="cistagegroups"></a>`groups` | [`CiGroupConnection`](#cigroupconnection) | Group of jobs for the stage. (see [Connections](#connections)) | +| <a id="cistageid"></a>`id` | [`ID!`](#id) | ID of the stage. | | <a id="cistagejobs"></a>`jobs` | [`CiJobConnection`](#cijobconnection) | Jobs for the stage. (see [Connections](#connections)) | | <a id="cistagename"></a>`name` | [`String`](#string) | Name of the stage. | | <a id="cistagestatus"></a>`status` | [`String`](#string) | Status of the pipeline stage. | @@ -8491,6 +8494,7 @@ four standard [pagination arguments](#connection-pagination-arguments): | <a id="detailedstatusgroup"></a>`group` | [`String`](#string) | Group of the status. | | <a id="detailedstatushasdetails"></a>`hasDetails` | [`Boolean`](#boolean) | Indicates if the status has further details. | | <a id="detailedstatusicon"></a>`icon` | [`String`](#string) | Icon of the status. | +| <a id="detailedstatusid"></a>`id` | [`String!`](#string) | ID for a detailed status. | | <a id="detailedstatuslabel"></a>`label` | [`String`](#string) | Label of the status. | | <a id="detailedstatustext"></a>`text` | [`String`](#string) | Text of the status. | | <a id="detailedstatustooltip"></a>`tooltip` | [`String`](#string) | Tooltip associated with the status. | @@ -13102,6 +13106,7 @@ Represents the Geo sync and verification state of a snippet repository. | ---- | ---- | ----------- | | <a id="statusactionbuttontitle"></a>`buttonTitle` | [`String`](#string) | Title for the button, for example: Retry this job. | | <a id="statusactionicon"></a>`icon` | [`String`](#string) | Icon used in the action button. | +| <a id="statusactionid"></a>`id` | [`String!`](#string) | ID for a status action. | | <a id="statusactionmethod"></a>`method` | [`String`](#string) | Method for the action, for example: :post. | | <a id="statusactionpath"></a>`path` | [`String`](#string) | Path for the action. | | <a id="statusactiontitle"></a>`title` | [`String`](#string) | Title for the action, for example: Retry. | @@ -15290,6 +15295,8 @@ Name of the feature that the callout is for. | <a id="usercalloutfeaturenameenumsuggest_popover_dismissed"></a>`SUGGEST_POPOVER_DISMISSED` | Callout feature name for suggest_popover_dismissed. | | <a id="usercalloutfeaturenameenumtabs_position_highlight"></a>`TABS_POSITION_HIGHLIGHT` | Callout feature name for tabs_position_highlight. | | <a id="usercalloutfeaturenameenumthreat_monitoring_info"></a>`THREAT_MONITORING_INFO` | Callout feature name for threat_monitoring_info. | +| <a id="usercalloutfeaturenameenumtrial_status_reminder_d14"></a>`TRIAL_STATUS_REMINDER_D14` | Callout feature name for trial_status_reminder_d14. | +| <a id="usercalloutfeaturenameenumtrial_status_reminder_d3"></a>`TRIAL_STATUS_REMINDER_D3` | Callout feature name for trial_status_reminder_d3. | | <a id="usercalloutfeaturenameenumultimate_trial"></a>`ULTIMATE_TRIAL` | Callout feature name for ultimate_trial. | | <a id="usercalloutfeaturenameenumunfinished_tag_cleanup_callout"></a>`UNFINISHED_TAG_CLEANUP_CALLOUT` | Callout feature name for unfinished_tag_cleanup_callout. | | <a id="usercalloutfeaturenameenumweb_ide_alert_dismissed"></a>`WEB_IDE_ALERT_DISMISSED` | Callout feature name for web_ide_alert_dismissed. | diff --git a/doc/development/github_importer.md b/doc/development/github_importer.md index cc289496301..3e70585499d 100644 --- a/doc/development/github_importer.md +++ b/doc/development/github_importer.md @@ -213,3 +213,41 @@ The code for this resides in: - `lib/gitlab/github_import/label_finder.rb` - `lib/gitlab/github_import/milestone_finder.rb` - `lib/gitlab/github_import/caching.rb` + +## Logs + +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/48512/diffs) in GitLab 13.7. +> - Number of imported objects [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64256) in GitLab 14.1. + +The import progress can be checked in the `logs/importer.log` file. Each relevant import is logged +with `"import_source": "github"` and the `"project_id"`. + +The last log entry reports the number of objects fetched and imported: + +```json +{ + "message": "GitHub project import finished", + "duration_s": 347.25, + "objects_imported": { + "fetched": { + "diff_note": 93, + "issue": 321, + "note": 794, + "pull_request": 108, + "pull_request_merged_by": 92, + "pull_request_review": 81 + }, + "imported": { + "diff_note": 93, + "issue": 321, + "note": 794, + "pull_request": 108, + "pull_request_merged_by": 92, + "pull_request_review": 81 + } + }, + "import_source": "github", + "project_id": 47, + "import_stage": "Gitlab::GithubImport::Stage::FinishImportWorker" +} +``` diff --git a/doc/development/usage_ping/dictionary.md b/doc/development/usage_ping/dictionary.md index 527da610623..0784a792d34 100644 --- a/doc/development/usage_ping/dictionary.md +++ b/doc/development/usage_ping/dictionary.md @@ -20362,6 +20362,8 @@ Number of users who have run a API Fuzzing scan Group: `category::fuzz testing` +Data Category: `Optional` + Status: `data_available` Tiers: `ultimate` @@ -20388,6 +20390,8 @@ Number of users who have run a Container Scanning scan Group: `group::composition analysis` +Data Category: `Optional` + Status: `data_available` Tiers: `ultimate` @@ -20414,6 +20418,8 @@ Number of users who have run a Coverage Fuzzing scan Group: `category::fuzz testing` +Data Category: `Optional` + Status: `data_available` Tiers: `ultimate` @@ -20440,6 +20446,8 @@ Number of users who have run a DAST scan Group: `group::dynamic analysis` +Data Category: `Optional` + Status: `data_available` Tiers: `ultimate` @@ -20466,6 +20474,8 @@ Number of users who have run a Dependency Scanning scan Group: `group::composition analysis` +Data Category: `Optional` + Status: `data_available` Tiers: `ultimate` @@ -20520,6 +20530,8 @@ Number of users who have run a SAST scan Group: `group::static analysis` +Data Category: `Optional` + Status: `data_available` Tiers: `ultimate` @@ -20546,6 +20558,8 @@ Number of users who have run a Secret Detection scan Group: `group::static analysis` +Data Category: `Optional` + Status: `data_available` Tiers: `ultimate` diff --git a/lib/gitlab/ci/status/core.rb b/lib/gitlab/ci/status/core.rb index e7ed2081f6a..f60f5243666 100644 --- a/lib/gitlab/ci/status/core.rb +++ b/lib/gitlab/ci/status/core.rb @@ -18,6 +18,10 @@ module Gitlab @user = user end + def id + "#{group}-#{subject.id}" + end + def icon raise NotImplementedError end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index eee9af5f627..988c511d2b3 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -14359,6 +14359,9 @@ msgstr "" msgid "Frequency" msgstr "" +msgid "Frequently searched" +msgstr "" + msgid "Friday" msgstr "" diff --git a/package.json b/package.json index f8e76cd72e2..3238a8b1f4b 100644 --- a/package.json +++ b/package.json @@ -65,32 +65,32 @@ "@rails/ujs": "6.1.3-2", "@sentry/browser": "5.26.0", "@sourcegraph/code-host-integration": "0.0.58", - "@tiptap/core": "^2.0.0-beta.75", - "@tiptap/extension-blockquote": "^2.0.0-beta.13", - "@tiptap/extension-bold": "^2.0.0-beta.13", - "@tiptap/extension-bullet-list": "^2.0.0-beta.13", - "@tiptap/extension-code": "^2.0.0-beta.13", - "@tiptap/extension-code-block-lowlight": "2.0.0-beta.25", + "@tiptap/core": "^2.0.0-beta.86", + "@tiptap/extension-blockquote": "^2.0.0-beta.14", + "@tiptap/extension-bold": "^2.0.0-beta.14", + "@tiptap/extension-bullet-list": "^2.0.0-beta.14", + "@tiptap/extension-code": "^2.0.0-beta.14", + "@tiptap/extension-code-block-lowlight": "2.0.0-beta.32", "@tiptap/extension-document": "^2.0.0-beta.12", - "@tiptap/extension-dropcursor": "^2.0.0-beta.14", - "@tiptap/extension-gapcursor": "^2.0.0-beta.17", - "@tiptap/extension-hard-break": "^2.0.0-beta.13", - "@tiptap/extension-heading": "^2.0.0-beta.13", - "@tiptap/extension-history": "^2.0.0-beta.12", - "@tiptap/extension-horizontal-rule": "^2.0.0-beta.16", - "@tiptap/extension-image": "^2.0.0-beta.13", - "@tiptap/extension-italic": "^2.0.0-beta.13", - "@tiptap/extension-link": "^2.0.0-beta.17", + "@tiptap/extension-dropcursor": "^2.0.0-beta.17", + "@tiptap/extension-gapcursor": "^2.0.0-beta.18", + "@tiptap/extension-hard-break": "^2.0.0-beta.14", + "@tiptap/extension-heading": "^2.0.0-beta.14", + "@tiptap/extension-history": "^2.0.0-beta.14", + "@tiptap/extension-horizontal-rule": "^2.0.0-beta.17", + "@tiptap/extension-image": "^2.0.0-beta.14", + "@tiptap/extension-italic": "^2.0.0-beta.14", + "@tiptap/extension-link": "^2.0.0-beta.18", "@tiptap/extension-list-item": "^2.0.0-beta.13", - "@tiptap/extension-ordered-list": "^2.0.0-beta.13", - "@tiptap/extension-paragraph": "^2.0.0-beta.14", - "@tiptap/extension-strike": "^2.0.0-beta.15", - "@tiptap/extension-table": "^2.0.0-beta.23", + "@tiptap/extension-ordered-list": "^2.0.0-beta.14", + "@tiptap/extension-paragraph": "^2.0.0-beta.15", + "@tiptap/extension-strike": "^2.0.0-beta.16", + "@tiptap/extension-table": "^2.0.0-beta.25", "@tiptap/extension-table-cell": "^2.0.0-beta.13", "@tiptap/extension-table-header": "^2.0.0-beta.15", "@tiptap/extension-table-row": "^2.0.0-beta.13", "@tiptap/extension-text": "^2.0.0-beta.12", - "@tiptap/vue-2": "^2.0.0-beta.34", + "@tiptap/vue-2": "^2.0.0-beta.39", "@toast-ui/editor": "^2.5.2", "@toast-ui/vue-editor": "^2.5.2", "apollo-cache-inmemory": "^1.6.6", diff --git a/spec/fast_spec_helper.rb b/spec/fast_spec_helper.rb index 597f2aa4362..cd20019115d 100644 --- a/spec/fast_spec_helper.rb +++ b/spec/fast_spec_helper.rb @@ -20,6 +20,7 @@ require 'active_support/all' ActiveSupport::Dependencies.autoload_paths << 'lib' ActiveSupport::Dependencies.autoload_paths << 'ee/lib' +ActiveSupport::Dependencies.autoload_paths << 'jh/lib' ActiveSupport::XmlMini.backend = 'Nokogiri' diff --git a/spec/frontend/search/store/getters_spec.js b/spec/frontend/search/store/getters_spec.js new file mode 100644 index 00000000000..081e6a986eb --- /dev/null +++ b/spec/frontend/search/store/getters_spec.js @@ -0,0 +1,32 @@ +import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from '~/search/store/constants'; +import * as getters from '~/search/store/getters'; +import createState from '~/search/store/state'; +import { MOCK_QUERY, MOCK_GROUPS, MOCK_PROJECTS } from '../mock_data'; + +describe('Global Search Store Getters', () => { + let state; + + beforeEach(() => { + state = createState({ query: MOCK_QUERY }); + }); + + describe('frequentGroups', () => { + beforeEach(() => { + state.frequentItems[GROUPS_LOCAL_STORAGE_KEY] = MOCK_GROUPS; + }); + + it('returns the correct data', () => { + expect(getters.frequentGroups(state)).toStrictEqual(MOCK_GROUPS); + }); + }); + + describe('frequentProjects', () => { + beforeEach(() => { + state.frequentItems[PROJECTS_LOCAL_STORAGE_KEY] = MOCK_PROJECTS; + }); + + it('returns the correct data', () => { + expect(getters.frequentProjects(state)).toStrictEqual(MOCK_PROJECTS); + }); + }); +}); diff --git a/spec/frontend/search/store/utils_spec.js b/spec/frontend/search/store/utils_spec.js index dbacde1b1a5..5055fa2cc3d 100644 --- a/spec/frontend/search/store/utils_spec.js +++ b/spec/frontend/search/store/utils_spec.js @@ -9,6 +9,9 @@ import { STALE_STORED_DATA, } from '../mock_data'; +const PREV_TIME = new Date().getTime() - 1; +const CURRENT_TIME = new Date().getTime(); + useLocalStorageSpy(); jest.mock('~/lib/utils/accessor', () => ({ isLocalStorageAccessSafe: jest.fn().mockReturnValue(true), @@ -52,28 +55,32 @@ describe('Global Search Store Utils', () => { describe('with existing data', () => { describe(`when frequency is less than ${MAX_FREQUENCY}`, () => { beforeEach(() => { - frequentItems[MOCK_LS_KEY] = [{ ...MOCK_GROUPS[0], frequency: 1 }]; + frequentItems[MOCK_LS_KEY] = [{ ...MOCK_GROUPS[0], frequency: 1, lastUsed: PREV_TIME }]; setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); }); - it('adds 1 to the frequency and calls localStorage.setItem', () => { + it('adds 1 to the frequency, tracks lastUsed, and calls localStorage.setItem', () => { expect(localStorage.setItem).toHaveBeenCalledWith( MOCK_LS_KEY, - JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 2 }]), + JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 2, lastUsed: CURRENT_TIME }]), ); }); }); describe(`when frequency is equal to ${MAX_FREQUENCY}`, () => { beforeEach(() => { - frequentItems[MOCK_LS_KEY] = [{ ...MOCK_GROUPS[0], frequency: MAX_FREQUENCY }]; + frequentItems[MOCK_LS_KEY] = [ + { ...MOCK_GROUPS[0], frequency: MAX_FREQUENCY, lastUsed: PREV_TIME }, + ]; setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); }); - it(`does not further increase frequency past ${MAX_FREQUENCY} and calls localStorage.setItem`, () => { + it(`does not further increase frequency past ${MAX_FREQUENCY}, tracks lastUsed, and calls localStorage.setItem`, () => { expect(localStorage.setItem).toHaveBeenCalledWith( MOCK_LS_KEY, - JSON.stringify([{ ...MOCK_GROUPS[0], frequency: MAX_FREQUENCY }]), + JSON.stringify([ + { ...MOCK_GROUPS[0], frequency: MAX_FREQUENCY, lastUsed: CURRENT_TIME }, + ]), ); }); }); @@ -85,10 +92,10 @@ describe('Global Search Store Utils', () => { setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); }); - it('adds a new entry with frequency 1 and calls localStorage.setItem', () => { + it('adds a new entry with frequency 1, tracks lastUsed, and calls localStorage.setItem', () => { expect(localStorage.setItem).toHaveBeenCalledWith( MOCK_LS_KEY, - JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 1 }]), + JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 1, lastUsed: CURRENT_TIME }]), ); }); }); @@ -96,18 +103,20 @@ describe('Global Search Store Utils', () => { describe('with multiple entries', () => { beforeEach(() => { frequentItems[MOCK_LS_KEY] = [ - { ...MOCK_GROUPS[0], frequency: 1 }, - { ...MOCK_GROUPS[1], frequency: 1 }, + { id: 1, frequency: 2, lastUsed: PREV_TIME }, + { id: 2, frequency: 1, lastUsed: PREV_TIME }, + { id: 3, frequency: 1, lastUsed: PREV_TIME }, ]; - setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[1]); + setFrequentItemToLS(MOCK_LS_KEY, frequentItems, { id: 3 }); }); - it('sorts the array by most frequent', () => { + it('sorts the array by most frequent and lastUsed', () => { expect(localStorage.setItem).toHaveBeenCalledWith( MOCK_LS_KEY, JSON.stringify([ - { ...MOCK_GROUPS[1], frequency: 2 }, - { ...MOCK_GROUPS[0], frequency: 1 }, + { id: 3, frequency: 2, lastUsed: CURRENT_TIME }, + { id: 1, frequency: 2, lastUsed: PREV_TIME }, + { id: 2, frequency: 1, lastUsed: PREV_TIME }, ]), ); }); @@ -116,24 +125,24 @@ describe('Global Search Store Utils', () => { describe('with max entries', () => { beforeEach(() => { frequentItems[MOCK_LS_KEY] = [ - { id: 1, frequency: 5 }, - { id: 2, frequency: 4 }, - { id: 3, frequency: 3 }, - { id: 4, frequency: 2 }, - { id: 5, frequency: 1 }, + { id: 1, frequency: 5, lastUsed: PREV_TIME }, + { id: 2, frequency: 4, lastUsed: PREV_TIME }, + { id: 3, frequency: 3, lastUsed: PREV_TIME }, + { id: 4, frequency: 2, lastUsed: PREV_TIME }, + { id: 5, frequency: 1, lastUsed: PREV_TIME }, ]; setFrequentItemToLS(MOCK_LS_KEY, frequentItems, { id: 6 }); }); - it('removes the least frequent', () => { + it('removes the last item in the array', () => { expect(localStorage.setItem).toHaveBeenCalledWith( MOCK_LS_KEY, JSON.stringify([ - { id: 1, frequency: 5 }, - { id: 2, frequency: 4 }, - { id: 3, frequency: 3 }, - { id: 4, frequency: 2 }, - { id: 6, frequency: 1 }, + { id: 1, frequency: 5, lastUsed: PREV_TIME }, + { id: 2, frequency: 4, lastUsed: PREV_TIME }, + { id: 3, frequency: 3, lastUsed: PREV_TIME }, + { id: 4, frequency: 2, lastUsed: PREV_TIME }, + { id: 6, frequency: 1, lastUsed: CURRENT_TIME }, ]), ); }); @@ -160,7 +169,7 @@ describe('Global Search Store Utils', () => { it('parses out extra data for LS', () => { expect(localStorage.setItem).toHaveBeenCalledWith( MOCK_LS_KEY, - JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 1 }]), + JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 1, lastUsed: CURRENT_TIME }]), ); }); }); diff --git a/spec/frontend/search/topbar/components/group_filter_spec.js b/spec/frontend/search/topbar/components/group_filter_spec.js index 21f18bb6864..fbd7ad6bb57 100644 --- a/spec/frontend/search/topbar/components/group_filter_spec.js +++ b/spec/frontend/search/topbar/components/group_filter_spec.js @@ -35,6 +35,9 @@ describe('GroupFilter', () => { ...initialState, }, actions: actionSpies, + getters: { + frequentGroups: () => [], + }, }); wrapper = shallowMount(GroupFilter, { diff --git a/spec/frontend/search/topbar/components/project_filter_spec.js b/spec/frontend/search/topbar/components/project_filter_spec.js index ecc9273395f..63b0f882ca4 100644 --- a/spec/frontend/search/topbar/components/project_filter_spec.js +++ b/spec/frontend/search/topbar/components/project_filter_spec.js @@ -35,6 +35,9 @@ describe('ProjectFilter', () => { ...initialState, }, actions: actionSpies, + getters: { + frequentProjects: () => [], + }, }); wrapper = shallowMount(ProjectFilter, { diff --git a/spec/frontend/search/topbar/components/searchable_dropdown_spec.js b/spec/frontend/search/topbar/components/searchable_dropdown_spec.js index 2ad46eeeb1e..b21cf5c6b79 100644 --- a/spec/frontend/search/topbar/components/searchable_dropdown_spec.js +++ b/spec/frontend/search/topbar/components/searchable_dropdown_spec.js @@ -2,9 +2,9 @@ import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlSkeletonLoader } from import { shallowMount, mount } from '@vue/test-utils'; import Vue from 'vue'; import Vuex from 'vuex'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; import { MOCK_GROUPS, MOCK_GROUP, MOCK_QUERY } from 'jest/search/mock_data'; import SearchableDropdown from '~/search/topbar/components/searchable_dropdown.vue'; -import SearchableDropdownItem from '~/search/topbar/components/searchable_dropdown_item.vue'; import { ANY_OPTION, GROUP_DATA } from '~/search/topbar/constants'; Vue.use(Vuex); @@ -29,13 +29,15 @@ describe('Global Search Searchable Dropdown', () => { }, }); - wrapper = mountFn(SearchableDropdown, { - store, - propsData: { - ...defaultProps, - ...props, - }, - }); + wrapper = extendedWrapper( + mountFn(SearchableDropdown, { + store, + propsData: { + ...defaultProps, + ...props, + }, + }), + ); }; afterEach(() => { @@ -45,10 +47,11 @@ describe('Global Search Searchable Dropdown', () => { const findGlDropdown = () => wrapper.findComponent(GlDropdown); const findGlDropdownSearch = () => findGlDropdown().findComponent(GlSearchBoxByType); const findDropdownText = () => findGlDropdown().find('.dropdown-toggle-text'); - const findSearchableDropdownItems = () => - findGlDropdown().findAllComponents(SearchableDropdownItem); + const findSearchableDropdownItems = () => wrapper.findAllByTestId('searchable-items'); + const findFrequentDropdownItems = () => wrapper.findAllByTestId('frequent-items'); const findAnyDropdownItem = () => findGlDropdown().findComponent(GlDropdownItem); - const findFirstGroupDropdownItem = () => findSearchableDropdownItems().at(0); + const findFirstSearchableDropdownItem = () => findSearchableDropdownItems().at(0); + const findFirstFrequentDropdownItem = () => findFrequentDropdownItems().at(0); const findLoader = () => wrapper.findComponent(GlSkeletonLoader); describe('template', () => { @@ -82,7 +85,7 @@ describe('Global Search Searchable Dropdown', () => { }); }); - describe('findDropdownItems', () => { + describe('Searchable Dropdown Items', () => { describe('when loading is false', () => { beforeEach(() => { createComponent({}, { items: MOCK_GROUPS }); @@ -96,7 +99,7 @@ describe('Global Search Searchable Dropdown', () => { expect(findAnyDropdownItem().exists()).toBe(true); }); - it('renders SearchableDropdownItem for each item', () => { + it('renders searchable dropdown item for each item', () => { expect(findSearchableDropdownItems()).toHaveLength(MOCK_GROUPS.length); }); }); @@ -114,12 +117,31 @@ describe('Global Search Searchable Dropdown', () => { expect(findAnyDropdownItem().exists()).toBe(true); }); - it('does not render SearchableDropdownItem', () => { + it('does not render searchable dropdown items', () => { expect(findSearchableDropdownItems()).toHaveLength(0); }); }); }); + describe.each` + searchText | frequentItems | length + ${''} | ${[]} | ${0} + ${''} | ${MOCK_GROUPS} | ${MOCK_GROUPS.length} + ${'test'} | ${[]} | ${0} + ${'test'} | ${MOCK_GROUPS} | ${0} + `('Frequent Dropdown Items', ({ searchText, frequentItems, length }) => { + describe(`when search is ${searchText} and frequentItems length is ${frequentItems.length}`, () => { + beforeEach(() => { + createComponent({}, { frequentItems }); + wrapper.setData({ searchText }); + }); + + it(`should${length ? '' : ' not'} render frequent dropdown items`, () => { + expect(findFrequentDropdownItems()).toHaveLength(length); + }); + }); + }); + describe('Dropdown Text', () => { describe('when selectedItem is any', () => { beforeEach(() => { @@ -145,7 +167,7 @@ describe('Global Search Searchable Dropdown', () => { describe('actions', () => { beforeEach(() => { - createComponent({}, { items: MOCK_GROUPS }); + createComponent({}, { items: MOCK_GROUPS, frequentItems: MOCK_GROUPS }); }); it('clicking "Any" dropdown item $emits @change with ANY_OPTION', () => { @@ -154,8 +176,14 @@ describe('Global Search Searchable Dropdown', () => { expect(wrapper.emitted('change')[0]).toEqual([ANY_OPTION]); }); - it('on SearchableDropdownItem @change, the wrapper $emits change with the item', () => { - findFirstGroupDropdownItem().vm.$emit('change', MOCK_GROUPS[0]); + it('on searchable item @change, the wrapper $emits change with the item', () => { + findFirstSearchableDropdownItem().vm.$emit('change', MOCK_GROUPS[0]); + + expect(wrapper.emitted('change')[0]).toEqual([MOCK_GROUPS[0]]); + }); + + it('on frequent item @change, the wrapper $emits change with the item', () => { + findFirstFrequentDropdownItem().vm.$emit('change', MOCK_GROUPS[0]); expect(wrapper.emitted('change')[0]).toEqual([MOCK_GROUPS[0]]); }); diff --git a/spec/graphql/types/ci/detailed_status_type_spec.rb b/spec/graphql/types/ci/detailed_status_type_spec.rb index 9fa3280657a..5ed79b73a47 100644 --- a/spec/graphql/types/ci/detailed_status_type_spec.rb +++ b/spec/graphql/types/ci/detailed_status_type_spec.rb @@ -8,14 +8,26 @@ RSpec.describe Types::Ci::DetailedStatusType do specify { expect(described_class.graphql_name).to eq('DetailedStatus') } it 'has all fields' do - expect(described_class).to have_graphql_fields(:group, :icon, :favicon, + expect(described_class).to have_graphql_fields(:id, :group, :icon, :favicon, :details_path, :has_details, :label, :text, :tooltip, :action) end + let_it_be(:stage) { create(:ci_stage_entity, status: :skipped) } + + describe 'id field' do + it 'correctly renders the field' do + parent_object = double(:parent_object, object: stage) + parent = double(:parent, object: parent_object) + status = stage.detailed_status(stage.pipeline.user) + expected_id = "#{status.id}-#{stage.id}" + + expect(resolve_field('id', status, extras: { parent: parent })).to eq(expected_id) + end + end + describe 'action field' do it 'correctly renders the field' do - stage = create(:ci_stage_entity, status: :skipped) status = stage.detailed_status(stage.pipeline.user) expected_status = { diff --git a/spec/graphql/types/ci/group_type_spec.rb b/spec/graphql/types/ci/group_type_spec.rb index d7ce5602612..f563b31342f 100644 --- a/spec/graphql/types/ci/group_type_spec.rb +++ b/spec/graphql/types/ci/group_type_spec.rb @@ -7,6 +7,7 @@ RSpec.describe Types::Ci::GroupType do it 'exposes the expected fields' do expected_fields = %i[ + id name size jobs diff --git a/spec/graphql/types/ci/stage_type_spec.rb b/spec/graphql/types/ci/stage_type_spec.rb index b5752785923..48c569eca16 100644 --- a/spec/graphql/types/ci/stage_type_spec.rb +++ b/spec/graphql/types/ci/stage_type_spec.rb @@ -7,6 +7,7 @@ RSpec.describe Types::Ci::StageType do it 'exposes the expected fields' do expected_fields = %i[ + id name groups detailedStatus diff --git a/spec/graphql/types/ci/status_action_type_spec.rb b/spec/graphql/types/ci/status_action_type_spec.rb index 8a99068e44f..ab7dee3dd11 100644 --- a/spec/graphql/types/ci/status_action_type_spec.rb +++ b/spec/graphql/types/ci/status_action_type_spec.rb @@ -3,10 +3,13 @@ require 'spec_helper' RSpec.describe Types::Ci::StatusActionType do + include GraphqlHelpers + specify { expect(described_class.graphql_name).to eq('StatusAction') } it 'exposes the expected fields' do expected_fields = %i[ + id buttonTitle icon path @@ -16,4 +19,21 @@ RSpec.describe Types::Ci::StatusActionType do expect(described_class).to have_graphql_fields(*expected_fields) end + + describe 'id field' do + it 'correctly renders the field' do + stage = build(:ci_stage_entity, status: :skipped) + status = stage.detailed_status(stage.pipeline.user) + + grandparent_object = double(:grandparent_object, object: stage) + parent_object = double(:parent_object, object: status) + + grandparent = double(:parent, object: grandparent_object) + parent = double(:parent, object: parent_object, parent: grandparent) + + expected_id = "#{stage.class.name}-#{status.id}" + + expect(resolve_field('id', status, extras: { parent: parent })).to eq(expected_id) + end + end end diff --git a/spec/requests/api/graphql/ci/jobs_spec.rb b/spec/requests/api/graphql/ci/jobs_spec.rb index 3fb89d6e815..10f05efa1b8 100644 --- a/spec/requests/api/graphql/ci/jobs_spec.rb +++ b/spec/requests/api/graphql/ci/jobs_spec.rb @@ -38,9 +38,15 @@ RSpec.describe 'Query.project.pipeline' do name groups { nodes { + detailedStatus { + id + } name jobs { nodes { + detailedStatus { + id + } name needs { nodes { #{all_graphql_fields_for('CiBuildNeed')} } diff --git a/spec/services/namespace_settings/update_service_spec.rb b/spec/services/namespace_settings/update_service_spec.rb index d94e65a903e..e0f32cb3821 100644 --- a/spec/services/namespace_settings/update_service_spec.rb +++ b/spec/services/namespace_settings/update_service_spec.rb @@ -76,50 +76,61 @@ RSpec.describe NamespaceSettings::UpdateService do end end - context "updating :prevent_sharing_groups_outside_hierarchy" do - let(:settings) { { prevent_sharing_groups_outside_hierarchy: true } } + describe 'validating settings param for root group' do + using RSpec::Parameterized::TableSyntax - context 'when user is a group owner' do - before do - group.add_owner(user) - end - - it 'changes settings' do - expect { service.execute } - .to change { group.namespace_settings.prevent_sharing_groups_outside_hierarchy } - .from(false).to(true) - end + where(:setting_key, :setting_changes_from, :setting_changes_to) do + :prevent_sharing_groups_outside_hierarchy | false | true + :new_user_signups_cap | nil | 100 end - context 'when user is not a group owner' do - before do - group.add_maintainer(user) + with_them do + let(:settings) do + { setting_key => setting_changes_to } end - it 'does not change settings' do - expect { service.execute }.not_to change { group.namespace_settings.prevent_sharing_groups_outside_hierarchy } - end + context 'when user is not a group owner' do + before do + group.add_maintainer(user) + end - it 'returns the group owner error' do - service.execute + it 'does not change settings' do + expect { service.execute }.not_to change { group.namespace_settings.public_send(setting_key) } + end + + it 'returns the group owner error' do + service.execute - expect(group.namespace_settings.errors.messages[:prevent_sharing_groups_outside_hierarchy]).to include('can only be changed by a group admin.') + expect(group.namespace_settings.errors.messages[setting_key]).to include('can only be changed by a group admin.') + end end - end - context 'with a subgroup' do - let(:subgroup) { create(:group, parent: group) } + context 'with a subgroup' do + let(:subgroup) { create(:group, parent: group) } - before do - group.add_owner(user) - end + before do + group.add_owner(user) + end + + it 'does not change settings' do + service = described_class.new(user, subgroup, settings) - it 'does not change settings' do - service = described_class.new(user, subgroup, settings) + expect { service.execute }.not_to change { group.namespace_settings.public_send(setting_key) } + + expect(subgroup.namespace_settings.errors.messages[setting_key]).to include('only available on top-level groups.') + end + end - expect { service.execute }.not_to change { group.namespace_settings.prevent_sharing_groups_outside_hierarchy } + context 'when user is a group owner' do + before do + group.add_owner(user) + end - expect(subgroup.namespace_settings.errors.messages[:prevent_sharing_groups_outside_hierarchy]).to include('only available on top-level groups.') + it 'changes settings' do + expect { service.execute } + .to change { group.namespace_settings.public_send(setting_key) } + .from(setting_changes_from).to(setting_changes_to) + end end end end diff --git a/spec/support/shared_examples/services/snippets_shared_examples.rb b/spec/support/shared_examples/services/snippets_shared_examples.rb index 56b2ce3353d..5a44f739b27 100644 --- a/spec/support/shared_examples/services/snippets_shared_examples.rb +++ b/spec/support/shared_examples/services/snippets_shared_examples.rb @@ -22,18 +22,6 @@ RSpec.shared_examples 'checking spam' do subject end - - context 'when snippet_spam flag is disabled' do - before do - stub_feature_flags(snippet_spam: false) - end - - it 'request parameter is not passed to the service' do - expect(Spam::SpamActionService).not_to receive(:new) - - subject - end - end end shared_examples 'invalid params error response' do diff --git a/yarn.lock b/yarn.lock index 8840bb4670b..93d06635536 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1305,151 +1305,151 @@ dom-accessibility-api "^0.5.1" pretty-format "^26.4.2" -"@tiptap/core@^2.0.0-beta.75": - version "2.0.0-beta.75" - resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.75.tgz#8295dfa7ca4b22de61e9c68a102763343b26e03a" - integrity sha512-o5+xUIXnrEv6I2VrCTDI4d75tFW2NGXed+cuhYZw4+iikamL7SkrqgW/+EvIFPDggGo1b3D7xGd1CrXz9eEBhA== +"@tiptap/core@^2.0.0-beta.86": + version "2.0.0-beta.86" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.86.tgz#11b575aee4ad2f30f73114c786da5cd13dde30e0" + integrity sha512-EeR6euRTJV9LhUog1PuiN1oLYRsz0SCEU5cQnGElzRzbd8dMnmFVc9cs81fbfjR8R1bfiarOJExrU2+OPHKXDw== dependencies: "@types/prosemirror-commands" "^1.0.4" "@types/prosemirror-inputrules" "^1.0.4" "@types/prosemirror-keymap" "^1.0.4" - "@types/prosemirror-model" "^1.13.0" + "@types/prosemirror-model" "^1.13.1" "@types/prosemirror-schema-list" "^1.0.3" - "@types/prosemirror-state" "^1.2.6" - "@types/prosemirror-transform" "^1.1.3" - "@types/prosemirror-view" "^1.17.1" - prosemirror-commands "^1.1.8" + "@types/prosemirror-state" "^1.2.7" + "@types/prosemirror-transform" "^1.1.4" + "@types/prosemirror-view" "^1.17.2" + prosemirror-commands "^1.1.10" prosemirror-inputrules "^1.1.3" prosemirror-keymap "^1.1.3" - prosemirror-model "^1.14.1" - prosemirror-schema-list "^1.1.4" + prosemirror-model "^1.14.2" + prosemirror-schema-list "^1.1.5" prosemirror-state "^1.3.4" prosemirror-transform "^1.3.2" - prosemirror-view "^1.18.7" + prosemirror-view "^1.18.8" -"@tiptap/extension-blockquote@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.13.tgz#72a26dd54e5edb9abc4488ad7c1f0a43d4089bd5" - integrity sha512-7Pis9bXMjyyXVIZS9zIytfRohofEhbTS8tQWCPrBNfb3ceSMQhNZf4jBBXQsngQntkO+0Di5LI1hFpa+XF+RYA== +"@tiptap/extension-blockquote@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.14.tgz#f49872981aecdd21341c4d5db32ab68cba945756" + integrity sha512-1U/mJA1Yncl1Uvdv66oRhWrT7RZC/GdrZrvzU4EHdpRRwW4s71jvDVzqGX2tYwMO70TnwmkqMEWm0Csb1pOhMg== dependencies: prosemirror-inputrules "^1.1.3" -"@tiptap/extension-bold@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.13.tgz#d6b8f3797a6f7932ae38b9d761cc1effa886b715" - integrity sha512-hMA6GItX/cWN1K9TBI1LeEPo8bFhX9JrE1flr6dxGJ9q58XVbzb2/ojZzcRFVdUp7oxNyQaFe6yP1JhTVcIrog== +"@tiptap/extension-bold@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.14.tgz#6bf9ea70f7e24e6d674c7780471fcb6a7a4b91f4" + integrity sha512-WhKB3GfXhIDISQE2jYIVYe0aVQCvQRJQZCRFeac7kMxHE2veHWpjqjbp7jSbvTQ7YVZxPZFvezVs+3HWz1K0xg== -"@tiptap/extension-bubble-menu@^2.0.0-beta.20": - version "2.0.0-beta.20" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.20.tgz#248c70910bf232ed5fb9eb3a7c084bc592d2341d" - integrity sha512-eomoCnZBGuPBWvacMHtaLJ2EqTrA0OZoLEwMKiPy4Y3eD2/Us9nLVFWq2DqaB7nXxG0BCN1ZnaKTtpoJtdEgSQ== +"@tiptap/extension-bubble-menu@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.24.tgz#e6db5bc0386ccdbd483e57296b22eb6dd55914ba" + integrity sha512-u1btwasgaidUr9JLQwFQwf9oeXUYPv9TyBzUn/soj9F8qKrWxQxTi/EQUsudvjumzsQOX+tZQIj/YtO5EzR+hA== dependencies: prosemirror-state "^1.3.4" - prosemirror-view "^1.18.7" + prosemirror-view "^1.18.8" tippy.js "^6.3.1" -"@tiptap/extension-bullet-list@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.13.tgz#8b2c4ec8decc5562ae9bb5d97b0a99e0b27f9794" - integrity sha512-6W0T6U/Gm3ypLJDTe79K/0mFc88svJrP6TFjj3tcXwpygnwcCpBmpJv4DG656eGmB6rGGVPe1K/zoT1j6HB8+A== +"@tiptap/extension-bullet-list@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.14.tgz#29b9bfa2e908cdb01943242f75daf82115f5afd1" + integrity sha512-PcyaTNk/aGaXVC98mPAq4TRjXG6dDNb0CAeBqFIo8hLywwwKTaLfLQJNHtm605MSoEo2f8XO6gfQhWgJQQ6qwA== dependencies: prosemirror-inputrules "^1.1.3" -"@tiptap/extension-code-block-lowlight@2.0.0-beta.25": - version "2.0.0-beta.25" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.0.0-beta.25.tgz#eb5f721fa8a4035244b7883e3cfc770f17fae27f" - integrity sha512-wfqbu27/LTtb2W1ExR3pmJoNJosM/Vq7VJeg5FB+Bt6hyBZ6GVRd8ABEnJb4SXeCRBXXs6sJoEkcGyEMgAtcZg== +"@tiptap/extension-code-block-lowlight@2.0.0-beta.32": + version "2.0.0-beta.32" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block-lowlight/-/extension-code-block-lowlight-2.0.0-beta.32.tgz#ef9ff6883f2d669e6be79c69f26749641462e1ea" + integrity sha512-RnKAlE981k7VYIUUZ2jYZVGzZJalzrRw6dCf0rfgPvSY3T+ih9gVjKr+APGTuX3tsSR+s3UHs6YUI9+83pje3A== dependencies: - "@tiptap/extension-code-block" "^2.0.0-beta.15" - "@types/lowlight" "^0.0.2" + "@tiptap/extension-code-block" "^2.0.0-beta.16" + "@types/lowlight" "^0.0.3" lowlight "^1.20.0" - prosemirror-model "^1.14.1" + prosemirror-model "^1.14.2" prosemirror-state "^1.3.4" - prosemirror-view "^1.18.7" + prosemirror-view "^1.18.8" -"@tiptap/extension-code-block@^2.0.0-beta.15": - version "2.0.0-beta.15" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.15.tgz#3fb0f04c38f8276195a1a958cc7d3399b52dc46a" - integrity sha512-iBuK/nnUw37O9mZVnuZu+viSNzLz7SRktjDtFhp6RM3ZVSOYIYjt6pJ05EVJ263QEeXB4Q1Qae8/xJOPPHN9hw== +"@tiptap/extension-code-block@^2.0.0-beta.16": + version "2.0.0-beta.16" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.16.tgz#7788ee1af04eb84fe194261bb1bb835dbe7ad59e" + integrity sha512-FgKuobqybmkVidRsOSatgVYEyHldvGPBu7/nr5z131PHMqTe7Z35c4r2ts5DCZRsOoby17Nn4iLAENqtsmyyJQ== dependencies: prosemirror-inputrules "^1.1.3" -"@tiptap/extension-code@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.13.tgz#fa2d14c61fe213c2c40b196e1b1b7a8862cec987" - integrity sha512-em1rGWZXYlH6DrcIWRTvYefBzig34y7HBeWIB3uRHULd2GpRIowfbl8SRFgeapoKj1kbYjAtVr+wshlNi9/ujw== +"@tiptap/extension-code@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.14.tgz#679a741589d63006140605553be7c6148c000814" + integrity sha512-Z67Ae2BPTAXG8VxHaw2SAS9HjUmfL1fUew5IUdaML8GOSaBYjzIffvN/+0MNdxkBEFxMJu4zm3o/WdWIoUckdQ== "@tiptap/extension-document@^2.0.0-beta.12": version "2.0.0-beta.12" resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.12.tgz#dfbc7e686075a38662a43708903cd2047cf7f4b2" integrity sha512-i5anc2n98Jg1gi6WDLTaS76jLIUe41FHuMHgL4DCIDXv8m2q0qnktfmOvh9AMF7cPzJ2NVAR9xYw0Pxm3qXY4w== -"@tiptap/extension-dropcursor@^2.0.0-beta.14": - version "2.0.0-beta.14" - resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.14.tgz#b5e4137d4be1afe14a8f67d932af5e6d3df7cb56" - integrity sha512-F6sbclgoWPiindx/g1Hxf7jfimne7mrxeCBXvI8xfbcHwTubFhR+nZ+tiIfttcxdM4FNusSsLsDJo7rfE/kiUg== +"@tiptap/extension-dropcursor@^2.0.0-beta.17": + version "2.0.0-beta.17" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.17.tgz#3ca59c264b49a91c1a5b2ce8de3e898903d0a5bc" + integrity sha512-f7hSA4e9xaVi1GAb6JJErVy2QtdpTxjJmtyV8nG7xGvoI0QH1IIiftD88FWGvUGN1CHBg83XpPpmIIFH7oKthw== dependencies: - "@types/prosemirror-dropcursor" "^1.0.1" + "@types/prosemirror-dropcursor" "^1.0.2" prosemirror-dropcursor "^1.3.5" -"@tiptap/extension-floating-menu@^2.0.0-beta.16": - version "2.0.0-beta.16" - resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.16.tgz#109226c060351b83916441cd58d631eff47d6bb2" - integrity sha512-ByiBBZHOhVH2SslWjc/rwo/aQFJpAfMJAELw1Q8CaUqzTCbgQzvuyM+y6dGL/uLuZuvtncLyPYcGhnK87mZb2Q== +"@tiptap/extension-floating-menu@^2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.18.tgz#4d9b7f58c73f6c718a74503c5ff514b06f615e27" + integrity sha512-1fCRGdTxCiRm5DV91GwKYn9yu43oonq6iuRAlgcTZ2ON03MAAG55j+cDA2S3JSwbsA7Vr49ijmXBY/fEdU/fiQ== dependencies: prosemirror-state "^1.3.4" - prosemirror-view "^1.18.7" + prosemirror-view "^1.18.8" tippy.js "^6.3.1" -"@tiptap/extension-gapcursor@^2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.17.tgz#774037fddab50379b21a58cab91bfd988b9b793f" - integrity sha512-ItucjmbjpIfjBkoarkekfZ2BB4nsJuBptZc2xWj36zpC9ehQvH3uVcgyRPM/5To2gvj4uj8MmYyxO8Q6/PszAg== +"@tiptap/extension-gapcursor@^2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.18.tgz#67c2266ec21c90f003e989862b709475f5427fea" + integrity sha512-J75xnNrNWHILZviu5ikHtIKF5WFMmmAgkwyateNwgoMwRpyTrZI5Go2LpZ1VEw4AhEA2OcBEvPBEtxWefrBV5g== dependencies: - "@types/prosemirror-gapcursor" "^1.0.3" + "@types/prosemirror-gapcursor" "^1.0.4" prosemirror-gapcursor "^1.1.5" -"@tiptap/extension-hard-break@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.13.tgz#36b5433e70e8eac121d6d26871ff60527b500442" - integrity sha512-C84BzpP3G+86iPJOyJTlfA7RK2IhLkiosvo3qKzPMCELVc2I8mICbuA7cEbveO0Rpg24AAyeec0Q0GYf+WiItw== +"@tiptap/extension-hard-break@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.14.tgz#dce00c49dc614caac82720b930501a59b38d5584" + integrity sha512-PbGQJGvgYdsEzeHidlodVCaOkcPaib4A7i0MJlXIyzUnBz8Eiv5+Ks2UBG5JgfBB4GGopatZaLfz8VkG3qfGxw== -"@tiptap/extension-heading@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.13.tgz#7d6f4a0e28af47ad1a1e455af01dbd1997a9f948" - integrity sha512-fGuFs6ZG1mBWceSwes4fAWf4d97xKhbdDWaMjo2+2WAdx6y9fX1s64psYJYwQ5KXnKHaCU+JBPged9igDcXVsg== +"@tiptap/extension-heading@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.14.tgz#63df6d7282afd3c2db2253af2e538c3bf2800751" + integrity sha512-ezJRM5ikZK5bmzYCsvq6xCw1KlellSwHcmAVJsupHk3aPD3UF2IEXnKQYbtDjGN62sB2KwnNy6gKFJ5v48gpxA== dependencies: prosemirror-inputrules "^1.1.3" -"@tiptap/extension-history@^2.0.0-beta.12": - version "2.0.0-beta.12" - resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.12.tgz#a25607aab594998d6b46576724d56701a2833689" - integrity sha512-8H7fQ1dHMAnNxRar6WOdDJ9+7/S7DX8Mg2hJbahUqN3UfTKZxqorXJB+k/QSeicozz5xWHp+b/RxqiHA3nMu5g== +"@tiptap/extension-history@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.14.tgz#7990a592a521ca4147e733eed78fcb738ed6ba95" + integrity sha512-Uf9FKgp2/+Z1FD5R55huDvkBorZZMeOU3dfo8K4YL/lnSc4Yyk4huQu+6kK9XDrisIK68NlfYY1GFts49KbZmA== dependencies: - "@types/prosemirror-history" "^1.0.2" + "@types/prosemirror-history" "^1.0.3" prosemirror-history "^1.1.3" -"@tiptap/extension-horizontal-rule@^2.0.0-beta.16": - version "2.0.0-beta.16" - resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.16.tgz#7f8a3e14de2fc8bbb52816a697450a61d8797689" - integrity sha512-Yh8AM5ArI/FfzdA0TcvIZEpMkRo0Rd9lLyEXYfWV0Be6qkPApa/QDzEreQMf4JIKDE8z0R0yX0XRxh/N5iUmew== +"@tiptap/extension-horizontal-rule@^2.0.0-beta.17": + version "2.0.0-beta.17" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.17.tgz#25c15bfab5794a3f1bcf6f4df03bef56ddac80aa" + integrity sha512-JDjwRSEWFTgdx0ob4zKjfzKcRxkiQTyPEGEZ2uIcTeXTPD0B0j2ysuWIWnqgwtpFdYfv1wOCU59kNLQx+a5JmA== dependencies: prosemirror-state "^1.3.4" -"@tiptap/extension-image@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.13.tgz#58a2e66533e2ef63e67aeb7980fe642b75fa17a0" - integrity sha512-3uapkYVV8xp62+qYWteKYYIzUgP8AK8HzWFnnN/QMO5yZg7Me3u+r+1hJ7FrCQeT+4IyxBlni7jHDEDftmVR4w== +"@tiptap/extension-image@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.14.tgz#31eae69cce3d81af81a1c0fbd253beca3c253429" + integrity sha512-OguktQVJ8D0wFm8jrnct16Pu+T5J0N+rzMNk5kguJJCMiFjhQZ4USZw5jHU6BIAKwulupXmZ/PUBIYCx02LhIA== -"@tiptap/extension-italic@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.13.tgz#8b0810e41dc5c3bfb0640d638b0b40464cd81fea" - integrity sha512-IUvXnR9bnOiyE+k0Oa2ugCW5p5Nibvstr6W6g/C6RA36AbV9K/zr4XzQgClfZo96pM8Ay5Ia+jCYeYGOD6Mdaw== +"@tiptap/extension-italic@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.14.tgz#5b56a806ef6507dc2001eaeeeb234ee0b25d8544" + integrity sha512-kDdHVHfHuQe3s0A+xrJm0OTE3MrCRWDFHiJ+rC5JnY3/b8GEzovOD6cslz6CeVSZAUDERmHKVPF+ioAct7HXtw== -"@tiptap/extension-link@^2.0.0-beta.17": - version "2.0.0-beta.17" - resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.17.tgz#5a3c28762cf332bb4de0fb13ce6973b11496697a" - integrity sha512-/xvUEMRh3E651kXidTEpmlSGqdVXjtnA0KuVModmCmxMchDCpO7kTIpjzS60joCl2Nx2WgICFoJ4SO6dSTMf/w== +"@tiptap/extension-link@^2.0.0-beta.18": + version "2.0.0-beta.18" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.18.tgz#792c671daf3db79873b8425e68da43dd19af230b" + integrity sha512-i87vd82hsBCw6ROR8qjffWMsm7pd/4kwqhytq3l8zrArWLZXxC6JwknYjVNcwiWs2JFr+xJNAnzNgr0oGXguTg== dependencies: prosemirror-state "^1.3.4" @@ -1458,22 +1458,22 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.13.tgz#49f32d70a554897ffa3b37b492ebaf5953f8a975" integrity sha512-5nvrCvcV35J6WjLd8xQCQWnj2HIDsfTalr0D57jMwym3ZCIEvLwf23DQQ1nNsOHhopmS/Emixh+RQpXUZjH8lQ== -"@tiptap/extension-ordered-list@^2.0.0-beta.13": - version "2.0.0-beta.13" - resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.13.tgz#4df2264e1405f73848cd2fedcea95f3064911cd7" - integrity sha512-BX4cGRmiNJ/n6VHao7BALJOMAofwcp1zrleWI5d0/7YqkUKP7ExIMiRFVrgjrg4qxq9cVNXa00GLs++FeuySQA== +"@tiptap/extension-ordered-list@^2.0.0-beta.14": + version "2.0.0-beta.14" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.14.tgz#54487f8b9246226586d0190d07a449a97536436a" + integrity sha512-7Tq8jotj7WSUIRlMhNWCv6u99Yu+lyuI8SLx7hRZbmUiGShCQX1J5YI+dti4qlrlhOjjqs1kV95Dgg0JaBtNQw== dependencies: prosemirror-inputrules "^1.1.3" -"@tiptap/extension-paragraph@^2.0.0-beta.14": - version "2.0.0-beta.14" - resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.14.tgz#6b8c64166f3b581a1f8e1ae415b895e5bd2952d1" - integrity sha512-IFc2/WMgmpPTRS/h++5vNCiSyT4yTj/NGG9L+x35aPCDQutTYW2V2i1Lwe2lcxpPVF4ofDX50skjdIiWZoGEqA== - -"@tiptap/extension-strike@^2.0.0-beta.15": +"@tiptap/extension-paragraph@^2.0.0-beta.15": version "2.0.0-beta.15" - resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.15.tgz#c274ae85b1067f80d45a1cb30d0cad24733c9be7" - integrity sha512-8R6L4jVxeGabItZ2a4B8lvcy60yhD95nRkO4ruH4iBQ5qlyGwShRbvuJQQGT/2j2RY7W793nXZ/Uohcd/5gJCw== + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.15.tgz#89483a2f438d8412287d441c890304985c2ac07f" + integrity sha512-mYGjo85oyLVwgWc8+XZ0cvr5GSHSKvkj5t2t1PyHXDmt6Nhl5cJcHgXDztIUhyh0gbRVFKjwQMeUAZWg6DGxMg== + +"@tiptap/extension-strike@^2.0.0-beta.16": + version "2.0.0-beta.16" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.16.tgz#cccce9713824e05ebde895f84f747b8bbed45f7d" + integrity sha512-SPSCUVzxFLKZzgMXYfeUZE+xy52CJckswo0dZ/8NcUthl3mkDS/TwzokpQ/wsyEsKaJNYt8vh2S9HpadSrLcug== "@tiptap/extension-table-cell@^2.0.0-beta.13": version "2.0.0-beta.13" @@ -1490,27 +1490,27 @@ resolved "https://registry.yarnpkg.com/@tiptap/extension-table-row/-/extension-table-row-2.0.0-beta.13.tgz#3f9a61112afcde750228f4437ae3cd7b82d02f74" integrity sha512-tGE3/ADBaVgpBYXgdx5YkAs7waYLKDRormUXKNnTpR+4qVHKUmXrDUTdJ2urXaANaB95F8R5Lj146h+EYiLxgw== -"@tiptap/extension-table@^2.0.0-beta.23": - version "2.0.0-beta.23" - resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.0.0-beta.23.tgz#12b4b586654874b86f8ceb93b0536e846744a04e" - integrity sha512-o8V7MTCQuf0iXoKpF7q6HWTjCRu1HnpDJoKzyJN6AB1ecVDPNOce72L2EjceRgziYJy0QDBHK1xm/+C4t8h44Q== +"@tiptap/extension-table@^2.0.0-beta.25": + version "2.0.0-beta.25" + resolved "https://registry.yarnpkg.com/@tiptap/extension-table/-/extension-table-2.0.0-beta.25.tgz#57accf19c07e96bd0db868eb791da20bd423af36" + integrity sha512-mVUJL3FKX1vksmrnUcNqRzbAk4kJjKVxAf5RMuUQRcyp8sp3vJinR/C8v5nBrDgurXLB3wF0bD2/FRu7GWEqPA== dependencies: prosemirror-tables "^1.1.1" - prosemirror-view "^1.18.7" + prosemirror-view "^1.18.8" "@tiptap/extension-text@^2.0.0-beta.12": version "2.0.0-beta.12" resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.12.tgz#b857f36dda5e8cedd350f9bad7115e4060f8d9c0" integrity sha512-JEWLYOJKSpmpaI0YTzj30uodpsrSYDGSvy5dT5bYvWovIvLmggKPHl0iKIPDWAM5xfd07CkP2+BFFRblMh96IA== -"@tiptap/vue-2@^2.0.0-beta.34": - version "2.0.0-beta.34" - resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.34.tgz#df9309eb812b50a85315c4623ac222db751fc97a" - integrity sha512-gt45v1GgTWDh/cVcWHW3Nn80pLi/qQMInn1bv/zVUTGZxay5kstLJ5eD7yQ3SfS9oOS3ubRDkdYdhbUKUYH0hw== +"@tiptap/vue-2@^2.0.0-beta.39": + version "2.0.0-beta.39" + resolved "https://registry.yarnpkg.com/@tiptap/vue-2/-/vue-2-2.0.0-beta.39.tgz#f6d75af99b072848381f0c443b50ec09186eb43b" + integrity sha512-O8hCzrAZTbjebcD3XWsbUieudnD7rvDFGmHSRmb0igg//ARO43IWe2xdu2Hlx1MT9b+83YjgDhRyMjHcsKRtzw== dependencies: - "@tiptap/extension-bubble-menu" "^2.0.0-beta.20" - "@tiptap/extension-floating-menu" "^2.0.0-beta.16" - prosemirror-view "^1.18.7" + "@tiptap/extension-bubble-menu" "^2.0.0-beta.24" + "@tiptap/extension-floating-menu" "^2.0.0-beta.18" + prosemirror-view "^1.18.8" "@toast-ui/editor@^2.5.2": version "2.5.2" @@ -1632,10 +1632,10 @@ resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/lowlight@^0.0.2": - version "0.0.2" - resolved "https://registry.yarnpkg.com/@types/lowlight/-/lowlight-0.0.2.tgz#bb517f1486477a8c59dea11be0dfaf96d629d35d" - integrity sha512-37DldsUs2l4rXI2YQgVn+NKVEaaUbBIzJg3eYzAXimGrtre8vxqE65wAGqYs9W6IsoOfgj74se/rBc9yoRXOHQ== +"@types/lowlight@^0.0.3": + version "0.0.3" + resolved "https://registry.yarnpkg.com/@types/lowlight/-/lowlight-0.0.3.tgz#433b03dd63894dde17860063f4c90a688431194b" + integrity sha512-R83q/yPX2nIlo9D3WtSjyUDd57t8s+GVLaL8YIv3k7zMMWpYpOXqjJgrWp80qXUJB/a1t76nTyBpxrv0JNYaEg== "@types/mdast@^3.0.0": version "3.0.3" @@ -1693,25 +1693,25 @@ "@types/prosemirror-state" "*" "@types/prosemirror-view" "*" -"@types/prosemirror-dropcursor@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.1.tgz#3ba98dd861ff2a62559e70f453f996a1ef5ec55d" - integrity sha512-nHokhFypOZjknolZBm2XShlR7fx1IUcCiA3S2fBwmAraWu6zv3gboDSwwFpoS9UB2xKc4ismAmBxh2bpL3YNkg== +"@types/prosemirror-dropcursor@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.2.tgz#476b90a661f32d6d6a21599f53fcd71e36c65a1f" + integrity sha512-5Ez7yIAvHQgn5YJkuafEh0w4sHV7pksCX9LTPBFRjCuznamcKsnYCez4mR0PwIWq/WuPDvHkR+wqKb4l0t9/aQ== dependencies: "@types/prosemirror-state" "*" -"@types/prosemirror-gapcursor@^1.0.3": - version "1.0.3" - resolved "https://registry.yarnpkg.com/@types/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.3.tgz#989e98c734e01e2ed4cab39992e60a1b0646cab6" - integrity sha512-kBVjjbMmUk7ZsgpI1NOyY15makulu1skEGr+V9GgY7GQnT9vqjo8/XiNSgSj9s9vRTsTb/KAaTI9KJwWlhbhxQ== +"@types/prosemirror-gapcursor@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.4.tgz#7df7d373edb33ea8da12084bfd462cf84cd69761" + integrity sha512-9xKjFIG5947dzerFvkLWp6F53JwrUYoYwh3SgcTFEp8SbSfNNrez/PFYVZKPnoqPoaK5WtTdQTaMwpCV9rXQIg== dependencies: "@types/prosemirror-model" "*" "@types/prosemirror-state" "*" -"@types/prosemirror-history@^1.0.2": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@types/prosemirror-history/-/prosemirror-history-1.0.2.tgz#f90a009a0dcd71393faa69ce705593dec76347a1" - integrity sha512-AcfpWo+HkIuvq/H2zYjIMi2jxa2GWfYaTNiFTB2sigjkpWNM93CIlb7Cimy/4vNH8lVPp0GwLBjYIMRX6zOUyA== +"@types/prosemirror-history@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-history/-/prosemirror-history-1.0.3.tgz#f1110efbe758129b5475e466ff077f0a8d9b964f" + integrity sha512-5TloMDRavgLjOAKXp1Li8u0xcsspzbT1Cm9F2pwHOkgvQOz1jWQb2VIXO7RVNsFjLBZdIXlyfSLivro3DuMWXg== dependencies: "@types/prosemirror-model" "*" "@types/prosemirror-state" "*" @@ -1734,10 +1734,10 @@ "@types/prosemirror-state" "*" "@types/prosemirror-view" "*" -"@types/prosemirror-model@*", "@types/prosemirror-model@^1.13.0": - version "1.13.0" - resolved "https://registry.yarnpkg.com/@types/prosemirror-model/-/prosemirror-model-1.13.0.tgz#d05937e918c3cac2cf49630ccab04a65fc5fffd6" - integrity sha512-EIUr2R38Zh9n1eA8BQ1C3NX/XLV9U44DhNVk8x3Sth2RW+wa7jNA82XHMPOoapsOTfmpnh32xaHBOzREiBqdPQ== +"@types/prosemirror-model@*", "@types/prosemirror-model@^1.13.1": + version "1.13.1" + resolved "https://registry.yarnpkg.com/@types/prosemirror-model/-/prosemirror-model-1.13.1.tgz#53df04ee174a7e1dc12747005b1b4c02565adcc4" + integrity sha512-tA1AlI+YR2t3Ve5eeQVJnQm4yV4wVlNfeogHusD1X3OEqqMYTuPssThgIMR4PxPHtvV871Ix8a20bUiJvULDgw== dependencies: "@types/orderedmap" "*" @@ -1750,26 +1750,26 @@ "@types/prosemirror-model" "*" "@types/prosemirror-state" "*" -"@types/prosemirror-state@*", "@types/prosemirror-state@^1.2.6": - version "1.2.6" - resolved "https://registry.yarnpkg.com/@types/prosemirror-state/-/prosemirror-state-1.2.6.tgz#bb0169084239a8393b354c6fda5420fc347d6bab" - integrity sha512-tJo0wC+/cQvbrPDVx01Fnng9Fs41bAMVxgJY1KLOyIsUPN0otUN1KdoQurLMmHNHTvIna9ZXxjZD//xJKLYfJw== +"@types/prosemirror-state@*", "@types/prosemirror-state@^1.2.7": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/prosemirror-state/-/prosemirror-state-1.2.7.tgz#cd55062e4043a31e3426f47668f1d7038b5d8dfb" + integrity sha512-clJf5uw3/XQnBJtl2RqYXoLMGBySnLYl43xtDvFfQZKkLnnYcM1SDU8dcz7lWjl2Dm+H98RpLOl44pp7DYT+wA== dependencies: "@types/prosemirror-model" "*" "@types/prosemirror-transform" "*" "@types/prosemirror-view" "*" -"@types/prosemirror-transform@*", "@types/prosemirror-transform@^1.1.3": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@types/prosemirror-transform/-/prosemirror-transform-1.1.3.tgz#cf30d275976978d1c0317d0659145426fc49ce6f" - integrity sha512-qtnd4jMoBgUAF2Vy2uRCVY4/LN3d069PP9XTIKrfk7mwWPYKonBYv1NsaBGTpK26sOPu0p7eJNZwaiNYmbfIwA== +"@types/prosemirror-transform@*", "@types/prosemirror-transform@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-transform/-/prosemirror-transform-1.1.4.tgz#c3565e81b2ef3ce3254e6927d6f63eb8d7bb20d0" + integrity sha512-HP1PauvkqSgDquZut8HaLOTUDQ6jja/LAy4OA7tTS1XG7wqRnX3gLUyEj0mD6vFd4y8BPkNddNdOh/BeGHlUjg== dependencies: "@types/prosemirror-model" "*" -"@types/prosemirror-view@*", "@types/prosemirror-view@^1.17.1": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@types/prosemirror-view/-/prosemirror-view-1.17.1.tgz#0895df5a57ae6e68d4f3f8020d9be4ef52192980" - integrity sha512-PNiGGc6BffxHQzMR09UUilsBR8xFPDsKiPIXb4K/g56voPIvqq1pqySnWFfSR50Vo4ZL0tss3VBLWiiiKzVahQ== +"@types/prosemirror-view@*", "@types/prosemirror-view@^1.17.2": + version "1.17.2" + resolved "https://registry.yarnpkg.com/@types/prosemirror-view/-/prosemirror-view-1.17.2.tgz#3aff71a0802bdfc310404db8a37ced2db69fd74f" + integrity sha512-1yUTQZ3yx2YvJTHZdY/rmvSiJ8tJLhUmlNgbFdkFaFcKC6LTBntg5lQvOZ53Aytadab+M/xz7/TzGX8iYB/7gw== dependencies: "@types/prosemirror-model" "*" "@types/prosemirror-state" "*" @@ -9698,10 +9698,10 @@ prosemirror-collab@^1.2.2: dependencies: prosemirror-state "^1.0.0" -prosemirror-commands@^1.1.4, prosemirror-commands@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.1.8.tgz#61aec59ac101b7990ec59726199f2a31ef0cd8ca" - integrity sha512-EIj/WAlrK2rVugxNxsFG6pI4430RL63ka2QKB9dO7vvStsLO//nq/oMjmd3VXp08+QNrmmLE23utqBUZwbS9Jg== +prosemirror-commands@^1.1.10, prosemirror-commands@^1.1.4: + version "1.1.10" + resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.1.10.tgz#406a6589966e6cd80809cea2d801fb998639b37d" + integrity sha512-IWyBBXNAd44RM6NnBPljwq+/CM2oYCQJkF+YhKEAZNwzW0uFdGf4qComhjbKZzqFdu6Iub2ZhNsXgwPibA0lCQ== dependencies: prosemirror-model "^1.0.0" prosemirror-state "^1.0.0" @@ -9759,7 +9759,7 @@ prosemirror-markdown@^1.5.1: markdown-it "^10.0.0" prosemirror-model "^1.0.0" -prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.13.1, prosemirror-model@^1.13.3, prosemirror-model@^1.14.1, prosemirror-model@^1.2.0, prosemirror-model@^1.8.1: +prosemirror-model@^1.0.0, prosemirror-model@^1.1.0, prosemirror-model@^1.13.1, prosemirror-model@^1.13.3, prosemirror-model@^1.14.2, prosemirror-model@^1.2.0, prosemirror-model@^1.8.1: version "1.14.2" resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.14.2.tgz#4e8c39cfff4e097631af4495e125d9a8a9773116" integrity sha512-TwkACyEiSi8FJiRhg2ffbzmQRy5DR+aTwAr7trNQNZL24HJR8ouxy4qCkG99PnWK0xZ0AjSMtPXSU6hnxAiP7Q== @@ -9773,10 +9773,10 @@ prosemirror-schema-basic@^1.1.2: dependencies: prosemirror-model "^1.2.0" -prosemirror-schema-list@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.1.4.tgz#471f9caf2d2bed93641d2e490434c0d2d4330df1" - integrity sha512-pNTuZflacFOBlxrTcWSdWhjoB8BaucwfJVp/gJNxztOwaN3wQiC65axclXyplf6TKgXD/EkWfS/QAov3/Znadw== +prosemirror-schema-list@^1.1.4, prosemirror-schema-list@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.1.5.tgz#e7ad9e337ea3d77da6d6a4250f3d7bd51ae980a4" + integrity sha512-9gadhga/wySVfb/iZ2vOpndbG0XroeLw0HkkZN5demNbOea6U5oQtJmvyYWC7ZVf3WkhmVdVsOXrllM9JcC20A== dependencies: prosemirror-model "^1.0.0" prosemirror-transform "^1.0.0" @@ -9812,10 +9812,10 @@ prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transfor dependencies: prosemirror-model "^1.0.0" -prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.16.5, prosemirror-view@^1.18.7: - version "1.18.7" - resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.18.7.tgz#d9843337a1649f532401589899b724e7e87e83c0" - integrity sha512-pUCxoyuWnbVfJ/ukhQ+7+bfDMArG3wu6hHnnTFi61C7Teb5OILUhkkhEhF2/RsppBFWrkwsNcf8rQm8SSoSKRg== +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.13.3, prosemirror-view@^1.16.5, prosemirror-view@^1.18.8: + version "1.18.9" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.18.9.tgz#29bc11759438aecc5b7fadaa8520165c84c2144a" + integrity sha512-AkknqYyt7QBJIfA993O5NNOXLyQji5vr0SnOk/eig18dr7hbe1CK9FKd4Cnh9/f0JSHhZwadHlc3w+wZkIdmIQ== dependencies: prosemirror-model "^1.1.0" prosemirror-state "^1.0.0" |