summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/ci/rails.gitlab-ci.yml4
-rw-r--r--app/assets/javascripts/diff_notes/models/discussion.js6
-rw-r--r--app/assets/javascripts/diff_notes/stores/comments.js6
-rw-r--r--app/assets/javascripts/environments/components/container.vue2
-rw-r--r--app/assets/javascripts/environments/components/environments_table.vue2
-rw-r--r--app/assets/javascripts/error_tracking_settings/utils.js2
-rw-r--r--app/assets/javascripts/helpers/diffs_helper.js10
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js4
-rw-r--r--app/assets/javascripts/lib/utils/webpack.js2
-rw-r--r--app/assets/javascripts/merge_conflicts/merge_conflict_store.js2
-rw-r--r--app/assets/javascripts/network/branch_graph.js10
-rw-r--r--app/assets/javascripts/notes.js2
-rw-r--r--app/assets/javascripts/registry/settings/components/registry_settings_app.vue2
-rw-r--r--app/assets/javascripts/registry/settings/components/settings_form.vue207
-rw-r--r--app/assets/javascripts/registry/settings/store/getters.js13
-rw-r--r--app/assets/javascripts/registry/settings/store/mutations.js4
-rw-r--r--app/assets/javascripts/registry/settings/utils.js6
-rw-r--r--app/assets/javascripts/registry/shared/components/expiration_policy_form.vue247
-rw-r--r--app/assets/javascripts/registry/shared/constants.js (renamed from app/assets/javascripts/registry/settings/constants.js)0
-rw-r--r--app/assets/javascripts/registry/shared/utils.js19
-rw-r--r--app/assets/javascripts/users_select.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/modal_copy_button.vue2
-rw-r--r--app/assets/javascripts/webpack.js2
-rw-r--r--app/assets/javascripts/zen_mode.js6
-rw-r--r--app/helpers/button_helper.rb2
-rw-r--r--app/models/concerns/delete_with_limit.rb11
-rw-r--r--app/models/event.rb2
-rw-r--r--app/models/hooks/web_hook_log.rb2
-rw-r--r--app/models/project_services/emails_on_push_service.rb7
-rw-r--r--app/views/sherlock/queries/_general.html.haml4
-rw-r--r--app/workers/prune_old_events_worker.rb16
-rw-r--r--app/workers/prune_web_hook_logs_worker.rb17
-rw-r--r--changelogs/unreleased/198577-fix-emails-on-push.yml5
-rw-r--r--changelogs/unreleased/pedroms-change-copy-to-clipboard-icon.yml5
-rw-r--r--config/initializers/graphql.rb6
-rw-r--r--package.json2
-rw-r--r--spec/features/projects/settings/operations_settings_spec.rb2
-rw-r--r--spec/features/projects/settings/registry_settings_spec.rb10
-rw-r--r--spec/frontend/error_tracking_settings/store/getters_spec.js2
-rw-r--r--spec/frontend/ide/components/ide_status_list_spec.js2
-rw-r--r--spec/frontend/mr_popover/mr_popover_spec.js2
-rw-r--r--spec/frontend/registry/settings/components/registry_settings_app_spec.js2
-rw-r--r--spec/frontend/registry/settings/components/settings_form_spec.js217
-rw-r--r--spec/frontend/registry/settings/store/actions_spec.js13
-rw-r--r--spec/frontend/registry/settings/store/getters_spec.js4
-rw-r--r--spec/frontend/registry/settings/store/mutations_spec.js4
-rw-r--r--spec/frontend/registry/shared/components/__snapshots__/expiration_policy_form_spec.js.snap (renamed from spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap)10
-rw-r--r--spec/frontend/registry/shared/components/expiration_policy_form_spec.js237
-rw-r--r--spec/frontend/registry/shared/mock_data.js (renamed from spec/frontend/registry/settings/mock_data.js)0
-rw-r--r--spec/frontend/releases/detail/components/app_spec.js2
-rw-r--r--spec/frontend/sidebar/confidential_issue_sidebar_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/recaptcha_modal_spec.js2
-rw-r--r--spec/frontend/vue_shared/components/slot_switch_spec.js2
-rw-r--r--spec/helpers/button_helper_spec.rb2
-rw-r--r--spec/models/concerns/delete_with_limit_spec.rb15
-rw-r--r--spec/models/project_services/emails_on_push_service_spec.rb16
-rw-r--r--spec/requests/api/services_spec.rb15
-rw-r--r--yarn.lock226
58 files changed, 808 insertions, 620 deletions
diff --git a/.gitlab/ci/rails.gitlab-ci.yml b/.gitlab/ci/rails.gitlab-ci.yml
index 8c3df170f6d..6b0a7f31f1a 100644
--- a/.gitlab/ci/rails.gitlab-ci.yml
+++ b/.gitlab/ci/rails.gitlab-ci.yml
@@ -165,7 +165,7 @@ rspec-ee migration pg9:
rspec-ee unit pg9:
extends: .rspec-ee-base-pg9
- parallel: 5
+ parallel: 10
rspec-ee integration pg9:
extends: .rspec-ee-base-pg9
@@ -186,7 +186,7 @@ rspec-ee unit pg10:
extends:
- .rspec-ee-base-pg10
- .only-master
- parallel: 5
+ parallel: 10
rspec-ee integration pg10:
extends:
diff --git a/app/assets/javascripts/diff_notes/models/discussion.js b/app/assets/javascripts/diff_notes/models/discussion.js
index daf61e5d467..97296a40d6e 100644
--- a/app/assets/javascripts/diff_notes/models/discussion.js
+++ b/app/assets/javascripts/diff_notes/models/discussion.js
@@ -1,4 +1,4 @@
-/* eslint-disable camelcase, guard-for-in, no-restricted-syntax */
+/* eslint-disable guard-for-in, no-restricted-syntax */
/* global NoteModel */
import $ from 'jquery';
@@ -40,13 +40,13 @@ class DiscussionModel {
return true;
}
- resolveAllNotes(resolved_by) {
+ resolveAllNotes(resolvedBy) {
for (const noteId in this.notes) {
const note = this.notes[noteId];
if (!note.resolved) {
note.resolved = true;
- note.resolved_by = resolved_by;
+ note.resolved_by = resolvedBy;
}
}
}
diff --git a/app/assets/javascripts/diff_notes/stores/comments.js b/app/assets/javascripts/diff_notes/stores/comments.js
index 69a972f644d..9bde18c4edf 100644
--- a/app/assets/javascripts/diff_notes/stores/comments.js
+++ b/app/assets/javascripts/diff_notes/stores/comments.js
@@ -1,4 +1,4 @@
-/* eslint-disable camelcase, no-restricted-syntax, guard-for-in */
+/* eslint-disable no-restricted-syntax, guard-for-in */
/* global DiscussionModel */
import Vue from 'vue';
@@ -26,11 +26,11 @@ window.CommentsStore = {
discussion.createNote(noteObj);
},
- update(discussionId, noteId, resolved, resolved_by) {
+ update(discussionId, noteId, resolved, resolvedBy) {
const discussion = this.state[discussionId];
const note = discussion.getNote(noteId);
note.resolved = resolved;
- note.resolved_by = resolved_by;
+ note.resolved_by = resolvedBy;
},
delete(discussionId, noteId) {
const discussion = this.state[discussionId];
diff --git a/app/assets/javascripts/environments/components/container.vue b/app/assets/javascripts/environments/components/container.vue
index cdf62259479..0a978ab5869 100644
--- a/app/assets/javascripts/environments/components/container.vue
+++ b/app/assets/javascripts/environments/components/container.vue
@@ -41,7 +41,7 @@ export default {
<div class="environments-container">
<gl-loading-icon
v-if="isLoading"
- :size="3"
+ size="md"
class="prepend-top-default"
label="Loading environments"
/>
diff --git a/app/assets/javascripts/environments/components/environments_table.vue b/app/assets/javascripts/environments/components/environments_table.vue
index 30299ccc7bc..8abc927c500 100644
--- a/app/assets/javascripts/environments/components/environments_table.vue
+++ b/app/assets/javascripts/environments/components/environments_table.vue
@@ -170,7 +170,7 @@ export default {
<template v-if="shouldRenderFolderContent(model)">
<div v-if="model.isLoadingFolderContent" :key="`loading-item-${i}`">
- <gl-loading-icon :size="2" class="prepend-top-16" />
+ <gl-loading-icon size="md" class="prepend-top-16" />
</div>
<template v-else>
diff --git a/app/assets/javascripts/error_tracking_settings/utils.js b/app/assets/javascripts/error_tracking_settings/utils.js
index 6613e04ee0e..450e8728121 100644
--- a/app/assets/javascripts/error_tracking_settings/utils.js
+++ b/app/assets/javascripts/error_tracking_settings/utils.js
@@ -13,6 +13,6 @@ export const transformFrontendSettings = ({ apiHost, enabled, token, selectedPro
return { api_host: apiHost || null, enabled, token: token || null, project };
};
-export const getDisplayName = project => `${project.organizationName} | ${project.name}`;
+export const getDisplayName = project => `${project.organizationName} | ${project.slug}`;
export default () => {};
diff --git a/app/assets/javascripts/helpers/diffs_helper.js b/app/assets/javascripts/helpers/diffs_helper.js
index 9695d01ad3d..d2b8cb11fe0 100644
--- a/app/assets/javascripts/helpers/diffs_helper.js
+++ b/app/assets/javascripts/helpers/diffs_helper.js
@@ -1,9 +1,9 @@
export function hasInlineLines(diffFile) {
- return diffFile?.highlighted_diff_lines?.length > 0; /* eslint-disable-line camelcase */
+ return diffFile?.highlighted_diff_lines?.length > 0;
}
export function hasParallelLines(diffFile) {
- return diffFile?.parallel_diff_lines?.length > 0; /* eslint-disable-line camelcase */
+ return diffFile?.parallel_diff_lines?.length > 0;
}
export function isSingleViewStyle(diffFile) {
@@ -11,9 +11,5 @@ export function isSingleViewStyle(diffFile) {
}
export function hasDiff(diffFile) {
- return (
- hasInlineLines(diffFile) ||
- hasParallelLines(diffFile) ||
- !diffFile?.blob?.readable_text /* eslint-disable-line camelcase */
- );
+ return hasInlineLines(diffFile) || hasParallelLines(diffFile) || !diffFile?.blob?.readable_text;
}
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index d94dccad962..62084892d13 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -133,9 +133,9 @@ export const loadBranch = ({ dispatch, getters }, { projectId, branchId }) =>
ref: branch.commit.id,
});
})
- .catch(() => {
+ .catch(err => {
dispatch('showBranchNotFoundError', branchId);
- return Promise.reject();
+ throw err;
});
export const openBranch = ({ dispatch, state, getters }, { projectId, branchId, basePath }) => {
diff --git a/app/assets/javascripts/lib/utils/webpack.js b/app/assets/javascripts/lib/utils/webpack.js
index 37b17f0fe23..390294afcb7 100644
--- a/app/assets/javascripts/lib/utils/webpack.js
+++ b/app/assets/javascripts/lib/utils/webpack.js
@@ -8,7 +8,7 @@ export function resetServiceWorkersPublicPath() {
// see: https://webpack.js.org/guides/public-path/
const relativeRootPath = (gon && gon.relative_url_root) || '';
const webpackAssetPath = joinPaths(relativeRootPath, '/assets/webpack/');
- __webpack_public_path__ = webpackAssetPath; // eslint-disable-line camelcase
+ __webpack_public_path__ = webpackAssetPath; // eslint-disable-line babel/camelcase
// monaco-editor-webpack-plugin currently (incorrectly) references the
// public path as a property of `window`. Once this is fixed upstream we
diff --git a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js
index e7fcc183715..25c357b6073 100644
--- a/app/assets/javascripts/merge_conflicts/merge_conflict_store.js
+++ b/app/assets/javascripts/merge_conflicts/merge_conflict_store.js
@@ -1,4 +1,4 @@
-/* eslint-disable no-param-reassign, camelcase, no-nested-ternary, no-continue */
+/* eslint-disable no-param-reassign, babel/camelcase, no-nested-ternary, no-continue */
import $ from 'jquery';
import Vue from 'vue';
diff --git a/app/assets/javascripts/network/branch_graph.js b/app/assets/javascripts/network/branch_graph.js
index c301c304409..3cc95168ba1 100644
--- a/app/assets/javascripts/network/branch_graph.js
+++ b/app/assets/javascripts/network/branch_graph.js
@@ -1,4 +1,4 @@
-/* eslint-disable func-names, consistent-return, camelcase */
+/* eslint-disable func-names, consistent-return */
import $ from 'jquery';
import { __ } from '../locale';
@@ -270,14 +270,14 @@ export default class BranchGraph {
stroke: 'none',
});
- const avatar_box_x = this.offsetX + this.unitSpace * this.mspace + 10;
- const avatar_box_y = y - 10;
+ const avatarBoxX = this.offsetX + this.unitSpace * this.mspace + 10;
+ const avatarBoxY = y - 10;
- r.rect(avatar_box_x, avatar_box_y, 20, 20).attr({
+ r.rect(avatarBoxX, avatarBoxY, 20, 20).attr({
stroke: this.colors[commit.space],
'stroke-width': 2,
});
- r.image(commit.author.icon, avatar_box_x, avatar_box_y, 20, 20);
+ r.image(commit.author.icon, avatarBoxX, avatarBoxY, 20, 20);
return r
.text(this.offsetX + this.unitSpace * this.mspace + 35, y, commit.message.split('\n')[0])
.attr({
diff --git a/app/assets/javascripts/notes.js b/app/assets/javascripts/notes.js
index 5756532d18d..c01024fc2cd 100644
--- a/app/assets/javascripts/notes.js
+++ b/app/assets/javascripts/notes.js
@@ -1,4 +1,4 @@
-/* eslint-disable no-restricted-properties, camelcase,
+/* eslint-disable no-restricted-properties, babel/camelcase,
no-unused-expressions, default-case,
consistent-return, no-alert, no-param-reassign, no-else-return,
no-shadow, no-useless-escape,
diff --git a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
index 28f4ef62242..2156c4469da 100644
--- a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
+++ b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
@@ -3,7 +3,7 @@ import { mapActions, mapState } from 'vuex';
import { GlAlert } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
-import { FETCH_SETTINGS_ERROR_MESSAGE } from '../constants';
+import { FETCH_SETTINGS_ERROR_MESSAGE } from '../../shared/constants';
import SettingsForm from './settings_form.vue';
diff --git a/app/assets/javascripts/registry/settings/components/settings_form.vue b/app/assets/javascripts/registry/settings/components/settings_form.vue
index 6a617f97271..ad2fdb4fd40 100644
--- a/app/assets/javascripts/registry/settings/components/settings_form.vue
+++ b/app/assets/javascripts/registry/settings/components/settings_form.vue
@@ -1,32 +1,16 @@
<script>
import { mapActions, mapState, mapGetters } from 'vuex';
-import {
- GlFormGroup,
- GlToggle,
- GlFormSelect,
- GlFormTextarea,
- GlButton,
- GlCard,
- GlLoadingIcon,
-} from '@gitlab/ui';
-import { s__, __, sprintf } from '~/locale';
import Tracking from '~/tracking';
import {
- NAME_REGEX_LENGTH,
UPDATE_SETTINGS_ERROR_MESSAGE,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
-} from '../constants';
+} from '../../shared/constants';
import { mapComputed } from '~/vuex_shared/bindings';
+import ExpirationPolicyForm from '../../shared/components/expiration_policy_form.vue';
export default {
components: {
- GlFormGroup,
- GlToggle,
- GlFormSelect,
- GlFormTextarea,
- GlButton,
- GlCard,
- GlLoadingIcon,
+ ExpirationPolicyForm,
},
mixins: [Tracking.mixin()],
labelsConfig: {
@@ -43,59 +27,7 @@ export default {
computed: {
...mapState(['formOptions', 'isLoading']),
...mapGetters({ isEdited: 'getIsEdited' }),
- ...mapComputed(
- [
- 'enabled',
- { key: 'cadence', getter: 'getCadence' },
- { key: 'older_than', getter: 'getOlderThan' },
- { key: 'keep_n', getter: 'getKeepN' },
- 'name_regex',
- ],
- 'updateSettings',
- 'settings',
- ),
- policyEnabledText() {
- return this.enabled ? __('enabled') : __('disabled');
- },
- toggleDescriptionText() {
- return sprintf(
- s__('ContainerRegistry|Docker tag expiration policy is %{toggleStatus}'),
- {
- toggleStatus: `<strong>${this.policyEnabledText}</strong>`,
- },
- false,
- );
- },
- regexHelpText() {
- return sprintf(
- s__(
- 'ContainerRegistry|Wildcards such as %{codeStart}*-stable%{codeEnd} or %{codeStart}production/*%{codeEnd} are supported. To select all tags, use %{codeStart}.*%{codeEnd}',
- ),
- {
- codeStart: '<code>',
- codeEnd: '</code>',
- },
- false,
- );
- },
- nameRegexPlaceholder() {
- return '.*';
- },
- nameRegexState() {
- return this.name_regex ? this.name_regex.length <= NAME_REGEX_LENGTH : null;
- },
- formIsInvalid() {
- return this.nameRegexState === false;
- },
- isFormElementDisabled() {
- return !this.enabled || this.isLoading;
- },
- isSubmitButtonDisabled() {
- return this.formIsInvalid || this.isLoading;
- },
- isCancelButtonDisabled() {
- return !this.isEdited || this.isLoading;
- },
+ ...mapComputed([{ key: 'settings', getter: 'getSettings' }], 'updateSettings'),
},
methods: {
...mapActions(['resetSettings', 'saveSettings']),
@@ -114,127 +46,12 @@ export default {
</script>
<template>
- <form ref="form-element" @submit.prevent="submit" @reset.prevent="reset">
- <gl-card>
- <template #header>
- {{ s__('ContainerRegistry|Tag expiration policy') }}
- </template>
- <template>
- <gl-form-group
- id="expiration-policy-toggle-group"
- :label-cols="$options.labelsConfig.cols"
- :label-align="$options.labelsConfig.align"
- label-for="expiration-policy-toggle"
- :label="s__('ContainerRegistry|Expiration policy:')"
- >
- <div class="d-flex align-items-start">
- <gl-toggle id="expiration-policy-toggle" v-model="enabled" :disabled="isLoading" />
- <span class="mb-2 ml-1 lh-2" v-html="toggleDescriptionText"></span>
- </div>
- </gl-form-group>
-
- <gl-form-group
- id="expiration-policy-interval-group"
- :label-cols="$options.labelsConfig.cols"
- :label-align="$options.labelsConfig.align"
- label-for="expiration-policy-interval"
- :label="s__('ContainerRegistry|Expiration interval:')"
- >
- <gl-form-select
- id="expiration-policy-interval"
- v-model="older_than"
- :disabled="isFormElementDisabled"
- >
- <option v-for="option in formOptions.olderThan" :key="option.key" :value="option.key">
- {{ option.label }}
- </option>
- </gl-form-select>
- </gl-form-group>
-
- <gl-form-group
- id="expiration-policy-schedule-group"
- :label-cols="$options.labelsConfig.cols"
- :label-align="$options.labelsConfig.align"
- label-for="expiration-policy-schedule"
- :label="s__('ContainerRegistry|Expiration schedule:')"
- >
- <gl-form-select
- id="expiration-policy-schedule"
- v-model="cadence"
- :disabled="isFormElementDisabled"
- >
- <option v-for="option in formOptions.cadence" :key="option.key" :value="option.key">
- {{ option.label }}
- </option>
- </gl-form-select>
- </gl-form-group>
-
- <gl-form-group
- id="expiration-policy-latest-group"
- :label-cols="$options.labelsConfig.cols"
- :label-align="$options.labelsConfig.align"
- label-for="expiration-policy-latest"
- :label="s__('ContainerRegistry|Number of tags to retain:')"
- >
- <gl-form-select
- id="expiration-policy-latest"
- v-model="keep_n"
- :disabled="isFormElementDisabled"
- >
- <option v-for="option in formOptions.keepN" :key="option.key" :value="option.key">
- {{ option.label }}
- </option>
- </gl-form-select>
- </gl-form-group>
-
- <gl-form-group
- id="expiration-policy-name-matching-group"
- :label-cols="$options.labelsConfig.cols"
- :label-align="$options.labelsConfig.align"
- label-for="expiration-policy-name-matching"
- :label="
- s__('ContainerRegistry|Docker tags with names matching this regex pattern will expire:')
- "
- :state="nameRegexState"
- :invalid-feedback="
- s__('ContainerRegistry|The value of this input should be less than 255 characters')
- "
- >
- <gl-form-textarea
- id="expiration-policy-name-matching"
- v-model="name_regex"
- :placeholder="nameRegexPlaceholder"
- :state="nameRegexState"
- :disabled="isFormElementDisabled"
- trim
- />
- <template #description>
- <span ref="regex-description" v-html="regexHelpText"></span>
- </template>
- </gl-form-group>
- </template>
- <template #footer>
- <div class="d-flex justify-content-end">
- <gl-button
- ref="cancel-button"
- type="reset"
- :disabled="isCancelButtonDisabled"
- class="mr-2 d-block"
- >
- {{ __('Cancel') }}
- </gl-button>
- <gl-button
- ref="save-button"
- type="submit"
- :disabled="isSubmitButtonDisabled"
- variant="success"
- class="d-flex justify-content-center align-items-center js-no-auto-disable"
- >
- {{ __('Save expiration policy') }}
- <gl-loading-icon v-if="isLoading" class="ml-2" />
- </gl-button>
- </div>
- </template>
- </gl-card>
- </form>
+ <expiration-policy-form
+ v-model="settings"
+ :form-options="formOptions"
+ :is-loading="isLoading"
+ :disable-cancel-button="!isEdited"
+ @submit="submit"
+ @reset="reset"
+ />
</template>
diff --git a/app/assets/javascripts/registry/settings/store/getters.js b/app/assets/javascripts/registry/settings/store/getters.js
index cd6392bd0cc..639becebeec 100644
--- a/app/assets/javascripts/registry/settings/store/getters.js
+++ b/app/assets/javascripts/registry/settings/store/getters.js
@@ -1,10 +1,21 @@
import { isEqual } from 'lodash';
-import { findDefaultOption } from '../utils';
+import { findDefaultOption } from '../../shared/utils';
export const getCadence = state =>
state.settings.cadence || findDefaultOption(state.formOptions.cadence);
+
export const getKeepN = state =>
state.settings.keep_n || findDefaultOption(state.formOptions.keepN);
+
export const getOlderThan = state =>
state.settings.older_than || findDefaultOption(state.formOptions.olderThan);
+
+export const getSettings = (state, getters) => ({
+ enabled: state.settings.enabled,
+ cadence: getters.getCadence,
+ older_than: getters.getOlderThan,
+ keep_n: getters.getKeepN,
+ name_regex: state.settings.name_regex,
+});
+
export const getIsEdited = state => !isEqual(state.original, state.settings);
diff --git a/app/assets/javascripts/registry/settings/store/mutations.js b/app/assets/javascripts/registry/settings/store/mutations.js
index b773f2dd44c..f562137db1a 100644
--- a/app/assets/javascripts/registry/settings/store/mutations.js
+++ b/app/assets/javascripts/registry/settings/store/mutations.js
@@ -9,8 +9,8 @@ export default {
olderThan: JSON.parse(initialState.olderThanOptions),
};
},
- [types.UPDATE_SETTINGS](state, settings) {
- state.settings = { ...state.settings, ...settings };
+ [types.UPDATE_SETTINGS](state, data) {
+ state.settings = { ...state.settings, ...data.settings };
},
[types.SET_SETTINGS](state, settings) {
state.settings = settings;
diff --git a/app/assets/javascripts/registry/settings/utils.js b/app/assets/javascripts/registry/settings/utils.js
deleted file mode 100644
index 75af401e96d..00000000000
--- a/app/assets/javascripts/registry/settings/utils.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export const findDefaultOption = options => {
- const item = options.find(o => o.default);
- return item ? item.key : null;
-};
-
-export default () => {};
diff --git a/app/assets/javascripts/registry/shared/components/expiration_policy_form.vue b/app/assets/javascripts/registry/shared/components/expiration_policy_form.vue
new file mode 100644
index 00000000000..c044add3759
--- /dev/null
+++ b/app/assets/javascripts/registry/shared/components/expiration_policy_form.vue
@@ -0,0 +1,247 @@
+<script>
+import { uniqueId } from 'lodash';
+import {
+ GlFormGroup,
+ GlToggle,
+ GlFormSelect,
+ GlFormTextarea,
+ GlButton,
+ GlCard,
+ GlLoadingIcon,
+} from '@gitlab/ui';
+import { s__, __, sprintf } from '~/locale';
+import { NAME_REGEX_LENGTH } from '../constants';
+import { mapComputedToEvent } from '../utils';
+
+export default {
+ components: {
+ GlFormGroup,
+ GlToggle,
+ GlFormSelect,
+ GlFormTextarea,
+ GlButton,
+ GlCard,
+ GlLoadingIcon,
+ },
+ props: {
+ formOptions: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ isLoading: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ value: {
+ type: Object,
+ required: false,
+ default: () => ({}),
+ },
+ labelCols: {
+ type: [Number, String],
+ required: false,
+ default: 3,
+ },
+ labelAlign: {
+ type: String,
+ required: false,
+ default: 'right',
+ },
+ disableCancelButton: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ },
+ nameRegexPlaceholder: '.*',
+ data() {
+ return {
+ uniqueId: uniqueId(),
+ };
+ },
+ computed: {
+ ...mapComputedToEvent(['enabled', 'cadence', 'older_than', 'keep_n', 'name_regex'], 'value'),
+ policyEnabledText() {
+ return this.enabled ? __('enabled') : __('disabled');
+ },
+ toggleDescriptionText() {
+ return sprintf(
+ s__('ContainerRegistry|Docker tag expiration policy is %{toggleStatus}'),
+ {
+ toggleStatus: `<strong>${this.policyEnabledText}</strong>`,
+ },
+ false,
+ );
+ },
+ regexHelpText() {
+ return sprintf(
+ s__(
+ 'ContainerRegistry|Wildcards such as %{codeStart}*-stable%{codeEnd} or %{codeStart}production/*%{codeEnd} are supported. To select all tags, use %{codeStart}.*%{codeEnd}',
+ ),
+ {
+ codeStart: '<code>',
+ codeEnd: '</code>',
+ },
+ false,
+ );
+ },
+ nameRegexState() {
+ return this.name_regex ? this.name_regex.length <= NAME_REGEX_LENGTH : null;
+ },
+ formIsInvalid() {
+ return this.nameRegexState === false;
+ },
+ isFormElementDisabled() {
+ return !this.enabled || this.isLoading;
+ },
+ isSubmitButtonDisabled() {
+ return this.formIsInvalid || this.isLoading;
+ },
+ isCancelButtonDisabled() {
+ return this.disableCancelButton || this.isLoading;
+ },
+ },
+ methods: {
+ idGenerator(id) {
+ return `${id}_${this.uniqueId}`;
+ },
+ },
+};
+</script>
+
+<template>
+ <form
+ ref="form-element"
+ class="lh-2"
+ @submit.prevent="$emit('submit')"
+ @reset.prevent="$emit('reset')"
+ >
+ <gl-card>
+ <template #header>
+ {{ s__('ContainerRegistry|Tag expiration policy') }}
+ </template>
+ <template>
+ <gl-form-group
+ :id="idGenerator('expiration-policy-toggle-group')"
+ :label-cols="labelCols"
+ :label-align="labelAlign"
+ :label-for="idGenerator('expiration-policy-toggle')"
+ :label="s__('ContainerRegistry|Expiration policy:')"
+ >
+ <div class="d-flex align-items-start">
+ <gl-toggle
+ :id="idGenerator('expiration-policy-toggle')"
+ v-model="enabled"
+ :disabled="isLoading"
+ />
+ <span class="mb-2 ml-1 lh-2" v-html="toggleDescriptionText"></span>
+ </div>
+ </gl-form-group>
+
+ <gl-form-group
+ :id="idGenerator('expiration-policy-interval-group')"
+ :label-cols="labelCols"
+ :label-align="labelAlign"
+ :label-for="idGenerator('expiration-policy-interval')"
+ :label="s__('ContainerRegistry|Expiration interval:')"
+ >
+ <gl-form-select
+ :id="idGenerator('expiration-policy-interval')"
+ v-model="older_than"
+ :disabled="isFormElementDisabled"
+ >
+ <option v-for="option in formOptions.olderThan" :key="option.key" :value="option.key">
+ {{ option.label }}
+ </option>
+ </gl-form-select>
+ </gl-form-group>
+
+ <gl-form-group
+ :id="idGenerator('expiration-policy-schedule-group')"
+ :label-cols="labelCols"
+ :label-align="labelAlign"
+ :label-for="idGenerator('expiration-policy-schedule')"
+ :label="s__('ContainerRegistry|Expiration schedule:')"
+ >
+ <gl-form-select
+ :id="idGenerator('expiration-policy-schedule')"
+ v-model="cadence"
+ :disabled="isFormElementDisabled"
+ >
+ <option v-for="option in formOptions.cadence" :key="option.key" :value="option.key">
+ {{ option.label }}
+ </option>
+ </gl-form-select>
+ </gl-form-group>
+
+ <gl-form-group
+ :id="idGenerator('expiration-policy-latest-group')"
+ :label-cols="labelCols"
+ :label-align="labelAlign"
+ :label-for="idGenerator('expiration-policy-latest')"
+ :label="s__('ContainerRegistry|Number of tags to retain:')"
+ >
+ <gl-form-select
+ :id="idGenerator('expiration-policy-latest')"
+ v-model="keep_n"
+ :disabled="isFormElementDisabled"
+ >
+ <option v-for="option in formOptions.keepN" :key="option.key" :value="option.key">
+ {{ option.label }}
+ </option>
+ </gl-form-select>
+ </gl-form-group>
+
+ <gl-form-group
+ :id="idGenerator('expiration-policy-name-matching-group')"
+ :label-cols="labelCols"
+ :label-align="labelAlign"
+ :label-for="idGenerator('expiration-policy-name-matching')"
+ :label="
+ s__('ContainerRegistry|Docker tags with names matching this regex pattern will expire:')
+ "
+ :state="nameRegexState"
+ :invalid-feedback="
+ s__('ContainerRegistry|The value of this input should be less than 255 characters')
+ "
+ >
+ <gl-form-textarea
+ :id="idGenerator('expiration-policy-name-matching')"
+ v-model="name_regex"
+ :placeholder="$options.nameRegexPlaceholder"
+ :state="nameRegexState"
+ :disabled="isFormElementDisabled"
+ trim
+ />
+ <template #description>
+ <span ref="regex-description" v-html="regexHelpText"></span>
+ </template>
+ </gl-form-group>
+ </template>
+ <template #footer>
+ <div class="d-flex justify-content-end">
+ <gl-button
+ ref="cancel-button"
+ type="reset"
+ class="mr-2 d-block"
+ :disabled="isCancelButtonDisabled"
+ >
+ {{ __('Cancel') }}
+ </gl-button>
+ <gl-button
+ ref="save-button"
+ type="submit"
+ :disabled="isSubmitButtonDisabled"
+ variant="success"
+ class="d-flex justify-content-center align-items-center js-no-auto-disable"
+ >
+ {{ __('Save expiration policy') }}
+ <gl-loading-icon v-if="isLoading" class="ml-2" />
+ </gl-button>
+ </div>
+ </template>
+ </gl-card>
+ </form>
+</template>
diff --git a/app/assets/javascripts/registry/settings/constants.js b/app/assets/javascripts/registry/shared/constants.js
index c0dac466b29..c0dac466b29 100644
--- a/app/assets/javascripts/registry/settings/constants.js
+++ b/app/assets/javascripts/registry/shared/constants.js
diff --git a/app/assets/javascripts/registry/shared/utils.js b/app/assets/javascripts/registry/shared/utils.js
new file mode 100644
index 00000000000..d85a3ad28c2
--- /dev/null
+++ b/app/assets/javascripts/registry/shared/utils.js
@@ -0,0 +1,19 @@
+export const findDefaultOption = options => {
+ const item = options.find(o => o.default);
+ return item ? item.key : null;
+};
+
+export const mapComputedToEvent = (list, root) => {
+ const result = {};
+ list.forEach(e => {
+ result[e] = {
+ get() {
+ return this[root][e];
+ },
+ set(value) {
+ this.$emit('input', { ...this[root], [e]: value });
+ },
+ };
+ });
+ return result;
+};
diff --git a/app/assets/javascripts/users_select.js b/app/assets/javascripts/users_select.js
index 6d7d863f273..6821df57b5a 100644
--- a/app/assets/javascripts/users_select.js
+++ b/app/assets/javascripts/users_select.js
@@ -1,4 +1,4 @@
-/* eslint-disable func-names, prefer-rest-params, consistent-return, no-shadow, no-else-return, no-self-compare, no-unused-expressions, yoda, prefer-spread, camelcase, no-param-reassign */
+/* eslint-disable func-names, prefer-rest-params, consistent-return, no-shadow, no-else-return, no-self-compare, no-unused-expressions, yoda, prefer-spread, babel/camelcase, no-param-reassign */
/* global Issuable */
/* global emitSidebarEvent */
diff --git a/app/assets/javascripts/vue_shared/components/modal_copy_button.vue b/app/assets/javascripts/vue_shared/components/modal_copy_button.vue
index cdcfff42981..271a375ade2 100644
--- a/app/assets/javascripts/vue_shared/components/modal_copy_button.vue
+++ b/app/assets/javascripts/vue_shared/components/modal_copy_button.vue
@@ -121,7 +121,7 @@ export default {
:title="title"
>
<slot>
- <icon name="duplicate" />
+ <icon name="copy-to-clipboard" />
</slot>
</gl-button>
</template>
diff --git a/app/assets/javascripts/webpack.js b/app/assets/javascripts/webpack.js
index ced847294ae..4f558843357 100644
--- a/app/assets/javascripts/webpack.js
+++ b/app/assets/javascripts/webpack.js
@@ -5,5 +5,5 @@
*/
if (gon && gon.webpack_public_path) {
- __webpack_public_path__ = gon.webpack_public_path; // eslint-disable-line camelcase
+ __webpack_public_path__ = gon.webpack_public_path; // eslint-disable-line babel/camelcase
}
diff --git a/app/assets/javascripts/zen_mode.js b/app/assets/javascripts/zen_mode.js
index 044d703630e..ab0b0b02aa8 100644
--- a/app/assets/javascripts/zen_mode.js
+++ b/app/assets/javascripts/zen_mode.js
@@ -1,4 +1,4 @@
-/* eslint-disable consistent-return, camelcase, class-methods-use-this */
+/* eslint-disable consistent-return, class-methods-use-this */
// Zen Mode (full screen) textarea
//
@@ -91,8 +91,8 @@ export default class ZenMode {
}
}
- scrollTo(zen_area) {
- return $.scrollTo(zen_area, 0, {
+ scrollTo(zenArea) {
+ return $.scrollTo(zenArea, 0, {
offset: -150,
});
}
diff --git a/app/helpers/button_helper.rb b/app/helpers/button_helper.rb
index 610d823dd3c..e1aed5393ea 100644
--- a/app/helpers/button_helper.rb
+++ b/app/helpers/button_helper.rb
@@ -53,7 +53,7 @@ module ButtonHelper
}
content_tag :button, button_attributes do
- concat(sprite_icon('duplicate')) unless hide_button_icon
+ concat(sprite_icon('copy-to-clipboard')) unless hide_button_icon
concat(button_text)
end
end
diff --git a/app/models/concerns/delete_with_limit.rb b/app/models/concerns/delete_with_limit.rb
new file mode 100644
index 00000000000..1ea18b6149b
--- /dev/null
+++ b/app/models/concerns/delete_with_limit.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+module DeleteWithLimit
+ extend ActiveSupport::Concern
+
+ class_methods do
+ def delete_with_limit(maximum)
+ limit(maximum).delete_all
+ end
+ end
+end
diff --git a/app/models/event.rb b/app/models/event.rb
index ba585937e1c..606c4d8302f 100644
--- a/app/models/event.rb
+++ b/app/models/event.rb
@@ -4,6 +4,8 @@ class Event < ApplicationRecord
include Sortable
include FromUnion
include Presentable
+ include DeleteWithLimit
+ include CreatedAtFilterable
default_scope { reorder(nil) }
diff --git a/app/models/hooks/web_hook_log.rb b/app/models/hooks/web_hook_log.rb
index ed2e4408ce3..03f1797f4f4 100644
--- a/app/models/hooks/web_hook_log.rb
+++ b/app/models/hooks/web_hook_log.rb
@@ -3,6 +3,8 @@
class WebHookLog < ApplicationRecord
include SafeUrl
include Presentable
+ include DeleteWithLimit
+ include CreatedAtFilterable
belongs_to :web_hook
diff --git a/app/models/project_services/emails_on_push_service.rb b/app/models/project_services/emails_on_push_service.rb
index eb78938324d..dd2f1359e76 100644
--- a/app/models/project_services/emails_on_push_service.rb
+++ b/app/models/project_services/emails_on_push_service.rb
@@ -25,10 +25,9 @@ class EmailsOnPushService < Service
end
def initialize_properties
- if properties.nil?
- self.properties = {}
- self.branches_to_be_notified ||= "all"
- end
+ super
+
+ self.branches_to_be_notified = 'all' if branches_to_be_notified.nil?
end
def execute(push_data)
diff --git a/app/views/sherlock/queries/_general.html.haml b/app/views/sherlock/queries/_general.html.haml
index 52c7bc47ca7..1514ad55d71 100644
--- a/app/views/sherlock/queries/_general.html.haml
+++ b/app/views/sherlock/queries/_general.html.haml
@@ -27,7 +27,7 @@
.card-header
.float-right
%button.js-clipboard-trigger.btn.btn-sm{ title: t('sherlock.copy_to_clipboard'), type: :button }
- = sprite_icon('duplicate')
+ = sprite_icon('copy-to-clipboard')
%pre.hidden
= @query.formatted_query
%strong
@@ -42,7 +42,7 @@
.card-header
.float-right
%button.js-clipboard-trigger.btn.btn-sm{ title: t('sherlock.copy_to_clipboard'), type: :button }
- = sprite_icon('duplicate')
+ = sprite_icon('copy-to-clipboard')
%pre.hidden
= @query.explain
%strong
diff --git a/app/workers/prune_old_events_worker.rb b/app/workers/prune_old_events_worker.rb
index f421e8dbf59..1d915832833 100644
--- a/app/workers/prune_old_events_worker.rb
+++ b/app/workers/prune_old_events_worker.rb
@@ -6,18 +6,12 @@ class PruneOldEventsWorker
feature_category_not_owned!
- # rubocop: disable CodeReuse/ActiveRecord
+ DELETE_LIMIT = 10_000
+
def perform
# Contribution calendar shows maximum 12 months of events, we retain 3 years for data integrity.
- # Double nested query is used because MySQL doesn't allow DELETE subqueries on the same table.
- Event.unscoped.where(
- '(id IN (SELECT id FROM (?) ids_to_remove))',
- Event.unscoped.where(
- 'created_at < ?',
- (3.years + 1.day).ago)
- .select(:id)
- .limit(10_000))
- .delete_all
+ cutoff_date = (3.years + 1.day).ago
+
+ Event.unscoped.created_before(cutoff_date).delete_with_limit(DELETE_LIMIT)
end
- # rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/app/workers/prune_web_hook_logs_worker.rb b/app/workers/prune_web_hook_logs_worker.rb
index 8e48b45fc34..69a1dd43e69 100644
--- a/app/workers/prune_web_hook_logs_worker.rb
+++ b/app/workers/prune_web_hook_logs_worker.rb
@@ -11,20 +11,9 @@ class PruneWebHookLogsWorker
# The maximum number of rows to remove in a single job.
DELETE_LIMIT = 50_000
- # rubocop: disable CodeReuse/ActiveRecord
def perform
- # MySQL doesn't allow "DELETE FROM ... WHERE id IN ( ... )" if the inner
- # query refers to the same table. To work around this we wrap the IN body in
- # another sub query.
- WebHookLog
- .where(
- 'id IN (SELECT id FROM (?) ids_to_remove)',
- WebHookLog
- .select(:id)
- .where('created_at < ?', 90.days.ago.beginning_of_day)
- .limit(DELETE_LIMIT)
- )
- .delete_all
+ cutoff_date = 90.days.ago.beginning_of_day
+
+ WebHookLog.created_before(cutoff_date).delete_with_limit(DELETE_LIMIT)
end
- # rubocop: enable CodeReuse/ActiveRecord
end
diff --git a/changelogs/unreleased/198577-fix-emails-on-push.yml b/changelogs/unreleased/198577-fix-emails-on-push.yml
new file mode 100644
index 00000000000..70eb7e48c37
--- /dev/null
+++ b/changelogs/unreleased/198577-fix-emails-on-push.yml
@@ -0,0 +1,5 @@
+---
+title: Fix emails on push integrations created before 12.7
+merge_request: 23699
+author:
+type: fixed
diff --git a/changelogs/unreleased/pedroms-change-copy-to-clipboard-icon.yml b/changelogs/unreleased/pedroms-change-copy-to-clipboard-icon.yml
new file mode 100644
index 00000000000..118441a4b82
--- /dev/null
+++ b/changelogs/unreleased/pedroms-change-copy-to-clipboard-icon.yml
@@ -0,0 +1,5 @@
+---
+title: Change vague copy to clipboard icon to a clearer icon.
+merge_request: 23983
+author:
+type: changed
diff --git a/config/initializers/graphql.rb b/config/initializers/graphql.rb
index 2b21c9d9729..206c4daceac 100644
--- a/config/initializers/graphql.rb
+++ b/config/initializers/graphql.rb
@@ -6,6 +6,8 @@ GraphQL::Field.accepts_definitions(authorize: GraphQL::Define.assign_metadata_ke
GraphQL::Schema::Object.accepts_definition(:authorize)
GraphQL::Schema::Field.accepts_definition(:authorize)
-GitlabSchema.middleware << GraphQL::Schema::TimeoutMiddleware.new(max_seconds: ENV.fetch('GITLAB_RAILS_GRAPHQL_TIMEOUT', 30).to_i) do |timeout_error, query|
- Gitlab::GraphqlLogger.error(message: timeout_error.to_s, query: query.query_string, query_variables: query.provided_variables)
+Gitlab::Application.config.after_initialize do
+ GitlabSchema.middleware << GraphQL::Schema::TimeoutMiddleware.new(max_seconds: ENV.fetch('GITLAB_RAILS_GRAPHQL_TIMEOUT', 30).to_i) do |timeout_error, query|
+ Gitlab::GraphqlLogger.error(message: timeout_error.to_s, query: query.query_string, query_variables: query.provided_variables)
+ end
end
diff --git a/package.json b/package.json
index c8d35ad585e..3bb3a21a245 100644
--- a/package.json
+++ b/package.json
@@ -146,7 +146,7 @@
},
"devDependencies": {
"@babel/plugin-transform-modules-commonjs": "^7.5.0",
- "@gitlab/eslint-config": "^2.0.0",
+ "@gitlab/eslint-config": "^2.1.1",
"@gitlab/eslint-plugin-i18n": "^1.1.0",
"@gitlab/eslint-plugin-vue-i18n": "^1.2.0",
"@vue/test-utils": "^1.0.0-beta.30",
diff --git a/spec/features/projects/settings/operations_settings_spec.rb b/spec/features/projects/settings/operations_settings_spec.rb
index 9bbeb0eb260..72e2865dd6a 100644
--- a/spec/features/projects/settings/operations_settings_spec.rb
+++ b/spec/features/projects/settings/operations_settings_spec.rb
@@ -61,7 +61,7 @@ describe 'Projects > Settings > For a forked project', :js do
within('div#project-dropdown') do
click_button('Select project')
- click_button('Sentry | Internal')
+ click_button('Sentry | internal')
end
click_button('Save changes')
diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb
index 1a1940f6efb..4c5bc290402 100644
--- a/spec/features/projects/settings/registry_settings_spec.rb
+++ b/spec/features/projects/settings/registry_settings_spec.rb
@@ -26,11 +26,11 @@ describe 'Project > Settings > CI/CD > Container registry tag expiration policy'
it 'saves expiration policy submit the form' do
within '#js-registry-policies' do
within '.card-body' do
- find('#expiration-policy-toggle button:not(.is-disabled)').click
- select('7 days until tags are automatically removed', from: 'expiration-policy-interval')
- select('Every day', from: 'expiration-policy-schedule')
- select('50 tags per image name', from: 'expiration-policy-latest')
- fill_in('expiration-policy-name-matching', with: '*-production')
+ find('.gl-toggle-wrapper button:not(.is-disabled)').click
+ select('7 days until tags are automatically removed', from: 'Expiration interval:')
+ select('Every day', from: 'Expiration schedule:')
+ select('50 tags per image name', from: 'Number of tags to retain:')
+ fill_in('Docker tags with names matching this regex pattern will expire:', with: '*-production')
end
submit_button = find('.card-footer .btn.btn-success')
expect(submit_button).not_to be_disabled
diff --git a/spec/frontend/error_tracking_settings/store/getters_spec.js b/spec/frontend/error_tracking_settings/store/getters_spec.js
index 2c5ff084b8a..b135fdee40b 100644
--- a/spec/frontend/error_tracking_settings/store/getters_spec.js
+++ b/spec/frontend/error_tracking_settings/store/getters_spec.js
@@ -47,7 +47,7 @@ describe('Error Tracking Settings - Getters', () => {
it('should display correctly when a project is selected', () => {
[state.selectedProject] = projectList;
- expect(getters.dropdownLabel(state, mockGetters)).toEqual('organizationName | name');
+ expect(getters.dropdownLabel(state, mockGetters)).toEqual('organizationName | slug');
});
it('should display correctly when no project is selected', () => {
diff --git a/spec/frontend/ide/components/ide_status_list_spec.js b/spec/frontend/ide/components/ide_status_list_spec.js
index 2762adfb57d..99c27ca30fb 100644
--- a/spec/frontend/ide/components/ide_status_list_spec.js
+++ b/spec/frontend/ide/components/ide_status_list_spec.js
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
-import IdeStatusList from '~/ide/components/ide_status_list';
+import IdeStatusList from '~/ide/components/ide_status_list.vue';
const TEST_FILE = {
name: 'lorem.md',
diff --git a/spec/frontend/mr_popover/mr_popover_spec.js b/spec/frontend/mr_popover/mr_popover_spec.js
index 0c0d4c73d91..3f62dca4a57 100644
--- a/spec/frontend/mr_popover/mr_popover_spec.js
+++ b/spec/frontend/mr_popover/mr_popover_spec.js
@@ -1,5 +1,5 @@
import { shallowMount } from '@vue/test-utils';
-import MRPopover from '~/mr_popover/components/mr_popover';
+import MRPopover from '~/mr_popover/components/mr_popover.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
describe('MR Popover', () => {
diff --git a/spec/frontend/registry/settings/components/registry_settings_app_spec.js b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
index 8a5c5d84198..e9ba65e4387 100644
--- a/spec/frontend/registry/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
@@ -4,7 +4,7 @@ import component from '~/registry/settings/components/registry_settings_app.vue'
import SettingsForm from '~/registry/settings/components/settings_form.vue';
import { createStore } from '~/registry/settings/store/';
import { SET_IS_DISABLED } from '~/registry/settings/store/mutation_types';
-import { FETCH_SETTINGS_ERROR_MESSAGE } from '~/registry/settings/constants';
+import { FETCH_SETTINGS_ERROR_MESSAGE } from '~/registry/shared/constants';
describe('Registry Settings App', () => {
let wrapper;
diff --git a/spec/frontend/registry/settings/components/settings_form_spec.js b/spec/frontend/registry/settings/components/settings_form_spec.js
index 89dd161ec3e..eefb0313a0b 100644
--- a/spec/frontend/registry/settings/components/settings_form_spec.js
+++ b/spec/frontend/registry/settings/components/settings_form_spec.js
@@ -1,49 +1,33 @@
-import { mount } from '@vue/test-utils';
+import { shallowMount } from '@vue/test-utils';
import Tracking from '~/tracking';
-import stubChildren from 'helpers/stub_children';
import component from '~/registry/settings/components/settings_form.vue';
+import expirationPolicyForm from '~/registry/shared/components/expiration_policy_form.vue';
import { createStore } from '~/registry/settings/store/';
import {
- NAME_REGEX_LENGTH,
UPDATE_SETTINGS_ERROR_MESSAGE,
UPDATE_SETTINGS_SUCCESS_MESSAGE,
-} from '~/registry/settings/constants';
-import { stringifiedFormOptions } from '../mock_data';
+} from '~/registry/shared/constants';
+import { stringifiedFormOptions } from '../../shared/mock_data';
describe('Settings Form', () => {
let wrapper;
let store;
let dispatchSpy;
- const FORM_ELEMENTS_ID_PREFIX = '#expiration-policy';
const trackingPayload = {
label: 'docker_container_retention_and_expiration_policies',
};
- const GlLoadingIcon = { name: 'gl-loading-icon-stub', template: '<svg></svg>' };
+ const findForm = () => wrapper.find(expirationPolicyForm);
- const findFormGroup = name => wrapper.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}-group`);
- const findFormElements = (name, parent = wrapper) =>
- parent.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}`);
- const findCancelButton = () => wrapper.find({ ref: 'cancel-button' });
- const findSaveButton = () => wrapper.find({ ref: 'save-button' });
- const findForm = () => wrapper.find({ ref: 'form-element' });
- const findLoadingIcon = (parent = wrapper) => parent.find(GlLoadingIcon);
-
- const mountComponent = (options = {}) => {
- wrapper = mount(component, {
- stubs: {
- ...stubChildren(component),
- GlCard: false,
- GlLoadingIcon,
- },
+ const mountComponent = () => {
+ wrapper = shallowMount(component, {
mocks: {
$toast: {
show: jest.fn(),
},
},
store,
- ...options,
});
};
@@ -59,170 +43,50 @@ describe('Settings Form', () => {
wrapper.destroy();
});
- it('renders', () => {
- expect(wrapper.element).toMatchSnapshot();
- });
-
- describe.each`
- elementName | modelName | value | disabledByToggle
- ${'toggle'} | ${'enabled'} | ${true} | ${'not disabled'}
- ${'interval'} | ${'older_than'} | ${'foo'} | ${'disabled'}
- ${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'}
- ${'latest'} | ${'keep_n'} | ${'foo'} | ${'disabled'}
- ${'name-matching'} | ${'name_regex'} | ${'foo'} | ${'disabled'}
- `(
- `${FORM_ELEMENTS_ID_PREFIX}-$elementName form element`,
- ({ elementName, modelName, value, disabledByToggle }) => {
- let formGroup;
- beforeEach(() => {
- formGroup = findFormGroup(elementName);
- });
- it(`${elementName} form group exist in the dom`, () => {
- expect(formGroup.exists()).toBe(true);
- });
-
- it(`${elementName} form group has a label-for property`, () => {
- expect(formGroup.attributes('label-for')).toBe(`expiration-policy-${elementName}`);
- });
-
- it(`${elementName} form group has a label-cols property`, () => {
- expect(formGroup.attributes('label-cols')).toBe(`${wrapper.vm.$options.labelsConfig.cols}`);
- });
-
- it(`${elementName} form group has a label-align property`, () => {
- expect(formGroup.attributes('label-align')).toBe(
- `${wrapper.vm.$options.labelsConfig.align}`,
- );
- });
-
- it(`${elementName} form group contains an input element`, () => {
- expect(findFormElements(elementName, formGroup).exists()).toBe(true);
- });
-
- it(`${elementName} form element change updated ${modelName} with ${value}`, () => {
- const element = findFormElements(elementName, formGroup);
- const modelUpdateEvent = element.vm.$options.model
- ? element.vm.$options.model.event
- : 'input';
- element.vm.$emit(modelUpdateEvent, value);
- return wrapper.vm.$nextTick().then(() => {
- expect(wrapper.vm[modelName]).toBe(value);
- });
- });
-
- it(`${elementName} is ${disabledByToggle} by enabled set to false`, () => {
- store.dispatch('updateSettings', { enabled: false });
- const expectation = disabledByToggle === 'disabled' ? 'true' : undefined;
- expect(findFormElements(elementName, formGroup).attributes('disabled')).toBe(expectation);
- });
- },
- );
-
- describe('form actions', () => {
+ describe('form', () => {
let form;
beforeEach(() => {
form = findForm();
});
- describe('cancel button', () => {
- it('has type reset', () => {
- expect(findCancelButton().attributes('type')).toBe('reset');
- });
-
- it('is disabled the form was not changed from his original value', () => {
- store.dispatch('receiveSettingsSuccess', { foo: 'bar' });
- return wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe('true');
- });
- });
-
- it('is disabled when the form data is loading', () => {
- store.dispatch('toggleLoading');
- return wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe('true');
- });
- });
-
- it('is enabled when the user changed something in the form and the data is not being loaded', () => {
- store.dispatch('receiveSettingsSuccess', { foo: 'bar' });
- store.dispatch('updateSettings', { foo: 'baz' });
- return wrapper.vm.$nextTick().then(() => {
- expect(findCancelButton().attributes('disabled')).toBe(undefined);
- });
+ describe('data binding', () => {
+ it('v-model change update the settings property', () => {
+ dispatchSpy.mockReturnValue();
+ form.vm.$emit('input', 'foo');
+ expect(dispatchSpy).toHaveBeenCalledWith('updateSettings', { settings: 'foo' });
});
});
- describe('form cancel event', () => {
+ describe('form reset event', () => {
it('calls the appropriate function', () => {
dispatchSpy.mockReturnValue();
- form.trigger('reset');
+ form.vm.$emit('reset');
expect(dispatchSpy).toHaveBeenCalledWith('resetSettings');
});
it('tracks the reset event', () => {
dispatchSpy.mockReturnValue();
- form.trigger('reset');
+ form.vm.$emit('reset');
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'reset_form', trackingPayload);
});
});
- it('save has type submit', () => {
- expect(findSaveButton().attributes('type')).toBe('submit');
- });
-
- describe('when isLoading is true', () => {
- beforeEach(() => {
- store.dispatch('toggleLoading');
- });
-
- afterEach(() => {
- store.dispatch('toggleLoading');
- });
-
- it.each`
- elementName
- ${'toggle'}
- ${'interval'}
- ${'schedule'}
- ${'latest'}
- ${'name-matching'}
- `(`${FORM_ELEMENTS_ID_PREFIX}-$elementName is disabled`, ({ elementName }) => {
- expect(findFormElements(elementName).attributes('disabled')).toBe('true');
- });
-
- it('submit button is disabled and shows a spinner', () => {
- const button = findSaveButton();
- expect(button.attributes('disabled')).toBeTruthy();
- expect(findLoadingIcon(button)).toExist();
- });
-
- it('cancel button is disabled', () => {
- expect(findCancelButton().attributes('disabled')).toBeTruthy();
- });
- });
-
describe('form submit event ', () => {
- it('calls the appropriate function', () => {
- dispatchSpy.mockResolvedValue();
- form.trigger('submit');
- expect(dispatchSpy).toHaveBeenCalled();
- });
-
it('dispatches the saveSettings action', () => {
dispatchSpy.mockResolvedValue();
- form.trigger('submit');
+ form.vm.$emit('submit');
expect(dispatchSpy).toHaveBeenCalledWith('saveSettings');
});
it('tracks the submit event', () => {
dispatchSpy.mockResolvedValue();
- form.trigger('submit');
+ form.vm.$emit('submit');
expect(Tracking.event).toHaveBeenCalledWith(undefined, 'submit_form', trackingPayload);
});
it('show a success toast when submit succeed', () => {
dispatchSpy.mockResolvedValue();
- form.trigger('submit');
+ form.vm.$emit('submit');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_SUCCESS_MESSAGE, {
type: 'success',
@@ -232,7 +96,7 @@ describe('Settings Form', () => {
it('show an error toast when submit fails', () => {
dispatchSpy.mockRejectedValue();
- form.trigger('submit');
+ form.vm.$emit('submit');
return wrapper.vm.$nextTick().then(() => {
expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(UPDATE_SETTINGS_ERROR_MESSAGE, {
type: 'error',
@@ -241,45 +105,4 @@ describe('Settings Form', () => {
});
});
});
-
- describe('form validation', () => {
- describe(`when name regex is longer than ${NAME_REGEX_LENGTH}`, () => {
- const invalidString = new Array(NAME_REGEX_LENGTH + 2).join(',');
- beforeEach(() => {
- store.dispatch('updateSettings', { name_regex: invalidString });
- });
-
- it('save btn is disabled', () => {
- expect(findSaveButton().attributes('disabled')).toBeTruthy();
- });
-
- it('nameRegexState is false', () => {
- expect(wrapper.vm.nameRegexState).toBe(false);
- });
- });
-
- it('if the user did not type validation is null', () => {
- store.dispatch('updateSettings', { name_regex: null });
- expect(wrapper.vm.nameRegexState).toBe(null);
- return wrapper.vm.$nextTick().then(() => {
- expect(findSaveButton().attributes('disabled')).toBeFalsy();
- });
- });
-
- it(`if the user typed and is less than ${NAME_REGEX_LENGTH} state is true`, () => {
- store.dispatch('updateSettings', { name_regex: 'abc' });
- expect(wrapper.vm.nameRegexState).toBe(true);
- });
- });
-
- describe('help text', () => {
- it('toggleDescriptionText text reflects enabled property', () => {
- const toggleHelpText = findFormGroup('toggle').find('span');
- expect(toggleHelpText.html()).toContain('disabled');
- wrapper.setData({ enabled: true });
- return wrapper.vm.$nextTick().then(() => {
- expect(toggleHelpText.html()).toContain('enabled');
- });
- });
- });
});
diff --git a/spec/frontend/registry/settings/store/actions_spec.js b/spec/frontend/registry/settings/store/actions_spec.js
index f904d0b660a..5038dc82416 100644
--- a/spec/frontend/registry/settings/store/actions_spec.js
+++ b/spec/frontend/registry/settings/store/actions_spec.js
@@ -10,11 +10,14 @@ describe('Actions Registry Store', () => {
${'updateSettings'} | ${types.UPDATE_SETTINGS} | ${'foo'}
${'toggleLoading'} | ${types.TOGGLE_LOADING} | ${undefined}
${'resetSettings'} | ${types.RESET_SETTINGS} | ${undefined}
- `('%s action invokes %s mutation with payload %s', ({ actionName, mutationName, payload }) => {
- it('should set the initial state', done => {
- testAction(actions[actionName], payload, {}, [{ type: mutationName, payload }], [], done);
- });
- });
+ `(
+ '$actionName invokes $mutationName with payload $payload',
+ ({ actionName, mutationName, payload }) => {
+ it('should set state', done => {
+ testAction(actions[actionName], payload, {}, [{ type: mutationName, payload }], [], done);
+ });
+ },
+ );
describe('receiveSettingsSuccess', () => {
it('calls SET_SETTINGS when data is present', () => {
diff --git a/spec/frontend/registry/settings/store/getters_spec.js b/spec/frontend/registry/settings/store/getters_spec.js
index d9ee53766d6..44631b97a39 100644
--- a/spec/frontend/registry/settings/store/getters_spec.js
+++ b/spec/frontend/registry/settings/store/getters_spec.js
@@ -1,6 +1,6 @@
import * as getters from '~/registry/settings/store/getters';
-import * as utils from '~/registry/settings/utils';
-import { formOptions } from '../mock_data';
+import * as utils from '~/registry/shared/utils';
+import { formOptions } from '../../shared/mock_data';
describe('Getters registry settings store', () => {
const settings = {
diff --git a/spec/frontend/registry/settings/store/mutations_spec.js b/spec/frontend/registry/settings/store/mutations_spec.js
index deb59089d60..8ab0196fd4d 100644
--- a/spec/frontend/registry/settings/store/mutations_spec.js
+++ b/spec/frontend/registry/settings/store/mutations_spec.js
@@ -1,7 +1,7 @@
import mutations from '~/registry/settings/store/mutations';
import * as types from '~/registry/settings/store/mutation_types';
import createState from '~/registry/settings/store/state';
-import { formOptions, stringifiedFormOptions } from '../mock_data';
+import { formOptions, stringifiedFormOptions } from '../../shared/mock_data';
describe('Mutations Registry Store', () => {
let mockState;
@@ -28,7 +28,7 @@ describe('Mutations Registry Store', () => {
mockState.settings = { foo: 'bar' };
const payload = { foo: 'baz' };
const expectedState = { ...mockState, settings: payload };
- mutations[types.UPDATE_SETTINGS](mockState, payload);
+ mutations[types.UPDATE_SETTINGS](mockState, { settings: payload });
expect(mockState.settings).toEqual(expectedState.settings);
});
});
diff --git a/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap b/spec/frontend/registry/shared/components/__snapshots__/expiration_policy_form_spec.js.snap
index 06f73c8f456..b53736951e1 100644
--- a/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap
+++ b/spec/frontend/registry/shared/components/__snapshots__/expiration_policy_form_spec.js.snap
@@ -1,7 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Settings Form renders 1`] = `
-<form>
+exports[`Expiration Policy Form renders 1`] = `
+<form
+ class="lh-2"
+>
<div
class="card"
>
@@ -56,7 +58,6 @@ exports[`Settings Form renders 1`] = `
<glformselect-stub
disabled="true"
id="expiration-policy-interval"
- value="bar"
>
<option
value="foo"
@@ -85,7 +86,6 @@ exports[`Settings Form renders 1`] = `
<glformselect-stub
disabled="true"
id="expiration-policy-schedule"
- value="bar"
>
<option
value="foo"
@@ -114,7 +114,6 @@ exports[`Settings Form renders 1`] = `
<glformselect-stub
disabled="true"
id="expiration-policy-latest"
- value="bar"
>
<option
value="foo"
@@ -159,7 +158,6 @@ exports[`Settings Form renders 1`] = `
>
<glbutton-stub
class="mr-2 d-block"
- disabled="true"
size="md"
type="reset"
variant="secondary"
diff --git a/spec/frontend/registry/shared/components/expiration_policy_form_spec.js b/spec/frontend/registry/shared/components/expiration_policy_form_spec.js
new file mode 100644
index 00000000000..b51519925f1
--- /dev/null
+++ b/spec/frontend/registry/shared/components/expiration_policy_form_spec.js
@@ -0,0 +1,237 @@
+import { mount } from '@vue/test-utils';
+import stubChildren from 'helpers/stub_children';
+import component from '~/registry/shared/components/expiration_policy_form.vue';
+
+import { NAME_REGEX_LENGTH } from '~/registry/shared/constants';
+import { formOptions } from '../mock_data';
+
+describe('Expiration Policy Form', () => {
+ let wrapper;
+
+ const FORM_ELEMENTS_ID_PREFIX = '#expiration-policy';
+
+ const GlLoadingIcon = { name: 'gl-loading-icon-stub', template: '<svg></svg>' };
+
+ const findFormGroup = name => wrapper.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}-group`);
+ const findFormElements = (name, parent = wrapper) =>
+ parent.find(`${FORM_ELEMENTS_ID_PREFIX}-${name}`);
+ const findCancelButton = () => wrapper.find({ ref: 'cancel-button' });
+ const findSaveButton = () => wrapper.find({ ref: 'save-button' });
+ const findForm = () => wrapper.find({ ref: 'form-element' });
+ const findLoadingIcon = (parent = wrapper) => parent.find(GlLoadingIcon);
+
+ const mountComponent = props => {
+ wrapper = mount(component, {
+ stubs: {
+ ...stubChildren(component),
+ GlCard: false,
+ GlLoadingIcon,
+ },
+ propsData: {
+ formOptions,
+ ...props,
+ },
+ methods: {
+ // override idGenerator to avoid having to test with dynamic uid
+ idGenerator: value => value,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders', () => {
+ mountComponent();
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ describe.each`
+ elementName | modelName | value | disabledByToggle
+ ${'toggle'} | ${'enabled'} | ${true} | ${'not disabled'}
+ ${'interval'} | ${'older_than'} | ${'foo'} | ${'disabled'}
+ ${'schedule'} | ${'cadence'} | ${'foo'} | ${'disabled'}
+ ${'latest'} | ${'keep_n'} | ${'foo'} | ${'disabled'}
+ ${'name-matching'} | ${'name_regex'} | ${'foo'} | ${'disabled'}
+ `(
+ `${FORM_ELEMENTS_ID_PREFIX}-$elementName form element`,
+ ({ elementName, modelName, value, disabledByToggle }) => {
+ it(`${elementName} form group exist in the dom`, () => {
+ mountComponent();
+ const formGroup = findFormGroup(elementName);
+ expect(formGroup.exists()).toBe(true);
+ });
+
+ it(`${elementName} form group has a label-for property`, () => {
+ mountComponent();
+ const formGroup = findFormGroup(elementName);
+ expect(formGroup.attributes('label-for')).toBe(`expiration-policy-${elementName}`);
+ });
+
+ it(`${elementName} form group has a label-cols property`, () => {
+ mountComponent({ labelCols: '1' });
+ const formGroup = findFormGroup(elementName);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(formGroup.attributes('label-cols')).toBe('1');
+ });
+ });
+
+ it(`${elementName} form group has a label-align property`, () => {
+ mountComponent({ labelAlign: 'foo' });
+ const formGroup = findFormGroup(elementName);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(formGroup.attributes('label-align')).toBe('foo');
+ });
+ });
+
+ it(`${elementName} form group contains an input element`, () => {
+ mountComponent();
+ const formGroup = findFormGroup(elementName);
+ expect(findFormElements(elementName, formGroup).exists()).toBe(true);
+ });
+
+ it(`${elementName} form element change updated ${modelName} with ${value}`, () => {
+ mountComponent();
+ const formGroup = findFormGroup(elementName);
+ const element = findFormElements(elementName, formGroup);
+
+ const modelUpdateEvent = element.vm.$options.model
+ ? element.vm.$options.model.event
+ : 'input';
+ element.vm.$emit(modelUpdateEvent, value);
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.emitted('input')).toEqual([[{ [modelName]: value }]]);
+ });
+ });
+
+ it(`${elementName} is ${disabledByToggle} by enabled set to false`, () => {
+ mountComponent({ settings: { enabled: false } });
+ const formGroup = findFormGroup(elementName);
+ const expectation = disabledByToggle === 'disabled' ? 'true' : undefined;
+ expect(findFormElements(elementName, formGroup).attributes('disabled')).toBe(expectation);
+ });
+ },
+ );
+
+ describe('form actions', () => {
+ describe('cancel button', () => {
+ it('has type reset', () => {
+ mountComponent();
+ expect(findCancelButton().attributes('type')).toBe('reset');
+ });
+
+ it('is disabled when disableCancelButton is true', () => {
+ mountComponent({ disableCancelButton: true });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCancelButton().attributes('disabled')).toBe('true');
+ });
+ });
+
+ it('is disabled isLoading is true', () => {
+ mountComponent({ isLoading: true });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCancelButton().attributes('disabled')).toBe('true');
+ });
+ });
+
+ it('is enabled when isLoading and disableCancelButton are false', () => {
+ mountComponent({ disableCancelButton: false, isLoading: false });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCancelButton().attributes('disabled')).toBe(undefined);
+ });
+ });
+ });
+
+ describe('form cancel event', () => {
+ it('calls the appropriate function', () => {
+ mountComponent();
+ findForm().trigger('reset');
+ expect(wrapper.emitted('reset')).toBeTruthy();
+ });
+ });
+
+ it('save has type submit', () => {
+ mountComponent();
+ expect(findSaveButton().attributes('type')).toBe('submit');
+ });
+
+ describe('when isLoading is true', () => {
+ beforeEach(() => {
+ mountComponent({ isLoading: true });
+ });
+
+ it.each`
+ elementName
+ ${'toggle'}
+ ${'interval'}
+ ${'schedule'}
+ ${'latest'}
+ ${'name-matching'}
+ `(`${FORM_ELEMENTS_ID_PREFIX}-$elementName is disabled`, ({ elementName }) => {
+ expect(findFormElements(elementName).attributes('disabled')).toBe('true');
+ });
+
+ it('submit button is disabled and shows a spinner', () => {
+ const button = findSaveButton();
+ expect(button.attributes('disabled')).toBeTruthy();
+ expect(findLoadingIcon(button)).toExist();
+ });
+ });
+
+ describe('form submit event ', () => {
+ it('calls the appropriate function', () => {
+ mountComponent();
+ findForm().trigger('submit');
+ expect(wrapper.emitted('submit')).toBeTruthy();
+ });
+ });
+ });
+
+ describe('form validation', () => {
+ describe(`when name regex is longer than ${NAME_REGEX_LENGTH}`, () => {
+ const invalidString = new Array(NAME_REGEX_LENGTH + 2).join(',');
+
+ beforeEach(() => {
+ mountComponent({ value: { name_regex: invalidString } });
+ });
+
+ it('save btn is disabled', () => {
+ expect(findSaveButton().attributes('disabled')).toBeTruthy();
+ });
+
+ it('nameRegexState is false', () => {
+ expect(wrapper.vm.nameRegexState).toBe(false);
+ });
+ });
+
+ it('if the user did not type validation is null', () => {
+ mountComponent({ value: { name_regex: '' } });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.nameRegexState).toBe(null);
+ expect(findSaveButton().attributes('disabled')).toBeFalsy();
+ });
+ });
+
+ it(`if the user typed and is less than ${NAME_REGEX_LENGTH} state is true`, () => {
+ mountComponent({ value: { name_regex: 'foo' } });
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.vm.nameRegexState).toBe(true);
+ });
+ });
+ });
+
+ describe('help text', () => {
+ it('toggleDescriptionText show disabled when settings.enabled is false', () => {
+ mountComponent();
+ const toggleHelpText = findFormGroup('toggle').find('span');
+ expect(toggleHelpText.html()).toContain('disabled');
+ });
+
+ it('toggleDescriptionText show enabled when settings.enabled is true', () => {
+ mountComponent({ value: { enabled: true } });
+ const toggleHelpText = findFormGroup('toggle').find('span');
+ expect(toggleHelpText.html()).toContain('enabled');
+ });
+ });
+});
diff --git a/spec/frontend/registry/settings/mock_data.js b/spec/frontend/registry/shared/mock_data.js
index 411363c2c95..411363c2c95 100644
--- a/spec/frontend/registry/settings/mock_data.js
+++ b/spec/frontend/registry/shared/mock_data.js
diff --git a/spec/frontend/releases/detail/components/app_spec.js b/spec/frontend/releases/detail/components/app_spec.js
index fd5239ad44e..894cd3a8f14 100644
--- a/spec/frontend/releases/detail/components/app_spec.js
+++ b/spec/frontend/releases/detail/components/app_spec.js
@@ -1,6 +1,6 @@
import Vuex from 'vuex';
import { mount } from '@vue/test-utils';
-import ReleaseDetailApp from '~/releases/detail/components/app';
+import ReleaseDetailApp from '~/releases/detail/components/app.vue';
import { release } from '../../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
diff --git a/spec/frontend/sidebar/confidential_issue_sidebar_spec.js b/spec/frontend/sidebar/confidential_issue_sidebar_spec.js
index 13b7c426366..4853d9795b1 100644
--- a/spec/frontend/sidebar/confidential_issue_sidebar_spec.js
+++ b/spec/frontend/sidebar/confidential_issue_sidebar_spec.js
@@ -4,7 +4,7 @@ import ConfidentialIssueSidebar from '~/sidebar/components/confidential/confiden
import EditForm from '~/sidebar/components/confidential/edit_form.vue';
import SidebarService from '~/sidebar/services/sidebar_service';
import createFlash from '~/flash';
-import RecaptchaModal from '~/vue_shared/components/recaptcha_modal';
+import RecaptchaModal from '~/vue_shared/components/recaptcha_modal.vue';
jest.mock('~/flash');
jest.mock('~/sidebar/services/sidebar_service');
diff --git a/spec/frontend/vue_shared/components/recaptcha_modal_spec.js b/spec/frontend/vue_shared/components/recaptcha_modal_spec.js
index 223e7187d99..8ab65efd388 100644
--- a/spec/frontend/vue_shared/components/recaptcha_modal_spec.js
+++ b/spec/frontend/vue_shared/components/recaptcha_modal_spec.js
@@ -2,7 +2,7 @@ import { shallowMount } from '@vue/test-utils';
import { eventHub } from '~/vue_shared/components/recaptcha_eventhub';
-import RecaptchaModal from '~/vue_shared/components/recaptcha_modal';
+import RecaptchaModal from '~/vue_shared/components/recaptcha_modal.vue';
describe('RecaptchaModal', () => {
const recaptchaFormId = 'recaptcha-form';
diff --git a/spec/frontend/vue_shared/components/slot_switch_spec.js b/spec/frontend/vue_shared/components/slot_switch_spec.js
index 71e6087c272..73307b5573f 100644
--- a/spec/frontend/vue_shared/components/slot_switch_spec.js
+++ b/spec/frontend/vue_shared/components/slot_switch_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
-import SlotSwitch from '~/vue_shared/components/slot_switch';
+import SlotSwitch from '~/vue_shared/components/slot_switch.vue';
describe('SlotSwitch', () => {
const slots = {
diff --git a/spec/helpers/button_helper_spec.rb b/spec/helpers/button_helper_spec.rb
index e918c34ffef..cf8887f9731 100644
--- a/spec/helpers/button_helper_spec.rb
+++ b/spec/helpers/button_helper_spec.rb
@@ -173,7 +173,7 @@ describe ButtonHelper do
expect(element.attr('data-clipboard-text')).to eq(nil)
expect(element.inner_text).to eq("")
- expect(element.to_html).to include sprite_icon('duplicate')
+ expect(element.to_html).to include sprite_icon('copy-to-clipboard')
end
end
diff --git a/spec/models/concerns/delete_with_limit_spec.rb b/spec/models/concerns/delete_with_limit_spec.rb
new file mode 100644
index 00000000000..52085f970f3
--- /dev/null
+++ b/spec/models/concerns/delete_with_limit_spec.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe DeleteWithLimit do
+ describe '.delete_with_limit' do
+ it 'deletes a limited amount of rows' do
+ create_list(:web_hook_log, 4)
+
+ expect do
+ WebHookLog.delete_with_limit(2)
+ end.to change { WebHookLog.count }.by(-2)
+ end
+ end
+end
diff --git a/spec/models/project_services/emails_on_push_service_spec.rb b/spec/models/project_services/emails_on_push_service_spec.rb
index 56f094ecb48..ce1952b503f 100644
--- a/spec/models/project_services/emails_on_push_service_spec.rb
+++ b/spec/models/project_services/emails_on_push_service_spec.rb
@@ -21,6 +21,22 @@ describe EmailsOnPushService do
end
end
+ context 'when properties is missing branches_to_be_notified' do
+ subject { described_class.new(properties: {}) }
+
+ it 'sets the default value to all' do
+ expect(subject.branches_to_be_notified).to eq('all')
+ end
+ end
+
+ context 'when branches_to_be_notified is already set' do
+ subject { described_class.new(properties: { branches_to_be_notified: 'protected' }) }
+
+ it 'does not overwrite it with the default value' do
+ expect(subject.branches_to_be_notified).to eq('protected')
+ end
+ end
+
context 'project emails' do
let(:push_data) { { object_kind: 'push' } }
let(:project) { create(:project, :repository) }
diff --git a/spec/requests/api/services_spec.rb b/spec/requests/api/services_spec.rb
index 5dc7de0ab8b..628d5533366 100644
--- a/spec/requests/api/services_spec.rb
+++ b/spec/requests/api/services_spec.rb
@@ -127,21 +127,6 @@ describe API::Services do
expect(json_response['properties'].keys).to match_array(service_instance.api_field_names)
end
- it "returns empty hash or nil values if properties and data fields are empty" do
- # deprecated services are not valid for update
- initialized_service.update_attribute(:properties, {})
-
- if initialized_service.data_fields_present?
- initialized_service.data_fields.destroy
- initialized_service.reload
- end
-
- get api("/projects/#{project.id}/services/#{dashed_service}", user)
-
- expect(response).to have_gitlab_http_status(200)
- expect(json_response['properties'].values.compact).to be_empty
- end
-
it "returns error when authenticated but not a project owner" do
project.add_developer(user2)
get api("/projects/#{project.id}/services/#{dashed_service}", user2)
diff --git a/yarn.lock b/yarn.lock
index bf9b9c1d653..58ab2e590f4 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -705,18 +705,22 @@
exec-sh "^0.3.2"
minimist "^1.2.0"
-"@gitlab/eslint-config@^2.0.0":
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/@gitlab/eslint-config/-/eslint-config-2.0.0.tgz#e30dbf2b170a7a4ca003a321de9f4170a2512510"
- integrity sha512-3Zw3ww8Q4hhVYxO7vliByD0yTeAQn4iBxOyqlASAZepZgdu/OmM4NPbWyntpTfDyHGoRGxmzEaCqv7DS6ubACA==
- dependencies:
- babel-eslint "^10.0.1"
- eslint-config-airbnb-base "^13.1.0"
- eslint-config-prettier "^3.3.0"
+"@gitlab/eslint-config@^2.1.1":
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/@gitlab/eslint-config/-/eslint-config-2.1.1.tgz#64fcc8135f1a6055181fd64b991e33eb43913153"
+ integrity sha512-+rQA+gIcZbkaQ7GIjDjfMnYz41fFtsEaF0cRmk0KSqXWTKmOi4gcYZppIPdRvJWKhNPRS735Y5Of3gdIObINYQ==
+ dependencies:
+ "@gitlab/eslint-plugin-i18n" "^1.1.0"
+ "@gitlab/eslint-plugin-vue-i18n" "^1.2.0"
+ babel-eslint "^10.0.3"
+ eslint-config-airbnb-base "^13.2.0"
+ eslint-config-prettier "^3.6.0"
+ eslint-plugin-babel "^5.3.0"
eslint-plugin-filenames "^1.3.2"
- eslint-plugin-import "^2.18.2"
- eslint-plugin-promise "^4.1.1"
- eslint-plugin-vue "^5.0.0"
+ eslint-plugin-import "^2.20.0"
+ eslint-plugin-no-jquery "^2.3.1"
+ eslint-plugin-promise "^4.2.1"
+ eslint-plugin-vue "^5.2.3"
"@gitlab/eslint-plugin-i18n@^1.1.0":
version "1.1.0"
@@ -1675,6 +1679,14 @@ array-unique@^0.3.2:
resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+array.prototype.flat@^1.2.1:
+ version "1.2.3"
+ resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.2.3.tgz#0de82b426b0318dbfdb940089e38b043d37f6c7b"
+ integrity sha512-gBlRZV0VSmfPIeWfuuy56XZMvbVfbEUnOXUvt3F/eUUUSyzlgLxhEX4YAEpxNAogRGehPSnfXyPtYyKAhkzQhQ==
+ dependencies:
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0-next.1"
+
arraybuffer.slice@~0.0.7:
version "0.0.7"
resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz#3bbc4275dd584cc1b10809b89d4e8b63a69e7675"
@@ -1832,17 +1844,17 @@ babel-code-frame@^6.26.0:
esutils "^2.0.2"
js-tokens "^3.0.2"
-babel-eslint@^10.0.1:
- version "10.0.1"
- resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.1.tgz#919681dc099614cd7d31d45c8908695092a1faed"
- integrity sha512-z7OT1iNV+TjOwHNLLyJk+HN+YVWX+CLE6fPD2SymJZOZQBs+QIexFjhm4keGTm8MW9xr4EC9Q0PbaLB24V5GoQ==
+babel-eslint@^10.0.3:
+ version "10.0.3"
+ resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-10.0.3.tgz#81a2c669be0f205e19462fed2482d33e4687a88a"
+ integrity sha512-z3U7eMY6r/3f3/JB9mTsLjyxrv0Yb1zb8PCWCLpguxfCzBIZUwy23R1t/XKewP+8mEN2Ck8Dtr4q20z6ce6SoA==
dependencies:
"@babel/code-frame" "^7.0.0"
"@babel/parser" "^7.0.0"
"@babel/traverse" "^7.0.0"
"@babel/types" "^7.0.0"
- eslint-scope "3.7.1"
eslint-visitor-keys "^1.0.0"
+ resolve "^1.12.0"
babel-jest@^24.1.0, babel-jest@^24.8.0:
version "24.8.0"
@@ -2878,6 +2890,11 @@ configstore@^3.0.0:
write-file-atomic "^2.0.0"
xdg-basedir "^3.0.0"
+confusing-browser-globals@^1.0.5:
+ version "1.0.9"
+ resolved "https://registry.yarnpkg.com/confusing-browser-globals/-/confusing-browser-globals-1.0.9.tgz#72bc13b483c0276801681871d4898516f8f54fdd"
+ integrity sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==
+
connect-history-api-fallback@^1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
@@ -4156,21 +4173,22 @@ error-ex@^1.2.0, error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
-es-abstract@^1.12.0, es-abstract@^1.5.1, es-abstract@^1.6.1, es-abstract@^1.7.0:
- version "1.16.2"
- resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.16.2.tgz#4e874331645e9925edef141e74fc4bd144669d34"
- integrity sha512-jYo/J8XU2emLXl3OLwfwtuFfuF2w6DYPs+xy9ZfVyPkDcrauu6LYrw/q2TyCtrbc/KUdCiC5e9UajRhgNkVopA==
+es-abstract@^1.12.0, es-abstract@^1.17.0-next.1, es-abstract@^1.5.1, es-abstract@^1.7.0:
+ version "1.17.4"
+ resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.4.tgz#e3aedf19706b20e7c2594c35fc0d57605a79e184"
+ integrity sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==
dependencies:
es-to-primitive "^1.2.1"
function-bind "^1.1.1"
has "^1.0.3"
has-symbols "^1.0.1"
- is-callable "^1.1.4"
- is-regex "^1.0.4"
+ is-callable "^1.1.5"
+ is-regex "^1.0.5"
object-inspect "^1.7.0"
object-keys "^1.1.1"
- string.prototype.trimleft "^2.1.0"
- string.prototype.trimright "^2.1.0"
+ object.assign "^4.1.0"
+ string.prototype.trimleft "^2.1.1"
+ string.prototype.trimright "^2.1.1"
es-to-primitive@^1.2.1:
version "1.2.1"
@@ -4213,19 +4231,19 @@ escodegen@^1.9.1:
optionalDependencies:
source-map "~0.6.1"
-eslint-config-airbnb-base@^13.1.0:
- version "13.1.0"
- resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz#b5a1b480b80dfad16433d6c4ad84e6605052c05c"
- integrity sha512-XWwQtf3U3zIoKO1BbHh6aUhJZQweOwSt4c2JrPDg9FP3Ltv3+YfEv7jIDB8275tVnO/qOHbfuYg3kzw6Je7uWw==
+eslint-config-airbnb-base@^13.2.0:
+ version "13.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.2.0.tgz#f6ea81459ff4dec2dda200c35f1d8f7419d57943"
+ integrity sha512-1mg/7eoB4AUeB0X1c/ho4vb2gYkNH8Trr/EgCT/aGmKhhG+F6vF5s8+iRBlWAzFIAphxIdp3YfEKgEl0f9Xg+w==
dependencies:
- eslint-restricted-globals "^0.1.1"
+ confusing-browser-globals "^1.0.5"
object.assign "^4.1.0"
- object.entries "^1.0.4"
+ object.entries "^1.1.0"
-eslint-config-prettier@^3.3.0:
- version "3.3.0"
- resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-3.3.0.tgz#41afc8d3b852e757f06274ed6c44ca16f939a57d"
- integrity sha512-Bc3bh5bAcKNvs3HOpSi6EfGA2IIp7EzWcg2tS4vP7stnXu/J1opihHDM7jI9JCIckyIDTgZLSWn7J3HY0j2JfA==
+eslint-config-prettier@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-3.6.0.tgz#8ca3ffac4bd6eeef623a0651f9d754900e3ec217"
+ integrity sha512-ixJ4U3uTLXwJts4rmSVW/lMXjlGwCijhBJHk8iVqKKSifeI0qgFEfWl8L63isfc8Od7EiBALF6BX3jKLluf/jQ==
dependencies:
get-stdin "^6.0.0"
@@ -4262,14 +4280,21 @@ eslint-import-resolver-webpack@^0.10.1:
resolve "^1.4.0"
semver "^5.3.0"
-eslint-module-utils@^2.4.0:
- version "2.4.1"
- resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.4.1.tgz#7b4675875bf96b0dbf1b21977456e5bb1f5e018c"
- integrity sha512-H6DOj+ejw7Tesdgbfs4jeS4YMFrT8uI8xwd1gtQqXssaR0EQ26L+2O/w6wkYFy2MymON0fTwHmXBvvfLNZVZEw==
+eslint-module-utils@^2.4.1:
+ version "2.5.2"
+ resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.5.2.tgz#7878f7504824e1b857dd2505b59a8e5eda26a708"
+ integrity sha512-LGScZ/JSlqGKiT8OC+cYRxseMjyqt6QO54nl281CK93unD89ijSeRV6An8Ci/2nvWVKe8K/Tqdm75RQoIOCr+Q==
dependencies:
- debug "^2.6.8"
+ debug "^2.6.9"
pkg-dir "^2.0.0"
+eslint-plugin-babel@^5.3.0:
+ version "5.3.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-babel/-/eslint-plugin-babel-5.3.0.tgz#2e7f251ccc249326da760c1a4c948a91c32d0023"
+ integrity sha512-HPuNzSPE75O+SnxHIafbW5QB45r2w78fxqwK3HmjqIUoPfPzVrq6rD+CINU3yzoDSzEhUkX07VUphbF73Lth/w==
+ dependencies:
+ eslint-rule-composer "^0.3.0"
+
eslint-plugin-filenames@^1.3.2:
version "1.3.2"
resolved "https://registry.yarnpkg.com/eslint-plugin-filenames/-/eslint-plugin-filenames-1.3.2.tgz#7094f00d7aefdd6999e3ac19f72cea058e590cf7"
@@ -4280,22 +4305,23 @@ eslint-plugin-filenames@^1.3.2:
lodash.snakecase "4.1.1"
lodash.upperfirst "4.3.1"
-eslint-plugin-import@^2.18.2:
- version "2.18.2"
- resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.18.2.tgz#02f1180b90b077b33d447a17a2326ceb400aceb6"
- integrity sha512-5ohpsHAiUBRNaBWAF08izwUGlbrJoJJ+W9/TBwsGoR1MnlgfwMIKrFeSjWbt6moabiXW9xNvtFz+97KHRfI4HQ==
+eslint-plugin-import@^2.20.0:
+ version "2.20.0"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.20.0.tgz#d749a7263fb6c29980def8e960d380a6aa6aecaa"
+ integrity sha512-NK42oA0mUc8Ngn4kONOPsPB1XhbUvNHqF+g307dPV28aknPoiNnKLFd9em4nkswwepdF5ouieqv5Th/63U7YJQ==
dependencies:
array-includes "^3.0.3"
+ array.prototype.flat "^1.2.1"
contains-path "^0.1.0"
debug "^2.6.9"
doctrine "1.5.0"
eslint-import-resolver-node "^0.3.2"
- eslint-module-utils "^2.4.0"
+ eslint-module-utils "^2.4.1"
has "^1.0.3"
minimatch "^3.0.4"
object.values "^1.1.0"
read-pkg-up "^2.0.0"
- resolve "^1.11.0"
+ resolve "^1.12.0"
eslint-plugin-jasmine@^2.10.1:
version "2.10.1"
@@ -4307,35 +4333,27 @@ eslint-plugin-jest@^22.3.0:
resolved "https://registry.yarnpkg.com/eslint-plugin-jest/-/eslint-plugin-jest-22.3.0.tgz#a10f10dedfc92def774ec9bb5bfbd2fb8e1c96d2"
integrity sha512-P1mYVRNlOEoO5T9yTqOfucjOYf1ktmJ26NjwjH8sxpCFQa6IhBGr5TpKl3hcAAT29hOsRJVuMWmTsHoUVo9FoA==
-eslint-plugin-no-jquery@^2.3.0:
- version "2.3.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.3.0.tgz#fccdad84afa61baa4c0527dd6249cdcbfa0f74a8"
- integrity sha512-XQQZM5yKO72Y8QAojNhH8oYLnLZU34FovNHVoJlPLBuBPJk0kkiPNOS/K6wRFbVgn47iZHsT6E+7mSLwbcQEsg==
+eslint-plugin-no-jquery@^2.3.0, eslint-plugin-no-jquery@^2.3.1:
+ version "2.3.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-no-jquery/-/eslint-plugin-no-jquery-2.3.1.tgz#1c364cb863a38cc1570c8020155b6004cca62178"
+ integrity sha512-/fiQUBSOMUETnfBuiK5ewvtRbek1IRTy5ov/6RZ6nlybvZ337vyGaNPWM1KgaIoIeN7dairNrPfq0h7A0tpT3A==
-eslint-plugin-promise@^4.1.1:
- version "4.1.1"
- resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.1.1.tgz#1e08cb68b5b2cd8839f8d5864c796f56d82746db"
- integrity sha512-faAHw7uzlNPy7b45J1guyjazw28M+7gJokKUjC5JSFoYfUEyy6Gw/i7YQvmv2Yk00sUjWcmzXQLpU1Ki/C2IZQ==
+eslint-plugin-promise@^4.2.1:
+ version "4.2.1"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-4.2.1.tgz#845fd8b2260ad8f82564c1222fce44ad71d9418a"
+ integrity sha512-VoM09vT7bfA7D+upt+FjeBO5eHIJQBUWki1aPvB+vbNiHS3+oGIJGIeyBtKQTME6UPXXy3vV07OL1tHd3ANuDw==
-eslint-plugin-vue@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-5.0.0.tgz#4a2cc1c0e71ea45e1bd9c1a60f925bfe68bb5710"
- integrity sha512-mSv2Ebz3RaPP+XJO/mu7F+SdR9lrMyGISSExnarLFqqf3pF5wTmwWNrhHW1o9zKzKI811UVTIIkWJJvgO6SsUQ==
+eslint-plugin-vue@^5.2.3:
+ version "5.2.3"
+ resolved "https://registry.yarnpkg.com/eslint-plugin-vue/-/eslint-plugin-vue-5.2.3.tgz#3ee7597d823b5478804b2feba9863b1b74273961"
+ integrity sha512-mGwMqbbJf0+VvpGR5Lllq0PMxvTdrZ/ZPjmhkacrCHbubJeJOt+T6E3HUzAifa2Mxi7RSdJfC9HFpOeSYVMMIw==
dependencies:
- vue-eslint-parser "^4.0.2"
+ vue-eslint-parser "^5.0.0"
-eslint-restricted-globals@^0.1.1:
- version "0.1.1"
- resolved "https://registry.yarnpkg.com/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz#35f0d5cbc64c2e3ed62e93b4b1a7af05ba7ed4d7"
- integrity sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=
-
-eslint-scope@3.7.1:
- version "3.7.1"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8"
- integrity sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=
- dependencies:
- esrecurse "^4.1.0"
- estraverse "^4.1.1"
+eslint-rule-composer@^0.3.0:
+ version "0.3.0"
+ resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9"
+ integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg==
eslint-scope@^4.0.0, eslint-scope@^4.0.3:
version "4.0.3"
@@ -5033,7 +5051,7 @@ fstream@^1.0.0, fstream@^1.0.12:
mkdirp ">=0.5 0"
rimraf "2"
-function-bind@^1.1.0, function-bind@^1.1.1:
+function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
@@ -5932,10 +5950,10 @@ is-buffer@^2.0.0, is-buffer@^2.0.2:
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.3.tgz#4ecf3fcf749cbd1e472689e109ac66261a25e725"
integrity sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==
-is-callable@^1.1.4:
- version "1.1.4"
- resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
- integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
+is-callable@^1.1.4, is-callable@^1.1.5:
+ version "1.1.5"
+ resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.5.tgz#f7e46b596890456db74e7f6e976cb3273d06faab"
+ integrity sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==
is-ci@^1.0.10:
version "1.2.1"
@@ -6153,12 +6171,12 @@ is-redirect@^1.0.0:
resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
-is-regex@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
- integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=
+is-regex@^1.0.5:
+ version "1.0.5"
+ resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.5.tgz#39d589a358bf18967f726967120b8fc1aed74eae"
+ integrity sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==
dependencies:
- has "^1.0.1"
+ has "^1.0.3"
is-regexp@^1.0.0:
version "1.0.0"
@@ -8254,15 +8272,15 @@ object.assign@^4.1.0:
has-symbols "^1.0.0"
object-keys "^1.0.11"
-object.entries@^1.0.4:
- version "1.0.4"
- resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.0.4.tgz#1bf9a4dd2288f5b33f3a993d257661f05d161a5f"
- integrity sha1-G/mk3SKI9bM/Opk9JXZh8F0WGl8=
+object.entries@^1.1.0:
+ version "1.1.1"
+ resolved "https://registry.yarnpkg.com/object.entries/-/object.entries-1.1.1.tgz#ee1cf04153de02bb093fec33683900f57ce5399b"
+ integrity sha512-ilqR7BgdyZetJutmDPfXCDffGa0/Yzl2ivVNpbx/g4UeWrCdRnFDUBrKJGLhGieRHDATnyZXWBeCb29k9CJysQ==
dependencies:
- define-properties "^1.1.2"
- es-abstract "^1.6.1"
- function-bind "^1.1.0"
- has "^1.0.1"
+ define-properties "^1.1.3"
+ es-abstract "^1.17.0-next.1"
+ function-bind "^1.1.1"
+ has "^1.0.3"
object.getownpropertydescriptors@^2.0.3:
version "2.0.3"
@@ -9811,10 +9829,10 @@ resolve@1.1.7:
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
-resolve@1.x, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0:
- version "1.12.0"
- resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6"
- integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==
+resolve@1.x, resolve@^1.10.0, resolve@^1.12.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0:
+ version "1.15.0"
+ resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.15.0.tgz#1b7ca96073ebb52e741ffd799f6b39ea462c67f5"
+ integrity sha512-+hTmAldEGE80U2wJJDC1lebb5jWqvTYAfm3YZ1ckk1gBr0MnCqUKlwK1e+anaFljIl+F5tR5IoZcm4ZDA1zMQw==
dependencies:
path-parse "^1.0.6"
@@ -10593,18 +10611,18 @@ string-width@^4.1.0:
is-fullwidth-code-point "^3.0.0"
strip-ansi "^5.2.0"
-string.prototype.trimleft@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634"
- integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==
+string.prototype.trimleft@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz#9bdb8ac6abd6d602b17a4ed321870d2f8dcefc74"
+ integrity sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==
dependencies:
define-properties "^1.1.3"
function-bind "^1.1.1"
-string.prototype.trimright@^2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58"
- integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==
+string.prototype.trimright@^2.1.1:
+ version "2.1.1"
+ resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz#440314b15996c866ce8a0341894d45186200c5d9"
+ integrity sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==
dependencies:
define-properties "^1.1.3"
function-bind "^1.1.1"
@@ -11659,10 +11677,10 @@ vue-apollo@^3.0.0-beta.28:
chalk "^2.4.1"
throttle-debounce "^2.0.0"
-vue-eslint-parser@^4.0.2:
- version "4.0.3"
- resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-4.0.3.tgz#80cf162e484387b2640371ad21ba1f86e0c10a61"
- integrity sha512-AUeQsYdO6+7QXCems+WvGlrXd37PHv/zcRQSQdY1xdOMwdFAPEnMBsv7zPvk0TPGulXkK/5p/ITgrjiYB7k3ag==
+vue-eslint-parser@^5.0.0:
+ version "5.0.0"
+ resolved "https://registry.yarnpkg.com/vue-eslint-parser/-/vue-eslint-parser-5.0.0.tgz#00f4e4da94ec974b821a26ff0ed0f7a78402b8a1"
+ integrity sha512-JlHVZwBBTNVvzmifwjpZYn0oPWH2SgWv5dojlZBsrhablDu95VFD+hriB1rQGwbD+bms6g+rAFhQHk6+NyiS6g==
dependencies:
debug "^4.1.0"
eslint-scope "^4.0.0"