Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2022-07-27 12:10:44 +00:00
parent d0a683e342
commit a4068557f4
55 changed files with 1055 additions and 827 deletions

View File

@ -6,6 +6,13 @@ import {
GlInputGroupText,
GlLink,
GlAlert,
GlButton,
GlButtonGroup,
GlDropdown,
GlDropdownItem,
GlDropdownText,
GlTruncate,
GlSearchBoxByType,
} from '@gitlab/ui';
import { debounce } from 'lodash';
@ -15,6 +22,11 @@ import { createAlert } from '~/flash';
import { slugify } from '~/lib/utils/text_utility';
import axios from '~/lib/utils/axios_utils';
import { helpPagePath } from '~/helpers/help_page_helper';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { MINIMUM_SEARCH_LENGTH } from '~/graphql_shared/constants';
import { DEBOUNCE_DELAY } from '~/vue_shared/components/filtered_search_bar/constants';
import searchGroupsWhereUserCanCreateSubgroups from '../queries/search_groups_where_user_can_create_subgroups.query.graphql';
const DEBOUNCE_DURATION = 1000;
@ -22,7 +34,6 @@ export default {
i18n: {
inputs: {
name: {
label: s__('Groups|Group name'),
placeholder: __('My awesome group'),
description: s__(
'Groups|Must start with letter, digit, emoji, or underscore. Can also contain periods, dashes, spaces, and parentheses.',
@ -30,7 +41,6 @@ export default {
invalidFeedback: s__('Groups|Enter a descriptive name for your group.'),
},
path: {
label: s__('Groups|Group URL'),
placeholder: __('my-awesome-group'),
invalidFeedbackInvalidPattern: s__(
'GroupSettings|Choose a group path that does not start with a dash or end with a period. It can also contain alphanumeric characters and underscores.',
@ -40,9 +50,6 @@ export default {
),
validFeedback: s__('Groups|Group path is available.'),
},
groupId: {
label: s__('Groups|Group ID'),
},
},
apiLoadingMessage: s__('Groups|Checking group URL availability...'),
apiErrorMessage: __(
@ -51,7 +58,7 @@ export default {
changingUrlWarningMessage: s__('Groups|Changing group URL can have unintended side effects.'),
learnMore: s__('Groups|Learn more'),
},
nameInputSize: { md: 'lg' },
inputSize: { md: 'lg' },
changingGroupPathHelpPagePath: helpPagePath('user/group/index', {
anchor: 'change-a-groups-path',
}),
@ -63,8 +70,35 @@ export default {
GlInputGroupText,
GlLink,
GlAlert,
GlButton,
GlButtonGroup,
GlDropdown,
GlDropdownItem,
GlDropdownText,
GlTruncate,
GlSearchBoxByType,
},
inject: ['fields', 'basePath', 'mattermostEnabled'],
apollo: {
currentUserGroups: {
query: searchGroupsWhereUserCanCreateSubgroups,
variables() {
return {
search: this.search,
};
},
update(data) {
return data.currentUser?.groups?.nodes || [];
},
skip() {
const hasNotEnoughSearchCharacters =
this.search.length > 0 && this.search.length < MINIMUM_SEARCH_LENGTH;
return this.shouldSkipQuery || hasNotEnoughSearchCharacters;
},
debounce: DEBOUNCE_DELAY,
},
},
inject: ['fields', 'basePath', 'newSubgroup', 'mattermostEnabled'],
data() {
return {
name: this.fields.name.value,
@ -76,9 +110,27 @@ export default {
pathFeedbackState: null,
pathInvalidFeedback: null,
activeApiRequestAbortController: null,
search: '',
currentUserGroups: {},
shouldSkipQuery: true,
selectedGroup: {
id: this.fields.parentId.value,
fullPath: this.fields.parentFullPath.value,
},
};
},
computed: {
inputLabels() {
return {
name: this.newSubgroup ? s__('Groups|Subgroup name') : s__('Groups|Group name'),
path: this.newSubgroup ? s__('Groups|Subgroup slug') : s__('Groups|Group URL'),
subgroupPath: s__('Groups|Subgroup URL'),
groupId: s__('Groups|Group ID'),
};
},
pathInputSize() {
return this.newSubgroup ? {} : this.$options.inputSize;
},
computedPath() {
return this.apiSuggestedPath || this.path;
},
@ -129,9 +181,11 @@ export default {
try {
const {
data: { exists, suggests },
} = await getGroupPathAvailability(this.path, this.fields.parentId?.value, {
signal: this.activeApiRequestAbortController.signal,
});
} = await getGroupPathAvailability(
this.path,
this.selectedGroup.id || this.fields.parentId.value,
{ signal: this.activeApiRequestAbortController.signal },
);
this.apiLoading = false;
@ -198,6 +252,21 @@ export default {
this.pathInvalidFeedback = this.$options.i18n.inputs.path.invalidFeedbackInvalidPattern;
this.pathFeedbackState = false;
},
handleDropdownShown() {
if (this.shouldSkipQuery) {
this.shouldSkipQuery = false;
}
this.$refs.search.focusInput();
},
handleDropdownItemClick({ id, fullPath }) {
this.selectedGroup = {
id: getIdFromGraphQLId(id),
fullPath,
};
this.debouncedValidatePath();
},
},
};
</script>
@ -208,10 +277,10 @@ export default {
:id="fields.parentId.id"
type="hidden"
:name="fields.parentId.name"
:value="fields.parentId.value"
:value="selectedGroup.id"
/>
<gl-form-group
:label="$options.i18n.inputs.name.label"
:label="inputLabels.name"
:description="$options.i18n.inputs.name.description"
:label-for="fields.name.id"
:invalid-feedback="$options.i18n.inputs.name.invalidFeedback"
@ -220,46 +289,102 @@ export default {
<gl-form-input
:id="fields.name.id"
v-model="name"
class="gl-field-error-ignore"
class="gl-field-error-ignore gl-h-auto!"
required
:name="fields.name.name"
:placeholder="$options.i18n.inputs.name.placeholder"
data-qa-selector="group_name_field"
:size="$options.nameInputSize"
:size="$options.inputSize"
:state="nameFeedbackState"
@invalid="handleInvalidName"
/>
</gl-form-group>
<gl-form-group
:label="$options.i18n.inputs.path.label"
:label-for="fields.path.id"
:description="pathDescription"
:state="pathFeedbackState"
:valid-feedback="$options.i18n.inputs.path.validFeedback"
:invalid-feedback="pathInvalidFeedback"
>
<gl-form-input-group>
<template #prepend>
<gl-input-group-text class="group-root-path">{{ basePath }}</gl-input-group-text>
</template>
<gl-form-input
:id="fields.path.id"
class="gl-field-error-ignore"
:name="fields.path.name"
:value="computedPath"
:placeholder="$options.i18n.inputs.path.placeholder"
:maxlength="fields.path.maxLength"
:pattern="fields.path.pattern"
:state="pathFeedbackState"
:size="$options.nameInputSize"
required
data-qa-selector="group_path_field"
:data-bind-in="mattermostEnabled ? $options.mattermostDataBindName : null"
@input="handlePathInput"
@invalid="handleInvalidPath"
/>
</gl-form-input-group>
</gl-form-group>
<div :class="newSubgroup && 'row gl-mb-3'">
<gl-form-group v-if="newSubgroup" class="col-sm-6 gl-pr-0" :label="inputLabels.subgroupPath">
<div class="input-group gl-flex-nowrap">
<gl-button-group class="gl-w-full">
<gl-button class="js-group-namespace-button gl-text-truncate gl-flex-grow-0!" label>
{{ basePath }}
</gl-button>
<gl-dropdown
class="js-group-namespace-dropdown gl-flex-grow-1"
toggle-class="gl-rounded-top-right-base! gl-rounded-bottom-right-base! gl-w-20"
@shown="handleDropdownShown"
>
<template #button-text>
<gl-truncate
v-if="selectedGroup.fullPath"
:text="selectedGroup.fullPath"
position="start"
with-tooltip
/>
</template>
<gl-search-box-by-type
ref="search"
v-model.trim="search"
:is-loading="$apollo.queries.currentUserGroups.loading"
/>
<template v-if="!$apollo.queries.currentUserGroups.loading">
<template v-if="currentUserGroups.length">
<gl-dropdown-item
v-for="group of currentUserGroups"
:key="group.id"
data-testid="select_group_dropdown_item"
@click="handleDropdownItemClick(group)"
>
{{ group.fullPath }}
</gl-dropdown-item>
</template>
<gl-dropdown-text v-else>{{ __('No matches found') }}</gl-dropdown-text>
</template>
</gl-dropdown>
</gl-button-group>
<div class="gl-align-self-center gl-pl-5">
<span class="gl-display-none gl-md-display-inline">/</span>
</div>
</div>
</gl-form-group>
<gl-form-group
:class="newSubgroup && 'col-sm-6'"
:label="inputLabels.path"
:label-for="fields.path.id"
:description="pathDescription"
:state="pathFeedbackState"
:valid-feedback="$options.i18n.inputs.path.validFeedback"
:invalid-feedback="pathInvalidFeedback"
>
<gl-form-input-group>
<template v-if="!newSubgroup" #prepend>
<gl-input-group-text class="group-root-path">
{{ basePath.concat(fields.parentFullPath.value) }}
</gl-input-group-text>
</template>
<gl-form-input
:id="fields.path.id"
class="gl-field-error-ignore gl-h-auto!"
:name="fields.path.name"
:value="computedPath"
:placeholder="$options.i18n.inputs.path.placeholder"
:maxlength="fields.path.maxLength"
:pattern="fields.path.pattern"
:state="pathFeedbackState"
:size="pathInputSize"
required
data-qa-selector="group_path_field"
:data-bind-in="mattermostEnabled ? $options.mattermostDataBindName : null"
@input="handlePathInput"
@invalid="handleInvalidPath"
/>
</gl-form-input-group>
</gl-form-group>
</div>
<template v-if="isEditingGroup">
<gl-alert class="gl-mb-5" :dismissible="false" variant="warning">
{{ $options.i18n.changingUrlWarningMessage }}
@ -267,7 +392,7 @@ export default {
>{{ $options.i18n.learnMore }}
</gl-link>
</gl-alert>
<gl-form-group :label="$options.i18n.inputs.groupId.label" :label-for="fields.groupId.id">
<gl-form-group :label="inputLabels.groupId" :label-for="fields.groupId.id">
<gl-form-input
:id="fields.groupId.id"
:value="fields.groupId.value"

View File

@ -1,8 +1,12 @@
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql';
import { parseRailsFormFields } from '~/lib/utils/forms';
import { parseBoolean } from '~/lib/utils/common_utils';
import GroupNameAndPath from './components/group_name_and_path.vue';
Vue.use(VueApollo);
export const initGroupNameAndPath = () => {
const elements = document.querySelectorAll('.js-group-name-and-path');
@ -12,13 +16,17 @@ export const initGroupNameAndPath = () => {
elements.forEach((element) => {
const fields = parseRailsFormFields(element);
const { basePath, mattermostEnabled } = element.dataset;
const { basePath, newSubgroup, mattermostEnabled } = element.dataset;
return new Vue({
el: element,
apolloProvider: new VueApollo({
defaultClient: createDefaultClient(),
}),
provide: {
fields,
basePath,
newSubgroup: parseBoolean(newSubgroup),
mattermostEnabled: parseBoolean(mattermostEnabled),
},
render(h) {

View File

@ -0,0 +1,11 @@
query searchGroupsWhereUserCanCreateSubgroups($search: String) {
currentUser {
id
groups(permissionScope: TRANSFER_PROJECTS, search: $search) {
nodes {
id
fullPath
}
}
}
}

View File

@ -2,51 +2,74 @@
import importGroupIllustration from '@gitlab/svgs/dist/illustrations/group-import.svg';
import newGroupIllustration from '@gitlab/svgs/dist/illustrations/group-new.svg';
import { s__ } from '~/locale';
import { __, s__ } from '~/locale';
import NewNamespacePage from '~/vue_shared/new_namespace/new_namespace_page.vue';
import createGroupDescriptionDetails from './create_group_description_details.vue';
const PANELS = [
{
name: 'create-group-pane',
selector: '#create-group-pane',
title: s__('GroupsNew|Create group'),
description: s__(
'GroupsNew|Assemble related projects together and grant members access to several projects at once.',
),
illustration: newGroupIllustration,
details: createGroupDescriptionDetails,
},
{
name: 'import-group-pane',
selector: '#import-group-pane',
title: s__('GroupsNew|Import group'),
description: s__('GroupsNew|Import a group and related data from another GitLab instance.'),
illustration: importGroupIllustration,
details: 'Migrate your existing groups from another instance of GitLab.',
},
];
export default {
components: {
NewNamespacePage,
},
props: {
parentGroupName: {
type: String,
required: false,
default: '',
},
importExistingGroupPath: {
type: String,
required: false,
default: '',
},
hasErrors: {
type: Boolean,
required: false,
default: false,
},
},
PANELS,
computed: {
initialBreadcrumb() {
return this.parentGroupName || __('New group');
},
panels() {
return [
{
name: 'create-group-pane',
selector: '#create-group-pane',
title: this.parentGroupName
? s__('GroupsNew|Create subgroup')
: s__('GroupsNew|Create group'),
description: s__(
'GroupsNew|Assemble related projects together and grant members access to several projects at once.',
),
illustration: newGroupIllustration,
details: createGroupDescriptionDetails,
detailProps: {
parentGroupName: this.parentGroupName,
importExistingGroupPath: this.importExistingGroupPath,
},
},
{
name: 'import-group-pane',
selector: '#import-group-pane',
title: s__('GroupsNew|Import group'),
description: s__(
'GroupsNew|Import a group and related data from another GitLab instance.',
),
illustration: importGroupIllustration,
details: 'Migrate your existing groups from another instance of GitLab.',
},
];
},
},
};
</script>
<template>
<new-namespace-page
:jump-to-last-persisted-panel="hasErrors"
:initial-breadcrumb="__('New group')"
:panels="$options.PANELS"
:initial-breadcrumb="initialBreadcrumb"
:panels="panels"
:title="s__('GroupsNew|Create new group')"
persistence-key="new_group_last_active_tab"
/>

View File

@ -1,6 +1,22 @@
<script>
import { GlSprintf, GlLink } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { s__ } from '~/locale';
const DESCRIPTION_DETAILS = {
group: [
s__(
'GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects.',
),
s__('GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}.'),
],
subgroup: [
s__(
'GroupsNew|%{groupsLinkStart}Groups%{groupsLinkEnd} and %{subgroupsLinkStart}subgroups%{subgroupsLinkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects.',
),
s__('GroupsNew|You can also %{linkStart}import an existing group%{linkEnd}.'),
],
};
export default {
components: {
@ -11,30 +27,46 @@ export default {
groupsHelpPath: helpPagePath('user/group/index'),
subgroupsHelpPath: helpPagePath('user/group/subgroups/index'),
},
props: {
parentGroupName: {
type: String,
required: false,
default: '',
},
importExistingGroupPath: {
type: String,
required: false,
default: '',
},
},
descriptionDetails: DESCRIPTION_DETAILS,
};
</script>
<template>
<div>
<p>
<gl-sprintf
:message="
s__(
'GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects.',
)
"
>
<gl-sprintf v-if="parentGroupName" :message="$options.descriptionDetails.subgroup[0]">
<template #groupsLink="{ content }">
<gl-link :href="$options.paths.groupsHelpPath" target="_blank">{{ content }}</gl-link>
</template>
<template #subgroupsLink="{ content }">
<gl-link :href="$options.paths.subgroupsHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
<gl-sprintf v-else :message="$options.descriptionDetails.group[0]">
<template #link="{ content }">
<gl-link :href="$options.paths.groupsHelpPath" target="_blank">{{ content }}</gl-link>
</template>
</gl-sprintf>
</p>
<p>
<gl-sprintf
:message="
s__('GroupsNew|Groups can also be nested by creating %{linkStart}subgroups%{linkEnd}.')
"
>
<gl-sprintf v-if="parentGroupName" :message="$options.descriptionDetails.subgroup[1]">
<template #link="{ content }">
<gl-link :href="importExistingGroupPath">{{ content }}</gl-link>
</template>
</gl-sprintf>
<gl-sprintf v-else :message="$options.descriptionDetails.group[1]">
<template #link="{ content }">
<gl-link :href="$options.paths.subgroupsHelpPath" target="_blank">{{ content }}</gl-link>
</template>

View File

@ -16,9 +16,18 @@ BindInOut.initAll();
initFilePickers();
function initNewGroupCreation(el) {
const { hasErrors, verificationRequired, verificationFormUrl, subscriptionsUrl } = el.dataset;
const {
hasErrors,
parentGroupName,
importExistingGroupPath,
verificationRequired,
verificationFormUrl,
subscriptionsUrl,
} = el.dataset;
const props = {
parentGroupName,
importExistingGroupPath,
hasErrors: parseBoolean(hasErrors),
};

View File

@ -34,6 +34,36 @@ const nonStandardEvents = {
},
counter: {},
},
metrics: {
uniqueUser: {
expand: ['i_testing_metrics_report_widget_total'],
},
counter: {},
},
browserPerformance: {
uniqueUser: {
expand: ['i_testing_web_performance_widget_total'],
},
counter: {},
},
licenseCompliance: {
uniqueUser: {
expand: ['i_testing_license_compliance_widget_total'],
},
counter: {},
},
loadPerformance: {
uniqueUser: {
expand: ['i_testing_load_performance_widget_total'],
},
counter: {},
},
statusChecks: {
uniqueUser: {
expand: ['i_testing_status_checks_widget'],
},
counter: {},
},
};
function combineDeepArray(path, ...objects) {

View File

@ -6,7 +6,6 @@ import { EXTENSION_ICONS } from '../../constants';
export default {
name: 'WidgetAccessibility',
enablePolling: true,
telemetry: false,
i18n: {
loading: s__('Reports|Accessibility scanning results are being parsed'),
error: s__('Reports|Accessibility scanning failed loading results'),

View File

@ -14,6 +14,7 @@ import { glEmojiTag } from '~/emoji';
import createFlash from '~/flash';
import { followUser, unfollowUser } from '~/rest_api';
import { isUserBusy } from '~/set_status_modal/utils';
import Tracking from '~/tracking';
import { USER_POPOVER_DELAY } from './constants';
const MAX_SKELETON_LINES = 4;
@ -37,6 +38,7 @@ export default {
directives: {
SafeHtml: GlSafeHtmlDirective,
},
mixins: [Tracking.mixin()],
props: {
target: {
type: HTMLElement,
@ -117,6 +119,11 @@ export default {
},
async follow() {
this.toggleFollowLoading = true;
this.track('click_button', {
label: 'follow_from_user_popover',
});
try {
await followUser(this.user.id);
this.$emit('follow');
@ -132,6 +139,11 @@ export default {
},
async unfollow() {
this.toggleFollowLoading = true;
this.track('click_button', {
label: 'unfollow_from_user_popover',
});
try {
await unfollowUser(this.user.id);
this.$emit('unfollow');

View File

@ -125,7 +125,7 @@ export default {
<h4>{{ activePanel.title }}</h4>
<p v-if="hasTextDetails">{{ details }}</p>
<component :is="details" v-else />
<component :is="details" v-else v-bind="activePanel.detailProps || {}" />
<slot name="extra-description"></slot>
</div>

View File

@ -1,4 +1,4 @@
= content_tag tag, {**@button_options, **base_attributes, class: button_class, href: @href, target: @target } do
= content_for :pajamas_button_content, flush: true do
- if @loading
= gl_loading_icon(inline: true, css_class: 'gl-button-icon gl-button-loading-indicator')
- if @icon && (!@loading || content)
@ -6,3 +6,10 @@
- if content
%span.gl-button-text{ class: @button_text_classes }
= content
- if link?
= link_to @href, { **@button_options, **base_attributes, class: button_class, target: @target, method: @method } do
= content_for :pajamas_button_content
- else
= content_tag 'button', { **@button_options, **base_attributes, class: button_class } do
= content_for :pajamas_button_content

View File

@ -13,6 +13,7 @@ module Pajamas
# @param [String] icon
# @param [String] href
# @param [String] target
# @param [Symbol] method
# @param [Hash] button_options
# @param [String] button_text_classes
# @param [String] icon_classes
@ -28,6 +29,7 @@ module Pajamas
icon: nil,
href: nil,
target: nil,
method: nil,
button_options: {},
button_text_classes: nil,
icon_classes: nil
@ -43,6 +45,7 @@ module Pajamas
@icon = icon
@href = href
@target = filter_attribute(target, TARGET_OPTIONS)
@method = filter_attribute(method, METHOD_OPTIONS)
@button_options = button_options
@button_text_classes = button_text_classes
@icon_classes = icon_classes
@ -75,6 +78,7 @@ module Pajamas
SIZE_OPTIONS = [:small, :medium].freeze
TYPE_OPTIONS = [:button, :reset, :submit].freeze
TARGET_OPTIONS = %w[_self _blank _parent _top].freeze
METHOD_OPTIONS = [:get, :post, :put, :delete, :patch].freeze
CATEGORY_CLASSES = {
primary: '',
@ -101,8 +105,8 @@ module Pajamas
delegate :sprite_icon, to: :helpers
delegate :gl_loading_icon, to: :helpers
def tag
@href ? 'a' : 'button'
def link?
@href.present?
end
def base_attributes

View File

@ -13,7 +13,6 @@ module Mutations
if pipeline.cancelable?
pipeline.cancel_running
pipeline.cancel
{ success: true, errors: [] }
else

View File

@ -134,6 +134,13 @@ module GroupsHelper
@group_projects_sort || @sort || params[:sort] || sort_value_recently_created
end
def subgroup_creation_data(group)
{
parent_group_name: group.parent&.name,
import_existing_group_path: new_group_path(parent_id: group.parent_id, anchor: 'import-group-pane')
}
end
def verification_for_group_creation_data
# overridden in EE
{}
@ -144,11 +151,9 @@ module GroupsHelper
false
end
def group_name_and_path_app_data(group)
parent = group.parent
def group_name_and_path_app_data
{
base_path: URI.join(root_url, parent&.full_path || "").to_s,
base_path: root_url,
mattermost_enabled: Gitlab.config.mattermost.enabled.to_s
}
end
@ -156,7 +161,7 @@ module GroupsHelper
def subgroups_and_projects_list_app_data(group)
{
show_schema_markup: 'true',
new_subgroup_path: new_group_path(parent_id: group.id),
new_subgroup_path: new_group_path(parent_id: group.id, anchor: 'create-group-pane'),
new_project_path: new_project_path(namespace_id: group.id),
new_subgroup_illustration: image_path('illustrations/subgroup-create-new-sm.svg'),
new_project_illustration: image_path('illustrations/project-create-new-sm.svg'),

View File

@ -42,7 +42,7 @@ module Nav
::Gitlab::Nav::TopNavMenuItem.build(
id: 'new_subgroup',
title: _('New subgroup'),
href: new_group_path(parent_id: group.id),
href: new_group_path(parent_id: group.id, anchor: 'create-group-pane'),
data: { track_action: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown' }
)
)

View File

@ -15,23 +15,7 @@ module Emails
email = user.notification_email_or_default
mail to: email, subject: "Unsubscribed from GitLab administrator notifications"
end
def user_auto_banned_email(admin_id, user_id, max_project_downloads:, within_seconds:, group: nil)
admin = User.find(admin_id)
@user = User.find(user_id)
@max_project_downloads = max_project_downloads
@within_minutes = within_seconds / 60
@ban_scope = if group.present?
_('your group (%{group_name})' % { group_name: group.name })
else
_('your GitLab instance')
end
Gitlab::I18n.with_locale(admin.preferred_language) do
email_with_layout(
to: admin.notification_email_or_default,
subject: subject(_("We've detected unusual activity")))
end
end
end
end
Emails::AdminNotification.prepend_mod

View File

@ -9,7 +9,7 @@
= _('Update your group name, description, avatar, and visibility.')
= link_to _('Learn more about groups.'), help_page_path('user/group/index')
.col-lg-8
= render 'shared/group_form', f: f
= render 'shared/groups/group_name_and_path_fields', f: f
= render 'shared/group_form_description', f: f
.form-group.gl-form-group{ role: 'group' }
= f.label :avatar, _("Group avatar"), class: 'gl-display-block col-form-label'

View File

@ -33,7 +33,10 @@
.js-vue-notification-dropdown{ data: { disabled: emails_disabled.to_s, dropdown_items: notification_dropdown_items(@notification_setting).to_json, notification_level: @notification_setting.level, help_page_path: help_page_path('user/profile/notifications'), group_id: @group.id, container_class: 'gl-mx-2 gl-mt-3 gl-vertical-align-top', no_flip: 'true' } }
- if can_create_subgroups
.gl-px-2.gl-sm-w-auto.gl-w-full
= link_to _("New subgroup"), new_group_path(parent_id: @group.id), class: "btn btn-default gl-button gl-mt-3 gl-sm-w-auto gl-w-full", data: { qa_selector: 'new_subgroup_button' }
= link_to _("New subgroup"),
new_group_path(parent_id: @group.id, anchor: 'create-group-pane'),
class: "btn btn-default gl-button gl-mt-3 gl-sm-w-auto gl-w-full",
data: { qa_selector: 'new_subgroup_button' }
- if can_create_projects
.gl-px-2.gl-sm-w-auto.gl-w-full
= link_to _("New project"), new_project_path(namespace_id: @group.id), class: "btn btn-confirm gl-button gl-mt-3 gl-sm-w-auto gl-w-full", data: { qa_selector: 'new_project_button' }

View File

@ -1,31 +1,34 @@
- parent = @group.parent
- submit_label = parent ? s_('GroupsNew|Create subgroup') : s_('GroupsNew|Create group')
= form_errors(@group, pajamas_alert: true)
= render 'shared/group_form', f: f, autofocus: true
= render 'shared/groups/group_name_and_path_fields', f: f, autofocus: true, new_subgroup: !!parent
.row
.form-group.gl-form-group.col-sm-12
%label.label-bold
= _('Visibility level')
%p
= _('Who will be able to see this group?')
= link_to _('View the documentation'), help_page_path("user/public_access"), target: '_blank', rel: 'noopener noreferrer'
= render 'shared/visibility_level', f: f, visibility_level: default_group_visibility, can_change_visibility_level: true, form_model: @group, with_label: false
- if Gitlab.config.mattermost.enabled
- unless parent
.row
= render 'create_chat_team', f: f
.form-group.gl-form-group.col-sm-12
%label.label-bold
= _('Visibility level')
%p
= _('Who will be able to see this group?')
= link_to _('View the documentation'), help_page_path("user/public_access"), target: '_blank', rel: 'noopener noreferrer'
= render 'shared/visibility_level', f: f, visibility_level: default_group_visibility, can_change_visibility_level: true, form_model: @group, with_label: false
- unless Gitlab::CurrentSettings.current_application_settings.hide_third_party_offers?
= render 'personalize', f: f
- if Gitlab.config.mattermost.enabled
.row
= render 'create_chat_team', f: f
.row.js-invite-members-section
.col-sm-4
= render_if_exists 'shared/groups/invite_members'
- unless Gitlab::CurrentSettings.current_application_settings.hide_third_party_offers?
= render 'personalize', f: f
- if captcha_required?
.row.recaptcha
.row.js-invite-members-section
.col-sm-4
= recaptcha_tags nonce: content_security_policy_nonce
= render_if_exists 'shared/groups/invite_members'
- if captcha_required?
.row.recaptcha
.col-sm-4
= recaptcha_tags nonce: content_security_policy_nonce
.row
.col-sm-12
= f.submit _('Create group'), class: "btn gl-button btn-confirm"
= f.submit submit_label, class: "btn gl-button btn-confirm", data: { qa_selector: 'create_group_button' }
= link_to _('Cancel'), dashboard_groups_path, class: 'btn gl-button btn-default btn-cancel'

View File

@ -6,7 +6,8 @@
.group-edit-container.gl-mt-5
.js-new-group-creation{ data: { has_errors: @group.errors.any?.to_s }.merge(verification_for_group_creation_data) }
.js-new-group-creation{ data: { has_errors: @group.errors.any?.to_s }.merge(subgroup_creation_data(@group),
verification_for_group_creation_data) }
.row{ 'v-cloak': true }
#create-group-pane.tab-pane

View File

@ -1,4 +1,23 @@
- return unless google_tag_manager_enabled?
- if Feature.enabled?(:gitlab_gtm_datalayer, type: :ops)
= javascript_tag do
:plain
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('consent', 'default', {
'analytics_storage': 'denied',
'ad_storage': 'denied',
'functionality_storage': 'denied',
'region': ['EU', 'UK', 'PE', 'RU'],
'wait_for_update': 500
});
gtag('consent', 'default', {
'analytics_storage': 'granted',
'ad_storage': 'granted',
'functionality_storage': 'granted',
'wait_for_update': 500
});
- if Feature.enabled?(:gtm_nonce, type: :ops)
= javascript_tag nonce: content_security_policy_nonce do

View File

@ -1,9 +0,0 @@
- link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer">'.html_safe
- link_end = '</a>'.html_safe
= email_default_heading(_("We've detected some unusual activity"))
%p
= _('We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes.') % { username: sanitize_name(@user.name), max_project_downloads: @max_project_downloads, within_minutes: @within_minutes, scope: @ban_scope }
%p
= _('If this is a mistake, you can %{link_start}unban them%{link_end}.').html_safe % { link_start: link_start % { url: admin_users_url(filter: 'banned') }, link_end: link_end }
%p
= _('You can adjust rules on auto-banning %{link_start}here%{link_end}.').html_safe % { link_start: link_start % { url: network_admin_application_settings_url(anchor: 'js-ip-limits-settings') }, link_end: link_end }

View File

@ -1,7 +0,0 @@
<%= _("We've detected some unusual activity") %>
<%= _('We want to let you know %{username} has been banned from %{scope} due to them downloading more than %{max_project_downloads} project repositories within %{within_minutes} minutes.') % { username: sanitize_name(@user.name), max_project_downloads: @max_project_downloads, within_minutes: @within_minutes, scope: @ban_scope } %>
<%= _('If this is a mistake, you can unban them: %{url}.') % { url: admin_users_url(filter: 'banned') } %>
<%= _('You can adjust rules on auto-banning here: %{url}.') % { url: network_admin_application_settings_url(anchor: 'js-ip-limits-settings') } %>

View File

@ -1,6 +0,0 @@
- parent = @group.parent
- group_path = root_url
- group_path << parent.full_path + '/' if parent
= render 'shared/groups/group_name_and_path_fields', f: f

View File

@ -1,5 +1,6 @@
.js-group-name-and-path{ data: group_name_and_path_app_data(@group) }
.js-group-name-and-path{ data: group_name_and_path_app_data.merge(new_subgroup: local_assigns[:new_subgroup].to_s) }
= f.hidden_field :name, data: { js_name: 'name' }
= f.hidden_field :path, maxlength: ::Namespace::URL_MAX_LENGTH, pattern: Gitlab::PathRegex::NAMESPACE_FORMAT_REGEX_JS, data: { js_name: 'path' }
= f.hidden_field :parent_id, value: @group.parent&.id, data: { js_name: 'parentId' }
= f.hidden_field :parent_full_path, value: @group.parent&.full_path, data: { js_name: 'parentFullPath' }
= f.hidden_field :id, data: { js_name: 'groupId' }

View File

@ -20,10 +20,10 @@
#promote-milestone-modal
- if milestone.active?
= render Pajamas::ButtonComponent.new(href: update_milestone_path(milestone, { state_event: :close }), button_options: { class: 'btn-grouped btn-close', data: { method: 'put' }, rel: 'nofollow' }) do
= render Pajamas::ButtonComponent.new(href: update_milestone_path(milestone, { state_event: :close }), method: :put, button_options: { class: 'btn-grouped btn-close' }) do
= _('Close milestone')
- else
= render Pajamas::ButtonComponent.new(href: update_milestone_path(milestone, { state_event: :activate }), button_options: { class: 'btn-grouped', data: { method: 'put' }, rel: 'nofollow' }) do
= render Pajamas::ButtonComponent.new(href: update_milestone_path(milestone, { state_event: :activate }), method: :put, button_options: { class: 'btn-grouped' }) do
= _('Reopen milestone')
= render 'shared/milestones/delete_button'

View File

@ -42,11 +42,13 @@
= sprite_icon('user')
- if current_user && current_user.id != @user.id
- if current_user.following?(@user)
= link_to user_unfollow_path(@user, :json) , class: link_classes + 'btn gl-button btn-default', method: :post do
= _('Unfollow')
= form_tag user_unfollow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do
= render Pajamas::ButtonComponent.new(type: :submit, button_options: { class: 'gl-w-full', data: { track_action: 'click_button', track_label: 'unfollow_from_profile' } }) do
= _('Unfollow')
- else
= link_to user_follow_path(@user, :json) , class: link_classes + 'btn gl-button btn-confirm', method: :post, data: { qa_selector: 'follow_user_link' } do
= _('Follow')
= form_tag user_follow_path(@user, :json), class: link_classes + 'gl-display-inline-block' do
= render Pajamas::ButtonComponent.new(variant: :confirm, type: :submit, button_options: { class: 'gl-w-full', data: { qa_selector: 'follow_user_link', track_action: 'click_button', track_label: 'follow_from_profile' } }) do
= _('Follow')
.profile-header{ class: [('with-no-profile-tabs' if profile_tabs.empty?)] }
.avatar-holder

View File

@ -12,9 +12,23 @@ module Ci
feature_category :runner_fleet
urgency :low
deduplicate :until_executed
idempotent!
def perform
def perform(cronjob_scheduled = true)
if cronjob_scheduled
# Introduce some randomness across the day so that instances don't all hit the GitLab Releases API
# around the same time of day
period = rand(0..12.hours.in_seconds)
self.class.perform_in(period, false)
Sidekiq.logger.info(
class: self.class.name,
message: "rescheduled job for #{period.seconds.from_now}")
return
end
result = ::Ci::Runners::ReconcileExistingRunnerVersionsService.new.execute
result.each { |key, value| log_extra_metadata_on_done(key, value) }
end

View File

@ -542,7 +542,7 @@ production: &base
# Periodically update ci_runner_versions table with up-to-date versions and status.
ci_runner_versions_reconciliation_worker:
cron: "20 * * * *"
cron: "@daily"
# GitLab EE only jobs. These jobs are automatically enabled for an EE
# installation, and ignored for a CE installation.

View File

@ -631,7 +631,7 @@ Settings.cron_jobs['loose_foreign_keys_cleanup_worker'] ||= Settingslogic.new({}
Settings.cron_jobs['loose_foreign_keys_cleanup_worker']['cron'] ||= '*/1 * * * *'
Settings.cron_jobs['loose_foreign_keys_cleanup_worker']['job_class'] = 'LooseForeignKeys::CleanupWorker'
Settings.cron_jobs['ci_runner_versions_reconciliation_worker'] ||= Settingslogic.new({})
Settings.cron_jobs['ci_runner_versions_reconciliation_worker']['cron'] ||= '20 * * * *'
Settings.cron_jobs['ci_runner_versions_reconciliation_worker']['cron'] ||= '@daily'
Settings.cron_jobs['ci_runner_versions_reconciliation_worker']['job_class'] = 'Ci::Runners::ReconcileExistingRunnerVersionsCronWorker'
Gitlab.ee do

View File

@ -5,34 +5,42 @@ info: To determine the technical writer assigned to the Stage/Group associated w
type: reference, howto
---
# DAST browser-based crawler **(ULTIMATE)**
# DAST browser-based analyzer **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/323423) in GitLab 13.12.
WARNING:
This product is in an early-access stage and is considered a [beta](../../../policy/alpha-beta-support.md#beta-features) feature.
GitLab DAST's new browser-based crawler is a crawl engine built by GitLab to test Single Page Applications (SPAs) and traditional web applications.
Due to the reliance of modern web applications on JavaScript, handling SPAs or applications that are dependent on JavaScript is paramount to ensuring proper coverage of an application for Dynamic Application Security Testing (DAST).
GitLab DAST's browser-based analyzer was built by GitLab to test Single Page Applications (SPAs) and
traditional web applications. It both crawls the web application and analyzes the resulting output
for vulnerabilities. Analysis of modern applications, heavily reliant on JavaScript, is vital to
ensuring DAST coverage.
The browser-based crawler works by loading the target application into a specially-instrumented Chromium browser. A snapshot of the page is taken before a search to find any actions that a user might perform,
such as clicking on a link or filling in a form. For each action found, the crawler executes it, takes a new snapshot, and determines what in the page changed from the previous snapshot.
Crawling continues by taking more snapshots and finding subsequent actions.
The browser-based scanner works by loading the target application into a specially-instrumented
Chromium browser. A snapshot of the page is taken before a search to find any actions that a user
might perform, such as clicking on a link or filling in a form. For each action found, the
browser-based scanner executes it, takes a new snapshot, and determines what in the page changed
from the previous snapshot. Crawling continues by taking more snapshots and finding subsequent
actions. The benefit of scanning by following user actions in a browser is that the crawler can
interact with the target application much like a real user would, identifying complex flows that
traditional web crawlers don't understand. This results in better coverage of the website.
The benefit of crawling by following user actions in a browser is that the crawler can interact with the target application much like a real user would, identifying complex flows that traditional web crawlers don't understand. This results in better coverage of the website.
The browser-based scanner should provide greater coverage for most web applications, compared
with the current DAST AJAX crawler. While both crawlers are
used together with the current DAST scanner, the combination of the browser-based crawler with the
current DAST scanner is much more effective at finding and testing every page in an application.
Using the browser-based crawler should provide greater coverage for most web applications, compared with the current DAST AJAX crawler. The new crawler replaces the AJAX crawler and is specifically designed to maximize crawl coverage in modern web applications. While both crawlers are currently used in conjunction with the existing DAST scanner, the combination of the browser-based crawler with the current DAST scanner is much more effective at finding and testing every page in an application.
## Enable browser-based analyzer
## Enable browser-based crawler
The browser-based crawler is an extension to the GitLab DAST product. DAST should be included in the CI/CD configuration and the browser-based crawler enabled using CI/CD variables:
To enable the browser-based analyzer:
1. Ensure the DAST [prerequisites](index.md#prerequisites) are met.
1. Include the [DAST CI template](index.md#include-the-dast-template).
1. Set the target website using the `DAST_WEBSITE` CI/CD variable.
1. Include the [DAST CI/CD template](index.md#include-the-dast-template).
1. Set the target website using the [`DAST_WEBSITE` CI/CD variable](index.md#available-cicd-variables).
1. Set the CI/CD variable `DAST_BROWSER_SCAN` to `true`.
An example configuration might look like the following:
Example extract of `.gitlab-ci.yml` file:
```yaml
include:
@ -77,13 +85,20 @@ The [DAST variables](index.md#available-cicd-variables) `SECURE_ANALYZERS_PREFIX
## Vulnerability detection
While the browser-based crawler crawls modern web applications efficiently, vulnerability detection is still managed by the standard DAST/Zed Attack Proxy (ZAP) solution.
Vulnerability detection is gradually being migrated from the default Zed Attack Proxy (ZAP) solution
to the browser-based analyzer. For details of the vulnerability detection already migrated, see
[browser-based vulnerability checks](checks/index.md).
The crawler runs the target website in a browser with DAST/ZAP configured as the proxy server. This ensures that all requests and responses made by the browser are passively scanned by DAST/ZAP.
When running a full scan, active vulnerability checks executed by DAST/ZAP do not use a browser. This difference in how vulnerabilities are checked can cause issues that require certain features of the target website to be disabled to ensure the scan works as intended.
The crawler runs the target website in a browser with DAST/ZAP configured as the proxy server. This
ensures that all requests and responses made by the browser are passively scanned by DAST/ZAP. When
running a full scan, active vulnerability checks executed by DAST/ZAP do not use a browser. This
difference in how vulnerabilities are checked can cause issues that require certain features of the
target website to be disabled to ensure the scan works as intended.
For example, for a target website that contains forms with Anti-CSRF tokens, a passive scan works as intended because the browser displays pages and forms as if a user is viewing the page.
However, active vulnerability checks that run in a full scan cannot submit forms containing Anti-CSRF tokens. In such cases, we recommend you disable Anti-CSRF tokens when running a full scan.
For example, for a target website that contains forms with Anti-CSRF tokens, a passive scan works as
intended because the browser displays pages and forms as if a user is viewing the page. However,
active vulnerability checks that run in a full scan cannot submit forms containing Anti-CSRF tokens.
In such cases, we recommend you disable Anti-CSRF tokens when running a full scan.
## Managing scan time

View File

@ -68,12 +68,14 @@ bugsCharts:
description: "Open bugs created per month"
type: bar
query:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
group_by: month
period_limit: 24
data_source: issuables
params:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
group_by: month
period_limit: 24
```
Each chart definition is made up of a hash composed of key-value pairs.
@ -85,12 +87,14 @@ For example, here's single chart definition:
description: "Open bugs created per month"
type: bar
query:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
group_by: month
period_limit: 24
data_source: issuables
params:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
group_by: month
period_limit: 24
```
## Configuration parameters
@ -104,7 +108,7 @@ The following table lists available parameters for charts:
| [`title`](#title) | The title of the chart. This displays on the Insights page. |
| [`description`](#description) | A description for the individual chart. This displays above the relevant chart. |
| [`type`](#type) | The type of chart: `bar`, `line` or `stacked-bar`. |
| [`query`](#query) | A hash that defines the conditions for issues / merge requests to be part of the chart. |
| [`query`](#query) | A hash that defines the data source and filtering conditions for the chart. |
## Parameter details
@ -155,11 +159,33 @@ Supported values are:
### `query`
`query` allows to define the conditions for issues / merge requests to be part
of the chart.
`query` allows to define the data source and various filtering conditions for the chart.
Example:
```yaml
monthlyBugsCreated:
title: "Monthly bugs created"
description: "Open bugs created per month"
type: bar
query:
data_source: issuables
params:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
collection_labels:
- S1
- S2
- S3
- S4
group_by: week
period_limit: 104
```
The legacy format without the `data_source` parameter is still supported:
```yaml
monthlyBugsCreated:
title: "Monthly bugs created"
@ -179,7 +205,15 @@ monthlyBugsCreated:
period_limit: 104
```
#### `query.issuable_type`
#### `query.data_source`
> [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/725) in GitLab 15.3.
The `data_source` parameter was introduced to allow visualizing data from different data sources. Currently `issuable` is the only supported value.
#### `Issuable` query parameters
##### `query.params.issuable_type`
Defines the type of "issuable" you want to create a chart for.
@ -188,7 +222,7 @@ Supported values are:
- `issue`: The chart displays issues' data.
- `merge_request`: The chart displays merge requests' data.
#### `query.issuable_state`
##### `query.params.issuable_state`
Filter by the current state of the queried "issuable".
@ -202,7 +236,7 @@ Supported values are:
- `merged`: Merged merge requests.
- `all`: Issues / merge requests in all states
#### `query.filter_labels`
##### `query.params.filter_labels`
Filter by labels currently applied to the queried "issuable".
@ -216,14 +250,16 @@ monthlyBugsCreated:
title: "Monthly regressions created"
type: bar
query:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
- regression
data_source: issuables
params:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
- regression
```
#### `query.collection_labels`
#### `query.params.collection_labels`
Group "issuable" by the configured labels.
@ -237,15 +273,17 @@ weeklyBugsBySeverity:
title: "Weekly bugs by severity"
type: stacked-bar
query:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
collection_labels:
- S1
- S2
- S3
- S4
data_source: issuables
params:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
collection_labels:
- S1
- S2
- S3
- S4
```
#### `query.group_by`
@ -325,10 +363,12 @@ monthlyBugsCreated:
description: "Open bugs created per month"
type: bar
query:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
data_source: issuables
params:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
projects:
only:
- 3 # You can use the project ID
@ -355,41 +395,47 @@ bugsCharts:
type: bar
<<: *projectsOnly
query:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
group_by: month
period_limit: 24
data_source: issuables
params:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
group_by: month
period_limit: 24
- title: "Weekly bugs by severity"
type: stacked-bar
<<: *projectsOnly
query:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
collection_labels:
- S1
- S2
- S3
- S4
group_by: week
period_limit: 104
data_source: issuables
params:
issuable_type: issue
issuable_state: opened
filter_labels:
- bug
collection_labels:
- S1
- S2
- S3
- S4
group_by: week
period_limit: 104
- title: "Monthly bugs by team"
type: line
<<: *projectsOnly
query:
issuable_type: merge_request
issuable_state: opened
filter_labels:
- bug
collection_labels:
- Manage
- Plan
- Create
group_by: month
period_limit: 24
data_source: issuables
params:
issuable_type: merge_request
issuable_state: opened
filter_labels:
- bug
collection_labels:
- Manage
- Plan
- Create
group_by: month
period_limit: 24
```

View File

@ -18802,6 +18802,9 @@ msgstr ""
msgid "GroupsEmptyState|You do not have necessary permissions to create a subgroup or project in this group. Please contact an owner of this group to create a new subgroup or project."
msgstr ""
msgid "GroupsNew|%{groupsLinkStart}Groups%{groupsLinkEnd} and %{subgroupsLinkStart}subgroups%{subgroupsLinkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects."
msgstr ""
msgid "GroupsNew|%{linkStart}Groups%{linkEnd} allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects."
msgstr ""
@ -18820,6 +18823,9 @@ msgstr ""
msgid "GroupsNew|Create new group"
msgstr ""
msgid "GroupsNew|Create subgroup"
msgstr ""
msgid "GroupsNew|Create this in the %{pat_link_start}user settings%{pat_link_end} of the source GitLab instance. For %{short_living_link_start}security reasons%{short_living_link_end}, use a short expiration date when creating the token."
msgstr ""
@ -18865,6 +18871,9 @@ msgstr ""
msgid "GroupsNew|Upload file"
msgstr ""
msgid "GroupsNew|You can also %{linkStart}import an existing group%{linkEnd}."
msgstr ""
msgid "GroupsNew|e.g. h8d3f016698e..."
msgstr ""
@ -18943,6 +18952,15 @@ msgstr ""
msgid "Groups|Save changes"
msgstr ""
msgid "Groups|Subgroup URL"
msgstr ""
msgid "Groups|Subgroup name"
msgstr ""
msgid "Groups|Subgroup slug"
msgstr ""
msgid "Guideline"
msgstr ""
@ -23516,9 +23534,6 @@ msgstr ""
msgid "LinkedResources|Linked resources"
msgstr ""
msgid "LinkedResources|Read more about linked resources"
msgstr ""
msgid "LinkedResources|Remove"
msgstr ""
@ -23534,6 +23549,9 @@ msgstr ""
msgid "LinkedResources|Text (Optional)"
msgstr ""
msgid "LinkedResources|Use this space to add links to the resources your team needs as they work to resolve the incident."
msgstr ""
msgid "Links"
msgstr ""

View File

@ -123,7 +123,7 @@
"graphql": "^15.7.2",
"graphql-tag": "^2.11.0",
"highlight.js": "^11.5.1",
"immer": "^7.0.7",
"immer": "^9.0.15",
"ipaddr.js": "^1.9.1",
"jed": "^1.1.1",
"jquery": "^3.6.0",
@ -239,7 +239,7 @@
"md5": "^2.2.1",
"miragejs": "^0.1.40",
"mock-apollo-client": "1.2.0",
"nodemon": "^2.0.4",
"nodemon": "^2.0.19",
"prettier": "2.2.1",
"prosemirror-schema-basic": "^1.1.2",
"prosemirror-schema-list": "^1.1.6",

View File

@ -12,7 +12,7 @@ module QA
end
view 'app/views/groups/_new_group_fields.html.haml' do
element :create_group_button, "submit _('Create group')" # rubocop:disable QA/ElementWithPattern
element :create_group_button
end
view 'app/views/groups/_import_group_from_another_instance_panel.html.haml' do
@ -34,6 +34,10 @@ module QA
click_button 'Create group'
end
def create_subgroup
click_button 'Create subgroup'
end
def set_gitlab_url(url)
fill_element(:import_gitlab_url, url)
end

View File

@ -6,6 +6,7 @@ module QA
module Settings
class Integrations < QA::Page::Base
view 'app/assets/javascripts/integrations/index/components/integrations_table.vue' do
element :jenkins_link, %q(:data-qa-selector="`${item.name}_link`") # rubocop:disable QA/ElementWithPattern
element :prometheus_link, %q(:data-qa-selector="`${item.name}_link`") # rubocop:disable QA/ElementWithPattern
element :jira_link, %q(:data-qa-selector="`${item.name}_link`") # rubocop:disable QA/ElementWithPattern
element :pipelines_email_link, %q(:data-qa-selector="`${item.name}_link`") # rubocop:disable QA/ElementWithPattern
@ -22,10 +23,12 @@ module QA
def click_jira_link
click_element :jira_link
end
def click_jenkins_ci_link
click_element :jenkins_link
end
end
end
end
end
end
QA::Page::Project::Settings::Integrations.prepend_mod_with('Page::Project::Settings::Integrations', namespace: QA)

View File

@ -38,10 +38,8 @@ module QA
group_show.go_to_new_subgroup
Page::Group::New.perform do |group_new|
group_new.click_create_group
group_new.set_path(path)
group_new.set_visibility('Public')
group_new.create
group_new.create_subgroup
end
# Ensure that the group was actually created

View File

@ -9,7 +9,7 @@ RSpec.describe Pajamas::ButtonComponent, type: :component do
let(:content) { "Button content" }
let(:options) { {} }
describe 'basic usage' do
RSpec.shared_examples 'basic button behavior' do
before do
render_inline(subject) do |c|
content
@ -59,7 +59,7 @@ RSpec.describe Pajamas::ButtonComponent, type: :component do
describe 'disabled' do
context 'by default (false)' do
it 'does not have disabled styling and behavior' do
expect(page).not_to have_css ".disabled[disabled='disabled'][aria-disabled='true']"
expect(page).not_to have_css ".disabled[disabled][aria-disabled]"
end
end
@ -67,7 +67,7 @@ RSpec.describe Pajamas::ButtonComponent, type: :component do
let(:options) { { disabled: true } }
it 'has disabled styling and behavior' do
expect(page).to have_css ".disabled[disabled='disabled'][aria-disabled='true']"
expect(page).to have_css ".disabled[disabled][aria-disabled]"
end
end
end
@ -75,7 +75,7 @@ RSpec.describe Pajamas::ButtonComponent, type: :component do
describe 'loading' do
context 'by default (false)' do
it 'is not disabled' do
expect(page).not_to have_css ".disabled[disabled='disabled']"
expect(page).not_to have_css ".disabled[disabled]"
end
it 'does not render a spinner' do
@ -87,7 +87,7 @@ RSpec.describe Pajamas::ButtonComponent, type: :component do
let(:options) { { loading: true } }
it 'is disabled' do
expect(page).to have_css ".disabled[disabled='disabled']"
expect(page).to have_css ".disabled[disabled]"
end
it 'renders a spinner' do
@ -218,9 +218,13 @@ RSpec.describe Pajamas::ButtonComponent, type: :component do
end
end
end
end
context 'button component renders a button' do
include_examples 'basic button behavior'
describe 'type' do
context 'by default (without href)' do
context 'by default' do
it 'has type "button"' do
expect(page).to have_css "button[type='button']"
end
@ -238,34 +242,42 @@ RSpec.describe Pajamas::ButtonComponent, type: :component do
end
end
context 'when set to unkown type' do
context 'when set to unknown type' do
let(:options) { { type: :madeup } }
it 'has type "button"' do
expect(page).to have_css "button[type='button']"
end
end
end
end
context 'for links (with href)' do
let(:options) { { href: 'https://example.com', type: :reset } }
context 'button component renders a link' do
let(:options) { { href: 'https://gitlab.com', target: '_blank' } }
it 'ignores type' do
expect(page).not_to have_css "[type]"
end
it "renders a link instead of the button" do
expect(page).not_to have_css "button[type='button']"
expect(page).to have_css "a[href='https://gitlab.com'][target='_blank']"
end
include_examples 'basic button behavior'
describe 'type' do
let(:options) { { href: 'https://example.com', type: :reset } }
it 'ignores type' do
expect(page).not_to have_css "[type]"
end
end
describe 'link button' do
it 'renders a button tag with type="button" when "href" is not set' do
expect(page).to have_css "button[type='button']"
end
describe 'method' do
where(:method) { [:get, :post, :put, :delete, :patch] }
context 'when "href" is provided' do
let(:options) { { href: 'https://gitlab.com', target: '_blank' } }
let(:options) { { href: 'https://gitlab.com', method: method } }
it "renders a link instead of the button" do
expect(page).not_to have_css "button[type='button']"
expect(page).to have_css "a[href='https://gitlab.com'][target='_blank']"
with_them do
it 'has the correct data-method attribute' do
expect(page).to have_css "a[data-method='#{method}']"
end
end
end

View File

@ -84,7 +84,7 @@ RSpec.describe 'Group show page' do
it 'shows `Create new subgroup` link' do
expect(page).to have_link(
s_('GroupsEmptyState|Create new subgroup'),
href: new_group_path(parent_id: group.id)
href: new_group_path(parent_id: group.id, anchor: 'create-group-pane')
)
end

View File

@ -221,14 +221,13 @@ RSpec.describe 'Group' do
let(:user) { create(:admin) }
before do
visit new_group_path(parent_id: group.id)
visit new_group_path(parent_id: group.id, anchor: 'create-group-pane')
end
context 'when admin mode is enabled', :enable_admin_mode do
it 'creates a nested group' do
click_link 'Create group'
fill_in 'Group name', with: 'bar'
click_button 'Create group'
fill_in 'Subgroup name', with: 'bar'
click_button 'Create subgroup'
expect(page).to have_current_path(group_path('foo/bar'), ignore_query: true)
expect(page).to have_selector 'h1', text: 'bar'
@ -237,7 +236,7 @@ RSpec.describe 'Group' do
context 'when admin mode is disabled' do
it 'is not allowed' do
expect(page).not_to have_button('Create group')
expect(page).not_to have_button('Create subgroup')
end
end
end
@ -250,11 +249,10 @@ RSpec.describe 'Group' do
sign_out(:user)
sign_in(user)
visit new_group_path(parent_id: group.id)
click_link 'Create group'
visit new_group_path(parent_id: group.id, anchor: 'create-group-pane')
fill_in 'Group name', with: 'bar'
click_button 'Create group'
fill_in 'Subgroup name', with: 'bar'
click_button 'Create subgroup'
expect(page).to have_current_path(group_path('foo/bar'), ignore_query: true)
expect(page).to have_selector 'h1', text: 'bar'
@ -268,7 +266,7 @@ RSpec.describe 'Group' do
end
context 'when creating subgroup' do
let(:path) { new_group_path(parent_id: group.id) }
let(:path) { new_group_path(parent_id: group.id, anchor: 'create-group-pane') }
it 'does not render recaptcha' do
visit path
@ -278,24 +276,50 @@ RSpec.describe 'Group' do
end
end
context 'when many parent groups are available' do
let_it_be(:group2) { create(:group, path: 'foo2') }
let_it_be(:group3) { create(:group, path: 'foo3') }
before do
group.add_owner(user)
group2.add_maintainer(user)
group3.add_developer(user)
visit new_group_path(parent_id: group.id, anchor: 'create-group-pane')
end
it 'creates private subgroup' do
fill_in 'Subgroup name', with: 'bar'
click_button 'foo'
expect(page).to have_css('[data-testid="select_group_dropdown_item"]', text: 'foo2')
expect(page).not_to have_css('[data-testid="select_group_dropdown_item"]', text: 'foo3')
click_button 'foo2'
click_button 'Create subgroup'
expect(page).to have_current_path(group_path('foo2/bar'), ignore_query: true)
expect(page).to have_selector('h1', text: 'bar')
expect(page).to have_selector('.visibility-icon [data-testid="lock-icon"]')
end
end
describe 'real-time group url validation', :js do
let_it_be(:subgroup) { create(:group, path: 'sub', parent: group) }
before do
group.add_owner(user)
visit new_group_path(parent_id: group.id)
click_link 'Create group'
visit new_group_path(parent_id: group.id, anchor: 'create-group-pane')
end
it 'shows a message if group url is available' do
fill_in 'Group URL', with: group.path
fill_in 'Subgroup slug', with: group.path
wait_for_requests
expect(page).to have_content('Group path is available')
end
it 'shows an error if group url is taken' do
fill_in 'Group URL', with: subgroup.path
fill_in 'Subgroup slug', with: subgroup.path
wait_for_requests
expect(page).to have_content("Group path is unavailable. Path has been replaced with a suggested available path.")
@ -308,7 +332,7 @@ RSpec.describe 'Group' do
sign_out(:user)
sign_in(create(:user))
visit new_group_path(parent_id: group.id)
visit new_group_path(parent_id: group.id, anchor: 'create-group-pane')
expect(page).to have_title('Not Found')
expect(page).to have_content('Page Not Found')

View File

@ -394,7 +394,7 @@ RSpec.describe 'Pipeline', :js do
expect(page).to have_selector('button[aria-label="Cancel downstream pipeline"]')
end
context 'when canceling' do
context 'when canceling', :sidekiq_inline do
before do
find('button[aria-label="Cancel downstream pipeline"]').click
wait_for_requests

View File

@ -132,10 +132,10 @@ RSpec.describe 'User page' do
let_it_be(:followee) { create(:user) }
let_it_be(:follower) { create(:user) }
it 'does not show link to follow' do
it 'does not show button to follow' do
subject
expect(page).not_to have_link(text: 'Follow', class: 'gl-button')
expect(page).not_to have_button(text: 'Follow', class: 'gl-button')
end
it 'shows 0 followers and 0 following' do
@ -155,11 +155,11 @@ RSpec.describe 'User page' do
expect(page).to have_content('1 following')
end
it 'does show link to follow' do
it 'does show button to follow' do
sign_in(user)
visit user_path(followee)
expect(page).to have_link(text: 'Follow', class: 'gl-button')
expect(page).to have_button(text: 'Follow', class: 'gl-button')
end
it 'does show link to unfollow' do
@ -168,7 +168,7 @@ RSpec.describe 'User page' do
visit user_path(followee)
expect(page).to have_link(text: 'Unfollow', class: 'gl-button')
expect(page).to have_button(text: 'Unfollow', class: 'gl-button')
end
end
end

View File

@ -1,18 +1,23 @@
import { nextTick } from 'vue';
import Vue, { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import { merge } from 'lodash';
import { GlAlert } from '@gitlab/ui';
import { GlAlert, GlDropdown, GlTruncate, GlDropdownItem } from '@gitlab/ui';
import { mountExtended, extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
import GroupNameAndPath from '~/groups/components/group_name_and_path.vue';
import { getGroupPathAvailability } from '~/rest_api';
import { createAlert } from '~/flash';
import { helpPagePath } from '~/helpers/help_page_helper';
import searchGroupsWhereUserCanCreateSubgroups from '~/groups/queries/search_groups_where_user_can_create_subgroups.query.graphql';
jest.mock('~/flash');
jest.mock('~/rest_api', () => ({
getGroupPathAvailability: jest.fn(),
}));
Vue.use(VueApollo);
describe('GroupNameAndPath', () => {
let wrapper;
@ -20,6 +25,17 @@ describe('GroupNameAndPath', () => {
const mockGroupUrl = 'my-awesome-group';
const mockGroupUrlSuggested = 'my-awesome-group1';
const mockQueryResponse = jest.fn().mockResolvedValue({
data: {
currentUser: {
id: '1',
groups: {
nodes: [{ id: '2', fullPath: '/path2' }],
},
},
},
});
const defaultProvide = {
basePath: 'http://gitlab.com/',
fields: {
@ -32,13 +48,20 @@ describe('GroupNameAndPath', () => {
pattern: '[a-zA-Z0-9_\\.][a-zA-Z0-9_\\-\\.]*[a-zA-Z0-9_\\-]|[a-zA-Z0-9_]',
},
parentId: { name: 'group[parent_id]', id: 'group_parent_id', value: '1' },
parentFullPath: { name: 'group[parent_full_path]', id: 'group_full_path', value: '/path1' },
groupId: { name: 'group[id]', id: 'group_id', value: '' },
},
newSubgroup: false,
mattermostEnabled: false,
};
const createComponent = ({ provide = {} } = {}) => {
wrapper = mountExtended(GroupNameAndPath, { provide: merge({}, defaultProvide, provide) });
wrapper = mountExtended(GroupNameAndPath, {
provide: merge({}, defaultProvide, provide),
apolloProvider: createMockApollo([
[searchGroupsWhereUserCanCreateSubgroups, mockQueryResponse],
]),
});
};
const createComponentEditGroup = ({ path = mockGroupUrl } = {}) => {
createComponent({
@ -46,8 +69,11 @@ describe('GroupNameAndPath', () => {
});
};
const findGroupNameField = () => wrapper.findByLabelText(GroupNameAndPath.i18n.inputs.name.label);
const findGroupUrlField = () => wrapper.findByLabelText(GroupNameAndPath.i18n.inputs.path.label);
const findGroupNameField = () => wrapper.findByLabelText('Group name');
const findGroupUrlField = () => wrapper.findByLabelText('Group URL');
const findSubgroupNameField = () => wrapper.findByLabelText('Subgroup name');
const findSubgroupSlugField = () => wrapper.findByLabelText('Subgroup slug');
const findSelectedGroup = () => wrapper.findComponent(GlTruncate);
const findAlert = () => extendedWrapper(wrapper.findComponent(GlAlert));
const apiMockAvailablePath = () => {
@ -79,6 +105,41 @@ describe('GroupNameAndPath', () => {
});
});
describe('when creating a new subgroup', () => {
beforeEach(() => {
createComponent({ provide: { newSubgroup: true } });
});
it('updates `Subgroup slug` field as user types', async () => {
await findSubgroupNameField().setValue(mockGroupName);
expect(findSubgroupSlugField().element.value).toBe(mockGroupUrl);
});
describe('when user selects parent group', () => {
it('updates `Subgroup URL` dropdown and calls API', async () => {
expect(findSelectedGroup().text()).toContain('/path1');
await findSubgroupNameField().setValue(mockGroupName);
wrapper.findComponent(GlDropdown).vm.$emit('shown');
await wrapper.vm.$apollo.queries.currentUserGroups.refetch();
jest.runOnlyPendingTimers();
await waitForPromises();
wrapper.findComponent(GlDropdownItem).vm.$emit('click');
await nextTick();
expect(findSelectedGroup().text()).toContain('/path2');
expect(getGroupPathAvailability).toHaveBeenCalled();
expect(wrapper.findByText(GroupNameAndPath.i18n.inputs.path.validFeedback).exists()).toBe(
true,
);
});
});
});
describe('when editing a group', () => {
it('does not update `Group URL` field and does not call API', async () => {
const groupUrl = 'foo-bar';
@ -346,9 +407,7 @@ describe('GroupNameAndPath', () => {
it('shows `Group ID` field', () => {
createComponentEditGroup();
expect(
wrapper.findByLabelText(GroupNameAndPath.i18n.inputs.groupId.label).element.value,
).toBe('1');
expect(wrapper.findByLabelText('Group ID').element.value).toBe('1');
});
});
});

View File

@ -0,0 +1,39 @@
import { shallowMount } from '@vue/test-utils';
import App from '~/pages/groups/new/components/app.vue';
import NewNamespacePage from '~/vue_shared/new_namespace/new_namespace_page.vue';
describe('App component', () => {
let wrapper;
const createComponent = (propsData = {}) => {
wrapper = shallowMount(App, { propsData });
};
const findNewNamespacePage = () => wrapper.findComponent(NewNamespacePage);
const findCreateGroupPanel = () =>
findNewNamespacePage()
.props('panels')
.find((panel) => panel.name === 'create-group-pane');
afterEach(() => {
wrapper.destroy();
});
it('creates correct component for group creation', () => {
createComponent();
expect(findNewNamespacePage().props('initialBreadcrumb')).toBe('New group');
expect(findCreateGroupPanel().title).toBe('Create group');
});
it('creates correct component for subgroup creation', () => {
const props = { parentGroupName: 'parent', importExistingGroupPath: '/path' };
createComponent(props);
expect(findNewNamespacePage().props('initialBreadcrumb')).toBe('parent');
expect(findCreateGroupPanel().title).toBe('Create subgroup');
expect(findCreateGroupPanel().detailProps).toEqual(props);
});
});

View File

@ -0,0 +1,57 @@
import { shallowMount } from '@vue/test-utils';
import { GlSprintf, GlLink } from '@gitlab/ui';
import CreateGroupDescriptionDetails from '~/pages/groups/new/components/create_group_description_details.vue';
import { helpPagePath } from '~/helpers/help_page_helper';
describe('CreateGroupDescriptionDetails component', () => {
let wrapper;
const createComponent = (propsData = {}) => {
wrapper = shallowMount(CreateGroupDescriptionDetails, {
propsData,
stubs: { GlSprintf, GlLink },
});
};
const findLinkHref = (at) => wrapper.findAllComponents(GlLink).at(at);
afterEach(() => {
wrapper.destroy();
});
it('creates correct component for group creation', () => {
createComponent();
const groupsLink = findLinkHref(0);
expect(groupsLink.attributes('href')).toBe(helpPagePath('user/group/index'));
expect(groupsLink.text()).toBe('Groups');
const subgroupsLink = findLinkHref(1);
expect(subgroupsLink.text()).toBe('subgroups');
expect(subgroupsLink.attributes('href')).toBe(helpPagePath('user/group/subgroups/index'));
expect(wrapper.text()).toBe(
'Groups allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects. Groups can also be nested by creating subgroups.',
);
});
it('creates correct component for subgroup creation', () => {
createComponent({ parentGroupName: 'parent', importExistingGroupPath: '/path' });
const groupsLink = findLinkHref(0);
expect(groupsLink.attributes('href')).toBe(helpPagePath('user/group/index'));
expect(groupsLink.text()).toBe('Groups');
const subgroupsLink = findLinkHref(1);
expect(subgroupsLink.text()).toBe('subgroups');
expect(subgroupsLink.attributes('href')).toBe(helpPagePath('user/group/subgroups/index'));
const importGroupLink = findLinkHref(2);
expect(importGroupLink.text()).toBe('import an existing group');
expect(importGroupLink.attributes('href')).toBe('/path');
expect(wrapper.text()).toBe(
'Groups and subgroups allow you to manage and collaborate across multiple projects. Members of a group have access to all of its projects. You can also import an existing group.',
);
});
});

View File

@ -6,6 +6,7 @@ import UserPopover from '~/vue_shared/components/user_popover/user_popover.vue';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { followUser, unfollowUser } from '~/api/user_api';
import { mockTracking } from 'helpers/tracking_helper';
jest.mock('~/flash');
jest.mock('~/api/user_api', () => ({
@ -51,6 +52,18 @@ describe('User Popover Component', () => {
const findUserLocalTime = () => wrapper.findByTestId('user-popover-local-time');
const findToggleFollowButton = () => wrapper.findByTestId('toggle-follow-button');
const itTracksToggleFollowButtonClick = (expectedLabel) => {
it('tracks click', async () => {
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
await findToggleFollowButton().trigger('click');
expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_button', {
label: expectedLabel,
});
});
};
const createWrapper = (props = {}) => {
wrapper = mountExtended(UserPopover, {
propsData: {
@ -341,6 +354,8 @@ describe('User Popover Component', () => {
expect(wrapper.emitted().unfollow).toBeFalsy();
});
itTracksToggleFollowButtonClick('follow_from_user_popover');
describe('when an error occurs', () => {
beforeEach(() => {
followUser.mockRejectedValue({});
@ -388,6 +403,8 @@ describe('User Popover Component', () => {
expect(wrapper.emitted().unfollow.length).toBe(1);
});
itTracksToggleFollowButtonClick('unfollow_from_user_popover');
describe('when an error occurs', () => {
beforeEach(async () => {
unfollowUser.mockRejectedValue({});

View File

@ -452,9 +452,31 @@ RSpec.describe GroupsHelper do
end
end
describe '#group_name_and_path_app_data' do
let_it_be(:group) { build(:group, name: 'My awesome group', path: 'my-awesome-group') }
describe '#subgroup_creation_data' do
let_it_be(:name) { 'parent group' }
let_it_be(:group) { build(:group, name: name) }
let_it_be(:subgroup) { build(:group, parent: group) }
context 'when group has a parent' do
it 'returns expected hash' do
expect(subgroup_creation_data(subgroup)).to eq({
import_existing_group_path: '/groups/new#import-group-pane',
parent_group_name: name
})
end
end
context 'when group does not have a parent' do
it 'returns expected hash' do
expect(subgroup_creation_data(group)).to eq({
import_existing_group_path: '/groups/new#import-group-pane',
parent_group_name: nil
})
end
end
end
describe '#group_name_and_path_app_data' do
let_it_be(:root_url) { 'https://gitlab.com/' }
before do
@ -464,17 +486,10 @@ RSpec.describe GroupsHelper do
context 'when group has a parent' do
it 'returns expected hash' do
expect(group_name_and_path_app_data(subgroup)).to match(
{ base_path: 'https://gitlab.com/my-awesome-group', mattermost_enabled: 'true' }
)
end
end
context 'when group does not have a parent' do
it 'returns expected hash' do
expect(group_name_and_path_app_data(group)).to match(
{ base_path: root_url, mattermost_enabled: 'true' }
)
expect(group_name_and_path_app_data).to match({
base_path: 'https://gitlab.com/',
mattermost_enabled: 'true'
})
end
end
end
@ -493,7 +508,7 @@ RSpec.describe GroupsHelper do
it 'returns expected hash' do
expect(helper.subgroups_and_projects_list_app_data(group)).to match({
show_schema_markup: 'true',
new_subgroup_path: including("groups/new?parent_id=#{group.id}"),
new_subgroup_path: including("groups/new?parent_id=#{group.id}#create-group-pane"),
new_project_path: including("/projects/new?namespace_id=#{group.id}"),
new_subgroup_illustration: including('illustrations/subgroup-create-new-sm'),
new_project_illustration: including('illustrations/project-create-new-sm'),

View File

@ -173,7 +173,7 @@ RSpec.describe Nav::NewDropdownHelper do
menu_item: ::Gitlab::Nav::TopNavMenuItem.build(
id: 'new_subgroup',
title: 'New subgroup',
href: "/groups/new?parent_id=#{group.id}",
href: "/groups/new?parent_id=#{group.id}#create-group-pane",
data: { track_action: 'click_link_new_subgroup', track_label: 'plus_menu_dropdown' }
)
)

View File

@ -11,68 +11,4 @@ RSpec.describe Emails::AdminNotification do
expect(Notify).to be_respond_to(email_method)
end
end
describe 'user_auto_banned_email' do
let_it_be(:admin) { create(:user) }
let_it_be(:user) { create(:user) }
let(:max_project_downloads) { 5 }
let(:time_period) { 600 }
let(:group) { nil }
subject do
Notify.user_auto_banned_email(
admin.id, user.id,
max_project_downloads: max_project_downloads,
within_seconds: time_period,
group: group
)
end
it_behaves_like 'an email sent from GitLab'
it_behaves_like 'it should not have Gmail Actions links'
it_behaves_like 'a user cannot unsubscribe through footer link'
it_behaves_like 'appearance header and footer enabled'
it_behaves_like 'appearance header and footer not enabled'
it 'is sent to the administrator' do
is_expected.to deliver_to admin.email
end
it 'has the correct subject' do
is_expected.to have_subject "We've detected unusual activity"
end
it 'includes the name of the user' do
is_expected.to have_body_text user.name
end
it 'includes the scope of the ban' do
is_expected.to have_body_text "banned from your GitLab instance"
end
it 'includes the reason' do
is_expected.to have_body_text "due to them downloading more than 5 project repositories within 10 minutes"
end
it 'includes a link to unban the user' do
is_expected.to have_body_text admin_users_url(filter: 'banned')
end
it 'includes a link to change the settings' do
is_expected.to have_body_text network_admin_application_settings_url(anchor: 'js-ip-limits-settings')
end
it 'includes the email reason' do
is_expected.to have_body_text %r{You're receiving this email because of your account on <a .*>localhost<\/a>}
end
context 'when scoped to a group' do
let(:group) { create(:group) }
it 'includes the scope of the ban' do
is_expected.to have_body_text "banned from your group (#{group.name})"
end
end
end
end

View File

@ -40,7 +40,7 @@ RSpec.describe 'PipelineCancel' do
expect(build).not_to be_canceled
end
it "cancels all cancelable builds from a pipeline" do
it 'cancels all cancelable builds from a pipeline', :sidekiq_inline do
build = create(:ci_build, :running, pipeline: pipeline)
post_graphql_mutation(mutation, current_user: user)

View File

@ -162,12 +162,29 @@ RSpec.describe API::IssueLinks do
end
context 'when unauthenticated' do
it 'returns 401' do
issue_link = create(:issue_link)
context 'when accessing an issue of a private project' do
it 'returns 401' do
issue_link = create(:issue_link)
perform_request(issue_link.id)
perform_request(issue_link.id)
expect(response).to have_gitlab_http_status(:unauthorized)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
# This isn't ideal, see https://gitlab.com/gitlab-org/gitlab/-/issues/364077
context 'when accessing an issue of a public project' do
let(:project) { create(:project, :public) }
let(:issue) { create(:issue, project: project) }
let(:public_issue) { create(:issue, project: project) }
it 'returns 401' do
issue_link = create(:issue_link, source: issue, target: public_issue)
perform_request(issue_link.id)
expect(response).to have_gitlab_http_status(:unauthorized)
end
end
end

View File

@ -40,7 +40,10 @@ RSpec.describe 'layouts/header/_new_dropdown' do
it 'has a "New subgroup" link' do
render
expect(rendered).to have_link('New subgroup', href: new_group_path(parent_id: group.id))
expect(rendered).to have_link(
'New subgroup',
href: new_group_path(parent_id: group.id, anchor: 'create-group-pane')
)
end
end

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::Runners::ReconcileExistingRunnerVersionsCronWorker do
subject(:worker) { described_class.new }
describe '#perform' do
context 'when scheduled by cronjob' do
it 'reschedules itself' do
expect(described_class).to(receive(:perform_in).with(a_value_between(0, 12.hours.in_seconds), false))
expect(::Ci::Runners::ReconcileExistingRunnerVersionsService).not_to receive(:new)
worker.perform
end
end
context 'when self-scheduled' do
include_examples 'an idempotent worker' do
subject(:perform) { perform_multiple(false, worker: worker) }
it 'executes the service' do
expect_next_instance_of(Ci::Runners::ReconcileExistingRunnerVersionsService) do |service|
expect(service).to receive(:execute).and_return({})
end.exactly(worker_exec_times)
perform
end
end
it 'logs the service result' do
expect_next_instance_of(Ci::Runners::ReconcileExistingRunnerVersionsService) do |service|
expect(service).to receive(:execute).and_return({ some_job_result_key: 'some_value' })
end
worker.perform(false)
expect(worker.logging_extras).to eq({
'extra.ci_runners_reconcile_existing_runner_versions_cron_worker.some_job_result_key' => 'some_value'
})
end
end
end
end

View File

@ -19,6 +19,10 @@ mapping:
- source: ee/lib/(.+)\.rb
test: ee/spec/lib/%s_spec.rb
# See https://gitlab.com/gitlab-org/gitlab/-/issues/368628
- source: lib/gitlab/usage_data_counters/(.+)\.rb
test: spec/lib/gitlab/usage_data_spec.rb
# FOSS lib & tooling should map to respective spec
- source: (tooling/)?lib/(.+)\.rb
test: spec/%slib/%s_spec.rb

502
yarn.lock
View File

@ -1607,11 +1607,6 @@
"@sentry/types" "5.30.0"
tslib "^1.9.3"
"@sindresorhus/is@^0.14.0":
version "0.14.0"
resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea"
integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
"@sinonjs/commons@^1.7.0":
version "1.8.1"
resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.1.tgz#e7df00f98a203324f6dc7cc606cad9d4a8ab2217"
@ -1631,13 +1626,6 @@
resolved "https://registry.yarnpkg.com/@sourcegraph/code-host-integration/-/code-host-integration-0.0.60.tgz#2043877fabb7eb986fcb61b67ee480afbb29f4f0"
integrity sha512-T+MvM8SUF7daA279hyQgwmva3J5LvPqwgQ/mWwxdVshehOQIPLUd310I0c6x6nZ0F/x4UjDWgRWzAqy6NLwV1w==
"@szmarczak/http-timer@^1.1.2":
version "1.1.2"
resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421"
integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==
dependencies:
defer-to-connect "^1.0.1"
"@testing-library/dom@^7.16.2":
version "7.24.5"
resolved "https://registry.yarnpkg.com/@testing-library/dom/-/dom-7.24.5.tgz#862124eec8c37ad184716379f09742476b23815d"
@ -2628,13 +2616,6 @@ ajv@^8.0.0, ajv@^8.0.1, ajv@^8.10.0, ajv@^8.8.0:
require-from-string "^2.0.2"
uri-js "^4.2.2"
ansi-align@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb"
integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==
dependencies:
string-width "^3.0.0"
ansi-colors@^4.1.1:
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
@ -2653,9 +2634,9 @@ ansi-html-community@^0.0.8:
integrity sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==
ansi-regex@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
version "4.1.1"
resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed"
integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==
ansi-regex@^5.0.0, ansi-regex@^5.0.1:
version "5.0.1"
@ -3131,20 +3112,6 @@ bootstrap@4.5.3, "bootstrap@>=4.5.3 <5.0.0":
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.5.3.tgz#c6a72b355aaf323920be800246a6e4ef30997fe6"
integrity sha512-o9ppKQioXGqhw8Z7mah6KdTYpNQY//tipnkxppWhPbiSWdD+1raYsnhwEZjkTHYbGee4cVQ0Rx65EhOY/HNLcQ==
boxen@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64"
integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==
dependencies:
ansi-align "^3.0.0"
camelcase "^5.3.1"
chalk "^3.0.0"
cli-boxes "^2.2.0"
string-width "^4.1.0"
term-size "^2.1.0"
type-fest "^0.8.1"
widest-line "^3.1.0"
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@ -3385,19 +3352,6 @@ cache-loader@^4.1.0:
neo-async "^2.6.1"
schema-utils "^2.0.0"
cacheable-request@^6.0.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912"
integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==
dependencies:
clone-response "^1.0.2"
get-stream "^5.1.0"
http-cache-semantics "^4.0.0"
keyv "^3.0.0"
lowercase-keys "^2.0.0"
normalize-url "^4.1.0"
responselike "^1.0.2"
call-bind@^1.0.0, call-bind@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c"
@ -3473,14 +3427,6 @@ chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.1, chalk@^2.4.2:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
chalk@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4"
integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==
dependencies:
ansi-styles "^4.1.0"
supports-color "^7.1.0"
chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
@ -3528,7 +3474,7 @@ cheerio@^1.0.0-rc.9:
parse5-htmlparser2-tree-adapter "^6.0.1"
tslib "^2.2.0"
"chokidar@>=3.0.0 <4.0.0", chokidar@^2.1.8, chokidar@^3.2.2, chokidar@^3.4.1, chokidar@^3.5.3:
"chokidar@>=3.0.0 <4.0.0", chokidar@^2.1.8, chokidar@^3.4.1, chokidar@^3.5.2, chokidar@^3.5.3:
version "3.5.3"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
@ -3600,11 +3546,6 @@ clean-stack@^2.0.0:
resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b"
integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==
cli-boxes@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.0.tgz#538ecae8f9c6ca508e3c3c95b453fe93cb4c168d"
integrity sha512-gpaBrMAizVEANOpfZp/EEUixTXDyGt7DFzdK5hU+UbWt/J0lB0w20ncZj59Z9a93xHb9u12zF5BS6i9RKbtg4w==
clipboard@^2.0.0, clipboard@^2.0.8:
version "2.0.8"
resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.8.tgz#ffc6c103dd2967a83005f3f61976aa4655a4cdba"
@ -3639,13 +3580,6 @@ clone-regexp@^2.1.0:
dependencies:
is-regexp "^2.0.0"
clone-response@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b"
integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=
dependencies:
mimic-response "^1.0.0"
co@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184"
@ -3837,18 +3771,6 @@ config-chain@^1.1.12:
ini "^1.3.4"
proto-list "~1.2.1"
configstore@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96"
integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==
dependencies:
dot-prop "^5.2.0"
graceful-fs "^4.1.2"
make-dir "^3.0.0"
unique-string "^2.0.0"
write-file-atomic "^3.0.0"
xdg-basedir "^4.0.0"
confusing-browser-globals@^1.0.10:
version "1.0.10"
resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.10.tgz#30d1e7f3d1b882b25ec4933d1d1adac353d20a59"
@ -4098,11 +4020,6 @@ crypto-browserify@^3.11.0:
randombytes "^2.0.0"
randomfill "^1.0.3"
crypto-random-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5"
integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==
css-color-names@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0"
@ -4161,9 +4078,9 @@ css-values@^0.1.0:
postcss-value-parser "^3.3.0"
css-what@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.0.tgz#f0bf4f8bac07582722346ab243f6a35b512cfc47"
integrity sha512-qxyKHQvgKwzwDWC/rGbT821eJalfupxYW2qbSJSAtdSTimsr/MlaGONoNLllaUPZWf8QnbcKM/kPVYUQuEKAFA==
version "5.1.0"
resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.1.0.tgz#3f7b707aadf633baf62c2ceb8579b545bb40f7fe"
integrity sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw==
css@^2.1.0:
version "2.2.4"
@ -4773,7 +4690,7 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.9:
dependencies:
ms "2.0.0"
debug@^3.2.6, debug@^3.2.7:
debug@^3.2.7:
version "3.2.7"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
@ -4822,13 +4739,6 @@ decode-uri-component@^0.2.0:
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
decompress-response@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3"
integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
dependencies:
mimic-response "^1.0.0"
deep-equal@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
@ -4856,11 +4766,6 @@ default-gateway@^6.0.3:
dependencies:
execa "^5.0.0"
defer-to-connect@^1.0.1:
version "1.1.3"
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591"
integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==
define-lazy-prop@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f"
@ -5090,27 +4995,15 @@ domutils@^2.5.2, domutils@^2.6.0:
domelementtype "^2.2.0"
domhandler "^4.2.0"
dot-prop@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.2.0.tgz#c34ecc29556dc45f1f4c22697b6f4904e0cc4fcb"
integrity sha512-uEUyaDKoSQ1M4Oq8l45hSE26SnTxL6snNnqvK/VWx5wJhmff5z0FUVJDKDanor/6w3kzE3i7XZOk+7wC0EXr1A==
dependencies:
is-obj "^2.0.0"
dropzone@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/dropzone/-/dropzone-4.2.0.tgz#fbe7acbb9918e0706489072ef663effeef8a79f3"
integrity sha1-++esu5kY4HBkiQcu9mPv/u+KefM=
dset@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.1.tgz#07de5af7a8d03eab337ad1a8ba77fe17bba61a8c"
integrity sha512-hYf+jZNNqJBD2GiMYb+5mqOIX4R4RRHXU3qWMWYN+rqcR2/YpRL2bUHr8C8fU+5DNvqYjJ8YvMGSLuVPWU1cNg==
duplexer3@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
version "3.1.2"
resolved "https://registry.yarnpkg.com/dset/-/dset-3.1.2.tgz#89c436ca6450398396dc6538ea00abc0c54cd45a"
integrity sha512-g/M9sqy3oHe477Ar4voQxWtaPIFw1jTdKZuomOjhCcBx9nHUNn0pu6NopuFFrTh/TRZIKEj+76vLWFu9BNKk+Q==
duplexer@^0.1.2:
version "0.1.2"
@ -5191,11 +5084,6 @@ emoji-regex@^10.0.0:
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.0.0.tgz#96559e19f82231b436403e059571241d627c42b8"
integrity sha512-KmJa8l6uHi1HrBI34udwlzZY1jOEuID/ft4d8BSSEdRyap7PwBEt910453PJa5MuGvxkLqlt4Uvhu7tttFHViw==
emoji-regex@^7.0.1:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
emoji-regex@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37"
@ -5327,11 +5215,6 @@ escalade@^3.1.1:
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
escape-goat@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675"
integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
@ -6254,14 +6137,14 @@ get-stdin@~9.0.0:
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-9.0.0.tgz#3983ff82e03d56f1b2ea0d3e60325f39d703a575"
integrity sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==
get-stream@^4.0.0, get-stream@^4.1.0:
get-stream@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
dependencies:
pump "^3.0.0"
get-stream@^5.0.0, get-stream@^5.1.0:
get-stream@^5.0.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3"
integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==
@ -6332,13 +6215,6 @@ glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.2:
once "^1.3.0"
path-is-absolute "^1.0.0"
global-dirs@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.0.1.tgz#acdf3bb6685bcd55cb35e8a052266569e9469201"
integrity sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==
dependencies:
ini "^1.3.5"
global-modules@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
@ -6399,23 +6275,6 @@ good-listener@^1.2.2:
dependencies:
delegate "^3.1.2"
got@^9.6.0:
version "9.6.0"
resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85"
integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==
dependencies:
"@sindresorhus/is" "^0.14.0"
"@szmarczak/http-timer" "^1.1.2"
cacheable-request "^6.0.0"
decompress-response "^3.3.0"
duplexer3 "^0.1.4"
get-stream "^4.1.0"
lowercase-keys "^1.0.1"
mimic-response "^1.0.1"
p-cancelable "^1.0.0"
to-readable-stream "^1.0.0"
url-parse-lax "^3.0.0"
graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9, graceful-fs@^4.2.4, graceful-fs@^4.2.6:
version "4.2.10"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
@ -6579,11 +6438,6 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
has-yarn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==
has@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
@ -6725,9 +6579,9 @@ hoist-non-react-statics@^3.3.2:
react-is "^16.7.0"
hosted-git-info@^2.1.4:
version "2.8.8"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488"
integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==
version "2.8.9"
resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9"
integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==
hosted-git-info@^4.0.1:
version "4.1.0"
@ -6783,11 +6637,6 @@ htmlparser2@^6.1.0:
domutils "^2.5.2"
entities "^2.0.0"
http-cache-semantics@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390"
integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==
http-deceiver@^1.2.7:
version "1.2.7"
resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
@ -6924,10 +6773,10 @@ immediate@~3.0.5:
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
immer@^7.0.7:
version "7.0.7"
resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.7.tgz#9dfe713d49bf871cc59aedfce59b1992fa37a977"
integrity sha512-Q8yYwVADJXrNfp1ZUAh4XDHkcoE3wpdpb4mC5abDSajs2EbW8+cGdPyAnglMyLnm7EF6ojD2xBFX7L5i4TIytw==
immer@^9.0.15:
version "9.0.15"
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.15.tgz#0b9169e5b1d22137aba7d43f8a81a495dd1b62dc"
integrity sha512-2eB/sswms9AEUSkOm4SbV5Y7Vmt/bKRwByd52jfLkW4OLYeaTP3EEiJ9agqU0O/tq6Dk62Zfj+TJSqfm1rLVGQ==
immutable@^4.0.0:
version "4.1.0"
@ -6942,11 +6791,6 @@ import-fresh@^3.0.0, import-fresh@^3.2.1:
parent-module "^1.0.0"
resolve-from "^4.0.0"
import-lazy@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
import-lazy@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-4.0.0.tgz#e8eb627483a0a43da3c03f3e35548be5cb0cc153"
@ -7003,7 +6847,7 @@ inherits@2.0.3:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
ini@^1.3.4, ini@^1.3.5:
version "1.3.8"
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c"
integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==
@ -7193,11 +7037,6 @@ is-extglob@^2.1.1:
resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
is-fullwidth-code-point@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
is-fullwidth-code-point@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d"
@ -7215,24 +7054,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1:
dependencies:
is-extglob "^2.1.1"
is-installed-globally@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141"
integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==
dependencies:
global-dirs "^2.0.1"
is-path-inside "^3.0.1"
is-negative-zero@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150"
integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==
is-npm@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d"
integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==
is-number-object@^1.0.4:
version "1.0.7"
resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc"
@ -7252,16 +7078,6 @@ is-number@^7.0.0:
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
is-obj@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982"
integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
is-path-inside@^3.0.1:
version "3.0.3"
resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283"
integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
@ -7372,11 +7188,6 @@ is-wsl@^2.1.1, is-wsl@^2.2.0:
dependencies:
is-docker "^2.0.0"
is-yarn-global@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232"
integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==
isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
@ -8011,11 +7822,6 @@ jsesc@~0.5.0:
resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
json-buffer@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898"
integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=
json-parse-better-errors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
@ -8036,10 +7842,10 @@ json-schema-traverse@^1.0.0:
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2"
integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==
json-schema@0.2.3:
version "0.2.3"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
json-schema@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5"
integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==
json-stable-stringify-without-jsonify@^1.0.1:
version "1.0.1"
@ -8076,13 +7882,13 @@ jsonfile@^4.0.0:
graceful-fs "^4.1.6"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
version "1.4.2"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb"
integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==
dependencies:
assert-plus "1.0.0"
extsprintf "1.3.0"
json-schema "0.2.3"
json-schema "0.4.0"
verror "1.10.0"
jszip-utils@^0.0.2:
@ -8108,13 +7914,6 @@ katex@^0.13.2:
dependencies:
commander "^6.0.0"
keyv@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9"
integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==
dependencies:
json-buffer "3.0.0"
khroma@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/khroma/-/khroma-2.0.0.tgz#7577de98aed9f36c7a474c4d453d94c0d6c6588b"
@ -8173,13 +7972,6 @@ known-css-properties@^0.25.0:
resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.25.0.tgz#6ebc4d4b412f602e5cfbeb4086bd544e34c0a776"
integrity sha512-b0/9J1O9Jcyik1GC6KC42hJ41jKwdO/Mq8Mdo5sYN+IuRTXs2YFHZC3kZSx6ueusqa95x3wLYe/ytKjbAfGixA==
latest-version@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face"
integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==
dependencies:
package-json "^6.3.0"
leven@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
@ -8428,16 +8220,6 @@ loose-envify@^1.4.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
lowercase-keys@^1.0.0, lowercase-keys@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
lowercase-keys@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479"
integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==
lowlight@^1.20.0:
version "1.20.0"
resolved "https://registry.yarnpkg.com/lowlight/-/lowlight-1.20.0.tgz#ddb197d33462ad0d93bf19d17b6c301aa3941888"
@ -9174,11 +8956,6 @@ mimic-fn@^2.1.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
mimic-response@^1.0.0, mimic-response@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b"
integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==
min-document@^2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685"
@ -9520,9 +9297,9 @@ node-modules-regexp@^1.0.0:
integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=
node-notifier@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.0.tgz#a7eee2d51da6d0f7ff5094bc7108c911240c1620"
integrity sha512-46z7DUmcjoYdaWyXouuFNNfUo6eFa94t23c53c+lG/9Cvauk4a98rAUp9672X5dxGdQmLpPzTxzu8f/OeEPaFA==
version "8.0.2"
resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-8.0.2.tgz#f3167a38ef0d2c8a866a83e318c1ba0efeb702c5"
integrity sha512-oJP/9NAdd9+x2Q+rfphB2RJCHjod70RcRLjosiPMMu5gjIfwVnOUGq2nbTjTUbmy0DJ/tFIVT30+Qe3nzl4TJg==
dependencies:
growly "^1.3.0"
is-wsl "^2.2.0"
@ -9536,21 +9313,21 @@ node-releases@^2.0.3:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.5.tgz#280ed5bc3eba0d96ce44897d8aee478bfb3d9666"
integrity sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==
nodemon@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416"
integrity sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==
nodemon@^2.0.19:
version "2.0.19"
resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.19.tgz#cac175f74b9cb8b57e770d47841995eebe4488bd"
integrity sha512-4pv1f2bMDj0Eeg/MhGqxrtveeQ5/G/UVe9iO6uTZzjnRluSA4PVWf8CW99LUPwGB3eNIA7zUFoP77YuI7hOc0A==
dependencies:
chokidar "^3.2.2"
debug "^3.2.6"
chokidar "^3.5.2"
debug "^3.2.7"
ignore-by-default "^1.0.1"
minimatch "^3.0.4"
pstree.remy "^1.1.7"
pstree.remy "^1.1.8"
semver "^5.7.1"
simple-update-notifier "^1.0.7"
supports-color "^5.5.0"
touch "^3.1.0"
undefsafe "^2.0.2"
update-notifier "^4.0.0"
undefsafe "^2.0.5"
nopt@^4.0.3:
version "4.0.3"
@ -9599,11 +9376,6 @@ normalize-path@^3.0.0, normalize-path@~3.0.0:
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
normalize-url@^4.1.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.0.tgz#453354087e6ca96957bd8f5baf753f5982142129"
integrity sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==
npm-run-path@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
@ -9814,11 +9586,6 @@ osenv@^0.1.4:
os-homedir "^1.0.0"
os-tmpdir "^1.0.0"
p-cancelable@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc"
integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==
p-each-series@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48"
@ -9896,16 +9663,6 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
package-json@^6.3.0:
version "6.5.0"
resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0"
integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==
dependencies:
got "^9.6.0"
registry-auth-token "^4.0.0"
registry-url "^5.0.0"
semver "^6.2.0"
pako@~1.0.2, pako@~1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
@ -10243,11 +10000,6 @@ prelude-ls@~1.1.2:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
prepend-http@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897"
integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=
pretender@^3.4.3:
version "3.4.3"
resolved "https://registry.yarnpkg.com/pretender/-/pretender-3.4.3.tgz#a3b4160516007075d29127262f3a0063d19896e9"
@ -10495,7 +10247,7 @@ psl@^1.1.28:
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
pstree.remy@^1.1.7:
pstree.remy@^1.1.8:
version "1.1.8"
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a"
integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==
@ -10546,13 +10298,6 @@ punycode@^2.1.0, punycode@^2.1.1:
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
pupa@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.0.1.tgz#dbdc9ff48ffbea4a26a069b6f9f7abb051008726"
integrity sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==
dependencies:
escape-goat "^2.0.0"
purgecss-from-html@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/purgecss-from-html/-/purgecss-from-html-4.0.3.tgz#28d86d3dc8292581c4ab529a77a57daf7c2dd940"
@ -10646,16 +10391,6 @@ raw-loader@^4.0.2:
loader-utils "^2.0.0"
schema-utils "^3.0.0"
rc@^1.2.8:
version "1.2.8"
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
dependencies:
deep-extend "^0.6.0"
ini "~1.3.0"
minimist "^1.2.0"
strip-json-comments "~2.0.1"
react-is@^16.7.0, react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
@ -10804,20 +10539,6 @@ regexpu-core@^5.0.1:
unicode-match-property-ecmascript "^2.0.0"
unicode-match-property-value-ecmascript "^2.0.0"
registry-auth-token@^4.0.0:
version "4.1.1"
resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.1.1.tgz#40a33be1e82539460f94328b0f7f0f84c16d9479"
integrity sha512-9bKS7nTl9+/A1s7tnPeGrUpRcVY+LUh7bfFgzpndALdPfXQBfQV77rQVtqgUV3ti4vc/Ik81Ex8UJDWDQ12zQA==
dependencies:
rc "^1.2.8"
registry-url@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009"
integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==
dependencies:
rc "^1.2.8"
regjsgen@^0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.6.0.tgz#83414c5354afd7d6627b16af5f10f41c4e71808d"
@ -10988,13 +10709,6 @@ resolve@^1.10.0, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.2
path-parse "^1.0.7"
supports-preserve-symlinks-flag "^1.0.0"
responselike@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=
dependencies:
lowercase-keys "^1.0.0"
ret@~0.1.10:
version "0.1.15"
resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
@ -11225,24 +10939,17 @@ selfsigned@^2.0.1:
dependencies:
node-forge "^1"
semver-diff@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b"
integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==
dependencies:
semver "^6.3.0"
"semver@2 || 3 || 4 || 5", semver@^5.5.0, semver@^5.6.0, semver@^5.7.1:
version "5.7.1"
resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
semver@7.0.0:
semver@7.0.0, semver@~7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.0.0.tgz#5f3ca35761e47e05b206c6daff2cf814f0316b8e"
integrity sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.2.0, semver@^6.3.0:
semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
@ -11415,6 +11122,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9"
integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==
simple-update-notifier@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/simple-update-notifier/-/simple-update-notifier-1.0.7.tgz#7edf75c5bdd04f88828d632f762b2bc32996a9cc"
integrity sha512-BBKgR84BJQJm6WjWFMHgLVuo61FBDSj1z/xSFUIozqO6wO7ii0JxCqlIud7Enr/+LhlbNI0whErq96P2qHNWew==
dependencies:
semver "~7.0.0"
sirv@^1.0.7:
version "1.0.11"
resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.11.tgz#81c19a29202048507d6ec0d8ba8910fda52eb5a4"
@ -11632,16 +11346,16 @@ sshpk@^1.7.0:
tweetnacl "~0.14.0"
ssri@^6.0.1:
version "6.0.1"
resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
version "6.0.2"
resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5"
integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==
dependencies:
figgy-pudding "^3.5.1"
ssri@^8.0.0:
version "8.0.0"
resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.0.tgz#79ca74e21f8ceaeddfcb4b90143c458b8d988808"
integrity sha512-aq/pz989nxVYwn16Tsbj1TqFpD5LLrQxHf5zaHuieFV+R0Bbr4y8qUsOA45hXT/N4/9UNXTarBjnjVmjSOVaAA==
version "8.0.1"
resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af"
integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==
dependencies:
minipass "^3.1.1"
@ -11720,16 +11434,7 @@ string-length@^4.0.1:
char-regex "^1.0.2"
strip-ansi "^6.0.0"
string-width@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
dependencies:
emoji-regex "^7.0.1"
is-fullwidth-code-point "^2.0.0"
strip-ansi "^5.1.0"
string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010"
integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==
@ -11768,7 +11473,7 @@ string_decoder@~0.10.x:
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94"
integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=
strip-ansi@^5.1.0, strip-ansi@^5.2.0:
strip-ansi@^5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
@ -12018,11 +11723,6 @@ tar@^6.0.2:
mkdirp "^1.0.3"
yallist "^4.0.0"
term-size@^2.1.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.0.tgz#1f16adedfe9bdc18800e1776821734086fcc6753"
integrity sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==
terminal-link@^2.0.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994"
@ -12047,9 +11747,9 @@ terser-webpack-plugin@^1.4.3:
worker-farm "^1.7.0"
terser@^4.1.2:
version "4.3.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.3.1.tgz#09820bcb3398299c4b48d9a86aefc65127d0ed65"
integrity sha512-pnzH6dnFEsR2aa2SJaKb1uSCl3QmIsJ8dEkj0Fky+2AwMMcC9doMqLOQIH6wVTEKaVfKVvLSk5qxPBEZT9mywg==
version "4.8.1"
resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.1.tgz#a00e5634562de2239fd404c649051bf6fc21144f"
integrity sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==
dependencies:
commander "^2.20.0"
source-map "~0.6.1"
@ -12149,9 +11849,9 @@ tmp@^0.0.33:
os-tmpdir "~1.0.2"
tmpl@1.0.x:
version "1.0.4"
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=
version "1.0.5"
resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc"
integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==
to-arraybuffer@^1.0.0:
version "1.0.1"
@ -12170,11 +11870,6 @@ to-object-path@^0.3.0:
dependencies:
kind-of "^3.0.2"
to-readable-stream@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771"
integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==
to-regex-range@^2.1.0:
version "2.1.1"
resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
@ -12408,12 +12103,10 @@ unbox-primitive@^1.0.2:
has-symbols "^1.0.3"
which-boxed-primitive "^1.0.2"
undefsafe@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76"
integrity sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=
dependencies:
debug "^2.2.0"
undefsafe@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c"
integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==
underscore-contrib@~0.3.0:
version "0.3.0"
@ -12433,9 +12126,9 @@ underscore@~1.8.3:
integrity sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=
undici@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/undici/-/undici-5.0.0.tgz#3c1e08c7f0df90c485d5d8dbb0517e11e34f2090"
integrity sha512-VhUpiZ3No1DOPPQVQnsDZyfcbTTcHdcgWej1PdFnSvOeJmOVDgiOHkunJmBLfmjt4CqgPQddPVjSWW0dsTs5Yg==
version "5.8.0"
resolved "https://registry.yarnpkg.com/undici/-/undici-5.8.0.tgz#dec9a8ccd90e5a1d81d43c0eab6503146d649a4f"
integrity sha512-1F7Vtcez5w/LwH2G2tGnFIihuWUlc58YidwLiCv+jR2Z50x0tNXpRRw7eOIJ+GvqCqIkg9SB7NWAJ/T9TLfv8Q==
unicode-canonical-property-names-ecmascript@^2.0.0:
version "2.0.0"
@ -12497,13 +12190,6 @@ unique-slug@^2.0.0:
dependencies:
imurmurhash "^0.1.4"
unique-string@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d"
integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==
dependencies:
crypto-random-string "^2.0.0"
unist-builder@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/unist-builder/-/unist-builder-3.0.0.tgz#728baca4767c0e784e1e64bb44b5a5a753021a04"
@ -12594,25 +12280,6 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
update-notifier@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.0.tgz#4866b98c3bc5b5473c020b1250583628f9a328f3"
integrity sha512-w3doE1qtI0/ZmgeoDoARmI5fjDoT93IfKgEGqm26dGUOh8oNpaSTsGNdYRN/SjOuo10jcJGwkEL3mroKzktkew==
dependencies:
boxen "^4.2.0"
chalk "^3.0.0"
configstore "^5.0.1"
has-yarn "^2.1.0"
import-lazy "^2.1.0"
is-ci "^2.0.0"
is-installed-globally "^0.3.1"
is-npm "^4.0.0"
is-yarn-global "^0.3.0"
latest-version "^5.0.0"
pupa "^2.0.1"
semver-diff "^3.1.1"
xdg-basedir "^4.0.0"
uri-js@^4.2.2:
version "4.4.1"
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
@ -12634,13 +12301,6 @@ url-loader@^4.1.1:
mime-types "^2.1.27"
schema-utils "^3.0.0"
url-parse-lax@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c"
integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=
dependencies:
prepend-http "^2.0.0"
url@0.10.3:
version "0.10.3"
resolved "https://registry.yarnpkg.com/url/-/url-0.10.3.tgz#021e4d9c7705f21bbf37d03ceb58767402774c64"
@ -13200,13 +12860,6 @@ which@^2.0.1, which@^2.0.2:
dependencies:
isexe "^2.0.0"
widest-line@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca"
integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==
dependencies:
string-width "^4.0.0"
wildcard@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
@ -13274,11 +12927,6 @@ ws@^8.3.0, ws@^8.4.2:
resolved "https://registry.yarnpkg.com/ws/-/ws-8.5.0.tgz#bfb4be96600757fe5382de12c670dab984a1ed4f"
integrity sha512-BWX0SWVgLPzYwF8lTzEy1egjhS4S4OEAHfsO8o65WOVsrnSRGaSiUaa9e0ggGlkMTtBlmOpEXiie9RUcBO86qg==
xdg-basedir@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13"
integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==
xhr-mock@^2.5.1:
version "2.5.1"
resolved "https://registry.yarnpkg.com/xhr-mock/-/xhr-mock-2.5.1.tgz#c591498a8269cc1ce5fefac20d590357affd348b"
@ -13331,9 +12979,9 @@ xterm@3.14.5:
integrity sha512-DVmQ8jlEtL+WbBKUZuMxHMBgK/yeIZwkXB81bH+MGaKKnJGYwA+770hzhXPfwEIokK9On9YIFPRleVp/5G7z9g==
y18n@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
version "4.0.3"
resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.3.tgz#b5f259c82cd6e336921efd7bfd8bf560de9eeedf"
integrity sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==
yallist@^2.1.2:
version "2.1.2"