summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-06-05 00:08:38 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-06-05 00:08:38 +0000
commit38a00c219fffa802ffaa26689fc7912b59165ddc (patch)
treebb1f6a3525a7559fa1033ee4e8f9cead9402f270
parent37c8b3b44e6d3f5755e45b3db6913fab7fee5c89 (diff)
downloadgitlab-ce-38a00c219fffa802ffaa26689fc7912b59165ddc.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/ide/ide_router.js153
-rw-r--r--app/assets/javascripts/ide/index.js3
-rw-r--r--app/assets/javascripts/ide/stores/actions.js3
-rw-r--r--app/assets/javascripts/ide/stores/actions/file.js13
-rw-r--r--app/assets/javascripts/ide/stores/actions/project.js3
-rw-r--r--app/assets/javascripts/ide/stores/index.js2
-rw-r--r--app/assets/javascripts/ide/stores/modules/branches/index.js2
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/actions.js5
-rw-r--r--app/assets/javascripts/ide/stores/modules/commit/index.js2
-rw-r--r--app/assets/javascripts/lib/utils/common_utils.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue2
-rw-r--r--app/assets/stylesheets/components/related_items_list.scss1
-rw-r--r--app/helpers/subscribable_banner_helper.rb9
-rw-r--r--app/views/groups/show.html.haml4
-rw-r--r--app/views/layouts/_page.html.haml3
-rw-r--r--app/views/layouts/group.html.haml1
-rw-r--r--app/views/layouts/project.html.haml3
-rw-r--r--app/views/projects/_flash_messages.html.haml2
-rw-r--r--changelogs/unreleased/218716-iterate-on-epic-tree-card-spacing.yml5
-rw-r--r--doc/administration/auth/ldap/img/multi_login.gifbin180218 -> 321518 bytes
-rw-r--r--doc/administration/auth/ldap/index.md11
-rw-r--r--doc/ci/jenkins/index.md2
-rw-r--r--doc/development/documentation/styleguide.md2
-rw-r--r--doc/development/integrations/jenkins.md2
-rw-r--r--doc/gitlab-basics/start-using-git.md2
-rw-r--r--doc/integration/vault.md4
-rw-r--r--doc/ssh/README.md2
-rw-r--r--doc/topics/authentication/index.md2
-rw-r--r--doc/user/group/bulk_editing/index.md87
-rw-r--r--doc/user/group/epics/img/bulk_editing.pngbin72912 -> 0 bytes
-rw-r--r--doc/user/group/epics/index.md2
-rw-r--r--doc/user/group/epics/manage_epics.md13
-rw-r--r--doc/user/project/bulk_editing.md62
-rw-r--r--doc/user/project/clusters/serverless/aws.md2
-rw-r--r--doc/user/project/integrations/img/related_links_v13_1.pngbin0 -> 4086 bytes
-rw-r--r--doc/user/project/integrations/prometheus.md38
-rw-r--r--locale/gitlab.pot48
-rw-r--r--package.json4
-rw-r--r--spec/frontend/confirm_modal_spec.js6
-rw-r--r--spec/frontend/ide/components/branches/item_spec.js10
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_item_spec.js13
-rw-r--r--spec/frontend/ide/components/merge_requests/item_spec.js18
-rw-r--r--spec/frontend/ide/components/repo_commit_section_spec.js4
-rw-r--r--spec/frontend/ide/components/repo_tab_spec.js12
-rw-r--r--spec/frontend/ide/ide_router_spec.js37
-rw-r--r--spec/frontend/ide/stores/actions/file_spec.js4
-rw-r--r--spec/frontend/ide/stores/actions/project_spec.js9
-rw-r--r--spec/frontend/ide/stores/actions/tree_spec.js11
-rw-r--r--spec/frontend/ide/stores/actions_spec.js22
-rw-r--r--spec/frontend/ide/stores/modules/commit/actions_spec.js10
-rw-r--r--spec/frontend/ide/sync_router_and_store_spec.js12
-rw-r--r--spec/frontend/lib/utils/common_utils_spec.js27
-rw-r--r--spec/helpers/subscribable_banner_helper_spec.rb11
-rw-r--r--yarn.lock42
54 files changed, 477 insertions, 272 deletions
diff --git a/app/assets/javascripts/ide/ide_router.js b/app/assets/javascripts/ide/ide_router.js
index 0fab3ee0f3b..152f77effa3 100644
--- a/app/assets/javascripts/ide/ide_router.js
+++ b/app/assets/javascripts/ide/ide_router.js
@@ -2,8 +2,8 @@ import Vue from 'vue';
import IdeRouter from '~/ide/ide_router_extension';
import { joinPaths } from '~/lib/utils/url_utility';
import flash from '~/flash';
-import store from './stores';
import { __ } from '~/locale';
+import { syncRouterAndStore } from './sync_router_and_store';
Vue.use(IdeRouter);
@@ -33,80 +33,85 @@ const EmptyRouterComponent = {
},
};
-const router = new IdeRouter({
- mode: 'history',
- base: joinPaths(gon.relative_url_root || '', '/-/ide/'),
- routes: [
- {
- path: '/project/:namespace+/:project',
- component: EmptyRouterComponent,
- children: [
- {
- path: ':targetmode(edit|tree|blob)/:branchid+/-/*',
- component: EmptyRouterComponent,
- },
- {
- path: ':targetmode(edit|tree|blob)/:branchid+/',
- redirect: to => joinPaths(to.path, '/-/'),
- },
- {
- path: ':targetmode(edit|tree|blob)',
- redirect: to => joinPaths(to.path, '/master/-/'),
- },
- {
- path: 'merge_requests/:mrid',
- component: EmptyRouterComponent,
- },
- {
- path: '',
- redirect: to => joinPaths(to.path, '/edit/master/-/'),
- },
- ],
- },
- ],
-});
+// eslint-disable-next-line import/prefer-default-export
+export const createRouter = store => {
+ const router = new IdeRouter({
+ mode: 'history',
+ base: joinPaths(gon.relative_url_root || '', '/-/ide/'),
+ routes: [
+ {
+ path: '/project/:namespace+/:project',
+ component: EmptyRouterComponent,
+ children: [
+ {
+ path: ':targetmode(edit|tree|blob)/:branchid+/-/*',
+ component: EmptyRouterComponent,
+ },
+ {
+ path: ':targetmode(edit|tree|blob)/:branchid+/',
+ redirect: to => joinPaths(to.path, '/-/'),
+ },
+ {
+ path: ':targetmode(edit|tree|blob)',
+ redirect: to => joinPaths(to.path, '/master/-/'),
+ },
+ {
+ path: 'merge_requests/:mrid',
+ component: EmptyRouterComponent,
+ },
+ {
+ path: '',
+ redirect: to => joinPaths(to.path, '/edit/master/-/'),
+ },
+ ],
+ },
+ ],
+ });
-router.beforeEach((to, from, next) => {
- if (to.params.namespace && to.params.project) {
- store
- .dispatch('getProjectData', {
- namespace: to.params.namespace,
- projectId: to.params.project,
- })
- .then(() => {
- const basePath = to.params.pathMatch || '';
- const projectId = `${to.params.namespace}/${to.params.project}`;
- const branchId = to.params.branchid;
- const mergeRequestId = to.params.mrid;
+ router.beforeEach((to, from, next) => {
+ if (to.params.namespace && to.params.project) {
+ store
+ .dispatch('getProjectData', {
+ namespace: to.params.namespace,
+ projectId: to.params.project,
+ })
+ .then(() => {
+ const basePath = to.params.pathMatch || '';
+ const projectId = `${to.params.namespace}/${to.params.project}`;
+ const branchId = to.params.branchid;
+ const mergeRequestId = to.params.mrid;
- if (branchId) {
- store.dispatch('openBranch', {
- projectId,
- branchId,
- basePath,
- });
- } else if (mergeRequestId) {
- store.dispatch('openMergeRequest', {
- projectId,
- mergeRequestId,
- targetProjectId: to.query.target_project,
- });
- }
- })
- .catch(e => {
- flash(
- __('Error while loading the project data. Please try again.'),
- 'alert',
- document,
- null,
- false,
- true,
- );
- throw e;
- });
- }
+ if (branchId) {
+ store.dispatch('openBranch', {
+ projectId,
+ branchId,
+ basePath,
+ });
+ } else if (mergeRequestId) {
+ store.dispatch('openMergeRequest', {
+ projectId,
+ mergeRequestId,
+ targetProjectId: to.query.target_project,
+ });
+ }
+ })
+ .catch(e => {
+ flash(
+ __('Error while loading the project data. Please try again.'),
+ 'alert',
+ document,
+ null,
+ false,
+ true,
+ );
+ throw e;
+ });
+ }
- next();
-});
+ next();
+ });
-export default router;
+ syncRouterAndStore(router, store);
+
+ return router;
+};
diff --git a/app/assets/javascripts/ide/index.js b/app/assets/javascripts/ide/index.js
index 55a0dd848c8..850cfcb05e3 100644
--- a/app/assets/javascripts/ide/index.js
+++ b/app/assets/javascripts/ide/index.js
@@ -4,7 +4,7 @@ import Translate from '~/vue_shared/translate';
import { identity } from 'lodash';
import ide from './components/ide.vue';
import store from './stores';
-import router from './ide_router';
+import { createRouter } from './ide_router';
import { parseBoolean } from '../lib/utils/common_utils';
import { resetServiceWorkersPublicPath } from '../lib/utils/webpack';
import { DEFAULT_THEME } from './lib/themes';
@@ -32,6 +32,7 @@ export function initIde(el, options = {}) {
if (!el) return null;
const { rootComponent = ide, extendStore = identity } = options;
+ const router = createRouter(store);
return new Vue({
el,
diff --git a/app/assets/javascripts/ide/stores/actions.js b/app/assets/javascripts/ide/stores/actions.js
index 734ae57f46f..966ce397ea5 100644
--- a/app/assets/javascripts/ide/stores/actions.js
+++ b/app/assets/javascripts/ide/stores/actions.js
@@ -7,7 +7,6 @@ import * as types from './mutation_types';
import { decorateFiles } from '../lib/files';
import { stageKeys } from '../constants';
import service from '../services';
-import router from '../ide_router';
import eventHub from '../eventhub';
export const redirectToUrl = (self, url) => visitUrl(url);
@@ -262,7 +261,7 @@ export const renameEntry = ({ dispatch, commit, state, getters }, { path, name,
}
if (newEntry.opened) {
- router.push(`/project${newEntry.url}`);
+ dispatch('router/push', `/project${newEntry.url}`, { root: true });
}
}
diff --git a/app/assets/javascripts/ide/stores/actions/file.js b/app/assets/javascripts/ide/stores/actions/file.js
index 03146e8a315..397decd479d 100644
--- a/app/assets/javascripts/ide/stores/actions/file.js
+++ b/app/assets/javascripts/ide/stores/actions/file.js
@@ -3,7 +3,6 @@ import { __ } from '~/locale';
import eventHub from '../../eventhub';
import service from '../../services';
import * as types from '../mutation_types';
-import router from '../../ide_router';
import { setPageTitleForFile } from '../utils';
import { viewerTypes, stageKeys } from '../../constants';
@@ -30,10 +29,10 @@ export const closeFile = ({ commit, state, dispatch }, file) => {
keyPrefix: nextFileToOpen.staged ? 'staged' : 'unstaged',
});
} else {
- router.push(`/project${nextFileToOpen.url}`);
+ dispatch('router/push', `/project${nextFileToOpen.url}`, { root: true });
}
} else if (!state.openFiles.length) {
- router.push(`/project/${file.projectId}/tree/${file.branchId}/`);
+ dispatch('router/push', `/project/${file.projectId}/tree/${file.branchId}/`, { root: true });
}
eventHub.$emit(`editor.update.model.dispose.${file.key}`);
@@ -226,7 +225,7 @@ export const discardFileChanges = ({ dispatch, state, commit, getters }, path) =
if (!isDestructiveDiscard && file.path === getters.activeFile?.path) {
dispatch('updateDelayViewerUpdated', true)
.then(() => {
- router.push(`/project${file.url}`);
+ dispatch('router/push', `/project${file.url}`, { root: true });
})
.catch(e => {
throw e;
@@ -275,14 +274,16 @@ export const unstageChange = ({ commit, dispatch, getters }, path) => {
}
};
-export const openPendingTab = ({ commit, getters, state }, { file, keyPrefix }) => {
+export const openPendingTab = ({ commit, dispatch, getters, state }, { file, keyPrefix }) => {
if (getters.activeFile && getters.activeFile.key === `${keyPrefix}-${file.key}`) return false;
state.openFiles.forEach(f => eventHub.$emit(`editor.update.model.dispose.${f.key}`));
commit(types.ADD_PENDING_TAB, { file, keyPrefix });
- router.push(`/project/${file.projectId}/tree/${state.currentBranchId}/`);
+ dispatch('router/push', `/project/${file.projectId}/tree/${state.currentBranchId}/`, {
+ root: true,
+ });
return true;
};
diff --git a/app/assets/javascripts/ide/stores/actions/project.js b/app/assets/javascripts/ide/stores/actions/project.js
index 6c8fb9f90aa..d172bb31ae5 100644
--- a/app/assets/javascripts/ide/stores/actions/project.js
+++ b/app/assets/javascripts/ide/stores/actions/project.js
@@ -4,7 +4,6 @@ import { __, sprintf } from '~/locale';
import service from '../../services';
import api from '../../../api';
import * as types from '../mutation_types';
-import router from '../../ide_router';
export const getProjectData = ({ commit, state }, { namespace, projectId, force = false } = {}) =>
new Promise((resolve, reject) => {
@@ -57,7 +56,7 @@ export const createNewBranchFromDefault = ({ state, dispatch, getters }, branch)
})
.then(() => {
dispatch('setErrorMessage', null);
- router.push(`${router.currentRoute.path}?${Date.now()}`);
+ window.location.reload();
})
.catch(() => {
dispatch('setErrorMessage', {
diff --git a/app/assets/javascripts/ide/stores/index.js b/app/assets/javascripts/ide/stores/index.js
index 85550578e94..b5ae85c95ae 100644
--- a/app/assets/javascripts/ide/stores/index.js
+++ b/app/assets/javascripts/ide/stores/index.js
@@ -11,6 +11,7 @@ import branches from './modules/branches';
import fileTemplates from './modules/file_templates';
import paneModule from './modules/pane';
import clientsideModule from './modules/clientside';
+import routerModule from './modules/router';
Vue.use(Vuex);
@@ -28,6 +29,7 @@ export const createStore = () =>
fileTemplates: fileTemplates(),
rightPane: paneModule(),
clientside: clientsideModule(),
+ router: routerModule,
},
});
diff --git a/app/assets/javascripts/ide/stores/modules/branches/index.js b/app/assets/javascripts/ide/stores/modules/branches/index.js
index 04e7e0f08f1..deda95cd0c9 100644
--- a/app/assets/javascripts/ide/stores/modules/branches/index.js
+++ b/app/assets/javascripts/ide/stores/modules/branches/index.js
@@ -4,7 +4,7 @@ import mutations from './mutations';
export default {
namespaced: true,
- state: state(),
+ state,
actions,
mutations,
};
diff --git a/app/assets/javascripts/ide/stores/modules/commit/actions.js b/app/assets/javascripts/ide/stores/modules/commit/actions.js
index 65e2726a976..005bd0240e2 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/actions.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/actions.js
@@ -3,7 +3,6 @@ import flash from '~/flash';
import httpStatusCodes from '~/lib/utils/http_status';
import * as rootTypes from '../../mutation_types';
import { createCommitPayload, createNewMergeRequestUrl } from '../../utils';
-import router from '../../../ide_router';
import service from '../../../services';
import * as types from './mutation_types';
import consts from './constants';
@@ -196,8 +195,10 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
dispatch('updateViewer', 'editor', { root: true });
if (rootGetters.activeFile) {
- router.push(
+ dispatch(
+ 'router/push',
`/project/${rootState.currentProjectId}/blob/${branchName}/-/${rootGetters.activeFile.path}`,
+ { root: true },
);
}
}
diff --git a/app/assets/javascripts/ide/stores/modules/commit/index.js b/app/assets/javascripts/ide/stores/modules/commit/index.js
index 3bf65b02847..5cec73bde2e 100644
--- a/app/assets/javascripts/ide/stores/modules/commit/index.js
+++ b/app/assets/javascripts/ide/stores/modules/commit/index.js
@@ -5,7 +5,7 @@ import * as getters from './getters';
export default {
namespaced: true,
- state: state(),
+ state,
mutations,
actions,
getters,
diff --git a/app/assets/javascripts/lib/utils/common_utils.js b/app/assets/javascripts/lib/utils/common_utils.js
index e5cd1b005aa..a60748215ab 100644
--- a/app/assets/javascripts/lib/utils/common_utils.js
+++ b/app/assets/javascripts/lib/utils/common_utils.js
@@ -724,6 +724,8 @@ export const convertObjectProps = (conversionFunction, obj = {}, options = {}) =
} else {
acc[conversionFunction(prop)] = convertObjectProps(conversionFunction, val, options);
}
+ } else if (isObjParameterArray) {
+ acc[prop] = val;
} else {
acc[conversionFunction(prop)] = val;
}
diff --git a/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
index 4f1b1c758b2..63de1e009fd 100644
--- a/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
+++ b/app/assets/javascripts/vue_shared/components/issue/related_issuable_item.vue
@@ -85,7 +85,7 @@ export default {
class="confidential-icon append-right-4 align-self-baseline align-self-md-auto mt-xl-0"
:aria-label="__('Confidential')"
/>
- <a :href="computedPath" class="sortable-link">{{ title }}</a>
+ <a :href="computedPath" class="sortable-link gl-font-weight-normal">{{ title }}</a>
</div>
<!-- Info area: meta, path, and assignees -->
diff --git a/app/assets/stylesheets/components/related_items_list.scss b/app/assets/stylesheets/components/related_items_list.scss
index fd1108a7305..68b1b796ba6 100644
--- a/app/assets/stylesheets/components/related_items_list.scss
+++ b/app/assets/stylesheets/components/related_items_list.scss
@@ -73,7 +73,6 @@ $item-remove-button-space: 42px;
.sortable-link {
color: $gray-900;
- font-weight: normal;
}
}
diff --git a/app/helpers/subscribable_banner_helper.rb b/app/helpers/subscribable_banner_helper.rb
new file mode 100644
index 00000000000..c9d4370f8ad
--- /dev/null
+++ b/app/helpers/subscribable_banner_helper.rb
@@ -0,0 +1,9 @@
+# frozen_string_literal: true
+
+module SubscribableBannerHelper
+ # Overridden in EE
+ def display_subscription_banner!
+ end
+end
+
+SubscribableBannerHelper.prepend_if_ee('EE::SubscribableBannerHelper')
diff --git a/app/views/groups/show.html.haml b/app/views/groups/show.html.haml
index 032766327ca..7e5bf6ddde1 100644
--- a/app/views/groups/show.html.haml
+++ b/app/views/groups/show.html.haml
@@ -1,10 +1,6 @@
- breadcrumb_title _("Details")
- @content_class = "limit-container-width" unless fluid_layout
-= content_for :flash_message do
- - if Feature.enabled?(:subscribable_banner_subscription)
- = render_if_exists "layouts/header/ee_subscribable_banner", subscription: true
-
= content_for :meta_tags do
= auto_discovery_link_tag(:atom, group_url(@group, rss_url_options), title: "#{@group.name} activity")
diff --git a/app/views/layouts/_page.html.haml b/app/views/layouts/_page.html.haml
index 57445424b26..d1cf83b2a9f 100644
--- a/app/views/layouts/_page.html.haml
+++ b/app/views/layouts/_page.html.haml
@@ -6,8 +6,6 @@
.alert-wrapper
= render 'shared/outdated_browser'
= render_if_exists 'layouts/header/users_over_license_banner'
- - if Feature.enabled?(:subscribable_banner_license, default_enabled: true)
- = render_if_exists "layouts/header/ee_subscribable_banner"
= render_if_exists "layouts/header/licensed_user_count_threshold"
= render "layouts/broadcast"
= render "layouts/header/read_only_banner"
@@ -15,6 +13,7 @@
= yield :flash_message
= render "shared/ping_consent"
= render_account_recovery_regular_check
+ = render_if_exists "layouts/header/ee_subscribable_banner"
- unless @hide_breadcrumbs
= render "layouts/nav/breadcrumbs"
.d-flex
diff --git a/app/views/layouts/group.html.haml b/app/views/layouts/group.html.haml
index 49de821f1c2..36b664e5888 100644
--- a/app/views/layouts/group.html.haml
+++ b/app/views/layouts/group.html.haml
@@ -2,6 +2,7 @@
- page_description @group.description unless page_description
- header_title group_title(@group) unless header_title
- nav "group"
+- display_subscription_banner!
- @left_sidebar = true
- content_for :page_specific_javascripts do
diff --git a/app/views/layouts/project.html.haml b/app/views/layouts/project.html.haml
index b8ef38272fc..820cb9eea47 100644
--- a/app/views/layouts/project.html.haml
+++ b/app/views/layouts/project.html.haml
@@ -2,7 +2,8 @@
- page_description @project.description unless page_description
- header_title project_title(@project) unless header_title
- nav "project"
-- @left_sidebar = true
+- display_subscription_banner!
+- @left_sidebar = true
- content_for :project_javascripts do
- project = @target_project || @project
diff --git a/app/views/projects/_flash_messages.html.haml b/app/views/projects/_flash_messages.html.haml
index 8217608db4e..f9222387e97 100644
--- a/app/views/projects/_flash_messages.html.haml
+++ b/app/views/projects/_flash_messages.html.haml
@@ -8,6 +8,4 @@
- unless project.empty_repo?
= render 'shared/auto_devops_implicitly_enabled_banner', project: project
= render_if_exists 'projects/above_size_limit_warning', project: project
- - if Feature.enabled?(:subscribable_banner_subscription)
- = render_if_exists "layouts/header/ee_subscribable_banner", subscription: true
= render_if_exists 'shared/shared_runners_minutes_limit', project: project, classes: [container_class, ("limit-container-width" unless fluid_layout)]
diff --git a/changelogs/unreleased/218716-iterate-on-epic-tree-card-spacing.yml b/changelogs/unreleased/218716-iterate-on-epic-tree-card-spacing.yml
new file mode 100644
index 00000000000..843d27d1cea
--- /dev/null
+++ b/changelogs/unreleased/218716-iterate-on-epic-tree-card-spacing.yml
@@ -0,0 +1,5 @@
+---
+title: Reduced padding and increased emphasis of titles within the epic tree
+merge_request: 32873
+author:
+type: other
diff --git a/doc/administration/auth/ldap/img/multi_login.gif b/doc/administration/auth/ldap/img/multi_login.gif
index d317add9837..5aee6090793 100644
--- a/doc/administration/auth/ldap/img/multi_login.gif
+++ b/doc/administration/auth/ldap/img/multi_login.gif
Binary files differ
diff --git a/doc/administration/auth/ldap/index.md b/doc/administration/auth/ldap/index.md
index 278cfc5d6cc..e8801879018 100644
--- a/doc/administration/auth/ldap/index.md
+++ b/doc/administration/auth/ldap/index.md
@@ -413,10 +413,21 @@ gitlab_rails['ldap_servers'] = {
'host' => 'ad-secondary.example.net',
'port' => 636,
...
+ },
+
+'tertiary' => {
+ 'label' => 'GitLab Tertiary AD',
+ 'host' => 'ad-tertiary.example.net',
+ 'port' => 636,
+ ...
}
+
}
```
+NOTE: **Note:**
+Any number of LDAP servers can be configured. However, make sure to use a unique naming convention for the `label` section of each entry as this will be the display name of the tab shown on the sign-in page.
+
## User sync **(STARTER ONLY)**
Once per day, GitLab runs a worker to check and update GitLab
diff --git a/doc/ci/jenkins/index.md b/doc/ci/jenkins/index.md
index 8eeab6f6c2e..72839f74aeb 100644
--- a/doc/ci/jenkins/index.md
+++ b/doc/ci/jenkins/index.md
@@ -210,7 +210,7 @@ which can be used by projects in that instance.
Declarative Jenkinsfiles contain "Sections" and "Directives" which are used to control the behavior of your
pipelines. There are equivalents for all of these in GitLab, which we've documented below.
-This section is based on the [Jenkinsfile syntax documentation](http://www.jenkins.io/doc/book/pipeline/syntax/)
+This section is based on the [Jenkinsfile syntax documentation](https://www.jenkins.io/doc/book/pipeline/syntax/)
and is meant to be a mapping of concepts there to concepts in GitLab.
### Sections
diff --git a/doc/development/documentation/styleguide.md b/doc/development/documentation/styleguide.md
index ddd7ee39155..ea1837c034c 100644
--- a/doc/development/documentation/styleguide.md
+++ b/doc/development/documentation/styleguide.md
@@ -1049,7 +1049,7 @@ of language classes available.
| `xml` | |
| `yaml` | Alias: `yml`. |
-For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/engineering/ux/technical-writing/markdown-guide/#code-blocks).
+For a complete reference on code blocks, check the [Kramdown guide](https://about.gitlab.com/handbook/markdown-guide/#code-blocks).
## GitLab SVG icons
diff --git a/doc/development/integrations/jenkins.md b/doc/development/integrations/jenkins.md
index 3d6f314c02b..f2bc6532dde 100644
--- a/doc/development/integrations/jenkins.md
+++ b/doc/development/integrations/jenkins.md
@@ -1,6 +1,6 @@
# How to run Jenkins in development environment (on macOS) **(STARTER)**
-This is a step by step guide on how to set up [Jenkins](http://www.jenkins.io/) on your local machine and connect to it from your GitLab instance. GitLab triggers webhooks on Jenkins, and Jenkins connects to GitLab using the API. By running both applications on the same machine, we can make sure they are able to access each other.
+This is a step by step guide on how to set up [Jenkins](https://www.jenkins.io/) on your local machine and connect to it from your GitLab instance. GitLab triggers webhooks on Jenkins, and Jenkins connects to GitLab using the API. By running both applications on the same machine, we can make sure they are able to access each other.
## Install Jenkins
diff --git a/doc/gitlab-basics/start-using-git.md b/doc/gitlab-basics/start-using-git.md
index 21f43e359e0..212443a431c 100644
--- a/doc/gitlab-basics/start-using-git.md
+++ b/doc/gitlab-basics/start-using-git.md
@@ -50,7 +50,7 @@ prompt, terminal, and command line) of your preference. Here are some suggestion
- [iTerm2](https://www.iterm2.com/), which you can integrate with [zsh](https://git-scm.com/book/id/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Zsh) and [oh my zsh](https://ohmyz.sh/) for color highlighting, among other handy features for Git users.
- For Windows users:
- Built-in: **cmd**. Click the search icon on the bottom navbar on Windows and type "cmd" to find it.
- - [PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/install/installing-windows-powershell): a Windows "powered up" shell, from which you can execute a greater number of commands.
+ - [PowerShell](https://docs.microsoft.com/en-us/powershell/scripting/windows-powershell/install/installing-windows-powershell?view=powershell-7): a Windows "powered up" shell, from which you can execute a greater number of commands.
- Git Bash: it comes built into [Git for Windows](https://gitforwindows.org/).
- For Linux users:
- Built-in: [Linux Terminal](https://www.howtogeek.com/140679/beginner-geek-how-to-start-using-the-linux-terminal/).
diff --git a/doc/integration/vault.md b/doc/integration/vault.md
index f26c3df93f8..cead8f7592a 100644
--- a/doc/integration/vault.md
+++ b/doc/integration/vault.md
@@ -69,7 +69,7 @@ The following assumes you already have Vault installed and running.
1. **Write the OIDC Role Config:**
- Now that Vault has a GitLab application ID and secret, it needs to know the [**Redirect URIs**](https://www.vaultproject.io/docs/auth/jwt/#redirect-uris) and scopes given to GitLab during the application creation process. The redirect URIs need to match where your Vault instance is running. The `oidc_scopes` field needs to include the `openid`. Similarly to the previous step, replace `your_application_id` with the generated application ID from GitLab:
+ Now that Vault has a GitLab application ID and secret, it needs to know the [**Redirect URIs**](https://www.vaultproject.io/docs/auth/jwt#redirect-uris) and scopes given to GitLab during the application creation process. The redirect URIs need to match where your Vault instance is running. The `oidc_scopes` field needs to include the `openid`. Similarly to the previous step, replace `your_application_id` with the generated application ID from GitLab:
This configuration is saved under the name of the role you are creating. In this case, we are creating a `demo` role. Later, we'll show how you can access this role through the Vault CLI.
@@ -110,7 +110,7 @@ The following assumes you already have Vault installed and running.
1. In the **Write the OIDC Role Config** (step 4), we created a role called `demo`. We set `role=demo` so Vault knows which configuration we'd like to login in with.
1. To set Vault to use the `OIDC` sign-in method, we set `-method=oidc`.
- 1. To set the port that GitLab should redirect to, we set `port=8250` or another port number that matches the port given to GitLab when listing [Redirect URIs](https://www.vaultproject.io/docs/auth/jwt/#redirect-uris).
+ 1. To set the port that GitLab should redirect to, we set `port=8250` or another port number that matches the port given to GitLab when listing [Redirect URIs](https://www.vaultproject.io/docs/auth/jwt#redirect-uris).
Once you run the command above, it will present a link in the terminal.
Click the link in the terminal and a tab will open in the browser confirming you're signed into Vault via OIDC:
diff --git a/doc/ssh/README.md b/doc/ssh/README.md
index 595c426d1db..6b9f6340cc6 100644
--- a/doc/ssh/README.md
+++ b/doc/ssh/README.md
@@ -412,7 +412,7 @@ are *explicitly not supported* and may stop working at any time.
### Options for Microsoft Windows
-If you're running Windows 10, the [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10), and its latest [WSL 2](https://docs.microsoft.com/install-win10) version,
+If you're running Windows 10, the [Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/en-us/windows/wsl/install-win10), and its latest [WSL 2](https://docs.microsoft.com/en-us/install-win10) version,
support the installation of different Linux distributions, which include the Git and SSH clients.
For current versions of Windows, you can also install the Git and SSH clients with
diff --git a/doc/topics/authentication/index.md b/doc/topics/authentication/index.md
index eca37b5f73a..6ce5e203bbf 100644
--- a/doc/topics/authentication/index.md
+++ b/doc/topics/authentication/index.md
@@ -44,5 +44,5 @@ This page gathers all the resources for the topic **Authentication** within GitL
- [Kanboard Plugin GitLab Authentication](https://github.com/kanboard/plugin-gitlab-auth)
- [Jenkins GitLab OAuth Plugin](https://wiki.jenkins.io/display/JENKINS/GitLab+OAuth+Plugin)
-- [How to customize GitLab to support OpenID authentication](https://eric.van-der-vlist.com/blog/2013/11/23/how-to-customize-gitlab-to-support-openid-authentication//)
+- [How to customize GitLab to support OpenID authentication](https://blog.eric.van-der-vlist.com/2013/11/23/how-to-customize-gitlab-to-support-openid-authentication/)
- [OKD - Configuring Authentication and User Agent](https://docs.okd.io/3.11/install_config/configuring_authentication.html#GitLab)
diff --git a/doc/user/group/bulk_editing/index.md b/doc/user/group/bulk_editing/index.md
index 5547bacb809..c4ccc1f7b52 100644
--- a/doc/user/group/bulk_editing/index.md
+++ b/doc/user/group/bulk_editing/index.md
@@ -1,31 +1,74 @@
-# Bulk editing issues, merge requests, and epics at the group level **(PREMIUM)**
+---
+stage: Plan
+group: Project Management
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
+---
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7249) for issues in [GitLab Premium](https://about.gitlab.com/pricing/) 12.1.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12719) for merge requests in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2.
-> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7250) for epics in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2.
+# Bulk editing issues, epics, and merge requests at the group level **(PREMIUM)**
-## Editing milestones and labels
+NOTE: **Note:**
+Bulk editing issues and merge requests is also available at the **project level**.
+For more details, see [Bulk editing issues, epics, and merge requests](../../project/bulk_editing.md).
-> **Notes:**
->
-> - A permission level of `Reporter` or higher is required in order to manage issues.
-> - A permission level of `Developer` or higher is required in order to manage merge requests.
-> - A permission level of `Reporter` or higher is required in order to manage epics.
+If you want to update attributes across multiple issues, epics, or merge requests in a group, you
+can do it by bulk editing them, that is, editing them together.
-By using the bulk editing feature:
+![Bulk editing](img/bulk-editing.png)
-- Milestones can be updated simultaneously across multiple issues or merge requests.
-- Labels can be updated simultaneously across multiple issues, merge requests, or epics.
+## Bulk edit issues at the group level
-![Bulk editing](img/bulk-editing.png)
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7249) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.1.
+
+NOTE: **Note:**
+You need a permission level of [Reporter or higher](../../permissions.md) to manage issues.
+
+When bulk editing issues in a group, you can edit the following attributes:
+
+- Milestone
+- Labels
+
+To update multiple project issues at the same time:
+
+1. In a group, go to **{issues}** **Issues > List**.
+1. Click **Edit issues**. A sidebar on the right-hand side of your screen appears with editable fields.
+1. Select the checkboxes next to each issue you want to edit.
+1. Select the appropriate fields and their values from the sidebar.
+1. Click **Update all**.
+
+## Bulk edit epics
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/7250) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2.
+
+NOTE: **Note:**
+You need a permission level of [Reporter or higher](../../permissions.md) to manage epics.
+
+When bulk editing epics in a group, you can edit their labels.
+
+To update multiple epics at the same time:
+
+1. In a group, go to **{epic}** **Epics > List**.
+1. Click **Edit epics**. A sidebar on the right-hand side of your screen appears with editable fields.
+1. Check the checkboxes next to each epic you want to edit.
+1. Select the appropriate fields and their values from the sidebar.
+1. Click **Update all**.
+
+## Bulk edit merge requests at the group level
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/12719) in [GitLab Premium](https://about.gitlab.com/pricing/) 12.2.
+
+NOTE: **Note:**
+You need a permission level of [Developer or higher](../../permissions.md) to manage merge requests.
+
+When bulk editing merge requests in a group, you can edit the following attributes:
+
+- Milestone
+- Labels
-To bulk update group issues, merge requests, or epics:
+To update multiple group merge requests at the same time:
-1. Navigate to the issues, merge requests, or epics list.
-1. Click **Edit issues**, **Edit merge requests**, or **Edit epics**.
- - This will open a sidebar on the right-hand side where editable fields
- for milestones and labels will be displayed.
- - Checkboxes will also appear beside each issue, merge request, or epic.
-1. Check the checkbox beside each issue, merge request, or epic to be edited.
-1. Select the desired new values from the sidebar.
+1. In a group, go to **{merge-request}** **Merge Requests**.
+1. Click **Edit merge requests**. A sidebar on the right-hand side of your screen appears with
+ editable fields.
+1. Select the checkboxes next to each merge request you want to edit.
+1. Select the appropriate fields and their values from the sidebar.
1. Click **Update all**.
diff --git a/doc/user/group/epics/img/bulk_editing.png b/doc/user/group/epics/img/bulk_editing.png
deleted file mode 100644
index 85610bef83e..00000000000
--- a/doc/user/group/epics/img/bulk_editing.png
+++ /dev/null
Binary files differ
diff --git a/doc/user/group/epics/index.md b/doc/user/group/epics/index.md
index d33fcad4007..85164292265 100644
--- a/doc/user/group/epics/index.md
+++ b/doc/user/group/epics/index.md
@@ -28,7 +28,7 @@ milestones.
To learn what you can do with an epic, see [Manage epics](manage_epics.md). Possible actions include:
- [Create an epic](manage_epics.md#create-an-epic)
-- [Bulk-edit epics](manage_epics.md#bulk-edit-epics)
+- [Bulk-edit epics](../bulk_editing/index.md#bulk-edit-epics)
- [Delete an epic](manage_epics.md#delete-an-epic)
- [Close an epic](manage_epics.md#close-an-epic)
- [Reopen a closed epic](manage_epics.md#reopen-a-closed-epic)
diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md
index f19a55559f9..26d5cb51e01 100644
--- a/doc/user/group/epics/manage_epics.md
+++ b/doc/user/group/epics/manage_epics.md
@@ -43,17 +43,8 @@ An epic's page contains the following tabs:
## Bulk-edit epics
-You can edit multiple epics at once. For example, to apply labels to multiple epics:
-
-1. Go to the Epics list.
-1. Click **Edit epics**.
- - Checkboxes appear next to each epic.
- - A sidebar on the right-hand side appears with an editable field for labels.
-1. Select the checkbox next to each epic to be edited.
-1. Select the labels you want.
-1. Click **Update all**.
-
-![bulk editing](img/bulk_editing.png)
+You can edit multiple epics at once. To learn how to do it, visit
+[Bulk editing issues, epics, and merge requests at the group level](../bulk_editing/index.md#bulk-edit-epics).
## Delete an epic
diff --git a/doc/user/project/bulk_editing.md b/doc/user/project/bulk_editing.md
index 14a570fa17d..6d091c431a2 100644
--- a/doc/user/project/bulk_editing.md
+++ b/doc/user/project/bulk_editing.md
@@ -4,37 +4,57 @@ group: Project Management
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers
---
-# Bulk editing issues, epics, and merge requests
+# Bulk editing issues and merge requests at the project level
-> **Notes:**
->
-> - A permission level of `Reporter` or higher is required in order to manage
-> issues.
-> - A permission level of `Reporter` or higher is required in order to manage
-> epics.
-> - A permission level of `Developer` or higher is required in order to manage
-> merge requests.
+NOTE: **Note:**
+Bulk editing issues, epics, and merge requests is also available at the **group level**.
+For more details, see
+[Bulk editing issues, epics, and merge requests at the group level](../group/bulk_editing/index.md).
-Attributes can be updated simultaneously across multiple issues, epics, or merge requests
-by using the bulk editing feature.
+If you want to update attributes across multiple issues or merge requests, you can do it
+by bulk editing them, that is, editing them together.
![Bulk editing](img/bulk-editing.png)
+## Bulk edit issues at the project level
+
NOTE: **Note:**
-Bulk editing issues, epics, and merge requests is also available at the group level.
-For more details, see [bulk editing group issues and merge requests](../group/bulk_editing/index.md).
+You need a permission level of [Reporter or higher](../permissions.md) to manage issues.
+
+When bulk editing issues in a project, you can edit the following attributes:
+
+- Status (open/closed)
+- Assignee
+- Milestone
+- Labels
+- Subscriptions
-To update multiple project issues, epics, or merge requests at the same time:
+To update multiple project issues at the same time:
-1. Navigate to their respective list.
+1. In a project, go to **{issues}** **Issues > List**.
+1. Click **Edit issues**. A sidebar on the right-hand side of your screen appears with editable fields.
+1. Select the checkboxes next to each issue you want to edit.
+1. Select the appropriate fields and their values from the sidebar.
+1. Click **Update all**.
+
+## Bulk edit merge requests at the project level
+
+NOTE: **Note:**
+You need a permission level of [Developer or higher](../permissions.md) to manage merge requests.
-1. Click either **Edit issues**, **Edit epics**, or **Edit merge requests**.
+When bulk editing merge requests in a project, you can edit the following attributes:
- - This will open a sidebar on the right-hand side of your screen
- where editable fields will be displayed.
+- Status (open/closed)
+- Assignee
+- Milestone
+- Labels
+- Subscriptions
- - Checkboxes will also appear beside each issue or merge request.
+To update multiple project merge requests at the same time:
-1. Check the checkboxes of each items to be edited.
-1. Choose the appropriate fields and their values from the sidebar.
+1. In a project, go to **{merge-request}** **Merge Requests**.
+1. Click **Edit merge requests**. A sidebar on the right-hand side of your screen appears with
+ editable fields.
+1. Select the checkboxes next to each merge request you want to edit.
+1. Select the appropriate fields and their values from the sidebar.
1. Click **Update all**.
diff --git a/doc/user/project/clusters/serverless/aws.md b/doc/user/project/clusters/serverless/aws.md
index c26f622836c..15f7e14fda9 100644
--- a/doc/user/project/clusters/serverless/aws.md
+++ b/doc/user/project/clusters/serverless/aws.md
@@ -15,7 +15,7 @@ GitLab supports deployment of AWS Lambda functions through GitLab CI/CD using th
## Serverless Framework
-The [Serverless Framework can deploy to AWS](https://serverless.com/framework/docs/providers/aws/).
+The [Serverless Framework can deploy to AWS](https://www.serverless.com/framework/docs/providers/aws/).
We have prepared an example with a step-by-step guide to create a simple function and deploy it on AWS.
diff --git a/doc/user/project/integrations/img/related_links_v13_1.png b/doc/user/project/integrations/img/related_links_v13_1.png
new file mode 100644
index 00000000000..4dc141f0e7f
--- /dev/null
+++ b/doc/user/project/integrations/img/related_links_v13_1.png
Binary files differ
diff --git a/doc/user/project/integrations/prometheus.md b/doc/user/project/integrations/prometheus.md
index 0eb8cc61505..70fd0cb6780 100644
--- a/doc/user/project/integrations/prometheus.md
+++ b/doc/user/project/integrations/prometheus.md
@@ -378,16 +378,26 @@ The following tables outline the details of expected properties.
| ------ | ------ | ------ | ------ |
| `dashboard` | string | yes | Heading for the dashboard. Only one dashboard should be defined per file. |
| `panel_groups` | array | yes | The panel groups which should be on the dashboard. |
-| `templating` | Hash | no | Top level key under which templating related options can be added. |
+| `templating` | hash | no | Top level key under which templating related options can be added. |
+| `links` | array | no | Add links to display on the dashboard. |
##### **Templating (`templating`) properties**
| Property | Type | Required | Description |
| -------- | ---- | -------- | ----------- |
-| `variables` | Hash | no | Variables can be defined here. |
+| `variables` | hash | no | Variables can be defined here. |
Read the documentation on [templating](#templating-variables-for-metrics-dashboards).
+##### **Links (`links`) properties**
+
+| Property | Type | Required | Description |
+| -------- | ---- | -------- | ----------- |
+| `url` | string | yes | The address of the link. |
+| `title` | string | no | Display title for the link. |
+
+Read the documentation on [links](#add-related-links-to-custom-dashboards).
+
##### **Panel group (`panel_groups`) properties**
| Property | Type | Required | Description |
@@ -802,7 +812,7 @@ templating:
###### Full syntax
-This example creates a variable called `variable1`, with a default value of `var1_option_2`.
+This example creates a variable called `variable1`, with a default value of `value_option_2`.
The label for the text box on the UI will be the value of the `label` key.
The dashboard UI will display a dropdown with `Option 1` and `Option 2`
as the choices.
@@ -825,6 +835,28 @@ templating:
default: true # (Optional) This option should be the default value of this variable.
```
+### Add related links to custom dashboards
+
+> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/216385) in GitLab 13.1.
+
+Related links can be added to the top of your metrics dashboard, which can be used for quickly
+navigating between dashboards or external services. The links will open in the same tab.
+
+The `url` attribute is required for the link but the `title` attribute is optional; if the `title`
+is missing then the full address of the URL will be displayed.
+
+![Links UI](img/related_links_v13_1.png)
+
+#### Links Syntax
+
+```yaml
+links:
+ - title: GitLab.com
+ url: https://gitlab.com
+ - title: GitLab Documentation
+ url: https://docs.gitlab.com
+```
+
### View and edit the source file of a custom dashboard
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/34779) in GitLab 12.5.
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 4baf53d88d9..d47a78c8c29 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -373,6 +373,30 @@ msgstr ""
msgid "%{issuesSize} issues with a limit of %{maxIssueCount}"
msgstr ""
+msgid "%{labelStart}Class:%{labelEnd} %{class}"
+msgstr ""
+
+msgid "%{labelStart}Confidence:%{labelEnd} %{confidence}"
+msgstr ""
+
+msgid "%{labelStart}File:%{labelEnd} %{file}"
+msgstr ""
+
+msgid "%{labelStart}Image:%{labelEnd} %{image}"
+msgstr ""
+
+msgid "%{labelStart}Method:%{labelEnd} %{method}"
+msgstr ""
+
+msgid "%{labelStart}Namespace:%{labelEnd} %{namespace}"
+msgstr ""
+
+msgid "%{labelStart}Report Type:%{labelEnd} %{reportType}"
+msgstr ""
+
+msgid "%{labelStart}Severity:%{labelEnd} %{severity}"
+msgstr ""
+
msgid "%{label_for_message} unavailable"
msgstr ""
@@ -4386,9 +4410,6 @@ msgstr ""
msgid "Class"
msgstr ""
-msgid "Class:"
-msgstr ""
-
msgid "Classification Label (optional)"
msgstr ""
@@ -5741,9 +5762,6 @@ msgstr ""
msgid "Confidence"
msgstr ""
-msgid "Confidence: %{confidence}"
-msgstr ""
-
msgid "Confidential"
msgstr ""
@@ -9658,9 +9676,6 @@ msgstr ""
msgid "File upload error."
msgstr ""
-msgid "File:"
-msgstr ""
-
msgid "Files"
msgstr ""
@@ -11630,9 +11645,6 @@ msgstr ""
msgid "Image URL"
msgstr ""
-msgid "Image: %{image}"
-msgstr ""
-
msgid "ImageDiffViewer|2-up"
msgstr ""
@@ -13756,9 +13768,6 @@ msgstr ""
msgid "Method"
msgstr ""
-msgid "Method:"
-msgstr ""
-
msgid "Metric was successfully added."
msgstr ""
@@ -14348,9 +14357,6 @@ msgstr ""
msgid "Namespace is empty"
msgstr ""
-msgid "Namespace: %{namespace}"
-msgstr ""
-
msgid "Namespaces to index"
msgstr ""
@@ -18415,9 +18421,6 @@ msgstr ""
msgid "Report %{display_issuable_type} that are abusive, inappropriate or spam."
msgstr ""
-msgid "Report Type: %{report_type}"
-msgstr ""
-
msgid "Report abuse"
msgstr ""
@@ -20060,9 +20063,6 @@ msgstr ""
msgid "Severity"
msgstr ""
-msgid "Severity: %{severity}"
-msgstr ""
-
msgid "Shards (%{shards})"
msgstr ""
diff --git a/package.json b/package.json
index c1f20c3fc8d..8e60064f29f 100644
--- a/package.json
+++ b/package.json
@@ -41,7 +41,7 @@
"@babel/preset-env": "^7.8.4",
"@gitlab/at.js": "1.5.5",
"@gitlab/svgs": "1.137.0",
- "@gitlab/ui": "16.2.0",
+ "@gitlab/ui": "16.2.1",
"@gitlab/visual-review-tools": "1.6.1",
"@rails/actioncable": "^6.0.3-1",
"@sentry/browser": "^5.10.2",
@@ -58,7 +58,7 @@
"axios": "^0.19.0",
"babel-loader": "^8.0.6",
"babel-plugin-lodash": "^3.3.4",
- "bootstrap": "4.3.1",
+ "bootstrap": "4.4.1",
"brace-expansion": "^1.1.8",
"cache-loader": "^4.1.0",
"classlist-polyfill": "^1.2.0",
diff --git a/spec/frontend/confirm_modal_spec.js b/spec/frontend/confirm_modal_spec.js
index 89cfc3ef3a3..b14d1c3e01d 100644
--- a/spec/frontend/confirm_modal_spec.js
+++ b/spec/frontend/confirm_modal_spec.js
@@ -51,7 +51,7 @@ describe('ConfirmModal', () => {
const findModalOkButton = (modal, variant) =>
modal.querySelector(`.modal-footer .btn-${variant}`);
const findModalCancelButton = modal => modal.querySelector('.modal-footer .btn-secondary');
- const modalIsHidden = () => findModal().getAttribute('aria-hidden') === 'true';
+ const modalIsHidden = () => findModal() === null;
const serializeModal = (modal, buttonIndex) => {
const { modalAttributes } = buttons[buttonIndex];
@@ -101,7 +101,9 @@ describe('ConfirmModal', () => {
});
it('closes the modal', () => {
- expect(modalIsHidden()).toBe(true);
+ setImmediate(() => {
+ expect(modalIsHidden()).toBe(true);
+ });
});
});
});
diff --git a/spec/frontend/ide/components/branches/item_spec.js b/spec/frontend/ide/components/branches/item_spec.js
index 196951cce66..d8175025755 100644
--- a/spec/frontend/ide/components/branches/item_spec.js
+++ b/spec/frontend/ide/components/branches/item_spec.js
@@ -1,5 +1,6 @@
import { shallowMount } from '@vue/test-utils';
-import router from '~/ide/ide_router';
+import { createStore } from '~/ide/stores';
+import { createRouter } from '~/ide/ide_router';
import Item from '~/ide/components/branches/item.vue';
import Icon from '~/vue_shared/components/icon.vue';
import Timeago from '~/vue_shared/components/time_ago_tooltip.vue';
@@ -13,6 +14,8 @@ const TEST_PROJECT_ID = projectData.name_with_namespace;
describe('IDE branch item', () => {
let wrapper;
+ let store;
+ let router;
function createComponent(props = {}) {
wrapper = shallowMount(Item, {
@@ -26,6 +29,11 @@ describe('IDE branch item', () => {
});
}
+ beforeEach(() => {
+ store = createStore();
+ router = createRouter(store);
+ });
+
afterEach(() => {
wrapper.destroy();
});
diff --git a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
index ebb41448905..7ce628d4da7 100644
--- a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
+++ b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
@@ -1,17 +1,22 @@
import Vue from 'vue';
import { trimText } from 'helpers/text_helper';
import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
-import store from '~/ide/stores';
+import { createStore } from '~/ide/stores';
import listItem from '~/ide/components/commit_sidebar/list_item.vue';
-import router from '~/ide/ide_router';
-import { file, resetStore } from '../../helpers';
+import { createRouter } from '~/ide/ide_router';
+import { file } from '../../helpers';
describe('Multi-file editor commit sidebar list item', () => {
let vm;
let f;
let findPathEl;
+ let store;
+ let router;
beforeEach(() => {
+ store = createStore();
+ router = createRouter(store);
+
const Component = Vue.extend(listItem);
f = file('test-file');
@@ -28,8 +33,6 @@ describe('Multi-file editor commit sidebar list item', () => {
afterEach(() => {
vm.$destroy();
-
- resetStore(store);
});
const findPathText = () => trimText(findPathEl.textContent);
diff --git a/spec/frontend/ide/components/merge_requests/item_spec.js b/spec/frontend/ide/components/merge_requests/item_spec.js
index 551d5dab9f7..b1da89d7a9b 100644
--- a/spec/frontend/ide/components/merge_requests/item_spec.js
+++ b/spec/frontend/ide/components/merge_requests/item_spec.js
@@ -1,5 +1,7 @@
-import { mount } from '@vue/test-utils';
-import router from '~/ide/ide_router';
+import Vuex from 'vuex';
+import { mount, createLocalVue } from '@vue/test-utils';
+import { createStore } from '~/ide/stores';
+import { createRouter } from '~/ide/ide_router';
import Item from '~/ide/components/merge_requests/item.vue';
const TEST_ITEM = {
@@ -9,7 +11,12 @@ const TEST_ITEM = {
};
describe('IDE merge request item', () => {
+ const localVue = createLocalVue();
+ localVue.use(Vuex);
+
let wrapper;
+ let store;
+ let router;
const createComponent = (props = {}) => {
wrapper = mount(Item, {
@@ -21,11 +28,18 @@ describe('IDE merge request item', () => {
currentProjectId: TEST_ITEM.projectPathWithNamespace,
...props,
},
+ localVue,
router,
+ store,
});
};
const findIcon = () => wrapper.find('.ic-mobile-issue-close');
+ beforeEach(() => {
+ store = createStore();
+ router = createRouter(store);
+ });
+
afterEach(() => {
wrapper.destroy();
wrapper = null;
diff --git a/spec/frontend/ide/components/repo_commit_section_spec.js b/spec/frontend/ide/components/repo_commit_section_spec.js
index d4e4e064a52..43094796d4f 100644
--- a/spec/frontend/ide/components/repo_commit_section_spec.js
+++ b/spec/frontend/ide/components/repo_commit_section_spec.js
@@ -1,6 +1,6 @@
import { mount } from '@vue/test-utils';
import { createStore } from '~/ide/stores';
-import router from '~/ide/ide_router';
+import { createRouter } from '~/ide/ide_router';
import RepoCommitSection from '~/ide/components/repo_commit_section.vue';
import EmptyState from '~/ide/components/commit_sidebar/empty_state.vue';
import { stageKeys } from '~/ide/constants';
@@ -10,6 +10,7 @@ const TEST_NO_CHANGES_SVG = 'nochangessvg';
describe('RepoCommitSection', () => {
let wrapper;
+ let router;
let store;
function createComponent() {
@@ -55,6 +56,7 @@ describe('RepoCommitSection', () => {
beforeEach(() => {
store = createStore();
+ router = createRouter(store);
jest.spyOn(store, 'dispatch');
jest.spyOn(router, 'push').mockImplementation();
diff --git a/spec/frontend/ide/components/repo_tab_spec.js b/spec/frontend/ide/components/repo_tab_spec.js
index 82ea73ffbb1..5a591d3dcd0 100644
--- a/spec/frontend/ide/components/repo_tab_spec.js
+++ b/spec/frontend/ide/components/repo_tab_spec.js
@@ -1,11 +1,13 @@
import Vue from 'vue';
-import store from '~/ide/stores';
+import { createStore } from '~/ide/stores';
import repoTab from '~/ide/components/repo_tab.vue';
-import router from '~/ide/ide_router';
-import { file, resetStore } from '../helpers';
+import { createRouter } from '~/ide/ide_router';
+import { file } from '../helpers';
describe('RepoTab', () => {
let vm;
+ let store;
+ let router;
function createComponent(propsData) {
const RepoTab = Vue.extend(repoTab);
@@ -17,13 +19,13 @@ describe('RepoTab', () => {
}
beforeEach(() => {
+ store = createStore();
+ router = createRouter(store);
jest.spyOn(router, 'push').mockImplementation(() => {});
});
afterEach(() => {
vm.$destroy();
-
- resetStore(vm.$store);
});
it('renders a close link and a name link', () => {
diff --git a/spec/frontend/ide/ide_router_spec.js b/spec/frontend/ide/ide_router_spec.js
index 1461b756d13..b53e2019819 100644
--- a/spec/frontend/ide/ide_router_spec.js
+++ b/spec/frontend/ide/ide_router_spec.js
@@ -1,17 +1,20 @@
-import router from '~/ide/ide_router';
-import store from '~/ide/stores';
+import { createRouter } from '~/ide/ide_router';
+import { createStore } from '~/ide/stores';
+import waitForPromises from 'helpers/wait_for_promises';
describe('IDE router', () => {
const PROJECT_NAMESPACE = 'my-group/sub-group';
const PROJECT_NAME = 'my-project';
+ const TEST_PATH = `/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}/merge_requests/2`;
- afterEach(() => {
- router.push('/');
- });
+ let store;
+ let router;
- afterAll(() => {
- // VueRouter leaves this window.history at the "base" url. We need to clean this up.
+ beforeEach(() => {
window.history.replaceState({}, '', '/');
+ store = createStore();
+ router = createRouter(store);
+ jest.spyOn(store, 'dispatch').mockReturnValue(new Promise(() => {}));
});
[
@@ -31,8 +34,6 @@ describe('IDE router', () => {
`/project/${PROJECT_NAMESPACE}/${PROJECT_NAME}`,
].forEach(route => {
it(`finds project path when route is "${route}"`, () => {
- jest.spyOn(store, 'dispatch').mockReturnValue(new Promise(() => {}));
-
router.push(route);
expect(store.dispatch).toHaveBeenCalledWith('getProjectData', {
@@ -41,4 +42,22 @@ describe('IDE router', () => {
});
});
});
+
+ it('keeps router in sync when store changes', async () => {
+ expect(router.currentRoute.fullPath).toBe('/');
+
+ store.state.router.fullPath = TEST_PATH;
+
+ await waitForPromises();
+
+ expect(router.currentRoute.fullPath).toBe(TEST_PATH);
+ });
+
+ it('keeps store in sync when router changes', () => {
+ expect(store.dispatch).not.toHaveBeenCalled();
+
+ router.push(TEST_PATH);
+
+ expect(store.dispatch).toHaveBeenCalledWith('router/push', TEST_PATH, { root: true });
+ });
});
diff --git a/spec/frontend/ide/stores/actions/file_spec.js b/spec/frontend/ide/stores/actions/file_spec.js
index e50697af5eb..90b4d973222 100644
--- a/spec/frontend/ide/stores/actions/file_spec.js
+++ b/spec/frontend/ide/stores/actions/file_spec.js
@@ -5,7 +5,7 @@ import { createStore } from '~/ide/stores';
import * as actions from '~/ide/stores/actions/file';
import * as types from '~/ide/stores/mutation_types';
import service from '~/ide/services';
-import router from '~/ide/ide_router';
+import { createRouter } from '~/ide/ide_router';
import eventHub from '~/ide/eventhub';
import { file } from '../../helpers';
@@ -16,6 +16,7 @@ describe('IDE store file actions', () => {
let mock;
let originalGon;
let store;
+ let router;
beforeEach(() => {
mock = new MockAdapter(axios);
@@ -26,6 +27,7 @@ describe('IDE store file actions', () => {
};
store = createStore();
+ router = createRouter(store);
jest.spyOn(store, 'commit');
jest.spyOn(store, 'dispatch');
diff --git a/spec/frontend/ide/stores/actions/project_spec.js b/spec/frontend/ide/stores/actions/project_spec.js
index 1aaeebf19d4..f71cffb93ad 100644
--- a/spec/frontend/ide/stores/actions/project_spec.js
+++ b/spec/frontend/ide/stores/actions/project_spec.js
@@ -1,7 +1,6 @@
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import { createStore } from '~/ide/stores';
-import router from '~/ide/ide_router';
import {
refreshLastCommitData,
showBranchNotFoundError,
@@ -13,7 +12,6 @@ import {
} from '~/ide/stores/actions';
import service from '~/ide/services';
import api from '~/api';
-import { resetStore } from '../../helpers';
import testAction from '../../../helpers/vuex_action_helper';
const TEST_PROJECT_ID = 'abc/def';
@@ -33,8 +31,6 @@ describe('IDE store project actions', () => {
afterEach(() => {
mock.restore();
-
- resetStore(store);
});
describe('refreshLastCommitData', () => {
@@ -122,7 +118,6 @@ describe('IDE store project actions', () => {
describe('createNewBranchFromDefault', () => {
beforeEach(() => {
jest.spyOn(api, 'createBranch').mockResolvedValue();
- jest.spyOn(router, 'push').mockImplementation();
});
it('calls API', done => {
@@ -175,6 +170,8 @@ describe('IDE store project actions', () => {
});
it('reloads window', done => {
+ jest.spyOn(window.location, 'reload').mockImplementation();
+
createNewBranchFromDefault(
{
state: {
@@ -190,7 +187,7 @@ describe('IDE store project actions', () => {
'new-branch-name',
)
.then(() => {
- expect(router.push).toHaveBeenCalled();
+ expect(window.location.reload).toHaveBeenCalled();
})
.then(done)
.catch(done.fail);
diff --git a/spec/frontend/ide/stores/actions/tree_spec.js b/spec/frontend/ide/stores/actions/tree_spec.js
index 37594512fe9..44e2fcab436 100644
--- a/spec/frontend/ide/stores/actions/tree_spec.js
+++ b/spec/frontend/ide/stores/actions/tree_spec.js
@@ -3,14 +3,16 @@ import testAction from 'helpers/vuex_action_helper';
import { showTreeEntry, getFiles, setDirectoryData } from '~/ide/stores/actions/tree';
import * as types from '~/ide/stores/mutation_types';
import axios from '~/lib/utils/axios_utils';
-import store from '~/ide/stores';
+import { createStore } from '~/ide/stores';
import service from '~/ide/services';
-import router from '~/ide/ide_router';
-import { file, resetStore, createEntriesFromPaths } from '../../helpers';
+import { createRouter } from '~/ide/ide_router';
+import { file, createEntriesFromPaths } from '../../helpers';
describe('Multi-file store tree actions', () => {
let projectTree;
let mock;
+ let store;
+ let router;
const basicCallParameters = {
endpoint: 'rootEndpoint',
@@ -21,6 +23,8 @@ describe('Multi-file store tree actions', () => {
};
beforeEach(() => {
+ store = createStore();
+ router = createRouter(store);
jest.spyOn(router, 'push').mockImplementation();
mock = new MockAdapter(axios);
@@ -35,7 +39,6 @@ describe('Multi-file store tree actions', () => {
afterEach(() => {
mock.restore();
- resetStore(store);
});
describe('getFiles', () => {
diff --git a/spec/frontend/ide/stores/actions_spec.js b/spec/frontend/ide/stores/actions_spec.js
index 666ed8a24aa..3b8762e2fd8 100644
--- a/spec/frontend/ide/stores/actions_spec.js
+++ b/spec/frontend/ide/stores/actions_spec.js
@@ -1,7 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import { visitUrl } from '~/lib/utils/url_utility';
import { createStore } from '~/ide/stores';
-import router from '~/ide/ide_router';
+import { createRouter } from '~/ide/ide_router';
import {
stageAllChanges,
unstageAllChanges,
@@ -30,9 +30,11 @@ jest.mock('~/lib/utils/url_utility', () => ({
describe('Multi-file store actions', () => {
let store;
+ let router;
beforeEach(() => {
store = createStore();
+ router = createRouter(store);
jest.spyOn(store, 'commit');
jest.spyOn(store, 'dispatch');
@@ -339,10 +341,12 @@ describe('Multi-file store actions', () => {
it('adds all files from changedFiles to stagedFiles', () => {
stageAllChanges(store);
- expect(store.commit.mock.calls).toEqual([
- [types.SET_LAST_COMMIT_MSG, ''],
- [types.STAGE_CHANGE, expect.objectContaining({ path: file1.path })],
- ]);
+ expect(store.commit.mock.calls).toEqual(
+ expect.arrayContaining([
+ [types.SET_LAST_COMMIT_MSG, ''],
+ [types.STAGE_CHANGE, expect.objectContaining({ path: file1.path })],
+ ]),
+ );
});
it('opens pending tab if a change exists in that file', () => {
@@ -371,9 +375,11 @@ describe('Multi-file store actions', () => {
it('removes all files from stagedFiles after unstaging', () => {
unstageAllChanges(store);
- expect(store.commit.mock.calls).toEqual([
- [types.UNSTAGE_CHANGE, expect.objectContaining({ path: file2.path })],
- ]);
+ expect(store.commit.mock.calls).toEqual(
+ expect.arrayContaining([
+ [types.UNSTAGE_CHANGE, expect.objectContaining({ path: file2.path })],
+ ]),
+ );
});
it('opens pending tab if a change exists in that file', () => {
diff --git a/spec/frontend/ide/stores/modules/commit/actions_spec.js b/spec/frontend/ide/stores/modules/commit/actions_spec.js
index 649c05441f6..52870d7bc75 100644
--- a/spec/frontend/ide/stores/modules/commit/actions_spec.js
+++ b/spec/frontend/ide/stores/modules/commit/actions_spec.js
@@ -1,10 +1,10 @@
-import { resetStore, file } from 'jest/ide/helpers';
+import { file } from 'jest/ide/helpers';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { visitUrl } from '~/lib/utils/url_utility';
import { createStore } from '~/ide/stores';
import service from '~/ide/services';
-import router from '~/ide/ide_router';
+import { createRouter } from '~/ide/ide_router';
import eventHub from '~/ide/eventhub';
import consts from '~/ide/stores/modules/commit/constants';
import * as mutationTypes from '~/ide/stores/modules/commit/mutation_types';
@@ -18,12 +18,15 @@ jest.mock('~/lib/utils/url_utility', () => ({
}));
const TEST_COMMIT_SHA = '123456789';
-const store = createStore();
describe('IDE commit module actions', () => {
let mock;
+ let store;
+ let router;
beforeEach(() => {
+ store = createStore();
+ router = createRouter(store);
gon.api_version = 'v1';
mock = new MockAdapter(axios);
jest.spyOn(router, 'push').mockImplementation();
@@ -34,7 +37,6 @@ describe('IDE commit module actions', () => {
afterEach(() => {
delete gon.api_version;
mock.restore();
- resetStore(store);
});
describe('updateCommitMessage', () => {
diff --git a/spec/frontend/ide/sync_router_and_store_spec.js b/spec/frontend/ide/sync_router_and_store_spec.js
index c691a196916..c4ce92b99cc 100644
--- a/spec/frontend/ide/sync_router_and_store_spec.js
+++ b/spec/frontend/ide/sync_router_and_store_spec.js
@@ -1,14 +1,10 @@
-import Vue from 'vue';
import VueRouter from 'vue-router';
-import Vuex from 'vuex';
-import routerModule from '~/ide/stores/modules/router';
+import { createStore } from '~/ide/stores';
import { syncRouterAndStore } from '~/ide/sync_router_and_store';
import waitForPromises from 'helpers/wait_for_promises';
const TEST_ROUTE = '/test/lorem/ipsum';
-Vue.use(Vuex);
-
describe('~/ide/sync_router_and_store', () => {
let unsync;
let router;
@@ -32,11 +28,7 @@ describe('~/ide/sync_router_and_store', () => {
beforeEach(() => {
router = new VueRouter();
- store = new Vuex.Store({
- modules: {
- router: routerModule,
- },
- });
+ store = createStore();
jest.spyOn(store, 'dispatch');
onRouterChange = jest.fn();
diff --git a/spec/frontend/lib/utils/common_utils_spec.js b/spec/frontend/lib/utils/common_utils_spec.js
index 11debfe12a1..f597255538c 100644
--- a/spec/frontend/lib/utils/common_utils_spec.js
+++ b/spec/frontend/lib/utils/common_utils_spec.js
@@ -589,6 +589,7 @@ describe('common_utils', () => {
id: 1,
group_name: 'GitLab.org',
absolute_web_url: 'https://gitlab.com/gitlab-org/',
+ milestones: ['12.3', '12.4'],
},
objNested: {
project_name: 'GitLab CE',
@@ -599,6 +600,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
},
convertObjectPropsToCamelCase: {
@@ -606,6 +608,7 @@ describe('common_utils', () => {
id: 1,
group_name: 'GitLab.org',
absolute_web_url: 'https://gitlab.com/gitlab-org/',
+ milestones: ['12.3', '12.4'],
},
objNested: {
project_name: 'GitLab CE',
@@ -616,6 +619,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
},
convertObjectPropsToSnakeCase: {
@@ -623,6 +627,7 @@ describe('common_utils', () => {
id: 1,
groupName: 'GitLab.org',
absoluteWebUrl: 'https://gitlab.com/gitlab-org/',
+ milestones: ['12.3', '12.4'],
},
objNested: {
projectName: 'GitLab CE',
@@ -633,6 +638,7 @@ describe('common_utils', () => {
frontendFramework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
},
};
@@ -669,16 +675,19 @@ describe('common_utils', () => {
id_converted: 1,
group_name_converted: 'GitLab.org',
absolute_web_url_converted: 'https://gitlab.com/gitlab-org/',
+ milestones_converted: ['12.3', '12.4'],
},
convertObjectPropsToCamelCase: {
id: 1,
groupName: 'GitLab.org',
absoluteWebUrl: 'https://gitlab.com/gitlab-org/',
+ milestones: ['12.3', '12.4'],
},
convertObjectPropsToSnakeCase: {
id: 1,
group_name: 'GitLab.org',
absolute_web_url: 'https://gitlab.com/gitlab-org/',
+ milestones: ['12.3', '12.4'],
},
};
@@ -696,6 +705,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones_converted: ['12.3', '12.4'],
},
convertObjectPropsToCamelCase: {
projectName: 'GitLab CE',
@@ -706,6 +716,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
convertObjectPropsToSnakeCase: {
project_name: 'GitLab CE',
@@ -716,6 +727,7 @@ describe('common_utils', () => {
frontendFramework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
};
@@ -734,6 +746,7 @@ describe('common_utils', () => {
frontend_framework_converted: 'Vue',
database_converted: 'PostgreSQL',
},
+ milestones_converted: ['12.3', '12.4'],
},
convertObjectPropsToCamelCase: {
projectName: 'GitLab CE',
@@ -744,6 +757,7 @@ describe('common_utils', () => {
frontendFramework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
convertObjectPropsToSnakeCase: {
project_name: 'GitLab CE',
@@ -754,6 +768,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
};
@@ -783,6 +798,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones_converted: ['12.3', '12.4'],
},
convertObjectPropsToCamelCase: {
projectName: 'GitLab CE',
@@ -792,6 +808,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
convertObjectPropsToSnakeCase: {
project_name: 'GitLab CE',
@@ -801,6 +818,7 @@ describe('common_utils', () => {
frontendFramework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
};
@@ -826,6 +844,7 @@ describe('common_utils', () => {
backend_converted: 'Ruby',
frontend_framework_converted: 'Vue',
},
+ milestones_converted: ['12.3', '12.4'],
},
convertObjectPropsToCamelCase: {
projectName: 'GitLab CE',
@@ -834,6 +853,7 @@ describe('common_utils', () => {
backend: 'Ruby',
frontendFramework: 'Vue',
},
+ milestones: ['12.3', '12.4'],
},
convertObjectPropsToSnakeCase: {
project_name: 'GitLab CE',
@@ -842,6 +862,7 @@ describe('common_utils', () => {
backend: 'Ruby',
frontend_framework: 'Vue',
},
+ milestones: ['12.3', '12.4'],
},
};
@@ -872,6 +893,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones_converted: ['12.3', '12.4'],
},
convertObjectPropsToCamelCase: {
projectName: 'GitLab CE',
@@ -882,6 +904,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
convertObjectPropsToSnakeCase: {
project_name: 'GitLab CE',
@@ -892,6 +915,7 @@ describe('common_utils', () => {
frontendFramework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
};
@@ -919,6 +943,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database_converted: 'PostgreSQL',
},
+ milestones_converted: ['12.3', '12.4'],
},
convertObjectPropsToCamelCase: {
projectName: 'GitLab CE',
@@ -929,6 +954,7 @@ describe('common_utils', () => {
frontend_framework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
convertObjectPropsToSnakeCase: {
project_name: 'GitLab CE',
@@ -939,6 +965,7 @@ describe('common_utils', () => {
frontendFramework: 'Vue',
database: 'PostgreSQL',
},
+ milestones: ['12.3', '12.4'],
},
};
diff --git a/spec/helpers/subscribable_banner_helper_spec.rb b/spec/helpers/subscribable_banner_helper_spec.rb
new file mode 100644
index 00000000000..75f2e32d7d8
--- /dev/null
+++ b/spec/helpers/subscribable_banner_helper_spec.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe SubscribableBannerHelper do
+ describe '#display_subscription_banner!' do
+ it 'is over-written in EE' do
+ expect { helper.display_subscription_banner! }.not_to raise_error
+ end
+ end
+end
diff --git a/yarn.lock b/yarn.lock
index ef03db616ce..d1452bd6f0a 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -787,14 +787,14 @@
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-1.137.0.tgz#49fb1f33340cfdf0a47c83b7a613e3c7306dd53c"
integrity sha512-dhyiedyTKYJt/mXV+PjfY2pivAAPh3BAOHpVzNCZj6HmJ9VZFIJDzOAQTTxlxRz4UyPmHPuCiaal63q+JfLzcQ==
-"@gitlab/ui@16.2.0":
- version "16.2.0"
- resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-16.2.0.tgz#b187b54e2757c59473834114aceb886697abcae1"
- integrity sha512-9x+b8l2guCFAtvBA/kf8y6oDs1vsPbOxVpxaSDbf/yV0A4w/bxsIjtN0kBacntTlhmK73yNBmydfhOB4Il8xrg==
+"@gitlab/ui@16.2.1":
+ version "16.2.1"
+ resolved "https://registry.yarnpkg.com/@gitlab/ui/-/ui-16.2.1.tgz#52d1a7e21b36e8cdb2766a945d928c8815956449"
+ integrity sha512-JPkJUp9iyhS+u465qEMcVn9ZhZC7LqXjFBsTpF+plY9LuQWxNSEV9LU1WJ6lR1UsyNAQCJJ04qt9VgkxG52S7Q==
dependencies:
"@babel/standalone" "^7.0.0"
"@gitlab/vue-toasted" "^1.3.0"
- bootstrap-vue "2.1.0"
+ bootstrap-vue "2.13.1"
copy-to-clipboard "^3.0.8"
echarts "^4.2.1"
highlight.js "^9.13.1"
@@ -2213,21 +2213,21 @@ bonjour@^3.5.0:
multicast-dns "^6.0.1"
multicast-dns-service-types "^1.1.0"
-bootstrap-vue@2.1.0:
- version "2.1.0"
- resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.1.0.tgz#41c0cd265a6cea14ffe29eeea71543ec396d1789"
- integrity sha512-dftb5fc42x7QLv814nN+3Cx8MMuCB+xrGQjOmSXH81ET0+yo7KYb4lUN3/pOnf+8Tkv8oaawZ1OOth5/AZfktg==
+bootstrap-vue@2.13.1:
+ version "2.13.1"
+ resolved "https://registry.yarnpkg.com/bootstrap-vue/-/bootstrap-vue-2.13.1.tgz#dcefca78f2b0345508fbb85adb0a9897cce65fa1"
+ integrity sha512-FF1GLRvvj+TgpLkMG/A8+tCMQfWnfKpsPqt7s097VTX2lZv2/YmyhehRC1qraPHYqT7qQVy48TCxSw1H8hNh3Q==
dependencies:
"@nuxt/opencollective" "^0.3.0"
- bootstrap ">=4.3.1 <5.0.0"
- popper.js "^1.16.0"
- portal-vue "^2.1.6"
+ bootstrap ">=4.4.1 <5.0.0"
+ popper.js "^1.16.1"
+ portal-vue "^2.1.7"
vue-functional-data-merge "^3.1.0"
-bootstrap@4.3.1, "bootstrap@>=4.3.1 <5.0.0":
- version "4.3.1"
- resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.3.1.tgz#280ca8f610504d99d7b6b4bfc4b68cec601704ac"
- integrity sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag==
+bootstrap@4.4.1, "bootstrap@>=4.4.1 <5.0.0":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.4.1.tgz#8582960eea0c5cd2bede84d8b0baf3789c3e8b01"
+ integrity sha512-tbx5cHubwE6e2ZG7nqM3g/FZ5PQEDMWmMGNrCUBVRPHXTJaH7CBDdsLeu3eCh3B1tzAxTnAbtmrzvWEvT2NNEA==
boxen@^4.2.0:
version "4.2.0"
@@ -8910,15 +8910,15 @@ pofile@^1:
resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"
integrity sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg==
-popper.js@^1.16.0, popper.js@^1.16.1:
+popper.js@^1.16.1:
version "1.16.1"
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b"
integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==
-portal-vue@^2.1.6:
- version "2.1.6"
- resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.6.tgz#a7d4790b14a79af7fd159a60ec88c30cddc6c639"
- integrity sha512-lvCF85D4e8whd0nN32D8FqKwwkk7nYUI3Ku8UAEx4Z1reomu75dv5evRUTZNaj1EalxxWNXiNl0EHRq36fG8WA==
+portal-vue@^2.1.6, portal-vue@^2.1.7:
+ version "2.1.7"
+ resolved "https://registry.yarnpkg.com/portal-vue/-/portal-vue-2.1.7.tgz#ea08069b25b640ca08a5b86f67c612f15f4e4ad4"
+ integrity sha512-+yCno2oB3xA7irTt0EU5Ezw22L2J51uKAacE/6hMPMoO/mx3h4rXFkkBkT4GFsMDv/vEe8TNKC3ujJJ0PTwb6g==
portfinder@^1.0.25:
version "1.0.25"