summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitlab/CODEOWNERS2
-rw-r--r--app/assets/javascripts/api.js6
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue2
-rw-r--r--app/assets/javascripts/clusters/components/application_row.vue2
-rw-r--r--app/assets/javascripts/clusters/components/applications.vue2
-rw-r--r--app/assets/javascripts/diffs/components/app.vue38
-rw-r--r--app/assets/javascripts/diffs/components/commit_item.vue2
-rw-r--r--app/assets/javascripts/diffs/components/diff_file_header.vue3
-rw-r--r--app/assets/javascripts/diffs/components/inline_diff_expansion_row.vue2
-rw-r--r--app/assets/javascripts/diffs/store/actions.js5
-rw-r--r--app/assets/javascripts/diffs/store/modules/diff_state.js1
-rw-r--r--app/assets/javascripts/diffs/store/mutation_types.js1
-rw-r--r--app/assets/javascripts/diffs/store/mutations.js4
-rw-r--r--app/assets/javascripts/environments/components/environment_rollback.vue2
-rw-r--r--app/assets/javascripts/environments/components/stop_environment_modal.vue2
-rw-r--r--app/assets/javascripts/error_tracking_settings/components/project_dropdown.vue5
-rw-r--r--app/assets/javascripts/grafana_integration/components/grafana_integration.vue3
-rw-r--r--app/assets/javascripts/groups/components/item_stats.vue2
-rw-r--r--app/assets/javascripts/ide/components/commit_sidebar/list_item.vue4
-rw-r--r--app/assets/javascripts/ide/components/ide_tree.vue2
-rw-r--r--app/assets/javascripts/ide/components/ide_tree_list.vue2
-rw-r--r--app/assets/javascripts/ide/components/nav_dropdown.vue2
-rw-r--r--app/assets/javascripts/ide/components/new_dropdown/upload.vue2
-rw-r--r--app/assets/javascripts/ide/components/repo_commit_section.vue2
-rw-r--r--app/assets/javascripts/ide/components/repo_tabs.vue2
-rw-r--r--app/assets/javascripts/import_projects/components/provider_repo_table_row.vue2
-rw-r--r--app/assets/javascripts/jobs/components/stages_dropdown.vue2
-rw-r--r--app/assets/javascripts/monitoring/components/charts/anomaly.vue3
-rw-r--r--app/assets/javascripts/monitoring/components/embed.vue2
-rw-r--r--app/assets/javascripts/mr_popover/components/mr_popover.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/nav_controls.vue3
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_stop_modal.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/pipeline_url.vue2
-rw-r--r--app/assets/javascripts/pipelines/components/test_reports/test_summary.vue3
-rw-r--r--app/assets/javascripts/registry/settings/components/registry_settings_app.vue42
-rw-r--r--app/assets/javascripts/registry/settings/components/settings_form.vue158
-rw-r--r--app/assets/javascripts/registry/settings/constants.js15
-rw-r--r--app/assets/javascripts/registry/settings/registry_settings_bundle.js2
-rw-r--r--app/assets/javascripts/registry/settings/store/actions.js40
-rw-r--r--app/assets/javascripts/registry/settings/store/index.js (renamed from app/assets/javascripts/registry/settings/stores/index.js)0
-rw-r--r--app/assets/javascripts/registry/settings/store/mutation_types.js5
-rw-r--r--app/assets/javascripts/registry/settings/store/mutations.js20
-rw-r--r--app/assets/javascripts/registry/settings/store/state.js26
-rw-r--r--app/assets/javascripts/registry/settings/stores/actions.js6
-rw-r--r--app/assets/javascripts/registry/settings/stores/mutation_types.js4
-rw-r--r--app/assets/javascripts/registry/settings/stores/mutations.js8
-rw-r--r--app/assets/javascripts/registry/settings/stores/state.js10
-rw-r--r--app/assets/javascripts/releases/list/components/release_block.vue3
-rw-r--r--app/assets/javascripts/reports/components/modal.vue2
-rw-r--r--app/assets/javascripts/serverless/components/functions.vue2
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue3
-rw-r--r--app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue2
-rw-r--r--app/assets/javascripts/vue_shared/components/markdown/suggestions.vue1
-rw-r--r--app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_regular_label.vue3
-rw-r--r--app/assets/javascripts/vuex_shared/bindings.js16
-rw-r--r--app/assets/stylesheets/utilities.scss6
-rw-r--r--app/views/projects/registry/settings/_index.haml3
-rw-r--r--app/views/projects/settings/ci_cd/show.html.haml5
-rw-r--r--changelogs/unreleased/rk-118664-upgrade-monaco-editor.yml5
-rw-r--r--doc/user/application_security/dast/index.md9
-rw-r--r--locale/gitlab.pot70
-rw-r--r--package.json5
-rw-r--r--spec/controllers/projects/error_tracking/projects_controller_spec.rb2
-rw-r--r--spec/features/merge_request/user_suggests_changes_on_diff_spec.rb4
-rw-r--r--spec/frontend/api_spec.js15
-rw-r--r--spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap14
-rw-r--r--spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap155
-rw-r--r--spec/frontend/registry/settings/components/registry_settings_app_spec.js36
-rw-r--r--spec/frontend/registry/settings/components/settings_form_spec.js154
-rw-r--r--spec/frontend/registry/settings/store/actions_spec.js120
-rw-r--r--spec/frontend/registry/settings/store/mutations_spec.js54
-rw-r--r--spec/frontend/registry/settings/stores/actions_spec.js20
-rw-r--r--spec/frontend/registry/settings/stores/mutations_spec.js21
-rw-r--r--spec/frontend/vuex_shared/bindings_spec.js51
-rw-r--r--spec/javascripts/diffs/components/app_spec.js15
-rw-r--r--spec/javascripts/diffs/store/actions_spec.js4
-rw-r--r--spec/javascripts/diffs/store/mutations_spec.js10
-rw-r--r--yarn.lock8
78 files changed, 1036 insertions, 239 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS
index c8283326533..0e16e1407ac 100644
--- a/.gitlab/CODEOWNERS
+++ b/.gitlab/CODEOWNERS
@@ -3,7 +3,7 @@
*.rake @gitlab-org/maintainers/rails-backend
# Technical writing team are the default reviewers for everything in `doc/`
-/doc/ @gl-docsteam
+doc/ @gl-docsteam
# Frontend maintainers should see everything in `app/assets/`
app/assets/ @gitlab-org/maintainers/frontend
diff --git a/app/assets/javascripts/api.js b/app/assets/javascripts/api.js
index 071ae8ca8cf..5e3932db235 100644
--- a/app/assets/javascripts/api.js
+++ b/app/assets/javascripts/api.js
@@ -142,6 +142,12 @@ const Api = {
return axios.get(url);
},
+ // Update a single project
+ updateProject(projectPath, data) {
+ const url = Api.buildUrl(Api.projectPath).replace(':id', encodeURIComponent(projectPath));
+ return axios.put(url, data);
+ },
+
/**
* Get all projects for a forked relationship to a specified project
* @param {string} projectPath - Path or ID of a project
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index 5d7be0c705a..eeb0fbec1ed 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -9,7 +9,6 @@ import {
GlDropdownItem,
} from '@gitlab/ui';
-import Icon from '~/vue_shared/components/icon.vue';
import httpStatusCodes from '~/lib/utils/http_status';
import boardsStore from '../stores/boards_store';
import BoardForm from './board_form.vue';
@@ -19,7 +18,6 @@ const MIN_BOARDS_TO_VIEW_RECENT = 10;
export default {
name: 'BoardsSelector',
components: {
- Icon,
BoardForm,
GlLoadingIcon,
GlSearchBoxByType,
diff --git a/app/assets/javascripts/clusters/components/application_row.vue b/app/assets/javascripts/clusters/components/application_row.vue
index c6c8dc6352c..ab1e5f92698 100644
--- a/app/assets/javascripts/clusters/components/application_row.vue
+++ b/app/assets/javascripts/clusters/components/application_row.vue
@@ -2,7 +2,6 @@
/* eslint-disable vue/require-default-prop */
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { GlLink, GlModalDirective } from '@gitlab/ui';
-import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue';
import { s__, __, sprintf } from '~/locale';
import eventHub from '../event_hub';
import identicon from '../../vue_shared/components/identicon.vue';
@@ -16,7 +15,6 @@ export default {
components: {
loadingButton,
identicon,
- TimeagoTooltip,
GlLink,
UninstallApplicationButton,
UninstallApplicationConfirmationModal,
diff --git a/app/assets/javascripts/clusters/components/applications.vue b/app/assets/javascripts/clusters/components/applications.vue
index a0ab20a97aa..99844a356c8 100644
--- a/app/assets/javascripts/clusters/components/applications.vue
+++ b/app/assets/javascripts/clusters/components/applications.vue
@@ -19,7 +19,6 @@ import applicationRow from './application_row.vue';
import clipboardButton from '../../vue_shared/components/clipboard_button.vue';
import KnativeDomainEditor from './knative_domain_editor.vue';
import { CLUSTER_TYPE, PROVIDER_TYPE, APPLICATION_STATUS, INGRESS } from '../constants';
-import LoadingButton from '~/vue_shared/components/loading_button.vue';
import eventHub from '~/clusters/event_hub';
import CrossplaneProviderStack from './crossplane_provider_stack.vue';
@@ -27,7 +26,6 @@ export default {
components: {
applicationRow,
clipboardButton,
- LoadingButton,
GlLoadingIcon,
KnativeDomainEditor,
CrossplaneProviderStack,
diff --git a/app/assets/javascripts/diffs/components/app.vue b/app/assets/javascripts/diffs/components/app.vue
index 8ea443814e9..c07850b1a4f 100644
--- a/app/assets/javascripts/diffs/components/app.vue
+++ b/app/assets/javascripts/diffs/components/app.vue
@@ -2,7 +2,6 @@
import { mapState, mapGetters, mapActions } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import Mousetrap from 'mousetrap';
-import Icon from '~/vue_shared/components/icon.vue';
import { __ } from '~/locale';
import createFlash from '~/flash';
import PanelResizer from '~/vue_shared/components/panel_resizer.vue';
@@ -27,7 +26,6 @@ import {
export default {
name: 'DiffsApp',
components: {
- Icon,
CompareVersions,
DiffFile,
NoChanges,
@@ -95,7 +93,6 @@ export default {
parseInt(localStorage.getItem(TREE_LIST_WIDTH_STORAGE_KEY), 10) || INITIAL_TREE_WIDTH;
return {
- assignedDiscussions: false,
treeWidth,
};
},
@@ -114,6 +111,7 @@ export default {
numVisibleFiles: state => state.diffs.size,
plainDiffPath: state => state.diffs.plainDiffPath,
emailPatchPath: state => state.diffs.emailPatchPath,
+ retrievingBatches: state => state.diffs.retrievingBatches,
}),
...mapState('diffs', ['showTreeList', 'isLoading', 'startVersion']),
...mapGetters('diffs', ['isParallelView', 'currentDiffIndex']),
@@ -144,9 +142,6 @@ export default {
isLimitedContainer() {
return !this.showTreeList && !this.isParallelView && !this.isFluidLayout;
},
- shouldSetDiscussions() {
- return this.isNotesFetched && !this.assignedDiscussions && !this.isLoading;
- },
},
watch: {
diffViewType() {
@@ -163,10 +158,8 @@ export default {
},
isLoading: 'adjustView',
showTreeList: 'adjustView',
- shouldSetDiscussions(newVal) {
- if (newVal) {
- this.setDiscussions();
- }
+ retrievingBatches(newVal) {
+ if (!newVal) this.unwatchDiscussions();
},
},
mounted() {
@@ -192,10 +185,14 @@ export default {
},
created() {
this.adjustView();
- eventHub.$once('fetchedNotesData', this.setDiscussions);
eventHub.$once('fetchDiffData', this.fetchData);
eventHub.$on('refetchDiffData', this.refetchDiffData);
this.CENTERED_LIMITED_CONTAINER_CLASSES = CENTERED_LIMITED_CONTAINER_CLASSES;
+
+ this.unwatchDiscussions = this.$watch(
+ () => `${this.diffFiles.length}:${this.$store.state.notes.discussions.length}`,
+ () => this.setDiscussions(),
+ );
},
beforeDestroy() {
eventHub.$off('fetchDiffData', this.fetchData);
@@ -217,7 +214,6 @@ export default {
'toggleShowTreeList',
]),
refetchDiffData() {
- this.assignedDiscussions = false;
this.fetchData(false);
},
startDiffRendering() {
@@ -269,17 +265,13 @@ export default {
}
},
setDiscussions() {
- if (this.shouldSetDiscussions) {
- this.assignedDiscussions = true;
-
- requestIdleCallback(
- () =>
- this.assignDiscussionsToDiff()
- .then(this.$nextTick)
- .then(this.startTaskList),
- { timeout: 1000 },
- );
- }
+ requestIdleCallback(
+ () =>
+ this.assignDiscussionsToDiff()
+ .then(this.$nextTick)
+ .then(this.startTaskList),
+ { timeout: 1000 },
+ );
},
adjustView() {
if (this.shouldShow) {
diff --git a/app/assets/javascripts/diffs/components/commit_item.vue b/app/assets/javascripts/diffs/components/commit_item.vue
index 43a7703f611..cfffccd54eb 100644
--- a/app/assets/javascripts/diffs/components/commit_item.vue
+++ b/app/assets/javascripts/diffs/components/commit_item.vue
@@ -2,7 +2,6 @@
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import Icon from '~/vue_shared/components/icon.vue';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
-import CIIcon from '~/vue_shared/components/ci_icon.vue';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import CommitPipelineStatus from '~/projects/tree/components/commit_pipeline_status_component.vue';
import initUserPopovers from '../../user_popovers';
@@ -25,7 +24,6 @@ export default {
UserAvatarLink,
Icon,
ClipboardButton,
- CIIcon,
TimeAgoTooltip,
CommitPipelineStatus,
},
diff --git a/app/assets/javascripts/diffs/components/diff_file_header.vue b/app/assets/javascripts/diffs/components/diff_file_header.vue
index 91d374eafc0..5d27c6eb865 100644
--- a/app/assets/javascripts/diffs/components/diff_file_header.vue
+++ b/app/assets/javascripts/diffs/components/diff_file_header.vue
@@ -1,7 +1,7 @@
<script>
import _ from 'underscore';
import { mapActions, mapGetters } from 'vuex';
-import { GlButton, GlTooltipDirective, GlTooltip, GlLoadingIcon } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective, GlLoadingIcon } from '@gitlab/ui';
import { polyfillSticky } from '~/lib/utils/sticky';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import Icon from '~/vue_shared/components/icon.vue';
@@ -15,7 +15,6 @@ import { scrollToElement } from '~/lib/utils/common_utils';
export default {
components: {
- GlTooltip,
GlLoadingIcon,
GlButton,
ClipboardButton,
diff --git a/app/assets/javascripts/diffs/components/inline_diff_expansion_row.vue b/app/assets/javascripts/diffs/components/inline_diff_expansion_row.vue
index 6e732727f42..071a988d789 100644
--- a/app/assets/javascripts/diffs/components/inline_diff_expansion_row.vue
+++ b/app/assets/javascripts/diffs/components/inline_diff_expansion_row.vue
@@ -1,11 +1,9 @@
<script>
-import Icon from '~/vue_shared/components/icon.vue';
import DiffExpansionCell from './diff_expansion_cell.vue';
import { MATCH_LINE_TYPE } from '../constants';
export default {
components: {
- Icon,
DiffExpansionCell,
},
props: {
diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js
index 992b45c97ac..6f2467ddf71 100644
--- a/app/assets/javascripts/diffs/store/actions.js
+++ b/app/assets/javascripts/diffs/store/actions.js
@@ -91,6 +91,7 @@ export const fetchDiffFiles = ({ state, commit }) => {
export const fetchDiffFilesBatch = ({ commit, state }) => {
commit(types.SET_BATCH_LOADING, true);
+ commit(types.SET_RETRIEVING_BATCHES, true);
const getBatch = page =>
axios
@@ -100,9 +101,11 @@ export const fetchDiffFilesBatch = ({ commit, state }) => {
.then(({ data: { pagination, diff_files } }) => {
commit(types.SET_DIFF_DATA_BATCH, { diff_files });
commit(types.SET_BATCH_LOADING, false);
+ if (!pagination.next_page) commit(types.SET_RETRIEVING_BATCHES, false);
return pagination.next_page;
})
- .then(nextPage => nextPage && getBatch(nextPage));
+ .then(nextPage => nextPage && getBatch(nextPage))
+ .catch(() => commit(types.SET_RETRIEVING_BATCHES, false));
return getBatch()
.then(handleLocationHash)
diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js
index 7366c50752c..011cd24500a 100644
--- a/app/assets/javascripts/diffs/store/modules/diff_state.js
+++ b/app/assets/javascripts/diffs/store/modules/diff_state.js
@@ -9,6 +9,7 @@ const defaultViewType = INLINE_DIFF_VIEW_TYPE;
export default () => ({
isLoading: true,
isBatchLoading: false,
+ retrievingBatches: false,
addedLines: null,
removedLines: null,
endpoint: '',
diff --git a/app/assets/javascripts/diffs/store/mutation_types.js b/app/assets/javascripts/diffs/store/mutation_types.js
index 5a90d78b2bc..2097c8d3655 100644
--- a/app/assets/javascripts/diffs/store/mutation_types.js
+++ b/app/assets/javascripts/diffs/store/mutation_types.js
@@ -1,6 +1,7 @@
export const SET_BASE_CONFIG = 'SET_BASE_CONFIG';
export const SET_LOADING = 'SET_LOADING';
export const SET_BATCH_LOADING = 'SET_BATCH_LOADING';
+export const SET_RETRIEVING_BATCHES = 'SET_RETRIEVING_BATCHES';
export const SET_DIFF_DATA = 'SET_DIFF_DATA';
export const SET_DIFF_DATA_BATCH = 'SET_DIFF_DATA_BATCH';
export const SET_DIFF_VIEW_TYPE = 'SET_DIFF_VIEW_TYPE';
diff --git a/app/assets/javascripts/diffs/store/mutations.js b/app/assets/javascripts/diffs/store/mutations.js
index 859f43b3b6d..a4986e26966 100644
--- a/app/assets/javascripts/diffs/store/mutations.js
+++ b/app/assets/javascripts/diffs/store/mutations.js
@@ -40,6 +40,10 @@ export default {
Object.assign(state, { isBatchLoading });
},
+ [types.SET_RETRIEVING_BATCHES](state, retrievingBatches) {
+ Object.assign(state, { retrievingBatches });
+ },
+
[types.SET_DIFF_DATA](state, data) {
if (
!(
diff --git a/app/assets/javascripts/environments/components/environment_rollback.vue b/app/assets/javascripts/environments/components/environment_rollback.vue
index bafbc00597e..6279bbc83ee 100644
--- a/app/assets/javascripts/environments/components/environment_rollback.vue
+++ b/app/assets/javascripts/environments/components/environment_rollback.vue
@@ -8,7 +8,6 @@
import { GlTooltipDirective, GlLoadingIcon, GlModalDirective, GlButton } from '@gitlab/ui';
import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
-import ConfirmRollbackModal from './confirm_rollback_modal.vue';
import eventHub from '../event_hub';
export default {
@@ -16,7 +15,6 @@ export default {
Icon,
GlLoadingIcon,
GlButton,
- ConfirmRollbackModal,
},
directives: {
GlTooltip: GlTooltipDirective,
diff --git a/app/assets/javascripts/environments/components/stop_environment_modal.vue b/app/assets/javascripts/environments/components/stop_environment_modal.vue
index 1ea4e30a7c1..43ebd7b2824 100644
--- a/app/assets/javascripts/environments/components/stop_environment_modal.vue
+++ b/app/assets/javascripts/environments/components/stop_environment_modal.vue
@@ -3,7 +3,6 @@
import { GlTooltipDirective } from '@gitlab/ui';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
import { s__, sprintf } from '~/locale';
-import LoadingButton from '~/vue_shared/components/loading_button.vue';
import eventHub from '../event_hub';
export default {
@@ -12,7 +11,6 @@ export default {
components: {
GlModal: DeprecatedModal2,
- LoadingButton,
},
directives: {
diff --git a/app/assets/javascripts/error_tracking_settings/components/project_dropdown.vue b/app/assets/javascripts/error_tracking_settings/components/project_dropdown.vue
index 82df02afafd..11fd06fb40b 100644
--- a/app/assets/javascripts/error_tracking_settings/components/project_dropdown.vue
+++ b/app/assets/javascripts/error_tracking_settings/components/project_dropdown.vue
@@ -1,14 +1,11 @@
<script>
-import { GlDropdown, GlDropdownHeader, GlDropdownItem } from '@gitlab/ui';
-import Icon from '~/vue_shared/components/icon.vue';
+import { GlDropdown, GlDropdownItem } from '@gitlab/ui';
import { getDisplayName } from '../utils';
export default {
components: {
GlDropdown,
- GlDropdownHeader,
GlDropdownItem,
- Icon,
},
props: {
dropdownLabel: {
diff --git a/app/assets/javascripts/grafana_integration/components/grafana_integration.vue b/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
index 6258ee7f153..41d83e45c52 100644
--- a/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
+++ b/app/assets/javascripts/grafana_integration/components/grafana_integration.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton, GlFormGroup, GlFormInput, GlFormCheckbox, GlLink } from '@gitlab/ui';
+import { GlButton, GlFormGroup, GlFormInput, GlFormCheckbox } from '@gitlab/ui';
import { mapState, mapActions } from 'vuex';
import Icon from '~/vue_shared/components/icon.vue';
@@ -9,7 +9,6 @@ export default {
GlFormCheckbox,
GlFormGroup,
GlFormInput,
- GlLink,
Icon,
},
data() {
diff --git a/app/assets/javascripts/groups/components/item_stats.vue b/app/assets/javascripts/groups/components/item_stats.vue
index 675552e6c2b..53da3f7b2ee 100644
--- a/app/assets/javascripts/groups/components/item_stats.vue
+++ b/app/assets/javascripts/groups/components/item_stats.vue
@@ -1,5 +1,4 @@
<script>
-import icon from '~/vue_shared/components/icon.vue';
import { GlBadge } from '@gitlab/ui';
import timeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import {
@@ -13,7 +12,6 @@ import isProjectPendingRemoval from 'ee_else_ce/groups/mixins/is_project_pending
export default {
components: {
- icon,
timeAgoTooltip,
itemStatsValue,
GlBadge,
diff --git a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
index 230dfaf047b..46a96301e88 100644
--- a/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
+++ b/app/assets/javascripts/ide/components/commit_sidebar/list_item.vue
@@ -3,16 +3,12 @@ import { mapActions } from 'vuex';
import tooltip from '~/vue_shared/directives/tooltip';
import Icon from '~/vue_shared/components/icon.vue';
import FileIcon from '~/vue_shared/components/file_icon.vue';
-import StageButton from './stage_button.vue';
-import UnstageButton from './unstage_button.vue';
import { viewerTypes } from '../../constants';
import { getCommitIconMap } from '../../utils';
export default {
components: {
Icon,
- StageButton,
- UnstageButton,
FileIcon,
},
directives: {
diff --git a/app/assets/javascripts/ide/components/ide_tree.vue b/app/assets/javascripts/ide/components/ide_tree.vue
index f93496132a4..598f3a1dac6 100644
--- a/app/assets/javascripts/ide/components/ide_tree.vue
+++ b/app/assets/javascripts/ide/components/ide_tree.vue
@@ -1,13 +1,11 @@
<script>
import { mapState, mapGetters, mapActions } from 'vuex';
-import Icon from '~/vue_shared/components/icon.vue';
import IdeTreeList from './ide_tree_list.vue';
import Upload from './new_dropdown/upload.vue';
import NewEntryButton from './new_dropdown/button.vue';
export default {
components: {
- Icon,
Upload,
IdeTreeList,
NewEntryButton,
diff --git a/app/assets/javascripts/ide/components/ide_tree_list.vue b/app/assets/javascripts/ide/components/ide_tree_list.vue
index 3a0dd60f0e0..bacdfc7c05e 100644
--- a/app/assets/javascripts/ide/components/ide_tree_list.vue
+++ b/app/assets/javascripts/ide/components/ide_tree_list.vue
@@ -1,14 +1,12 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import { GlSkeletonLoading } from '@gitlab/ui';
-import Icon from '~/vue_shared/components/icon.vue';
import FileRow from '~/vue_shared/components/file_row.vue';
import NavDropdown from './nav_dropdown.vue';
import FileRowExtra from './file_row_extra.vue';
export default {
components: {
- Icon,
GlSkeletonLoading,
NavDropdown,
FileRow,
diff --git a/app/assets/javascripts/ide/components/nav_dropdown.vue b/app/assets/javascripts/ide/components/nav_dropdown.vue
index e45d2a62dae..2e290de0943 100644
--- a/app/assets/javascripts/ide/components/nav_dropdown.vue
+++ b/app/assets/javascripts/ide/components/nav_dropdown.vue
@@ -1,12 +1,10 @@
<script>
import $ from 'jquery';
-import Icon from '~/vue_shared/components/icon.vue';
import NavForm from './nav_form.vue';
import NavDropdownButton from './nav_dropdown_button.vue';
export default {
components: {
- Icon,
NavDropdownButton,
NavForm,
},
diff --git a/app/assets/javascripts/ide/components/new_dropdown/upload.vue b/app/assets/javascripts/ide/components/new_dropdown/upload.vue
index 188518dd419..e52613086a4 100644
--- a/app/assets/javascripts/ide/components/new_dropdown/upload.vue
+++ b/app/assets/javascripts/ide/components/new_dropdown/upload.vue
@@ -1,10 +1,8 @@
<script>
-import Icon from '~/vue_shared/components/icon.vue';
import ItemButton from './button.vue';
export default {
components: {
- Icon,
ItemButton,
},
props: {
diff --git a/app/assets/javascripts/ide/components/repo_commit_section.vue b/app/assets/javascripts/ide/components/repo_commit_section.vue
index 5201c33b1b4..35d52bf7528 100644
--- a/app/assets/javascripts/ide/components/repo_commit_section.vue
+++ b/app/assets/javascripts/ide/components/repo_commit_section.vue
@@ -1,7 +1,6 @@
<script>
import { mapState, mapActions, mapGetters } from 'vuex';
import tooltip from '~/vue_shared/directives/tooltip';
-import Icon from '~/vue_shared/components/icon.vue';
import DeprecatedModal from '~/vue_shared/components/deprecated_modal.vue';
import CommitFilesList from './commit_sidebar/list.vue';
import EmptyState from './commit_sidebar/empty_state.vue';
@@ -11,7 +10,6 @@ import { activityBarViews, stageKeys } from '../constants';
export default {
components: {
DeprecatedModal,
- Icon,
CommitFilesList,
EmptyState,
},
diff --git a/app/assets/javascripts/ide/components/repo_tabs.vue b/app/assets/javascripts/ide/components/repo_tabs.vue
index 4dbc4383894..1b7f149097b 100644
--- a/app/assets/javascripts/ide/components/repo_tabs.vue
+++ b/app/assets/javascripts/ide/components/repo_tabs.vue
@@ -1,13 +1,11 @@
<script>
import { mapActions } from 'vuex';
import RepoTab from './repo_tab.vue';
-import EditorMode from './editor_mode_dropdown.vue';
import router from '../ide_router';
export default {
components: {
RepoTab,
- EditorMode,
},
props: {
activeFile: {
diff --git a/app/assets/javascripts/import_projects/components/provider_repo_table_row.vue b/app/assets/javascripts/import_projects/components/provider_repo_table_row.vue
index 3c6c9c71b8c..6e227ab3d82 100644
--- a/app/assets/javascripts/import_projects/components/provider_repo_table_row.vue
+++ b/app/assets/javascripts/import_projects/components/provider_repo_table_row.vue
@@ -2,7 +2,6 @@
import { mapState, mapGetters, mapActions } from 'vuex';
import Select2Select from '~/vue_shared/components/select2_select.vue';
import { __ } from '~/locale';
-import LoadingButton from '~/vue_shared/components/loading_button.vue';
import eventHub from '../event_hub';
import { STATUSES } from '../constants';
import ImportStatus from './import_status.vue';
@@ -11,7 +10,6 @@ export default {
name: 'ProviderRepoTableRow',
components: {
Select2Select,
- LoadingButton,
ImportStatus,
},
props: {
diff --git a/app/assets/javascripts/jobs/components/stages_dropdown.vue b/app/assets/javascripts/jobs/components/stages_dropdown.vue
index 6e92b599b0a..09f9647a680 100644
--- a/app/assets/javascripts/jobs/components/stages_dropdown.vue
+++ b/app/assets/javascripts/jobs/components/stages_dropdown.vue
@@ -2,12 +2,10 @@
import _ from 'underscore';
import { GlLink } from '@gitlab/ui';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
-import Icon from '~/vue_shared/components/icon.vue';
export default {
components: {
CiIcon,
- Icon,
GlLink,
},
props: {
diff --git a/app/assets/javascripts/monitoring/components/charts/anomaly.vue b/app/assets/javascripts/monitoring/components/charts/anomaly.vue
index 1df7ca37a98..64704701d1a 100644
--- a/app/assets/javascripts/monitoring/components/charts/anomaly.vue
+++ b/app/assets/javascripts/monitoring/components/charts/anomaly.vue
@@ -1,6 +1,6 @@
<script>
import { flatten, isNumber } from 'underscore';
-import { GlLineChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
+import { GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
import { roundOffFloat } from '~/lib/utils/common_utils';
import { hexToRgb } from '~/lib/utils/color_utils';
import { areaOpacityValues, symbolSizes, colorValues } from '../../constants';
@@ -48,7 +48,6 @@ const AREA_COLOR_RGBA = `rgba(${hexToRgb(AREA_COLOR).join(',')},${AREA_OPACITY})
*/
export default {
components: {
- GlLineChart,
GlChartSeriesLabel,
MonitorTimeSeriesChart,
},
diff --git a/app/assets/javascripts/monitoring/components/embed.vue b/app/assets/javascripts/monitoring/components/embed.vue
index eb8945c1a57..2f562071764 100644
--- a/app/assets/javascripts/monitoring/components/embed.vue
+++ b/app/assets/javascripts/monitoring/components/embed.vue
@@ -2,7 +2,6 @@
import { mapActions, mapState, mapGetters } from 'vuex';
import PanelType from 'ee_else_ce/monitoring/components/panel_type.vue';
import { getParameterValues, removeParams } from '~/lib/utils/url_utility';
-import GraphGroup from './graph_group.vue';
import { sidebarAnimationDuration } from '../constants';
import { getTimeDiff } from '../utils';
@@ -10,7 +9,6 @@ let sidebarMutationObserver;
export default {
components: {
- GraphGroup,
PanelType,
},
props: {
diff --git a/app/assets/javascripts/mr_popover/components/mr_popover.vue b/app/assets/javascripts/mr_popover/components/mr_popover.vue
index ce08b0964a1..bbc2feae812 100644
--- a/app/assets/javascripts/mr_popover/components/mr_popover.vue
+++ b/app/assets/javascripts/mr_popover/components/mr_popover.vue
@@ -1,7 +1,6 @@
<script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import { GlPopover, GlSkeletonLoading } from '@gitlab/ui';
-import Icon from '../../vue_shared/components/icon.vue';
import CiIcon from '../../vue_shared/components/ci_icon.vue';
import timeagoMixin from '../../vue_shared/mixins/timeago';
import query from '../queries/merge_request.query.graphql';
@@ -13,7 +12,6 @@ export default {
components: {
GlPopover,
GlSkeletonLoading,
- Icon,
CiIcon,
},
mixins: [timeagoMixin],
diff --git a/app/assets/javascripts/pipelines/components/nav_controls.vue b/app/assets/javascripts/pipelines/components/nav_controls.vue
index c6990683ec7..5e4147f8805 100644
--- a/app/assets/javascripts/pipelines/components/nav_controls.vue
+++ b/app/assets/javascripts/pipelines/components/nav_controls.vue
@@ -1,12 +1,11 @@
<script>
-import { GlLink, GlButton } from '@gitlab/ui';
+import { GlButton } from '@gitlab/ui';
import LoadingButton from '../../vue_shared/components/loading_button.vue';
export default {
name: 'PipelineNavControls',
components: {
LoadingButton,
- GlLink,
GlButton,
},
props: {
diff --git a/app/assets/javascripts/pipelines/components/pipeline_stop_modal.vue b/app/assets/javascripts/pipelines/components/pipeline_stop_modal.vue
index 7c4e651373f..6ca96bbba5e 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_stop_modal.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_stop_modal.vue
@@ -2,7 +2,6 @@
import _ from 'underscore';
import { GlLink } from '@gitlab/ui';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
-import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import CiIcon from '~/vue_shared/components/ci_icon.vue';
import { s__, sprintf } from '~/locale';
@@ -15,7 +14,6 @@ export default {
components: {
GlModal: DeprecatedModal2,
GlLink,
- ClipboardButton,
CiIcon,
},
props: {
diff --git a/app/assets/javascripts/pipelines/components/pipeline_url.vue b/app/assets/javascripts/pipelines/components/pipeline_url.vue
index 30c830d78f9..743c3ea271d 100644
--- a/app/assets/javascripts/pipelines/components/pipeline_url.vue
+++ b/app/assets/javascripts/pipelines/components/pipeline_url.vue
@@ -2,7 +2,6 @@
import { GlLink, GlTooltipDirective } from '@gitlab/ui';
import _ from 'underscore';
import { __, sprintf } from '~/locale';
-import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import popover from '~/vue_shared/directives/popover';
const popoverTitle = sprintf(
@@ -17,7 +16,6 @@ const popoverTitle = sprintf(
export default {
components: {
- UserAvatarLink,
GlLink,
},
directives: {
diff --git a/app/assets/javascripts/pipelines/components/test_reports/test_summary.vue b/app/assets/javascripts/pipelines/components/test_reports/test_summary.vue
index 1bac7ce9ac5..2fa3fa41eed 100644
--- a/app/assets/javascripts/pipelines/components/test_reports/test_summary.vue
+++ b/app/assets/javascripts/pipelines/components/test_reports/test_summary.vue
@@ -1,5 +1,5 @@
<script>
-import { GlButton, GlLink, GlProgressBar } from '@gitlab/ui';
+import { GlButton, GlProgressBar } from '@gitlab/ui';
import { __ } from '~/locale';
import { formatTime, secondsToMilliseconds } from '~/lib/utils/datetime_utility';
import Icon from '~/vue_shared/components/icon.vue';
@@ -8,7 +8,6 @@ export default {
name: 'TestSummary',
components: {
GlButton,
- GlLink,
GlProgressBar,
Icon,
},
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 b2c700b817c..c770fd70260 100644
--- a/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
+++ b/app/assets/javascripts/registry/settings/components/registry_settings_app.vue
@@ -1,26 +1,23 @@
<script>
-import { mapState } from 'vuex';
-import { s__, sprintf } from '~/locale';
+import { mapState, mapActions } from 'vuex';
+import { GlLoadingIcon } from '@gitlab/ui';
+import SettingsForm from './settings_form.vue';
export default {
- components: {},
+ components: {
+ GlLoadingIcon,
+ SettingsForm,
+ },
computed: {
...mapState({
- helpPagePath: 'helpPagePath',
+ isLoading: 'isLoading',
}),
-
- helpText() {
- return sprintf(
- s__(
- 'PackageRegistry|Read more about the %{helpLinkStart}Container Registry tag retention policies%{helpLinkEnd}',
- ),
- {
- helpLinkStart: `<a href="${this.helpPagePath}" target="_blank">`,
- helpLinkEnd: '</a>',
- },
- false,
- );
- },
+ },
+ mounted() {
+ this.fetchSettings();
+ },
+ methods: {
+ ...mapActions(['fetchSettings']),
},
};
</script>
@@ -28,16 +25,19 @@ export default {
<template>
<div>
<p>
- {{ s__('PackageRegistry|Tag retention policies are designed to:') }}
+ {{ s__('ContainerRegistry|Tag expiration policy is designed to:') }}
</p>
<ul>
- <li>{{ s__('PackageRegistry|Keep and protect the images that matter most.') }}</li>
+ <li>{{ s__('ContainerRegistry|Keep and protect the images that matter most.') }}</li>
<li>
{{
- s__("PackageRegistry|Automatically remove extra images that aren't designed to be kept.")
+ s__(
+ "ContainerRegistry|Automatically remove extra images that aren't designed to be kept.",
+ )
}}
</li>
</ul>
- <p ref="help-link" v-html="helpText"></p>
+ <gl-loading-icon v-if="isLoading" ref="loading-icon" />
+ <settings-form v-else ref="settings-form" />
</div>
</template>
diff --git a/app/assets/javascripts/registry/settings/components/settings_form.vue b/app/assets/javascripts/registry/settings/components/settings_form.vue
new file mode 100644
index 00000000000..402763e2e21
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/components/settings_form.vue
@@ -0,0 +1,158 @@
+<script>
+import { mapActions } from 'vuex';
+import { GlFormGroup, GlToggle, GlFormSelect, GlFormTextarea, GlButton } from '@gitlab/ui';
+import { s__, __, sprintf } from '~/locale';
+import { NAME_REGEX_LENGTH } from '../constants';
+import { mapComputed } from '~/vuex_shared/bindings';
+
+export default {
+ components: {
+ GlFormGroup,
+ GlToggle,
+ GlFormSelect,
+ GlFormTextarea,
+ GlButton,
+ },
+ labelsConfig: {
+ cols: 3,
+ align: 'right',
+ },
+ computed: {
+ ...mapComputed('settings', 'updateSettings', [
+ 'enabled',
+ 'cadence',
+ 'older_than',
+ 'keep_n',
+ 'name_regex',
+ ]),
+ 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',
+ ),
+ {
+ codeStart: '<code>',
+ codeEnd: '</code>',
+ },
+ false,
+ );
+ },
+ nameRegexPlaceholder() {
+ return '.*';
+ },
+ nameRegexState() {
+ return this.name_regex ? this.name_regex.length <= NAME_REGEX_LENGTH : null;
+ },
+ formIsValid() {
+ return this.nameRegexState === false;
+ },
+ },
+ methods: {
+ ...mapActions(['resetSettings', 'saveSettings']),
+ },
+};
+</script>
+
+<template>
+ <div class="card">
+ <form ref="form-element" @submit.prevent="saveSettings" @reset.prevent="resetSettings">
+ <div class="card-header">
+ {{ s__('ContainerRegistry|Tag expiration policy') }}
+ </div>
+ <div class="card-body">
+ <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" />
+ <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">
+ <option value="1">{{ __('Option 1') }}</option>
+ <option value="2">{{ __('Option 2') }}</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">
+ <option value="1">{{ __('Option 1') }}</option>
+ <option value="2">{{ __('Option 2') }}</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|Expiration latest:')"
+ >
+ <gl-form-select id="expiration-policy-latest" v-model="keep_n">
+ <option value="1">{{ __('Option 1') }}</option>
+ <option value="2">{{ __('Option 2') }}</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|Expire Docker tags with name matching:')"
+ :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"
+ trim
+ />
+ <template #description>
+ <span ref="regex-description" v-html="regexHelpText"></span>
+ </template>
+ </gl-form-group>
+ </div>
+ <div class="card-footer text-right">
+ <gl-button ref="cancel-button" type="reset">{{ __('Cancel') }}</gl-button>
+ <gl-button ref="save-button" type="submit" :disabled="formIsValid" variant="success">
+ {{ __('Save Expiration Policy') }}
+ </gl-button>
+ </div>
+ </form>
+ </div>
+</template>
diff --git a/app/assets/javascripts/registry/settings/constants.js b/app/assets/javascripts/registry/settings/constants.js
new file mode 100644
index 00000000000..c0dac466b29
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/constants.js
@@ -0,0 +1,15 @@
+import { s__ } from '~/locale';
+
+export const FETCH_SETTINGS_ERROR_MESSAGE = s__(
+ 'ContainerRegistry|Something went wrong while fetching the expiration policy.',
+);
+
+export const UPDATE_SETTINGS_ERROR_MESSAGE = s__(
+ 'ContainerRegistry|Something went wrong while updating the expiration policy.',
+);
+
+export const UPDATE_SETTINGS_SUCCESS_MESSAGE = s__(
+ 'ContainerRegistry|Expiration policy successfully saved.',
+);
+
+export const NAME_REGEX_LENGTH = 255;
diff --git a/app/assets/javascripts/registry/settings/registry_settings_bundle.js b/app/assets/javascripts/registry/settings/registry_settings_bundle.js
index 2938178ea86..927b6059884 100644
--- a/app/assets/javascripts/registry/settings/registry_settings_bundle.js
+++ b/app/assets/javascripts/registry/settings/registry_settings_bundle.js
@@ -1,6 +1,6 @@
import Vue from 'vue';
import Translate from '~/vue_shared/translate';
-import store from './stores/';
+import store from './store/';
import RegistrySettingsApp from './components/registry_settings_app.vue';
Vue.use(Translate);
diff --git a/app/assets/javascripts/registry/settings/store/actions.js b/app/assets/javascripts/registry/settings/store/actions.js
new file mode 100644
index 00000000000..b161373dd0a
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/store/actions.js
@@ -0,0 +1,40 @@
+import Api from '~/api';
+import createFlash from '~/flash';
+import {
+ FETCH_SETTINGS_ERROR_MESSAGE,
+ UPDATE_SETTINGS_ERROR_MESSAGE,
+ UPDATE_SETTINGS_SUCCESS_MESSAGE,
+} from '../constants';
+import * as types from './mutation_types';
+
+export const setInitialState = ({ commit }, data) => commit(types.SET_INITIAL_STATE, data);
+export const updateSettings = ({ commit }, data) => commit(types.UPDATE_SETTINGS, data);
+export const toggleLoading = ({ commit }) => commit(types.TOGGLE_LOADING);
+export const receiveSettingsSuccess = ({ commit }, data = {}) => commit(types.SET_SETTINGS, data);
+export const receiveSettingsError = () => createFlash(FETCH_SETTINGS_ERROR_MESSAGE);
+export const updateSettingsError = () => createFlash(UPDATE_SETTINGS_ERROR_MESSAGE);
+export const resetSettings = ({ commit }) => commit(types.RESET_SETTINGS);
+
+export const fetchSettings = ({ dispatch, state }) => {
+ dispatch('toggleLoading');
+ return Api.project(state.projectId)
+ .then(({ tag_expiration_policies }) =>
+ dispatch('receiveSettingsSuccess', tag_expiration_policies),
+ )
+ .catch(() => dispatch('receiveSettingsError'))
+ .finally(() => dispatch('toggleLoading'));
+};
+
+export const saveSettings = ({ dispatch, state }) => {
+ dispatch('toggleLoading');
+ return Api.updateProject(state.projectId, { tag_expiration_policies: state.settings })
+ .then(({ tag_expiration_policies }) => {
+ dispatch('receiveSettingsSuccess', tag_expiration_policies);
+ createFlash(UPDATE_SETTINGS_SUCCESS_MESSAGE);
+ })
+ .catch(() => dispatch('updateSettingsError'))
+ .finally(() => dispatch('toggleLoading'));
+};
+
+// prevent babel-plugin-rewire from generating an invalid default during karma tests
+export default () => {};
diff --git a/app/assets/javascripts/registry/settings/stores/index.js b/app/assets/javascripts/registry/settings/store/index.js
index 91a35aac149..91a35aac149 100644
--- a/app/assets/javascripts/registry/settings/stores/index.js
+++ b/app/assets/javascripts/registry/settings/store/index.js
diff --git a/app/assets/javascripts/registry/settings/store/mutation_types.js b/app/assets/javascripts/registry/settings/store/mutation_types.js
new file mode 100644
index 00000000000..db499ffa761
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/store/mutation_types.js
@@ -0,0 +1,5 @@
+export const SET_INITIAL_STATE = 'SET_INITIAL_STATE';
+export const UPDATE_SETTINGS = 'UPDATE_SETTINGS';
+export const TOGGLE_LOADING = 'TOGGLE_LOADING';
+export const SET_SETTINGS = 'SET_SETTINGS';
+export const RESET_SETTINGS = 'RESET_SETTINGS';
diff --git a/app/assets/javascripts/registry/settings/store/mutations.js b/app/assets/javascripts/registry/settings/store/mutations.js
new file mode 100644
index 00000000000..b8384fd4a45
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/store/mutations.js
@@ -0,0 +1,20 @@
+import * as types from './mutation_types';
+
+export default {
+ [types.SET_INITIAL_STATE](state, initialState) {
+ state.projectId = initialState.projectId;
+ },
+ [types.UPDATE_SETTINGS](state, settings) {
+ state.settings = { ...state.settings, ...settings };
+ },
+ [types.SET_SETTINGS](state, settings) {
+ state.settings = settings;
+ state.original = Object.freeze(settings);
+ },
+ [types.RESET_SETTINGS](state) {
+ state.settings = { ...state.original };
+ },
+ [types.TOGGLE_LOADING](state) {
+ state.isLoading = !state.isLoading;
+ },
+};
diff --git a/app/assets/javascripts/registry/settings/store/state.js b/app/assets/javascripts/registry/settings/store/state.js
new file mode 100644
index 00000000000..c3a26083c9f
--- /dev/null
+++ b/app/assets/javascripts/registry/settings/store/state.js
@@ -0,0 +1,26 @@
+export default () => ({
+ /*
+ * Project Id used to build the API call
+ */
+ projectId: '',
+ /*
+ * Boolean to determine if the UI is loading data from the API
+ */
+ isLoading: false,
+ /*
+ * This contains the data shown and manipulated in the UI
+ * Has the following structure:
+ * {
+ * enabled: Boolean
+ * cadence: String,
+ * older_than: String,
+ * keep_n: String,
+ * name_regex: String
+ * }
+ */
+ settings: {},
+ /*
+ * Same structure as settings, above but Frozen object and used only in case the user clicks 'cancel'
+ */
+ original: {},
+});
diff --git a/app/assets/javascripts/registry/settings/stores/actions.js b/app/assets/javascripts/registry/settings/stores/actions.js
deleted file mode 100644
index f2c469d4edb..00000000000
--- a/app/assets/javascripts/registry/settings/stores/actions.js
+++ /dev/null
@@ -1,6 +0,0 @@
-import * as types from './mutation_types';
-
-export const setInitialState = ({ commit }, data) => commit(types.SET_INITIAL_STATE, data);
-
-// to avoid eslint error until more actions are added to the store
-export default () => {};
diff --git a/app/assets/javascripts/registry/settings/stores/mutation_types.js b/app/assets/javascripts/registry/settings/stores/mutation_types.js
deleted file mode 100644
index 8a0f519eabd..00000000000
--- a/app/assets/javascripts/registry/settings/stores/mutation_types.js
+++ /dev/null
@@ -1,4 +0,0 @@
-export const SET_INITIAL_STATE = 'SET_INITIAL_STATE';
-
-// to avoid eslint error until more actions are added to the store
-export default () => {};
diff --git a/app/assets/javascripts/registry/settings/stores/mutations.js b/app/assets/javascripts/registry/settings/stores/mutations.js
deleted file mode 100644
index 4f32e11ed52..00000000000
--- a/app/assets/javascripts/registry/settings/stores/mutations.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import * as types from './mutation_types';
-
-export default {
- [types.SET_INITIAL_STATE](state, initialState) {
- state.helpPagePath = initialState.helpPagePath;
- state.registrySettingsEndpoint = initialState.registrySettingsEndpoint;
- },
-};
diff --git a/app/assets/javascripts/registry/settings/stores/state.js b/app/assets/javascripts/registry/settings/stores/state.js
deleted file mode 100644
index 4c0439458b6..00000000000
--- a/app/assets/javascripts/registry/settings/stores/state.js
+++ /dev/null
@@ -1,10 +0,0 @@
-export default () => ({
- /*
- * Help page path to generate the link
- */
- helpPagePath: '',
- /*
- * Settings endpoint to call to fetch and update the settings
- */
- registrySettingsEndpoint: '',
-});
diff --git a/app/assets/javascripts/releases/list/components/release_block.vue b/app/assets/javascripts/releases/list/components/release_block.vue
index 4d8d8682401..d5621808ed7 100644
--- a/app/assets/javascripts/releases/list/components/release_block.vue
+++ b/app/assets/javascripts/releases/list/components/release_block.vue
@@ -1,7 +1,7 @@
<script>
/* eslint-disable @gitlab/vue-i18n/no-bare-strings */
import _ from 'underscore';
-import { GlTooltipDirective, GlLink, GlBadge, GlButton } from '@gitlab/ui';
+import { GlTooltipDirective, GlLink, GlBadge } from '@gitlab/ui';
import Icon from '~/vue_shared/components/icon.vue';
import UserAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
import timeagoMixin from '~/vue_shared/mixins/timeago';
@@ -20,7 +20,6 @@ export default {
EvidenceBlock,
GlLink,
GlBadge,
- GlButton,
Icon,
UserAvatarLink,
ReleaseBlockFooter,
diff --git a/app/assets/javascripts/reports/components/modal.vue b/app/assets/javascripts/reports/components/modal.vue
index 6019af2dfe0..40ce200befb 100644
--- a/app/assets/javascripts/reports/components/modal.vue
+++ b/app/assets/javascripts/reports/components/modal.vue
@@ -1,14 +1,12 @@
<script>
// import { sprintf, __ } from '~/locale';
import DeprecatedModal2 from '~/vue_shared/components/deprecated_modal_2.vue';
-import LoadingButton from '~/vue_shared/components/loading_button.vue';
import CodeBlock from '~/vue_shared/components/code_block.vue';
import { fieldTypes } from '../constants';
export default {
components: {
Modal: DeprecatedModal2,
- LoadingButton,
CodeBlock,
},
props: {
diff --git a/app/assets/javascripts/serverless/components/functions.vue b/app/assets/javascripts/serverless/components/functions.vue
index 308bc4a2ddd..cdbf57f3e55 100644
--- a/app/assets/javascripts/serverless/components/functions.vue
+++ b/app/assets/javascripts/serverless/components/functions.vue
@@ -2,7 +2,6 @@
import { mapState, mapActions, mapGetters } from 'vuex';
import { GlLoadingIcon } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
-import FunctionRow from './function_row.vue';
import EnvironmentRow from './environment_row.vue';
import EmptyState from './empty_state.vue';
import { CHECKING_INSTALLED } from '../constants';
@@ -10,7 +9,6 @@ import { CHECKING_INSTALLED } from '../constants';
export default {
components: {
EnvironmentRow,
- FunctionRow,
EmptyState,
GlLoadingIcon,
},
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue b/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
index 36f291e995c..96603d23374 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/mr_collapsible_extension.vue
@@ -1,12 +1,11 @@
<script>
-import { GlButton, GlLink, GlLoadingIcon } from '@gitlab/ui';
+import { GlButton, GlLoadingIcon } from '@gitlab/ui';
import { __ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
export default {
components: {
GlButton,
- GlLink,
GlLoadingIcon,
Icon,
},
diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
index e9aac8b385c..8f38ca69453 100644
--- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
+++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_missing_branch.vue
@@ -2,7 +2,6 @@
import { sprintf, s__ } from '~/locale';
import tooltip from '~/vue_shared/directives/tooltip';
import statusIcon from '../mr_widget_status_icon.vue';
-import mrWidgetMergeHelp from '../../components/mr_widget_merge_help.vue';
export default {
name: 'MRWidgetMissingBranch',
@@ -10,7 +9,6 @@ export default {
tooltip,
},
components: {
- mrWidgetMergeHelp,
statusIcon,
},
props: {
diff --git a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
index 7f0fcfac071..20a14d78f9b 100644
--- a/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
+++ b/app/assets/javascripts/vue_shared/components/markdown/suggestions.vue
@@ -5,7 +5,6 @@ import SuggestionDiff from './suggestion_diff.vue';
import Flash from '~/flash';
export default {
- components: { SuggestionDiff },
props: {
lineType: {
type: String,
diff --git a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_regular_label.vue b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_regular_label.vue
index 282b181f11e..f519f90445e 100644
--- a/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_regular_label.vue
+++ b/app/assets/javascripts/vue_shared/components/sidebar/labels_select/dropdown_value_regular_label.vue
@@ -1,10 +1,9 @@
<script>
-import { GlLink, GlTooltip } from '@gitlab/ui';
+import { GlTooltip } from '@gitlab/ui';
export default {
components: {
GlTooltip,
- GlLink,
},
props: {
label: {
diff --git a/app/assets/javascripts/vuex_shared/bindings.js b/app/assets/javascripts/vuex_shared/bindings.js
new file mode 100644
index 00000000000..51035ebc8a8
--- /dev/null
+++ b/app/assets/javascripts/vuex_shared/bindings.js
@@ -0,0 +1,16 @@
+export const mapComputed = (root, updateFn, list) => {
+ const result = {};
+ list.forEach(key => {
+ result[key] = {
+ get() {
+ return this.$store.state[root][key];
+ },
+ set(value) {
+ this.$store.dispatch(updateFn, { [key]: value });
+ },
+ };
+ });
+ return result;
+};
+
+export default () => {};
diff --git a/app/assets/stylesheets/utilities.scss b/app/assets/stylesheets/utilities.scss
index 1f4bba5fc33..d6bc4d26bff 100644
--- a/app/assets/stylesheets/utilities.scss
+++ b/app/assets/stylesheets/utilities.scss
@@ -22,6 +22,12 @@
}
}
+@each $index, $size in $type-scale {
+ #{'.lh-#{$index}'} {
+ line-height: $size;
+ }
+}
+
.border-width-1px { border-width: 1px; }
.border-style-dashed { border-style: dashed; }
.border-style-solid { border-style: solid; }
diff --git a/app/views/projects/registry/settings/_index.haml b/app/views/projects/registry/settings/_index.haml
index e1eed93664e..d023a083445 100644
--- a/app/views/projects/registry/settings/_index.haml
+++ b/app/views/projects/registry/settings/_index.haml
@@ -1,2 +1 @@
-#js-registry-settings{ data: { registry_settings_endpoint: '',
- help_page_path: help_page_path('user/project/operations/linking_to_an_external_dashboard') } }
+#js-registry-settings{ data: { project_id: @project.id, } }
diff --git a/app/views/projects/settings/ci_cd/show.html.haml b/app/views/projects/settings/ci_cd/show.html.haml
index 38483f599b7..9e7652fe663 100644
--- a/app/views/projects/settings/ci_cd/show.html.haml
+++ b/app/views/projects/settings/ci_cd/show.html.haml
@@ -63,10 +63,11 @@
%section.settings.no-animate#js-registry-polcies{ class: ('expanded' if expanded) }
.settings-header
%h4
- = _("Container Registry tag expiration policies")
+ = _("Container Registry tag expiration policy")
+ = link_to icon('question-circle'), help_page_path('user/packages/container_registry/index', anchor: 'retention-and-expiration-policy'), target: '_blank', rel: 'noopener noreferrer'
%button.btn.js-settings-toggle{ type: 'button' }
= expanded ? _('Collapse') : _('Expand')
%p
- = _("Expiration policies for the Container Registry are a perfect solution for keeping the Registry space down while still enjoying the full power of GitLab CI/CD.")
+ = _("Expiration policy for the Container Registry is a perfect solution for keeping the Registry space down while still enjoying the full power of GitLab CI/CD.")
.settings-content
= render 'projects/registry/settings/index'
diff --git a/changelogs/unreleased/rk-118664-upgrade-monaco-editor.yml b/changelogs/unreleased/rk-118664-upgrade-monaco-editor.yml
new file mode 100644
index 00000000000..53165ca34bb
--- /dev/null
+++ b/changelogs/unreleased/rk-118664-upgrade-monaco-editor.yml
@@ -0,0 +1,5 @@
+---
+title: Updated monaco-editor dependency
+merge_request: 21938
+author:
+type: other
diff --git a/doc/user/application_security/dast/index.md b/doc/user/application_security/dast/index.md
index 3a8a81f5f57..fd418748371 100644
--- a/doc/user/application_security/dast/index.md
+++ b/doc/user/application_security/dast/index.md
@@ -312,6 +312,15 @@ variable value.
| `DAST_FULL_SCAN_ENABLED` | no | Switches the tool to execute [ZAP Full Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Full-Scan) instead of [ZAP Baseline Scan](https://github.com/zaproxy/zaproxy/wiki/ZAP-Baseline-Scan). Boolean. `true`, `True`, or `1` are considered as true value, otherwise false. Defaults to `false`. |
| `DAST_FULL_SCAN_DOMAIN_VALIDATION_REQUIRED` | no | Requires [domain validation](#domain-validation) when running DAST full scans. Boolean. `true`, `True`, or `1` are considered as true value, otherwise false. Defaults to `false`. |
+## Reports JSON format
+
+CAUTION: **Caution:**
+The JSON report artifacts are not a public API of DAST and their format may change in the future.
+
+The DAST tool emits a JSON report report file. Sample report files can be found in the [DAST repository](https://gitlab.com/gitlab-org/security-products/dast/tree/master/test/end-to-end/expect).
+
+There are two formats of data in the JSON document that are used side by side: the proprietary ZAP format which will be eventually deprecated, and a "common" format which will be the default in the future.
+
## Security Dashboard
The Security Dashboard is a good place to get an overview of all the security
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index a0783b1d5da..719e8084c55 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4746,7 +4746,7 @@ msgstr ""
msgid "Container Registry"
msgstr ""
-msgid "Container Registry tag expiration policies"
+msgid "Container Registry tag expiration policy"
msgstr ""
msgid "Container Scanning"
@@ -4758,6 +4758,9 @@ msgstr ""
msgid "Container registry is not enabled on this GitLab instance. Ask an administrator to enable it in order for AutoDevOps to work."
msgstr ""
+msgid "ContainerRegistry|Automatically remove extra images that aren't designed to be kept."
+msgstr ""
+
msgid "ContainerRegistry|Container Registry"
msgstr ""
@@ -4773,12 +4776,36 @@ msgstr ""
msgid "ContainerRegistry|Docker connection error"
msgstr ""
+msgid "ContainerRegistry|Docker tag expiration policy is %{toggleStatus}"
+msgstr ""
+
+msgid "ContainerRegistry|Expiration interval:"
+msgstr ""
+
+msgid "ContainerRegistry|Expiration latest:"
+msgstr ""
+
+msgid "ContainerRegistry|Expiration policy successfully saved."
+msgstr ""
+
+msgid "ContainerRegistry|Expiration policy:"
+msgstr ""
+
+msgid "ContainerRegistry|Expiration schedule:"
+msgstr ""
+
+msgid "ContainerRegistry|Expire Docker tags with name matching:"
+msgstr ""
+
msgid "ContainerRegistry|If you are not already logged in, you need to authenticate to the Container Registry by using your GitLab username and password. If you have %{twofaDocLinkStart}Two-Factor Authentication%{twofaDocLinkEnd} enabled, use a %{personalAccessTokensDocLinkStart}Personal Access Token%{personalAccessTokensDocLinkEnd} instead of a password."
msgstr ""
msgid "ContainerRegistry|Image ID"
msgstr ""
+msgid "ContainerRegistry|Keep and protect the images that matter most."
+msgstr ""
+
msgid "ContainerRegistry|Last Updated"
msgstr ""
@@ -4799,12 +4826,27 @@ msgstr[1] ""
msgid "ContainerRegistry|Size"
msgstr ""
+msgid "ContainerRegistry|Something went wrong while fetching the expiration policy."
+msgstr ""
+
+msgid "ContainerRegistry|Something went wrong while updating the expiration policy."
+msgstr ""
+
msgid "ContainerRegistry|Tag"
msgstr ""
+msgid "ContainerRegistry|Tag expiration policy"
+msgstr ""
+
+msgid "ContainerRegistry|Tag expiration policy is designed to:"
+msgstr ""
+
msgid "ContainerRegistry|The last tag related to this image was recently removed. This empty image and any associated data will be automatically removed as part of the regular Garbage Collection process. If you have any questions, contact your administrator."
msgstr ""
+msgid "ContainerRegistry|The value of this input should be less than 255 characters"
+msgstr ""
+
msgid "ContainerRegistry|There are no container images available in this group"
msgstr ""
@@ -4817,6 +4859,9 @@ msgstr ""
msgid "ContainerRegistry|We are having trouble connecting to Docker, which could be due to an issue with your project name or path. %{docLinkStart}More Information%{docLinkEnd}"
msgstr ""
+msgid "ContainerRegistry|Wildcards such as %{codeStart}*-stable%{codeEnd} or %{codeStart}production/*%{codeEnd} are supported"
+msgstr ""
+
msgid "ContainerRegistry|With the Container Registry, every project can have its own space to store its Docker images. %{docLinkStart}More Information%{docLinkEnd}"
msgstr ""
@@ -7295,7 +7340,7 @@ msgstr ""
msgid "Expiration date"
msgstr ""
-msgid "Expiration policies for the Container Registry are a perfect solution for keeping the Registry space down while still enjoying the full power of GitLab CI/CD."
+msgid "Expiration policy for the Container Registry is a perfect solution for keeping the Registry space down while still enjoying the full power of GitLab CI/CD."
msgstr ""
msgid "Expired"
@@ -12416,6 +12461,12 @@ msgstr ""
msgid "OperationsDashboard|The operations dashboard provides a summary of each project's operational health, including pipeline and alert statuses."
msgstr ""
+msgid "Option 1"
+msgstr ""
+
+msgid "Option 2"
+msgstr ""
+
msgid "Optional"
msgstr ""
@@ -12476,9 +12527,6 @@ msgstr ""
msgid "Package was removed"
msgstr ""
-msgid "PackageRegistry|Automatically remove extra images that aren't designed to be kept."
-msgstr ""
-
msgid "PackageRegistry|Copy Maven XML"
msgstr ""
@@ -12518,9 +12566,6 @@ msgstr ""
msgid "PackageRegistry|Installation"
msgstr ""
-msgid "PackageRegistry|Keep and protect the images that matter most."
-msgstr ""
-
msgid "PackageRegistry|Learn how to %{noPackagesLinkStart}publish and share your packages%{noPackagesLinkEnd} with GitLab."
msgstr ""
@@ -12533,18 +12578,12 @@ msgstr ""
msgid "PackageRegistry|Package installation"
msgstr ""
-msgid "PackageRegistry|Read more about the %{helpLinkStart}Container Registry tag retention policies%{helpLinkEnd}"
-msgstr ""
-
msgid "PackageRegistry|Registry Setup"
msgstr ""
msgid "PackageRegistry|Remove package"
msgstr ""
-msgid "PackageRegistry|Tag retention policies are designed to:"
-msgstr ""
-
msgid "PackageRegistry|There are no packages yet"
msgstr ""
@@ -15522,6 +15561,9 @@ msgstr ""
msgid "Save Changes"
msgstr ""
+msgid "Save Expiration Policy"
+msgstr ""
+
msgid "Save anyway"
msgstr ""
diff --git a/package.json b/package.json
index 58656d27816..87bbc0caf4f 100644
--- a/package.json
+++ b/package.json
@@ -95,7 +95,7 @@
"katex": "^0.10.0",
"marked": "^0.3.12",
"mermaid": "^8.4.2",
- "monaco-editor": "^0.15.6",
+ "monaco-editor": "^0.18.1",
"monaco-editor-webpack-plugin": "^1.7.0",
"mousetrap": "^1.4.6",
"pdfjs-dist": "^2.0.943",
@@ -200,7 +200,8 @@
"yarn-deduplicate": "^1.1.1"
},
"resolutions": {
- "vue-jest/ts-jest": "24.0.0"
+ "vue-jest/ts-jest": "24.0.0",
+ "monaco-editor" : "0.18.1"
},
"engines": {
"node": ">=8.10.0",
diff --git a/spec/controllers/projects/error_tracking/projects_controller_spec.rb b/spec/controllers/projects/error_tracking/projects_controller_spec.rb
index e55495700c2..1737528b597 100644
--- a/spec/controllers/projects/error_tracking/projects_controller_spec.rb
+++ b/spec/controllers/projects/error_tracking/projects_controller_spec.rb
@@ -11,7 +11,7 @@ describe Projects::ErrorTracking::ProjectsController do
project.add_maintainer(user)
end
- describe 'POST #index' do
+ describe 'GET #index' do
context 'with insufficient permissions' do
before do
project.add_guest(user)
diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
index 7fe72e1bc8a..859638f1a52 100644
--- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
+++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb
@@ -97,9 +97,7 @@ describe 'User comments on a diff', :js do
end
context 'multiple suggestions in expanded lines' do
- # Report issue: https://gitlab.com/gitlab-org/gitlab/issues/38277
- # Fix issue: https://gitlab.com/gitlab-org/gitlab/issues/39095
- it 'suggestions are appliable', :quarantine do
+ it 'suggestions are appliable' do
diff_file = merge_request.diffs(paths: ['files/ruby/popen.rb']).diff_files.first
hash = Digest::SHA1.hexdigest(diff_file.file_path)
diff --git a/spec/frontend/api_spec.js b/spec/frontend/api_spec.js
index cef50bf553c..c0126b2330d 100644
--- a/spec/frontend/api_spec.js
+++ b/spec/frontend/api_spec.js
@@ -151,6 +151,21 @@ describe('Api', () => {
});
});
+ describe('updateProject', () => {
+ it('update a project with the given payload', done => {
+ const projectPath = 'foo';
+ const expectedUrl = `${dummyUrlRoot}/api/${dummyApiVersion}/projects/${projectPath}`;
+ mock.onPut(expectedUrl).reply(200, { foo: 'bar' });
+
+ Api.updateProject(projectPath, { foo: 'bar' })
+ .then(({ data }) => {
+ expect(data.foo).toBe('bar');
+ done();
+ })
+ .catch(done.fail);
+ });
+ });
+
describe('projectUsers', () => {
it('fetches all users of a particular project', done => {
const query = 'dummy query';
diff --git a/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap b/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
index c6dbb1da8e9..77f031db120 100644
--- a/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
+++ b/spec/frontend/registry/settings/components/__snapshots__/registry_settings_app_spec.js.snap
@@ -1,10 +1,10 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`Registry List renders 1`] = `
+exports[`Registry Settings App renders 1`] = `
<div>
<p>
- Tag retention policies are designed to:
+ Tag expiration policy is designed to:
</p>
@@ -20,14 +20,6 @@ exports[`Registry List renders 1`] = `
</li>
</ul>
- <p>
- Read more about the
- <a
- href="foo"
- target="_blank"
- >
- Container Registry tag retention policies
- </a>
- </p>
+ <settingsform-stub />
</div>
`;
diff --git a/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap b/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap
new file mode 100644
index 00000000000..0ae37f70273
--- /dev/null
+++ b/spec/frontend/registry/settings/components/__snapshots__/settings_form_spec.js.snap
@@ -0,0 +1,155 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Settings Form renders 1`] = `
+<div
+ class="card"
+>
+ <form>
+ <div
+ class="card-header"
+ >
+
+ Tag expiration policy
+
+ </div>
+
+ <div
+ class="card-body"
+ >
+ <glformgroup-stub
+ id="expiration-policy-toggle-group"
+ label="Expiration policy:"
+ label-align="right"
+ label-cols="3"
+ label-for="expiration-policy-toggle"
+ >
+ <div
+ class="d-flex align-items-start"
+ >
+ <gltoggle-stub
+ id="expiration-policy-toggle"
+ labeloff="Toggle Status: OFF"
+ labelon="Toggle Status: ON"
+ />
+
+ <span
+ class="mb-2 ml-1 lh-2"
+ >
+ Docker tag expiration policy is
+ <strong>
+ disabled
+ </strong>
+ </span>
+ </div>
+ </glformgroup-stub>
+
+ <glformgroup-stub
+ id="expiration-policy-interval-group"
+ label="Expiration interval:"
+ label-align="right"
+ label-cols="3"
+ label-for="expiration-policy-interval"
+ >
+ <glformselect-stub
+ id="expiration-policy-interval"
+ >
+ <option
+ value="1"
+ >
+ Option 1
+ </option>
+
+ <option
+ value="2"
+ >
+ Option 2
+ </option>
+ </glformselect-stub>
+ </glformgroup-stub>
+
+ <glformgroup-stub
+ id="expiration-policy-schedule-group"
+ label="Expiration schedule:"
+ label-align="right"
+ label-cols="3"
+ label-for="expiration-policy-schedule"
+ >
+ <glformselect-stub
+ id="expiration-policy-schedule"
+ >
+ <option
+ value="1"
+ >
+ Option 1
+ </option>
+
+ <option
+ value="2"
+ >
+ Option 2
+ </option>
+ </glformselect-stub>
+ </glformgroup-stub>
+
+ <glformgroup-stub
+ id="expiration-policy-latest-group"
+ label="Expiration latest:"
+ label-align="right"
+ label-cols="3"
+ label-for="expiration-policy-latest"
+ >
+ <glformselect-stub
+ id="expiration-policy-latest"
+ >
+ <option
+ value="1"
+ >
+ Option 1
+ </option>
+
+ <option
+ value="2"
+ >
+ Option 2
+ </option>
+ </glformselect-stub>
+ </glformgroup-stub>
+
+ <glformgroup-stub
+ id="expiration-policy-name-matching-group"
+ invalid-feedback="The value of this input should be less than 255 characters"
+ label="Expire Docker tags with name matching:"
+ label-align="right"
+ label-cols="3"
+ label-for="expiration-policy-name-matching"
+ >
+ <glformtextarea-stub
+ id="expiration-policy-name-matching"
+ placeholder=".*"
+ trim=""
+ value=""
+ />
+ </glformgroup-stub>
+ </div>
+
+ <div
+ class="card-footer text-right"
+ >
+ <glbutton-stub
+ type="reset"
+ >
+ Cancel
+ </glbutton-stub>
+
+ <glbutton-stub
+ type="submit"
+ variant="success"
+ >
+
+ Save Expiration Policy
+
+ </glbutton-stub>
+ </div>
+ </form>
+</div>
+`;
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 666d970aa6b..e0fe6172064 100644
--- a/spec/frontend/registry/settings/components/registry_settings_app_spec.js
+++ b/spec/frontend/registry/settings/components/registry_settings_app_spec.js
@@ -1,29 +1,34 @@
import Vuex from 'vuex';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import component from '~/registry/settings/components/registry_settings_app.vue';
-import { createStore } from '~/registry/settings/stores/';
+import { createStore } from '~/registry/settings/store/';
const localVue = createLocalVue();
localVue.use(Vuex);
-describe('Registry List', () => {
+describe('Registry Settings App', () => {
let wrapper;
let store;
+ let fetchSpy;
- const helpPagePath = 'foo';
- const findHelpLink = () => wrapper.find({ ref: 'help-link' }).find('a');
+ const findSettingsComponent = () => wrapper.find({ ref: 'settings-form' });
+ const findLoadingComponent = () => wrapper.find({ ref: 'loading-icon' });
- const mountComponent = (options = {}) =>
- shallowMount(component, {
+ const mountComponent = (options = {}) => {
+ fetchSpy = jest.fn();
+ wrapper = shallowMount(component, {
sync: false,
store,
+ methods: {
+ fetchSettings: fetchSpy,
+ },
...options,
});
+ };
beforeEach(() => {
store = createStore();
- store.dispatch('setInitialState', { helpPagePath });
- wrapper = mountComponent();
+ mountComponent();
});
afterEach(() => {
@@ -34,7 +39,18 @@ describe('Registry List', () => {
expect(wrapper.element).toMatchSnapshot();
});
- it('renders an help link dependant on the helphPagePath', () => {
- expect(findHelpLink().attributes('href')).toBe(helpPagePath);
+ it('call the store function to load the data on mount', () => {
+ expect(fetchSpy).toHaveBeenCalled();
+ });
+
+ it('renders a loader if isLoading is true', () => {
+ store.dispatch('toggleLoading');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findLoadingComponent().exists()).toBe(true);
+ expect(findSettingsComponent().exists()).toBe(false);
+ });
+ });
+ it('renders the setting form', () => {
+ expect(findSettingsComponent().exists()).toBe(true);
});
});
diff --git a/spec/frontend/registry/settings/components/settings_form_spec.js b/spec/frontend/registry/settings/components/settings_form_spec.js
new file mode 100644
index 00000000000..6d69b987c7f
--- /dev/null
+++ b/spec/frontend/registry/settings/components/settings_form_spec.js
@@ -0,0 +1,154 @@
+import Vuex from 'vuex';
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import component from '~/registry/settings/components/settings_form.vue';
+import { createStore } from '~/registry/settings/store/';
+import { NAME_REGEX_LENGTH } from '~/registry/settings/constants';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('Settings Form', () => {
+ let wrapper;
+ let store;
+ let saveSpy;
+ let resetSpy;
+
+ const helpPagePath = 'foo';
+ const findFormGroup = name => wrapper.find(`#expiration-policy-${name}-group`);
+ const findFormElements = (name, father = wrapper) => father.find(`#expiration-policy-${name}`);
+ const findCancelButton = () => wrapper.find({ ref: 'cancel-button' });
+ const findSaveButton = () => wrapper.find({ ref: 'save-button' });
+ const findForm = () => wrapper.find({ ref: 'form-element' });
+
+ const mountComponent = (options = {}) => {
+ saveSpy = jest.fn();
+ resetSpy = jest.fn();
+ wrapper = shallowMount(component, {
+ sync: false,
+ store,
+ methods: {
+ saveSettings: saveSpy,
+ resetSettings: resetSpy,
+ },
+ ...options,
+ });
+ };
+
+ beforeEach(() => {
+ store = createStore();
+ store.dispatch('setInitialState', { helpPagePath });
+ mountComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ describe.each`
+ elementName | modelName | value
+ ${'toggle'} | ${'enabled'} | ${true}
+ ${'interval'} | ${'older_than'} | ${'foo'}
+ ${'schedule'} | ${'cadence'} | ${'foo'}
+ ${'latest'} | ${'keep_n'} | ${'foo'}
+ ${'name-matching'} | ${'name_regex'} | ${'foo'}
+ `('%s form element', ({ elementName, modelName, value }) => {
+ 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);
+ element.vm.$emit('input', value);
+ expect(wrapper.vm[modelName]).toBe(value);
+ });
+ });
+
+ describe('form actions', () => {
+ let form;
+ beforeEach(() => {
+ form = findForm();
+ });
+ it('cancel has type reset', () => {
+ expect(findCancelButton().attributes('type')).toBe('reset');
+ });
+
+ it('form reset event call the appropriate function', () => {
+ form.trigger('reset');
+ expect(resetSpy).toHaveBeenCalled();
+ });
+
+ it('save has type submit', () => {
+ expect(findSaveButton().attributes('type')).toBe('submit');
+ });
+
+ it('form submit event call the appropriate function', () => {
+ form.trigger('submit');
+ expect(saveSpy).toHaveBeenCalled();
+ });
+ });
+
+ 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.vm.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
new file mode 100644
index 00000000000..71c815cd19c
--- /dev/null
+++ b/spec/frontend/registry/settings/store/actions_spec.js
@@ -0,0 +1,120 @@
+import Api from '~/api';
+import createFlash from '~/flash';
+import testAction from 'helpers/vuex_action_helper';
+import * as actions from '~/registry/settings/store/actions';
+import * as types from '~/registry/settings/store/mutation_types';
+import {
+ UPDATE_SETTINGS_ERROR_MESSAGE,
+ FETCH_SETTINGS_ERROR_MESSAGE,
+ UPDATE_SETTINGS_SUCCESS_MESSAGE,
+} from '~/registry/settings/constants';
+
+jest.mock('~/flash');
+
+describe('Actions Registry Store', () => {
+ describe.each`
+ actionName | mutationName | payload
+ ${'setInitialState'} | ${types.SET_INITIAL_STATE} | ${'foo'}
+ ${'updateSettings'} | ${types.UPDATE_SETTINGS} | ${'foo'}
+ ${'receiveSettingsSuccess'} | ${types.SET_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);
+ });
+ });
+
+ describe.each`
+ actionName | message
+ ${'receiveSettingsError'} | ${FETCH_SETTINGS_ERROR_MESSAGE}
+ ${'updateSettingsError'} | ${UPDATE_SETTINGS_ERROR_MESSAGE}
+ `('%s action', ({ actionName, message }) => {
+ it(`should call createFlash with ${message}`, done => {
+ testAction(actions[actionName], null, null, [], [], () => {
+ expect(createFlash).toHaveBeenCalledWith(message);
+ done();
+ });
+ });
+ });
+
+ describe('fetchSettings', () => {
+ const state = {
+ projectId: 'bar',
+ };
+
+ const payload = {
+ tag_expiration_policies: 'foo',
+ };
+
+ it('should fetch the data from the API', done => {
+ Api.project = jest.fn().mockResolvedValue(payload);
+ testAction(
+ actions.fetchSettings,
+ null,
+ state,
+ [],
+ [
+ { type: 'toggleLoading' },
+ { type: 'receiveSettingsSuccess', payload: payload.tag_expiration_policies },
+ { type: 'toggleLoading' },
+ ],
+ done,
+ );
+ });
+
+ it('should call receiveSettingsError on error', done => {
+ Api.project = jest.fn().mockRejectedValue();
+ testAction(
+ actions.fetchSettings,
+ null,
+ state,
+ [],
+ [{ type: 'toggleLoading' }, { type: 'receiveSettingsError' }, { type: 'toggleLoading' }],
+ done,
+ );
+ });
+ });
+
+ describe('saveSettings', () => {
+ const state = {
+ projectId: 'bar',
+ settings: 'baz',
+ };
+
+ const payload = {
+ tag_expiration_policies: 'foo',
+ };
+
+ it('should fetch the data from the API', done => {
+ Api.updateProject = jest.fn().mockResolvedValue(payload);
+ testAction(
+ actions.saveSettings,
+ null,
+ state,
+ [],
+ [
+ { type: 'toggleLoading' },
+ { type: 'receiveSettingsSuccess', payload: payload.tag_expiration_policies },
+ { type: 'toggleLoading' },
+ ],
+ () => {
+ expect(createFlash).toHaveBeenCalledWith(UPDATE_SETTINGS_SUCCESS_MESSAGE);
+ done();
+ },
+ );
+ });
+
+ it('should call receiveSettingsError on error', done => {
+ Api.updateProject = jest.fn().mockRejectedValue();
+ testAction(
+ actions.saveSettings,
+ null,
+ state,
+ [],
+ [{ type: 'toggleLoading' }, { type: 'updateSettingsError' }, { type: 'toggleLoading' }],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/registry/settings/store/mutations_spec.js b/spec/frontend/registry/settings/store/mutations_spec.js
new file mode 100644
index 00000000000..a8c7ed3bafa
--- /dev/null
+++ b/spec/frontend/registry/settings/store/mutations_spec.js
@@ -0,0 +1,54 @@
+import mutations from '~/registry/settings/store/mutations';
+import * as types from '~/registry/settings/store/mutation_types';
+import createState from '~/registry/settings/store/state';
+
+describe('Mutations Registry Store', () => {
+ let mockState;
+
+ beforeEach(() => {
+ mockState = createState();
+ });
+
+ describe('SET_INITIAL_STATE', () => {
+ it('should set the initial state', () => {
+ const payload = { helpPagePath: 'foo', projectId: 'bar' };
+ const expectedState = { ...mockState, ...payload };
+ mutations[types.SET_INITIAL_STATE](mockState, payload);
+
+ expect(mockState.projectId).toEqual(expectedState.projectId);
+ });
+ });
+
+ describe('UPDATE_SETTINGS', () => {
+ it('should update the settings', () => {
+ mockState.settings = { foo: 'bar' };
+ const payload = { foo: 'baz' };
+ const expectedState = { ...mockState, settings: payload };
+ mutations[types.UPDATE_SETTINGS](mockState, payload);
+ expect(mockState.settings).toEqual(expectedState.settings);
+ });
+ });
+ describe('SET_SETTINGS', () => {
+ it('should set the settings and original', () => {
+ const payload = { foo: 'baz' };
+ const expectedState = { ...mockState, settings: payload };
+ mutations[types.SET_SETTINGS](mockState, payload);
+ expect(mockState.settings).toEqual(expectedState.settings);
+ expect(mockState.original).toEqual(expectedState.settings);
+ });
+ });
+ describe('RESET_SETTINGS', () => {
+ it('should copy original over settings', () => {
+ mockState.settings = { foo: 'bar' };
+ mockState.original = { foo: 'baz' };
+ mutations[types.RESET_SETTINGS](mockState);
+ expect(mockState.settings).toEqual(mockState.original);
+ });
+ });
+ describe('TOGGLE_LOADING', () => {
+ it('should toggle the loading', () => {
+ mutations[types.TOGGLE_LOADING](mockState);
+ expect(mockState.isLoading).toEqual(true);
+ });
+ });
+});
diff --git a/spec/frontend/registry/settings/stores/actions_spec.js b/spec/frontend/registry/settings/stores/actions_spec.js
deleted file mode 100644
index 484f1b2dc0a..00000000000
--- a/spec/frontend/registry/settings/stores/actions_spec.js
+++ /dev/null
@@ -1,20 +0,0 @@
-import testAction from 'helpers/vuex_action_helper';
-import * as actions from '~/registry/settings/stores/actions';
-import * as types from '~/registry/settings/stores/mutation_types';
-
-jest.mock('~/flash.js');
-
-describe('Actions Registry Store', () => {
- describe('setInitialState', () => {
- it('should set the initial state', done => {
- testAction(
- actions.setInitialState,
- 'foo',
- {},
- [{ type: types.SET_INITIAL_STATE, payload: 'foo' }],
- [],
- done,
- );
- });
- });
-});
diff --git a/spec/frontend/registry/settings/stores/mutations_spec.js b/spec/frontend/registry/settings/stores/mutations_spec.js
deleted file mode 100644
index 421cd3f13cb..00000000000
--- a/spec/frontend/registry/settings/stores/mutations_spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import mutations from '~/registry/settings/stores/mutations';
-import * as types from '~/registry/settings/stores/mutation_types';
-import createState from '~/registry/settings/stores/state';
-
-describe('Mutations Registry Store', () => {
- let mockState;
-
- beforeEach(() => {
- mockState = createState();
- });
-
- describe('SET_INITIAL_STATE', () => {
- it('should set the initial state', () => {
- const payload = { helpPagePath: 'foo', registrySettingsEndpoint: 'bar' };
- const expectedState = { ...mockState, ...payload };
- mutations[types.SET_INITIAL_STATE](mockState, payload);
-
- expect(mockState.endpoint).toEqual(expectedState.endpoint);
- });
- });
-});
diff --git a/spec/frontend/vuex_shared/bindings_spec.js b/spec/frontend/vuex_shared/bindings_spec.js
new file mode 100644
index 00000000000..022d9e8e84c
--- /dev/null
+++ b/spec/frontend/vuex_shared/bindings_spec.js
@@ -0,0 +1,51 @@
+import { shallowMount } from '@vue/test-utils';
+import { mapComputed } from '~/vuex_shared/bindings';
+
+describe('Binding utils', () => {
+ describe('mapComputed', () => {
+ const dummyComponent = {
+ computed: {
+ ...mapComputed('foo', 'bar', ['baz']),
+ },
+ render() {
+ return null;
+ },
+ };
+ it('returns an object with keys equal to the last fn parameter ', () => {
+ const keyList = ['foo1', 'foo2'];
+ const result = mapComputed('foo', 'bar', keyList);
+ expect(Object.keys(result)).toEqual(keyList);
+ });
+ it('returned object has set and get function', () => {
+ const result = mapComputed('foo', 'bar', ['baz']);
+ expect(result.baz.set).toBeDefined();
+ expect(result.baz.get).toBeDefined();
+ });
+
+ it('set function invokes $store.dispatch', () => {
+ const context = shallowMount(dummyComponent, {
+ mocks: {
+ $store: {
+ dispatch: jest.fn(),
+ },
+ },
+ });
+ context.vm.baz = 'a';
+ expect(context.vm.$store.dispatch).toHaveBeenCalledWith('bar', { baz: 'a' });
+ });
+ it('get function returns $store.state[root][key]', () => {
+ const context = shallowMount(dummyComponent, {
+ mocks: {
+ $store: {
+ state: {
+ foo: {
+ baz: 1,
+ },
+ },
+ },
+ },
+ });
+ expect(context.vm.baz).toBe(1);
+ });
+ });
+});
diff --git a/spec/javascripts/diffs/components/app_spec.js b/spec/javascripts/diffs/components/app_spec.js
index 48e1ed18a2f..25754eca336 100644
--- a/spec/javascripts/diffs/components/app_spec.js
+++ b/spec/javascripts/diffs/components/app_spec.js
@@ -69,13 +69,19 @@ describe('diffs/components/app', () => {
describe('fetch diff methods', () => {
beforeEach(() => {
+ const fetchResolver = () => {
+ store.state.diffs.retrievingBatches = false;
+ return Promise.resolve();
+ };
spyOn(window, 'requestIdleCallback').and.callFake(fn => fn());
createComponent();
- spyOn(wrapper.vm, 'fetchDiffFiles').and.callFake(() => Promise.resolve());
- spyOn(wrapper.vm, 'fetchDiffFilesMeta').and.callFake(() => Promise.resolve());
- spyOn(wrapper.vm, 'fetchDiffFilesBatch').and.callFake(() => Promise.resolve());
+ spyOn(wrapper.vm, 'fetchDiffFiles').and.callFake(fetchResolver);
+ spyOn(wrapper.vm, 'fetchDiffFilesMeta').and.callFake(fetchResolver);
+ spyOn(wrapper.vm, 'fetchDiffFilesBatch').and.callFake(fetchResolver);
spyOn(wrapper.vm, 'setDiscussions');
spyOn(wrapper.vm, 'startRenderDiffsQueue');
+ spyOn(wrapper.vm, 'unwatchDiscussions');
+ store.state.diffs.retrievingBatches = true;
});
it('calls fetchDiffFiles if diffsBatchLoad is not enabled', done => {
@@ -87,6 +93,7 @@ describe('diffs/components/app', () => {
expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesMeta).not.toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesBatch).not.toHaveBeenCalled();
+ expect(wrapper.vm.unwatchDiscussions).toHaveBeenCalled();
done();
});
@@ -102,6 +109,7 @@ describe('diffs/components/app', () => {
expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesBatch).toHaveBeenCalled();
+ expect(wrapper.vm.unwatchDiscussions).toHaveBeenCalled();
});
});
@@ -114,6 +122,7 @@ describe('diffs/components/app', () => {
expect(wrapper.vm.startRenderDiffsQueue).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesMeta).toHaveBeenCalled();
expect(wrapper.vm.fetchDiffFilesBatch).toHaveBeenCalled();
+ expect(wrapper.vm.unwatchDiscussions).toHaveBeenCalled();
});
});
});
diff --git a/spec/javascripts/diffs/store/actions_spec.js b/spec/javascripts/diffs/store/actions_spec.js
index b23334d38dc..98a5348c3bc 100644
--- a/spec/javascripts/diffs/store/actions_spec.js
+++ b/spec/javascripts/diffs/store/actions_spec.js
@@ -163,10 +163,12 @@ describe('DiffsStoreActions', () => {
{ endpointBatch },
[
{ type: types.SET_BATCH_LOADING, payload: true },
+ { type: types.SET_RETRIEVING_BATCHES, payload: true },
{ type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: res1.diff_files } },
{ type: types.SET_BATCH_LOADING, payload: false },
{ type: types.SET_DIFF_DATA_BATCH, payload: { diff_files: [] } },
{ type: types.SET_BATCH_LOADING, payload: false },
+ { type: types.SET_RETRIEVING_BATCHES, payload: false },
],
[],
() => {
@@ -215,6 +217,8 @@ describe('DiffsStoreActions', () => {
describe('assignDiscussionsToDiff', () => {
it('should merge discussions into diffs', done => {
+ window.location.hash = 'ABC_123';
+
const state = {
diffFiles: [
{
diff --git a/spec/javascripts/diffs/store/mutations_spec.js b/spec/javascripts/diffs/store/mutations_spec.js
index 13f16e4f9a6..93dbf03e1ed 100644
--- a/spec/javascripts/diffs/store/mutations_spec.js
+++ b/spec/javascripts/diffs/store/mutations_spec.js
@@ -40,6 +40,16 @@ describe('DiffsStoreMutations', () => {
});
});
+ describe('SET_RETRIEVING_BATCHES', () => {
+ it('should set retrievingBatches state', () => {
+ const state = {};
+
+ mutations[types.SET_RETRIEVING_BATCHES](state, false);
+
+ expect(state.retrievingBatches).toEqual(false);
+ });
+ });
+
describe('SET_DIFF_DATA', () => {
it('should set diff data type properly', () => {
const state = {};
diff --git a/yarn.lock b/yarn.lock
index 0ec3509b4c4..95dd0355851 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -7820,10 +7820,10 @@ monaco-editor-webpack-plugin@^1.7.0:
dependencies:
"@types/webpack" "^4.4.19"
-monaco-editor@^0.15.6:
- version "0.15.6"
- resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.15.6.tgz#d63b3b06f86f803464f003b252627c3eb4a09483"
- integrity sha512-JoU9V9k6KqT9R9Tiw1RTU8ohZ+Xnf9DMg6Ktqqw5hILumwmq7xqa/KLXw513uTUsWbhtnHoSJYYR++u3pkyxJg==
+monaco-editor@0.18.1, monaco-editor@^0.18.1:
+ version "0.18.1"
+ resolved "https://registry.yarnpkg.com/monaco-editor/-/monaco-editor-0.18.1.tgz#ced7c305a23109875feeaf395a504b91f6358cfc"
+ integrity sha512-fmL+RFZ2Hrezy+X/5ZczQW51LUmvzfcqOurnkCIRFTyjdVjzR7JvENzI6+VKBJzJdPh6EYL4RoWl92b2Hrk9fw==
mousetrap@^1.4.6:
version "1.4.6"