Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-09-14 12:09:34 +00:00
parent 0923a94d58
commit 9a5dcad39c
185 changed files with 1927 additions and 1323 deletions

View File

@ -1 +1 @@
2.6.0
2.7.0

View File

@ -1,11 +1,9 @@
<script>
import { mapGetters, mapActions } from 'vuex';
import Sortable from 'sortablejs';
import isWipLimitsOn from 'ee_else_ce/boards/mixins/is_wip_limits';
import BoardListHeader from 'ee_else_ce/boards/components/board_list_header.vue';
import Tooltip from '~/vue_shared/directives/tooltip';
import EmptyComponent from '~/vue_shared/components/empty_component';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import BoardBlankState from './board_blank_state.vue';
import BoardList from './board_list.vue';
import boardsStore from '../stores/boards_store';
@ -23,7 +21,7 @@ export default {
directives: {
Tooltip,
},
mixins: [isWipLimitsOn, glFeatureFlagMixin()],
mixins: [isWipLimitsOn],
props: {
list: {
type: Object,
@ -64,7 +62,6 @@ export default {
};
},
computed: {
...mapGetters(['getIssues']),
showBoardListAndBoardInfo() {
return this.list.type !== ListType.blank && this.list.type !== ListType.promotion;
},
@ -72,36 +69,19 @@ export default {
// eslint-disable-next-line @gitlab/require-i18n-strings
return `boards.${this.boardId}.${this.list.type}.${this.list.id}`;
},
listIssues() {
if (!this.glFeatures.graphqlBoardLists) {
return this.list.issues;
}
return this.getIssues(this.list.id);
},
shouldFetchIssues() {
return this.glFeatures.graphqlBoardLists && this.list.type !== ListType.blank;
},
},
watch: {
filter: {
handler() {
if (this.shouldFetchIssues) {
this.fetchIssuesForList(this.list.id);
} else {
this.list.page = 1;
this.list.getIssues(true).catch(() => {
// TODO: handle request error
});
}
this.list.page = 1;
this.list.getIssues(true).catch(() => {
// TODO: handle request error
});
},
deep: true,
},
},
mounted() {
if (this.shouldFetchIssues) {
this.fetchIssuesForList(this.list.id);
}
const instance = this;
const sortableOptions = getBoardSortableDefaultOptions({
@ -128,7 +108,6 @@ export default {
Sortable.create(this.$el.parentNode, sortableOptions);
},
methods: {
...mapActions(['fetchIssuesForList']),
showListNewIssueForm(listId) {
eventHub.$emit('showForm', listId);
},
@ -163,7 +142,7 @@ export default {
:disabled="disabled"
:group-id="groupId || null"
:issue-link-base="issueLinkBase"
:issues="listIssues"
:issues="list.issues"
:list="list"
:loading="list.loading"
:root-path="rootPath"

View File

@ -6,7 +6,6 @@ import boardCard from './board_card.vue';
import eventHub from '../eventhub';
import boardsStore from '../stores/boards_store';
import { sprintf, __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import {
getBoardSortableDefaultOptions,
@ -25,7 +24,6 @@ export default {
boardNewIssue,
GlLoadingIcon,
},
mixins: [glFeatureFlagMixin()],
props: {
groupId: {
type: Number,
@ -85,7 +83,6 @@ export default {
deep: true,
},
issues() {
if (this.glFeatures.graphqlBoardLists) return;
this.$nextTick(() => {
if (
this.scrollHeight() <= this.listHeight() &&
@ -416,8 +413,6 @@ export default {
this.showIssueForm = !this.showIssueForm;
},
onScroll() {
if (this.glFeatures.graphqlBoardLists) return;
if (!this.list.loadingMore && this.scrollTop() > this.scrollHeight() - this.scrollOffset) {
this.loadNextPage();
}

View File

@ -129,9 +129,6 @@ export default {
collapsedTooltipTitle() {
return this.listTitle || this.listAssignee;
},
shouldDisplaySwimlanes() {
return this.glFeatures.boardsWithSwimlanes && this.isSwimlanesOn;
},
},
methods: {
...mapActions(['updateList']),
@ -161,7 +158,7 @@ export default {
}
},
updateListFunction() {
if (this.shouldDisplaySwimlanes || this.glFeatures.graphqlBoardLists) {
if (this.glFeatures.boardsWithSwimlanes && this.isSwimlanesHeader) {
this.updateList({ listId: this.list.id, collapsed: !this.list.isExpanded });
} else {
this.list.update();
@ -187,7 +184,7 @@ export default {
<h3
:class="{
'user-can-drag': !disabled && !list.preset,
'gl-py-3 gl-h-full': !list.isExpanded && !isSwimlanesHeader,
'gl-py-3': !list.isExpanded && !isSwimlanesHeader,
'gl-border-b-0': !list.isExpanded || isSwimlanesHeader,
'gl-py-2': !list.isExpanded && isSwimlanesHeader,
}"

View File

@ -42,9 +42,6 @@ export default {
}
return this.title === '';
},
shouldDisplaySwimlanes() {
return this.glFeatures.boardsWithSwimlanes && this.isSwimlanesOn;
},
},
mounted() {
this.$refs.input.focus();
@ -78,7 +75,7 @@ export default {
eventHub.$emit(`scroll-board-list-${this.list.id}`);
this.cancel();
if (this.shouldDisplaySwimlanes || this.glFeatures.graphqlBoardLists) {
if (this.glFeatures.boardsWithSwimlanes && this.isSwimlanesOn) {
this.addListIssue({ list: this.list, issue, position: 0 });
}
@ -88,7 +85,7 @@ export default {
// Need this because our jQuery very kindly disables buttons on ALL form submissions
$(this.$refs.submitButton).enable();
if (!this.shouldDisplaySwimlanes && !this.glFeatures.graphqlBoardLists) {
if (!this.glFeatures.boardsWithSwimlanes || !this.isSwimlanesOn) {
boardsStore.setIssueDetail(issue);
boardsStore.setListDetail(this.list);
}
@ -98,7 +95,7 @@ export default {
$(this.$refs.submitButton).enable();
// Remove the issue
if (this.shouldDisplaySwimlanes || this.glFeatures.graphqlBoardLists) {
if (this.glFeatures.boardsWithSwimlanes && this.isSwimlanesOn) {
this.addListIssueFailure({ list: this.list, issue });
} else {
this.list.removeIssue(issue);

View File

@ -27,7 +27,7 @@ export default class FilteredSearchBoards extends FilteredSearchManager {
updateObject(path) {
this.store.path = path.substr(1);
if (gon.features.boardsWithSwimlanes || gon.features.graphqlBoardLists) {
if (gon.features.boardsWithSwimlanes) {
boardsStore.updateFiltersUrl();
boardsStore.performSearch();
}

View File

@ -84,6 +84,10 @@ export default () => {
},
store,
apolloProvider,
provide: {
// TODO: Mv all non-reactive props from data/props to here.
rootPath: $boardApp.dataset.rootPath,
},
data() {
return {
state: boardsStore.state,

View File

@ -3,14 +3,13 @@
query ListIssues(
$fullPath: ID!
$boardId: ID!
$id: ID
$filters: BoardIssueInput
$isGroup: Boolean = false
$isProject: Boolean = false
) {
group(fullPath: $fullPath) @include(if: $isGroup) {
board(id: $boardId) {
lists(id: $id) {
lists {
nodes {
id
issues(filters: $filters) {
@ -24,7 +23,7 @@ query ListIssues(
}
project(fullPath: $fullPath) @include(if: $isProject) {
board(id: $boardId) {
lists(id: $id) {
lists {
nodes {
id
issues(filters: $filters) {

View File

@ -79,10 +79,10 @@ export default {
lists = lists.nodes.map(list =>
boardStore.updateListPosition({
...list,
doNotFetchIssues: true,
id: getIdFromGraphQLId(list.id),
}),
);
commit(types.RECEIVE_BOARD_LISTS_SUCCESS, sortBy(lists, 'position'));
commit(types.RECEIVE_LISTS, sortBy(lists, 'position'));
// Backlog list needs to be created if it doesn't exist
if (!lists.find(l => l.type === ListType.backlog)) {
dispatch('createList', { backlog: true });
@ -113,7 +113,7 @@ export default {
commit(types.CREATE_LIST_FAILURE);
} else {
const list = data.boardListCreate?.list;
dispatch('addList', list);
dispatch('addList', { ...list, id: getIdFromGraphQLId(list.id) });
}
})
.catch(() => {
@ -124,8 +124,8 @@ export default {
addList: ({ state, commit }, list) => {
const lists = state.boardLists;
// Temporarily using positioning logic from boardStore
lists.push(boardStore.updateListPosition({ ...list, doNotFetchIssues: true }));
commit(types.RECEIVE_BOARD_LISTS_SUCCESS, sortBy(lists, 'position'));
lists.push(boardStore.updateListPosition(list));
commit(types.RECEIVE_LISTS, sortBy(lists, 'position'));
},
showWelcomeList: ({ state, dispatch }) => {
@ -197,33 +197,8 @@ export default {
notImplemented();
},
fetchIssuesForList: ({ state, commit }, listId) => {
const { endpoints, boardType, filterParams } = state;
const { fullPath, boardId } = endpoints;
const variables = {
fullPath,
boardId: fullBoardId(boardId),
id: listId,
filters: filterParams,
isGroup: boardType === BoardType.group,
isProject: boardType === BoardType.project,
};
return gqlClient
.query({
query: listsIssuesQuery,
context: {
isSingleRequest: true,
},
variables,
})
.then(({ data }) => {
const { lists } = data[boardType]?.board;
const listIssues = formatListIssues(lists);
commit(types.RECEIVE_ISSUES_FOR_LIST_SUCCESS, { listIssues, listId });
})
.catch(() => commit(types.RECEIVE_ISSUES_FOR_LIST_FAILURE, listId));
fetchIssuesForList: () => {
notImplemented();
},
fetchIssuesForAllLists: ({ state, commit }) => {

View File

@ -304,11 +304,7 @@ const boardsStore = {
onNewListIssueResponse(list, issue, data) {
issue.refreshData(data);
if (
!gon.features.boardsWithSwimlanes &&
!gon.features.graphqlBoardLists &&
list.issues.length > 1
) {
if (!gon.features.boardsWithSwimlanes && list.issuesSize > 1) {
const moveBeforeId = list.issues[1].id;
this.moveIssue(issue.id, null, null, null, moveBeforeId);
}
@ -727,10 +723,6 @@ const boardsStore = {
newListIssue(list, issue) {
list.addIssue(issue, null, 0);
list.issuesSize += 1;
let listId = list.id;
if (typeof listId === 'string') {
listId = getIdFromGraphQLId(listId);
}
return this.newIssue(list.id, issue)
.then(res => res.data)

View File

@ -14,11 +14,6 @@ export default {
return state.issues[id] || {};
},
getIssues: (state, getters) => listId => {
const listIssueIds = state.issuesByListId[listId] || [];
return listIssueIds.map(id => getters.getIssueById(id));
},
getActiveIssue: state => {
return state.issues[state.activeId] || {};
},

View File

@ -2,7 +2,7 @@ export const SET_INITIAL_BOARD_DATA = 'SET_INITIAL_BOARD_DATA';
export const SET_FILTERS = 'SET_FILTERS';
export const CREATE_LIST_SUCCESS = 'CREATE_LIST_SUCCESS';
export const CREATE_LIST_FAILURE = 'CREATE_LIST_FAILURE';
export const RECEIVE_BOARD_LISTS_SUCCESS = 'RECEIVE_BOARD_LISTS_SUCCESS';
export const RECEIVE_LISTS = 'RECEIVE_LISTS';
export const SHOW_PROMOTION_LIST = 'SHOW_PROMOTION_LIST';
export const REQUEST_ADD_LIST = 'REQUEST_ADD_LIST';
export const RECEIVE_ADD_LIST_SUCCESS = 'RECEIVE_ADD_LIST_SUCCESS';
@ -13,8 +13,6 @@ export const REQUEST_REMOVE_LIST = 'REQUEST_REMOVE_LIST';
export const RECEIVE_REMOVE_LIST_SUCCESS = 'RECEIVE_REMOVE_LIST_SUCCESS';
export const RECEIVE_REMOVE_LIST_ERROR = 'RECEIVE_REMOVE_LIST_ERROR';
export const REQUEST_ISSUES_FOR_ALL_LISTS = 'REQUEST_ISSUES_FOR_ALL_LISTS';
export const RECEIVE_ISSUES_FOR_LIST_FAILURE = 'RECEIVE_ISSUES_FOR_LIST_FAILURE';
export const RECEIVE_ISSUES_FOR_LIST_SUCCESS = 'RECEIVE_ISSUES_FOR_LIST_SUCCESS';
export const RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS = 'RECEIVE_ISSUES_FOR_ALL_LISTS_SUCCESS';
export const RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE = 'RECEIVE_ISSUES_FOR_ALL_LISTS_FAILURE';
export const REQUEST_ADD_ISSUE = 'REQUEST_ADD_ISSUE';

View File

@ -35,7 +35,7 @@ export default {
state.showPromotion = showPromotion;
},
[mutationTypes.RECEIVE_BOARD_LISTS_SUCCESS]: (state, lists) => {
[mutationTypes.RECEIVE_LISTS]: (state, lists) => {
state.boardLists = lists;
},
@ -89,20 +89,6 @@ export default {
notImplemented();
},
[mutationTypes.RECEIVE_ISSUES_FOR_LIST_SUCCESS]: (state, { listIssues, listId }) => {
const { listData, issues } = listIssues;
Vue.set(state, 'issues', { ...state.issues, ...issues });
Vue.set(state.issuesByListId, listId, listData[listId]);
const listIndex = state.boardLists.findIndex(l => l.id === listId);
Vue.set(state.boardLists[listIndex], 'loading', false);
},
[mutationTypes.RECEIVE_ISSUES_FOR_LIST_FAILURE]: (state, listId) => {
state.error = __('An error occurred while fetching the board issues. Please reload the page.');
const listIndex = state.boardLists.findIndex(l => l.id === listId);
Vue.set(state.boardLists[listIndex], 'loading', false);
},
[mutationTypes.REQUEST_ISSUES_FOR_ALL_LISTS]: state => {
state.isLoadingIssues = true;
},

View File

@ -1,12 +1,12 @@
<script>
import { GlNewDropdown, GlNewDropdownItem, GlSprintf } from '@gitlab/ui';
import { GlDropdown, GlNewDropdownItem, GlSprintf } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
import allVersionsMixin from '../../mixins/all_versions';
import { findVersionId } from '../../utils/design_management_utils';
export default {
components: {
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlSprintf,
},
@ -63,7 +63,7 @@ export default {
</script>
<template>
<gl-new-dropdown :text="dropdownText" size="small">
<gl-dropdown :text="dropdownText" size="small">
<gl-new-dropdown-item
v-for="(version, index) in allVersions"
:key="version.id"
@ -77,5 +77,5 @@ export default {
</template>
</gl-sprintf>
</gl-new-dropdown-item>
</gl-new-dropdown>
</gl-dropdown>
</template>

View File

@ -1,8 +1,7 @@
<script>
/* eslint-disable vue/no-v-html */
import { mapActions, mapGetters, mapState } from 'vuex';
import { escape } from 'lodash';
import { GlLoadingIcon } from '@gitlab/ui';
import { GlLoadingIcon, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { __, sprintf } from '~/locale';
import { deprecatedCreateFlash as createFlash } from '~/flash';
@ -18,6 +17,9 @@ export default {
DiffContent,
GlLoadingIcon,
},
directives: {
SafeHtml,
},
mixins: [glFeatureFlagsMixin()],
props: {
file: {
@ -182,7 +184,7 @@ export default {
/>
<div v-if="forkMessageVisible" class="js-file-fork-suggestion-section file-fork-suggestion">
<span class="file-fork-suggestion-note" v-html="forkMessage"></span>
<span v-safe-html="forkMessage" class="file-fork-suggestion-note"></span>
<a
:href="file.fork_path"
class="js-fork-suggestion-button btn btn-grouped btn-inverted btn-success"
@ -200,7 +202,7 @@ export default {
<template v-else>
<div :id="`diff-content-${file.file_hash}`">
<div v-if="errorMessage" class="diff-viewer">
<div class="nothing-here-block" v-html="errorMessage"></div>
<div v-safe-html="errorMessage" class="nothing-here-block"></div>
</div>
<template v-else>
<div v-show="isCollapsed" class="nothing-here-block diff-collapsed">

View File

@ -47,6 +47,7 @@ export default {
'emptyRepo',
'currentTree',
'editorTheme',
'getUrlForPath',
]),
themeName() {
return window.gon?.user_color_scheme;
@ -71,7 +72,7 @@ export default {
return returnValue;
},
openFile(file) {
this.$router.push(`/project${file.url}`);
this.$router.push(this.getUrlForPath(file.path));
},
createNewFile() {
this.$refs.newModal.open(modalTypes.blob);

View File

@ -3,6 +3,7 @@
* This component is an iterative step towards refactoring and simplifying `vue_shared/components/file_row.vue`
* https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23720
*/
import { mapGetters } from 'vuex';
import FileRow from '~/vue_shared/components/file_row.vue';
import FileRowExtra from './file_row_extra.vue';
@ -23,6 +24,9 @@ export default {
dropdownOpen: false,
};
},
computed: {
...mapGetters(['getUrlForPath']),
},
methods: {
toggleDropdown(val) {
this.dropdownOpen = val;
@ -32,7 +36,13 @@ export default {
</script>
<template>
<file-row :file="file" v-bind="$attrs" @mouseleave="toggleDropdown(false)" v-on="$listeners">
<file-row
:file="file"
:file-url="getUrlForPath(file.path)"
v-bind="$attrs"
@mouseleave="toggleDropdown(false)"
v-on="$listeners"
>
<file-row-extra :file="file" :dropdown-open="dropdownOpen" @toggle="toggleDropdown($event)" />
</file-row>
</template>

View File

@ -10,7 +10,7 @@ export default {
EditorModeDropdown,
},
computed: {
...mapGetters(['currentMergeRequest', 'activeFile']),
...mapGetters(['currentMergeRequest', 'activeFile', 'getUrlForPath']),
...mapState(['viewer', 'currentMergeRequestId']),
showLatestChangesText() {
return !this.currentMergeRequestId || this.viewer === viewerTypes.diff;
@ -24,7 +24,7 @@ export default {
},
mounted() {
if (this.activeFile && this.activeFile.pending && !this.activeFile.deleted) {
this.$router.push(`/project${this.activeFile.url}`, () => {
this.$router.push(this.getUrlForPath(this.activeFile.path), () => {
this.updateViewer('editor');
});
} else if (this.activeFile && this.activeFile.deleted) {

View File

@ -15,13 +15,13 @@ export default {
},
computed: {
...mapState(['currentBranchId']),
...mapGetters(['currentProject', 'currentTree', 'activeFile']),
...mapGetters(['currentProject', 'currentTree', 'activeFile', 'getUrlForPath']),
},
mounted() {
if (!this.activeFile) return;
if (this.activeFile.pending && !this.activeFile.deleted) {
this.$router.push(`/project${this.activeFile.url}`, () => {
this.$router.push(this.getUrlForPath(this.activeFile.path), () => {
this.updateViewer('editor');
});
} else if (this.activeFile.deleted) {

View File

@ -48,6 +48,7 @@ export default {
'renderWhitespaceInCode',
'editorTheme',
'entries',
'currentProjectId',
]),
...mapGetters([
'currentMergeRequest',
@ -379,7 +380,7 @@ export default {
:path="file.rawPath || file.path"
:file-path="file.path"
:file-size="file.size"
:project-path="file.projectId"
:project-path="currentProjectId"
:commit-sha="currentBranchCommit"
:type="fileType"
/>
@ -390,7 +391,7 @@ export default {
:new-sha="currentMergeRequest.sha"
:old-path="file.mrChange.old_path"
:old-sha="currentMergeRequest.baseCommitSha"
:project-path="file.projectId"
:project-path="currentProjectId"
/>
</div>
</template>

View File

@ -1,5 +1,5 @@
<script>
import { mapActions } from 'vuex';
import { mapActions, mapGetters } from 'vuex';
import { GlIcon } from '@gitlab/ui';
import { __, sprintf } from '~/locale';
@ -26,6 +26,7 @@ export default {
};
},
computed: {
...mapGetters(['getUrlForPath']),
closeLabel() {
if (this.fileHasChanged) {
return sprintf(__(`%{tabname} changed`), { tabname: this.tab.name });
@ -52,7 +53,7 @@ export default {
if (tab.pending) {
this.openPendingTab({ file: tab, keyPrefix: tab.staged ? 'staged' : 'unstaged' });
} else {
this.$router.push(`/project${tab.url}`);
this.$router.push(this.getUrlForPath(tab.path));
}
},
mouseOverTab() {
@ -79,7 +80,7 @@ export default {
@mouseover="mouseOverTab"
@mouseout="mouseOutTab"
>
<div :title="tab.url" class="multi-file-tab">
<div :title="getUrlForPath(tab.path)" class="multi-file-tab">
<file-icon :file-name="tab.name" :size="16" />
{{ tab.name }}
<file-status-icon :file="tab" />

View File

@ -1,5 +1,5 @@
<script>
import { mapActions } from 'vuex';
import { mapActions, mapGetters } from 'vuex';
import RepoTab from './repo_tab.vue';
export default {
@ -20,6 +20,9 @@ export default {
required: true,
},
},
computed: {
...mapGetters(['getUrlForPath']),
},
methods: {
...mapActions(['updateViewer', 'removePendingTab']),
openFileViewer(viewer) {
@ -27,7 +30,7 @@ export default {
if (this.activeFile.pending) {
return this.removePendingTab(this.activeFile).then(() => {
this.$router.push(`/project${this.activeFile.url}`);
this.$router.push(this.getUrlForPath(this.activeFile.path));
});
}

View File

@ -15,8 +15,6 @@ export const splitParent = path => {
*/
export const decorateFiles = ({
data,
projectId,
branchId,
tempFile = false,
content = '',
binary = false,
@ -41,12 +39,9 @@ export const decorateFiles = ({
parentPath = parentFolder && parentFolder.path;
const tree = decorateData({
projectId,
branchId,
id: path,
name,
path,
url: `/${projectId}/tree/${branchId}/-/${path}/`,
type: 'tree',
tempFile,
changed: tempFile,
@ -77,12 +72,9 @@ export const decorateFiles = ({
parentPath = fileFolder && fileFolder.path;
file = decorateData({
projectId,
branchId,
id: path,
name,
path,
url: `/${projectId}/blob/${branchId}/-/${path}`,
type: 'blob',
tempFile,
changed: tempFile,

View File

@ -33,7 +33,7 @@ export default {
})
.then(({ data }) => data);
},
getBaseRawFileData(file, sha) {
getBaseRawFileData(file, projectId, ref) {
if (file.tempFile || file.baseRaw) return Promise.resolve(file.baseRaw);
// if files are renamed, their base path has changed
@ -44,10 +44,10 @@ export default {
.get(
joinPaths(
gon.relative_url_root || '/',
file.projectId,
projectId,
'-',
'raw',
sha,
ref,
escapeFileUrl(filePath),
),
{

View File

@ -54,8 +54,6 @@ export const createTempEntry = (
const data = decorateFiles({
data: [fullName],
projectId: state.currentProjectId,
branchId: state.currentBranchId,
type,
tempFile: true,
content,
@ -64,11 +62,7 @@ export const createTempEntry = (
});
const { file, parentPath } = data;
commit(types.CREATE_TMP_ENTRY, {
data,
projectId: state.currentProjectId,
branchId: state.currentBranchId,
});
commit(types.CREATE_TMP_ENTRY, { data });
if (type === 'blob') {
if (openFile) commit(types.TOGGLE_FILE_OPEN, file.path);
@ -254,7 +248,7 @@ export const renameEntry = ({ dispatch, commit, state, getters }, { path, name,
}
if (newEntry.opened) {
dispatch('router/push', `/project${newEntry.url}`, { root: true });
dispatch('router/push', getters.getUrlForPath(newEntry.path), { root: true });
}
}

View File

@ -6,7 +6,7 @@ import * as types from '../mutation_types';
import { setPageTitleForFile } from '../utils';
import { viewerTypes, stageKeys } from '../../constants';
export const closeFile = ({ commit, state, dispatch }, file) => {
export const closeFile = ({ commit, state, dispatch, getters }, file) => {
const { path } = file;
const indexOfClosedFile = state.openFiles.findIndex(f => f.key === file.key);
const fileWasActive = file.active;
@ -29,10 +29,12 @@ export const closeFile = ({ commit, state, dispatch }, file) => {
keyPrefix: nextFileToOpen.staged ? 'staged' : 'unstaged',
});
} else {
dispatch('router/push', `/project${nextFileToOpen.url}`, { root: true });
dispatch('router/push', getters.getUrlForPath(nextFileToOpen.path), { root: true });
}
} else if (!state.openFiles.length) {
dispatch('router/push', `/project/${file.projectId}/tree/${file.branchId}/`, { root: true });
dispatch('router/push', `/project/${state.currentProjectId}/tree/${state.currentBranchId}/`, {
root: true,
});
}
eventHub.$emit(`editor.update.model.dispose.${file.key}`);
@ -121,7 +123,7 @@ export const getRawFileData = ({ state, commit, dispatch, getters }, { path }) =
const baseSha =
(getters.currentMergeRequest && getters.currentMergeRequest.baseCommitSha) || '';
return service.getBaseRawFileData(file, baseSha).then(baseRaw => {
return service.getBaseRawFileData(file, state.currentProjectId, baseSha).then(baseRaw => {
commit(types.SET_FILE_BASE_RAW_DATA, {
file,
baseRaw,
@ -218,7 +220,7 @@ export const discardFileChanges = ({ dispatch, state, commit, getters }, path) =
if (!isDestructiveDiscard && file.path === getters.activeFile?.path) {
dispatch('updateDelayViewerUpdated', true)
.then(() => {
dispatch('router/push', `/project${file.url}`, { root: true });
dispatch('router/push', getters.getUrlForPath(file.path), { root: true });
})
.catch(e => {
throw e;
@ -274,7 +276,7 @@ export const openPendingTab = ({ commit, dispatch, getters, state }, { file, key
commit(types.ADD_PENDING_TAB, { file, keyPrefix });
dispatch('router/push', `/project/${file.projectId}/tree/${state.currentBranchId}/`, {
dispatch('router/push', `/project/${state.currentProjectId}/tree/${state.currentBranchId}/`, {
root: true,
});

View File

@ -61,11 +61,7 @@ export const getFiles = ({ state, commit, dispatch }, payload = {}) =>
service
.getFiles(selectedProject.path_with_namespace, ref)
.then(({ data }) => {
const { entries, treeList } = decorateFiles({
data,
projectId,
branchId,
});
const { entries, treeList } = decorateFiles({ data });
commit(types.SET_ENTRIES, entries);

View File

@ -174,3 +174,6 @@ export const getAvailableFileName = (state, getters) => path => {
return newPath;
};
export const getUrlForPath = state => path =>
`/project/${state.currentProjectId}/tree/${state.currentBranchId}/-/${path}/`;

View File

@ -7,7 +7,6 @@ import treeMutations from './mutations/tree';
import branchMutations from './mutations/branch';
import {
sortTree,
replaceFileUrl,
swapInParentTreeWithSorting,
updateFileCollections,
removeFromParentTree,
@ -49,7 +48,7 @@ export default {
entries,
});
},
[types.CREATE_TMP_ENTRY](state, { data, projectId, branchId }) {
[types.CREATE_TMP_ENTRY](state, { data }) {
Object.keys(data.entries).reduce((acc, key) => {
const entry = data.entries[key];
const foundEntry = state.entries[key];
@ -72,13 +71,12 @@ export default {
return acc.concat(key);
}, []);
const foundEntry = state.trees[`${projectId}/${branchId}`].tree.find(
e => e.path === data.treeList[0].path,
);
const currentTree = state.trees[`${state.currentProjectId}/${state.currentBranchId}`];
const foundEntry = currentTree.tree.find(e => e.path === data.treeList[0].path);
if (!foundEntry) {
Object.assign(state.trees[`${projectId}/${branchId}`], {
tree: sortTree(state.trees[`${projectId}/${branchId}`].tree.concat(data.treeList)),
Object.assign(currentTree, {
tree: sortTree(currentTree.tree.concat(data.treeList)),
});
}
},
@ -139,7 +137,6 @@ export default {
prevId: undefined,
prevPath: undefined,
prevName: undefined,
prevUrl: undefined,
prevKey: undefined,
prevParentPath: undefined,
});
@ -195,9 +192,6 @@ export default {
const oldEntry = state.entries[path];
const newPath = parentPath ? `${parentPath}/${name}` : name;
const isRevert = newPath === oldEntry.prevPath;
const newUrl = replaceFileUrl(oldEntry.url, oldEntry.path, newPath);
const newKey = oldEntry.key.replace(new RegExp(oldEntry.path, 'g'), newPath);
const baseProps = {
@ -205,7 +199,6 @@ export default {
name,
id: newPath,
path: newPath,
url: newUrl,
key: newKey,
parentPath: parentPath || '',
};
@ -216,7 +209,6 @@ export default {
prevId: undefined,
prevPath: undefined,
prevName: undefined,
prevUrl: undefined,
prevKey: undefined,
prevParentPath: undefined,
}
@ -224,7 +216,6 @@ export default {
prevId: oldEntry.prevId || oldEntry.id,
prevPath: oldEntry.prevPath || oldEntry.path,
prevName: oldEntry.prevName || oldEntry.name,
prevUrl: oldEntry.prevUrl || oldEntry.url,
prevKey: oldEntry.prevKey || oldEntry.key,
prevParentPath: oldEntry.prevParentPath || oldEntry.parentPath,
};

View File

@ -12,10 +12,7 @@ export const dataStructure = () => ({
// it can also contain a prefix `pending-` for files opened in review mode
key: '',
type: '',
projectId: '',
branchId: '',
name: '',
url: '',
path: '',
tempFile: false,
tree: [],
@ -44,10 +41,7 @@ export const dataStructure = () => ({
export const decorateData = entity => {
const {
id,
projectId,
branchId,
type,
url,
name,
path,
content = '',
@ -63,12 +57,9 @@ export const decorateData = entity => {
return Object.assign(dataStructure(), {
id,
projectId,
branchId,
key: `${name}-${type}-${id}`,
type,
name,
url,
path,
tempFile,
opened,
@ -189,11 +180,6 @@ export const mergeTrees = (fromTree, toTree) => {
return toTree;
};
export const replaceFileUrl = (url, oldPath, newPath) => {
// Add `/-/` so that we don't accidentally replace project path
return url.replace(`/-/${oldPath}`, `/-/${newPath}`);
};
export const swapInStateArray = (state, arr, key, entryPath) =>
Object.assign(state, {
[arr]: state[arr].map(f => (f.key === key ? state.entries[entryPath] : f)),

View File

@ -6,7 +6,7 @@ import {
GlIcon,
GlFormGroup,
GlFormCheckbox,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
} from '@gitlab/ui';
import {
@ -24,7 +24,7 @@ export default {
GlFormGroup,
GlIcon,
GlFormCheckbox,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
},
inject: ['service', 'alertSettings'],
@ -101,7 +101,7 @@ export default {
<gl-icon name="question" :size="12" />
</gl-link>
</label>
<gl-new-dropdown
<gl-dropdown
id="alert-integration-settings-issue-template"
data-qa-selector="incident_templates_dropdown"
:text="issueTemplateHeader"
@ -117,7 +117,7 @@ export default {
>
{{ template.name }}
</gl-new-dropdown-item>
</gl-new-dropdown>
</gl-dropdown>
</gl-form-group>
<gl-form-group class="gl-pl-0 gl-mb-5">

View File

@ -1,6 +1,6 @@
<script>
import { mapState } from 'vuex';
import { GlNewDropdown, GlNewDropdownItem, GlLink } from '@gitlab/ui';
import { GlDropdown, GlNewDropdownItem, GlLink } from '@gitlab/ui';
import { s__ } from '~/locale';
import { defaultIntegrationLevel, overrideDropdownDescriptions } from '../constants';
@ -19,7 +19,7 @@ export default {
dropdownOptions,
name: 'OverrideDropdown',
components: {
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlLink,
},
@ -73,7 +73,7 @@ export default {
}}</gl-link>
</span>
<input name="service[inherit_from_id]" :value="override ? '' : inheritFromId" type="hidden" />
<gl-new-dropdown :text="selected.text">
<gl-dropdown :text="selected.text">
<gl-new-dropdown-item
v-for="option in $options.dropdownOptions"
:key="option.value"
@ -81,6 +81,6 @@ export default {
>
{{ option.text }}
</gl-new-dropdown-item>
</gl-new-dropdown>
</gl-dropdown>
</div>
</template>

View File

@ -66,6 +66,7 @@ export default class IssuableForm {
gl.GfmAutoComplete && gl.GfmAutoComplete.dataSources,
).setup();
this.usersSelect = new UsersSelect();
this.reviewersSelect = new UsersSelect(undefined, '.js-reviewer-search');
this.zenMode = new ZenMode();
this.titleField = this.form.find('input[name*="[title]"]');

View File

@ -1,3 +1,4 @@
import { sanitize } from 'dompurify';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import updateDescription from '../utils/update_description';
@ -27,8 +28,8 @@ export default class Store {
const details =
descriptionSection != null && descriptionSection.getElementsByTagName('details');
this.state.descriptionHtml = updateDescription(data.description, details);
this.state.titleHtml = data.title;
this.state.descriptionHtml = updateDescription(sanitize(data.description), details);
this.state.titleHtml = sanitize(data.title);
this.state.lock_version = data.lock_version;
}

View File

@ -1,7 +1,12 @@
import { sanitize } from 'dompurify';
// We currently load + parse the data from the issue app and related merge request
let cachedParsedData;
export const parseIssuableData = () => {
try {
if (cachedParsedData) return cachedParsedData;
const initialDataEl = document.getElementById('js-issuable-app-initial-data');
const parsedData = JSON.parse(initialDataEl.textContent.replace(/&quot;/g, '"'));
@ -9,6 +14,8 @@ export const parseIssuableData = () => {
parsedData.initialTitleHtml = sanitize(parsedData.initialTitleHtml);
parsedData.initialDescriptionHtml = sanitize(parsedData.initialDescriptionHtml);
cachedParsedData = parsedData;
return parsedData;
} catch (e) {
console.error(e); // eslint-disable-line no-console

View File

@ -2,9 +2,9 @@
import {
GlAlert,
GlButton,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlNewDropdownText,
GlDropdownText,
GlFormGroup,
GlFormSelect,
GlIcon,
@ -34,9 +34,9 @@ export default {
components: {
GlAlert,
GlButton,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlNewDropdownText,
GlDropdownText,
GlFormGroup,
GlFormSelect,
GlIcon,
@ -293,7 +293,7 @@ export default {
<gl-icon name="arrow-right" :aria-label="__('Will be mapped to')" />
</template>
<template #cell(gitlabUsername)="data">
<gl-new-dropdown
<gl-dropdown
:text="data.value || $options.currentUsername"
class="w-100"
:aria-label="
@ -314,10 +314,10 @@ export default {
{{ user.username }} ({{ user.name }})
</gl-new-dropdown-item>
<gl-new-dropdown-text v-show="shouldShowNoMatchesFoundText" class="text-secondary">
<gl-dropdown-text v-show="shouldShowNoMatchesFoundText" class="text-secondary">
{{ __('No matches found') }}
</gl-new-dropdown-text>
</gl-new-dropdown>
</gl-dropdown-text>
</gl-dropdown>
</template>
</gl-table>

View File

@ -642,6 +642,16 @@ export const secondsToMilliseconds = seconds => seconds * 1000;
*/
export const secondsToDays = seconds => Math.round(seconds / 86400);
/**
* Returns the date n days after the date provided
*
* @param {Date} date the initial date
* @param {Number} numberOfDays number of days after
* @return {Date} the date following the date provided
*/
export const nDaysAfter = (date, numberOfDays) =>
new Date(newDate(date)).setDate(date.getDate() + numberOfDays);
/**
* Returns the date after the date provided
*

View File

@ -1,6 +1,6 @@
<script>
import {
GlNewDropdown,
GlDropdown,
GlNewDropdownDivider,
GlNewDropdownHeader,
GlNewDropdownItem,
@ -17,7 +17,7 @@ const SEARCH_DEBOUNCE_MS = 250;
export default {
components: {
GlNewDropdown,
GlDropdown,
GlNewDropdownDivider,
GlNewDropdownHeader,
GlNewDropdownItem,
@ -188,7 +188,7 @@ export default {
</script>
<template>
<gl-new-dropdown v-bind="$attrs" class="project-milestone-combobox" @shown="focusSearchBox">
<gl-dropdown v-bind="$attrs" class="project-milestone-combobox" @shown="focusSearchBox">
<template slot="button-content">
<span ref="buttonText" class="flex-grow-1 ml-1 text-muted">{{
selectedMilestonesLabel
@ -246,5 +246,5 @@ export default {
<gl-new-dropdown-item v-for="(item, idx) in extraLinks" :key="idx" :href="item.url">
<span class="pl-4">{{ item.text }}</span>
</gl-new-dropdown-item>
</gl-new-dropdown>
</gl-dropdown>
</template>

View File

@ -7,7 +7,7 @@ import {
GlButtonGroup,
GlFormGroup,
GlFormInput,
GlNewDropdown as GlDropdown,
GlDropdown,
GlNewDropdownItem as GlDropdownItem,
GlModal,
GlTooltipDirective,

View File

@ -2,7 +2,7 @@
import { mapState, mapGetters, mapActions } from 'vuex';
import {
GlDeprecatedButton,
GlNewDropdown,
GlDropdown,
GlNewDropdownDivider,
GlNewDropdownItem,
GlModal,
@ -23,7 +23,7 @@ import { getAddMetricTrackingOptions } from '../utils';
export default {
components: {
GlDeprecatedButton,
GlNewDropdown,
GlDropdown,
GlNewDropdownDivider,
GlNewDropdownItem,
GlModal,
@ -143,7 +143,7 @@ export default {
as part of https://gitlab.com/gitlab-org/gitlab-ui/-/issues/936
The variant will create a dropdown with an icon, no text and no caret
-->
<gl-new-dropdown
<gl-dropdown
v-gl-tooltip
data-testid="actions-menu"
data-qa-selector="actions_menu_dropdown"
@ -287,5 +287,5 @@ export default {
:project-path="projectPath"
/>
</template>
</gl-new-dropdown>
</gl-dropdown>
</template>

View File

@ -3,7 +3,7 @@ import { debounce } from 'lodash';
import { mapActions, mapState, mapGetters } from 'vuex';
import {
GlButton,
GlNewDropdown,
GlDropdown,
GlLoadingIcon,
GlNewDropdownItem,
GlNewDropdownHeader,
@ -28,7 +28,7 @@ export default {
components: {
GlIcon,
GlButton,
GlNewDropdown,
GlDropdown,
GlLoadingIcon,
GlNewDropdownItem,
GlNewDropdownHeader,
@ -181,7 +181,7 @@ export default {
<span aria-hidden="true" class="gl-pl-3 border-left gl-mb-3 d-none d-sm-block"></span>
<div class="mb-2 pr-2 d-flex d-sm-block">
<gl-new-dropdown
<gl-dropdown
id="monitor-environments-dropdown"
ref="monitorEnvironmentsDropdown"
class="flex-grow-1"
@ -214,7 +214,7 @@ export default {
{{ __('No matching results') }}
</div>
</div>
</gl-new-dropdown>
</gl-dropdown>
</div>
<div class="mb-2 pr-2 d-flex d-sm-block">

View File

@ -6,7 +6,7 @@ import {
GlIcon,
GlLink,
GlLoadingIcon,
GlNewDropdown as GlDropdown,
GlDropdown,
GlNewDropdownItem as GlDropdownItem,
GlNewDropdownDivider as GlDropdownDivider,
GlModal,

View File

@ -2,7 +2,7 @@
import { mapState, mapGetters } from 'vuex';
import {
GlIcon,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlNewDropdownHeader,
GlNewDropdownDivider,
@ -17,7 +17,7 @@ const events = {
export default {
components: {
GlIcon,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlNewDropdownHeader,
GlNewDropdownDivider,
@ -73,7 +73,7 @@ export default {
};
</script>
<template>
<gl-new-dropdown
<gl-dropdown
toggle-class="dropdown-menu-toggle"
menu-class="monitor-dashboard-dropdown-menu"
:text="selectedDashboardText"
@ -127,5 +127,5 @@ export default {
{{ __('No matching results') }}
</div>
</div>
</gl-new-dropdown>
</gl-dropdown>
</template>

View File

@ -4,7 +4,7 @@ import { mapActions } from 'vuex';
import {
GlButtonGroup,
GlButton,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlNewDropdownDivider,
GlTooltipDirective,
@ -48,7 +48,7 @@ export default {
components: {
GlButtonGroup,
GlButton,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlNewDropdownDivider,
},
@ -152,7 +152,7 @@ export default {
icon="retry"
@click="refresh"
/>
<gl-new-dropdown
<gl-dropdown
v-if="!disableMetricDashboardRefreshRate"
v-gl-tooltip
:title="s__('Metrics|Set refresh rate')"
@ -173,6 +173,6 @@ export default {
@click="setRefreshInterval(option)"
>{{ option.label }}</gl-new-dropdown-item
>
</gl-new-dropdown>
</gl-dropdown>
</gl-button-group>
</template>

View File

@ -1,11 +1,12 @@
<script>
import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
import { escape } from 'lodash';
import { GlModal, GlModalDirective } from '@gitlab/ui';
import { s__, sprintf } from '~/locale';
export default {
components: {
GlModal,
GlButton,
},
directives: {
'gl-modal': GlModalDirective,
@ -55,14 +56,14 @@ export default {
<template>
<div class="d-inline-block">
<button
<gl-button
v-gl-modal="modalId"
type="button"
class="btn btn-danger"
category="primary"
variant="danger"
data-qa-selector="delete_button"
>
{{ __('Delete') }}
</button>
</gl-button>
<gl-modal
:title="title"
:action-primary="{

View File

@ -9,7 +9,7 @@ import {
GlFormInput,
GlFormSelect,
GlLink,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlSearchBoxByType,
GlSprintf,
@ -37,7 +37,7 @@ export default {
GlFormInput,
GlFormSelect,
GlLink,
GlNewDropdown,
GlDropdown,
GlNewDropdownItem,
GlSearchBoxByType,
GlSprintf,
@ -173,7 +173,7 @@ export default {
>{{ error }}</gl-alert
>
<gl-form-group :label="s__('Pipeline|Run for')">
<gl-new-dropdown :text="refValue" block>
<gl-dropdown :text="refValue" block>
<gl-search-box-by-type
v-model.trim="searchTerm"
:placeholder="__('Search branches and tags')"
@ -189,7 +189,7 @@ export default {
>
{{ ref }}
</gl-new-dropdown-item>
</gl-new-dropdown>
</gl-dropdown>
<template #description>
<div>

View File

@ -130,14 +130,9 @@ export default {
{{ downstreamTitle }}
</span>
<div class="gl-text-truncate">
<gl-link
v-if="childPipeline"
class="gl-text-blue-500!"
:href="pipeline.path"
data-testid="childPipelineLink"
<gl-link class="gl-text-blue-500!" :href="pipeline.path" data-testid="pipelineLink"
>#{{ pipeline.id }}</gl-link
>
<span v-else>#{{ pipeline.id }}</span>
</div>
</div>
</div>

View File

@ -1,4 +1,4 @@
import { addIconStatus, formattedTime, sortTestCases } from './utils';
import { addIconStatus, formattedTime } from './utils';
export const getTestSuites = state => {
const { test_suites: testSuites = [] } = state.testReports;
@ -14,5 +14,5 @@ export const getSelectedSuite = state =>
export const getSuiteTests = state => {
const { test_cases: testCases = [] } = getSelectedSuite(state);
return testCases.sort(sortTestCases).map(addIconStatus);
return testCases.map(addIconStatus);
};

View File

@ -1,4 +1,3 @@
import { TestStatus } from '~/pipelines/constants';
import { __, sprintf } from '../../../locale';
export function iconForTestStatus(status) {
@ -25,18 +24,3 @@ export const addIconStatus = testCase => ({
icon: iconForTestStatus(testCase.status),
formattedTime: formattedTime(testCase.execution_time),
});
export const sortTestCases = (a, b) => {
if (a.status === b.status) {
return 0;
}
switch (b.status) {
case TestStatus.SUCCESS:
return -1;
case TestStatus.FAILED:
return 1;
default:
return 0;
}
};

View File

@ -2,7 +2,7 @@
import { debounce } from 'lodash';
import { mapState, mapActions } from 'vuex';
import {
GlNewDropdown,
GlDropdown,
GlNewDropdownHeader,
GlNewDropdownItem,
GlSearchBoxByType,
@ -18,7 +18,7 @@ const tooltipMessage = __('Searching by both author and message is currently not
export default {
name: 'AuthorSelect',
components: {
GlNewDropdown,
GlDropdown,
GlNewDropdownHeader,
GlNewDropdownItem,
GlSearchBoxByType,
@ -107,7 +107,7 @@ export default {
<template>
<div ref="dropdownContainer" v-gl-tooltip :title="tooltipTitle" :disabled="!hasSearchParam">
<gl-new-dropdown
<gl-dropdown
:text="dropdownText"
:disabled="hasSearchParam"
toggle-class="gl-py-3 gl-border-0"
@ -137,6 +137,6 @@ export default {
>
{{ author.name }}
</gl-new-dropdown-item>
</gl-new-dropdown>
</gl-dropdown>
</div>
</template>

View File

@ -1,7 +1,7 @@
<script>
import { mapActions, mapGetters, mapState } from 'vuex';
import {
GlNewDropdown,
GlDropdown,
GlNewDropdownDivider,
GlNewDropdownHeader,
GlSearchBoxByType,
@ -18,7 +18,7 @@ export default {
name: 'RefSelector',
store: createStore(),
components: {
GlNewDropdown,
GlDropdown,
GlNewDropdownDivider,
GlNewDropdownHeader,
GlSearchBoxByType,
@ -120,7 +120,7 @@ export default {
</script>
<template>
<gl-new-dropdown v-bind="$attrs" class="ref-selector" @shown="focusSearchBox">
<gl-dropdown v-bind="$attrs" class="ref-selector" @shown="focusSearchBox">
<template slot="button-content">
<span class="gl-flex-grow-1 gl-ml-2 gl-text-gray-400" data-testid="button-content">
<span v-if="selectedRef" class="gl-font-monospace">{{ selectedRef }}</span>
@ -208,5 +208,5 @@ export default {
</template>
</div>
</div>
</gl-new-dropdown>
</gl-dropdown>
</template>

View File

@ -59,7 +59,7 @@ export default {
};
},
assigneeUrl() {
return this.user.web_url;
return this.user.web_url || this.user.webUrl;
},
},
};

View File

@ -0,0 +1,37 @@
<script>
import { n__ } from '~/locale';
import UncollapsedAssigneeList from '~/sidebar/components/assignees/uncollapsed_assignee_list.vue';
export default {
components: {
UncollapsedAssigneeList,
},
inject: ['rootPath'],
props: {
users: {
type: Array,
required: true,
},
},
computed: {
assigneesText() {
return n__('Assignee', '%d Assignees', this.users.length);
},
emptyUsers() {
return this.users.length === 0;
},
},
};
</script>
<template>
<div class="gl-display-flex gl-flex-direction-column">
<label data-testid="assigneeLabel">{{ assigneesText }}</label>
<div v-if="emptyUsers" data-testid="none">
<span>
{{ __('None') }}
</span>
</div>
<uncollapsed-assignee-list v-else :users="users" :root-path="rootPath" />
</div>
</template>

View File

@ -73,9 +73,9 @@ export default {
:root-path="rootPath"
:issuable-type="issuableType"
>
<div class="ml-2">
<span class="author"> {{ user.name }} </span>
<span class="username"> {{ username }} </span>
<div class="ml-2 gl-line-height-normal">
<div>{{ user.name }}</div>
<div>{{ username }}</div>
</div>
</assignee-avatar-link>
<div v-else>

View File

@ -55,6 +55,7 @@ function UsersSelect(currentUser, els, options = {}) {
const defaultLabel = $dropdown.data('defaultLabel');
const issueURL = $dropdown.data('issueUpdate');
const $selectbox = $dropdown.closest('.selectbox');
const $assignToMeLink = $selectbox.next('.assign-to-me-link');
let $block = $selectbox.closest('.block');
const abilityName = $dropdown.data('abilityName');
let $value = $block.find('.value');
@ -161,7 +162,7 @@ function UsersSelect(currentUser, els, options = {}) {
});
};
$('.assign-to-me-link').on('click', e => {
$assignToMeLink.on('click', e => {
e.preventDefault();
$(e.currentTarget).hide();
@ -451,9 +452,9 @@ function UsersSelect(currentUser, els, options = {}) {
}
if (getSelected().find(u => u === gon.current_user_id)) {
$('.assign-to-me-link').hide();
$assignToMeLink.hide();
} else {
$('.assign-to-me-link').show();
$assignToMeLink.show();
}
}

View File

@ -4,7 +4,7 @@ import Mousetrap from 'mousetrap';
import { escape } from 'lodash';
import {
GlButton,
GlNewDropdown as GlDropdown,
GlDropdown,
GlNewDropdownHeader as GlDropdownHeader,
GlNewDropdownItem as GlDropdownItem,
GlTooltipDirective,

View File

@ -1,6 +1,6 @@
<script>
import {
GlNewDropdown,
GlDropdown,
GlNewDropdownHeader,
GlFormInputGroup,
GlButton,
@ -11,7 +11,7 @@ import { getHTTPProtocol } from '~/lib/utils/url_utility';
export default {
components: {
GlNewDropdown,
GlDropdown,
GlNewDropdownHeader,
GlFormInputGroup,
GlButton,
@ -45,7 +45,7 @@ export default {
};
</script>
<template>
<gl-new-dropdown right :text="$options.labels.defaultLabel" category="primary" variant="info">
<gl-dropdown right :text="$options.labels.defaultLabel" category="primary" variant="info">
<div class="pb-2 mx-1">
<template v-if="sshLink">
<gl-new-dropdown-header>{{ $options.labels.ssh }}</gl-new-dropdown-header>
@ -85,5 +85,5 @@ export default {
</div>
</template>
</div>
</gl-new-dropdown>
</gl-dropdown>
</template>

View File

@ -14,6 +14,11 @@ export default {
type: Object,
required: true,
},
fileUrl: {
type: String,
required: false,
default: '',
},
level: {
type: Number,
required: true,
@ -48,6 +53,9 @@ export default {
// don't output a title if we don't have the expanded path
return this.file?.tree?.length ? this.file.tree[0].parentPath : false;
},
fileRouterUrl() {
return this.fileUrl || `/project${this.file.url}`;
},
},
watch: {
'file.active': function fileActiveWatch(active) {
@ -74,7 +82,7 @@ export default {
this.toggleTreeOpen(this.file.path);
}
if (this.$router) this.$router.push(`/project${this.file.url}`);
if (this.$router && !this.hasUrlAtCurrentRoute()) this.$router.push(this.fileRouterUrl);
if (this.isBlob) this.clickedFile(this.file.path);
},
@ -104,7 +112,7 @@ export default {
hasUrlAtCurrentRoute() {
if (!this.$router || !this.$router.currentRoute) return true;
return this.$router.currentRoute.path === `/project${escapeFileUrl(this.file.url)}`;
return this.$router.currentRoute.path === escapeFileUrl(this.fileRouterUrl);
},
},
};

View File

@ -3,7 +3,7 @@ import {
GlFilteredSearch,
GlButtonGroup,
GlButton,
GlNewDropdown as GlDropdown,
GlDropdown,
GlNewDropdownItem as GlDropdownItem,
GlTooltipDirective,
} from '@gitlab/ui';

View File

@ -1,6 +1,6 @@
export const DEFAULT_RX = 0.4;
export const DEFAULT_BAR_WIDTH = 6;
export const DEFAULT_LABEL_WIDTH = 4;
export const DEFAULT_LABEL_HEIGHT = 5;
export const DEFAULT_BAR_WIDTH = 4;
export const DEFAULT_LABEL_WIDTH = 3;
export const DEFAULT_LABEL_HEIGHT = 3;
export const BAR_HEIGHTS = [5, 7, 9, 14, 21, 35, 50, 80];
export const GRID_YS = [30, 60, 90];

View File

@ -61,35 +61,37 @@ export default {
};
</script>
<template>
<gl-skeleton-loader :unique-key="uniqueKey">
<rect
v-for="(y, index) in $options.GRID_YS"
:key="`grid-${index}`"
data-testid="skeleton-chart-grid"
x="0"
:y="`${y}%`"
width="100%"
height="1px"
/>
<rect
v-for="(height, index) in $options.BAR_HEIGHTS"
:key="`bar-${index}`"
data-testid="skeleton-chart-bar"
:x="`${getBarXPosition(index)}%`"
:y="`${90 - height}%`"
:width="`${barWidth}%`"
:height="`${height}%`"
:rx="`${rx}%`"
/>
<rect
v-for="(height, index) in $options.BAR_HEIGHTS"
:key="`label-${index}`"
data-testid="skeleton-chart-label"
:x="`${labelCentering + getBarXPosition(index)}%`"
:y="`${100 - labelHeight}%`"
:width="`${labelWidth}%`"
:height="`${labelHeight}%`"
:rx="`${rx}%`"
/>
</gl-skeleton-loader>
<div class="gl-px-8">
<gl-skeleton-loader :unique-key="uniqueKey" class="gl-p-8">
<rect
v-for="(y, index) in $options.GRID_YS"
:key="`grid-${index}`"
data-testid="skeleton-chart-grid"
x="0"
:y="`${y}%`"
width="100%"
height="1px"
/>
<rect
v-for="(height, index) in $options.BAR_HEIGHTS"
:key="`bar-${index}`"
data-testid="skeleton-chart-bar"
:x="`${getBarXPosition(index)}%`"
:y="`${90 - height}%`"
:width="`${barWidth}%`"
:height="`${height}%`"
:rx="`${rx}%`"
/>
<rect
v-for="(height, index) in $options.BAR_HEIGHTS"
:key="`label-${index}`"
data-testid="skeleton-chart-label"
:x="`${labelCentering + getBarXPosition(index)}%`"
:y="`${100 - labelHeight}%`"
:width="`${labelWidth}%`"
:height="`${labelHeight}%`"
:rx="`${rx}%`"
/>
</gl-skeleton-loader>
</div>
</template>

View File

@ -1,12 +1,12 @@
<script>
import { GlNewDropdown, GlDeprecatedDropdownItem, GlSearchBoxByType, GlIcon } from '@gitlab/ui';
import { GlDropdown, GlDeprecatedDropdownItem, GlSearchBoxByType, GlIcon } from '@gitlab/ui';
import { __ } from '~/locale';
import autofocusonshow from '~/vue_shared/directives/autofocusonshow';
export default {
name: 'TimezoneDropdown',
components: {
GlNewDropdown,
GlDropdown,
GlDeprecatedDropdownItem,
GlSearchBoxByType,
GlIcon,
@ -74,7 +74,7 @@ export default {
};
</script>
<template>
<gl-new-dropdown :text="value" block lazy menu-class="gl-w-full!">
<gl-dropdown :text="value" block lazy menu-class="gl-w-full!">
<template #button-content>
<span class="gl-flex-grow-1" :class="{ 'gl-text-gray-300': !value }">
{{ selectedTimezoneLabel }}
@ -98,5 +98,5 @@ export default {
<gl-deprecated-dropdown-item v-if="!filteredResults.length" data-testid="noMatchingResults">
{{ $options.tranlations.noResultsText }}
</gl-deprecated-dropdown-item>
</gl-new-dropdown>
</gl-dropdown>
</template>

View File

@ -116,6 +116,7 @@
.board-title {
flex-direction: column;
height: 100%;
}
.board-title-caret {

View File

@ -361,13 +361,6 @@
margin: 0;
}
.username {
display: block;
margin-top: 4px;
font-size: 13px;
font-weight: $gl-font-weight-normal;
}
.hide-expanded {
display: none;
}

View File

@ -55,6 +55,29 @@ module FormHelper
dropdown_data
end
def reviewers_dropdown_options(issuable_type)
{
toggle_class: 'js-reviewer-search js-multiselect js-save-user-data',
title: 'Request review from',
filter: true,
dropdown_class: 'dropdown-menu-user dropdown-menu-selectable dropdown-menu-reviewer',
placeholder: _('Search users'),
data: {
first_user: current_user&.username,
null_user: true,
current_user: true,
project_id: (@target_project || @project)&.id,
field_name: "#{issuable_type}[reviewer_ids][]",
default_label: 'Unassigned',
'dropdown-header': 'Reviewer(s)',
multi_select: true,
'input-meta': 'name',
'always-show-selectbox': true,
current_user_info: UserSerializer.new.represent(current_user)
}
}
end
# Overwritten
def issue_supports_multiple_assignees?
false

View File

@ -181,7 +181,7 @@ module NotesHelper
reopenPath: reopen_issuable_path(issuable),
notesPath: notes_url,
prerenderedNotesCount: issuable.capped_notes_count(MAX_PRERENDERED_NOTES),
lastFetchedAt: Time.now.to_i
lastFetchedAt: Time.now.to_i * ::Gitlab::UpdatedNotesPaginator::MICROSECOND
}
if issuable.is_a?(MergeRequest)

View File

@ -6,15 +6,15 @@ module NotificationsHelper
def notification_icon_class(level)
case level.to_sym
when :disabled, :owner_disabled
'microphone-slash'
'notifications-off'
when :participating
'volume-up'
'notifications'
when :watch
'eye'
when :mention
'at'
when :global
'globe'
'earth'
end
end
@ -28,8 +28,8 @@ module NotificationsHelper
end
end
def notification_icon(level, text = nil)
icon("#{notification_icon_class(level)} fw", text: text)
def notification_icon(level)
sprite_icon("#{notification_icon_class(level)}")
end
def notification_title(level)

View File

@ -32,8 +32,6 @@ module AlertManagement
:acknowledged
].freeze
DETAILS_IGNORED_PARAMS = %w(start_time).freeze
belongs_to :project
belongs_to :issue, optional: true
belongs_to :prometheus_alert, optional: true
@ -119,7 +117,7 @@ module AlertManagement
end
delegate :iid, to: :issue, prefix: true, allow_nil: true
delegate :metrics_dashboard_url, :details_url, to: :present
delegate :metrics_dashboard_url, :details_url, :details, to: :present
scope :for_iid, -> (iid) { where(iid: iid) }
scope :for_status, -> (status) { where(status: status) }
@ -172,12 +170,6 @@ module AlertManagement
with_prometheus_alert.where(id: ids)
end
def details
details_payload = payload.except(*attributes.keys, *DETAILS_IGNORED_PARAMS)
Gitlab::Utils::InlineHash.merge_keys(details_payload)
end
def prometheus?
monitoring_tool == Gitlab::AlertManagement::AlertParams::MONITORING_TOOLS[:prometheus]
end

View File

@ -146,6 +146,7 @@ class Project < ApplicationRecord
has_one :discord_service
has_one :drone_ci_service
has_one :emails_on_push_service
has_one :ewm_service
has_one :pipelines_email_service
has_one :irker_service
has_one :pivotaltracker_service

View File

@ -0,0 +1,29 @@
# frozen_string_literal: true
class EwmService < IssueTrackerService
validates :project_url, :issues_url, :new_issue_url, presence: true, public_url: true, if: :activated?
def self.reference_pattern(only_long: true)
@reference_pattern ||= %r{(?<issue>\b(bug|task|work item|workitem|rtcwi|defect)\b\s+\d+)}i
end
def title
'EWM'
end
def description
s_('IssueTracker|EWM work items tracker')
end
def self.to_param
'ewm'
end
def can_test?
false
end
def issue_url(iid)
issues_url.gsub(':id', iid.to_s.split(' ')[-1])
end
end

View File

@ -13,7 +13,7 @@ class Service < ApplicationRecord
SERVICE_NAMES = %w[
alerts asana assembla bamboo bugzilla buildkite campfire confluence custom_issue_tracker discord
drone_ci emails_on_push external_wiki flowdock hangouts_chat hipchat irker jira
drone_ci emails_on_push ewm external_wiki flowdock hangouts_chat hipchat irker jira
mattermost mattermost_slash_commands microsoft_teams packagist pipelines_email
pivotaltracker prometheus pushover redmine slack slack_slash_commands teamcity unify_circuit webex_teams youtrack
].freeze

View File

@ -42,6 +42,10 @@ module AlertManagement
details_project_alert_management_url(project, alert.iid)
end
def details
Gitlab::Utils::InlineHash.merge_keys(payload)
end
private
attr_reader :alert, :project
@ -81,7 +85,7 @@ module AlertManagement
end
def details_list
alert.details
details
.map { |label, value| list_item(label, value) }
.join(MARKDOWN_LINE_BREAK)
end

View File

@ -12,10 +12,6 @@ module AlertManagement
alerting_alert.alert_markdown
end
def details_list
alerting_alert.annotation_list
end
def metric_embed_for_alert
alerting_alert.metric_embed_for_alert
end

View File

@ -3,7 +3,6 @@
module Projects
module Prometheus
class AlertPresenter < Gitlab::View::Presenter::Delegated
RESERVED_ANNOTATIONS = %w(gitlab_incident_markdown gitlab_y_label title).freeze
GENERIC_ALERT_SUMMARY_ANNOTATIONS = %w(monitoring_tool service hosts).freeze
MARKDOWN_LINE_BREAK = " \n".freeze
INCIDENT_LABEL_NAME = ::IncidentManagement::CreateIncidentLabelService::LABEL_PROPERTIES[:title].freeze
@ -56,11 +55,10 @@ module Projects
MARKDOWN
end
def annotation_list
strong_memoize(:annotation_list) do
annotations
.reject { |annotation| annotation.label.in?(RESERVED_ANNOTATIONS | GENERIC_ALERT_SUMMARY_ANNOTATIONS) }
.map { |annotation| list_item(annotation.label, annotation.value) }
def details_list
strong_memoize(:details_list) do
details
.map { |label, value| list_item(label, value) }
.join(MARKDOWN_LINE_BREAK)
end
end
@ -109,13 +107,17 @@ module Projects
metadata.join(MARKDOWN_LINE_BREAK)
end
def details
Gitlab::Utils::InlineHash.merge_keys(payload)
end
def alert_details
if annotation_list.present?
if details.present?
<<~MARKDOWN.chomp
#### Alert Details
#{annotation_list}
#{details_list}
MARKDOWN
end
end

View File

@ -44,6 +44,8 @@ module SystemNotes
def change_assignee(assignee)
body = assignee.nil? ? 'removed assignee' : "assigned to #{assignee.to_reference}"
issue_activity_counter.track_issue_assignee_changed_action(author: author) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'assignee'))
end
@ -74,6 +76,8 @@ module SystemNotes
body = text_parts.join(' and ')
issue_activity_counter.track_issue_assignee_changed_action(author: author) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'assignee'))
end
@ -96,6 +100,8 @@ module SystemNotes
body = "changed title from **#{marked_old_title}** to **#{marked_new_title}**"
issue_activity_counter.track_issue_title_changed_action(author: author) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'title'))
end
@ -113,6 +119,8 @@ module SystemNotes
def change_description
body = 'changed the description'
issue_activity_counter.track_issue_description_changed_action(author: author) if noteable.is_a?(Issue)
create_note(NoteSummary.new(noteable, project, author, body, action: 'description'))
end
@ -209,9 +217,13 @@ module SystemNotes
if noteable.confidential
body = 'made the issue confidential'
action = 'confidential'
issue_activity_counter.track_issue_made_confidential_action(author: author) if noteable.is_a?(Issue)
else
body = 'made the issue visible to everyone'
action = 'visible'
issue_activity_counter.track_issue_made_visible_action(author: author) if noteable.is_a?(Issue)
end
create_note(NoteSummary.new(noteable, project, author, body, action: action))
@ -353,6 +365,10 @@ module SystemNotes
noteable.respond_to?(:resource_state_events) &&
::Feature.enabled?(:track_resource_state_change_events, noteable.project, default_enabled: true)
end
def issue_activity_counter
Gitlab::UsageDataCounters::IssueActivityUniqueCounter
end
end
end

View File

@ -2,7 +2,7 @@
.gl-responsive-table-row.notification-list-item
.table-section.section-40
%span.notification.fa.fa-holder.gl-mr-2
%span.notification.gl-mr-2
= notification_icon(notification_icon_level(setting, emails_disabled))
%span.str-truncated

View File

@ -1,7 +1,7 @@
- emails_disabled = project.emails_disabled?
%li.notification-list-item
%span.notification.fa.fa-holder.gl-mr-2
%span.notification.gl-mr-2
= notification_icon(notification_icon_level(setting, emails_disabled))
%span.str-truncated

View File

@ -1,9 +1,12 @@
- if show_no_password_message?
.no-password-message.alert.alert-warning
- translation_params = { protocol: gitlab_config.protocol.upcase, set_password_link: link_to_set_password }
- set_password_message = _("You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account") % translation_params
= set_password_message.html_safe
.alert-link-group
= link_to _("Don't show again"), profile_path(user: {hide_no_password: true}), method: :put
|
= link_to _('Remind later'), '#', class: 'hide-no-password-message'
.no-password-message.gl-alert.gl-alert-warning
= sprite_icon('warning', size: 16, css_class: 'gl-icon gl-alert-icon gl-alert-icon-no-title')
%button.js-close.gl-alert-dismiss{ type: 'button', 'aria-label': _('Dismiss') }
= sprite_icon('close', size: 16, css_class: 'gl-icon')
.gl-alert-body
- translation_params = { protocol: gitlab_config.protocol.upcase, set_password_link: link_to_set_password }
- set_password_message = _("You won't be able to pull or push project code via %{protocol} until you %{set_password_link} on your account") % translation_params
= set_password_message.html_safe
.gl-alert-actions
= link_to _('Remind later'), '#', class: 'hide-no-password-message btn gl-alert-action btn-info btn-md gl-button'
= link_to _("Don't show again"), profile_path(user: {hide_no_password: true}), method: :put, role: 'button', class: 'btn gl-alert-action btn-md btn-default gl-button btn-default-secondary'

View File

@ -19,7 +19,7 @@
#board-app.boards-app.position-relative{ "v-cloak" => "true", data: board_data, ":class" => "{ 'is-compact': detailIssueVisible }" }
= render 'shared/issuable/search_bar', type: :boards, board: board
- if Feature.enabled?(:boards_with_swimlanes, current_board_parent) || Feature.enabled?(:graphql_board_lists, current_board_parent)
- if Feature.enabled?(:boards_with_swimlanes, current_board_parent)
%board-content{ "v-cloak" => "true",
"ref" => "board_content",
":lists" => "state.lists",

View File

@ -12,6 +12,10 @@
.form-group.row.merge-request-assignee
= render "shared/issuable/form/metadata_issuable_assignee", issuable: issuable, form: form, has_due_date: has_due_date
- if issuable.allows_reviewers?
.form-group.row.merge-request-reviewer
= render "shared/issuable/form/metadata_issuable_reviewer", issuable: issuable, form: form, has_due_date: has_due_date
= render_if_exists "shared/issuable/form/epic", issuable: issuable, form: form, project: project
- if issuable.supports_milestone?

View File

@ -0,0 +1,10 @@
= form.label :reviewer_id, "Reviewer", class: "col-form-label #{has_due_date ? "col-md-2 col-lg-4" : "col-sm-2"}"
.col-sm-10{ class: ("col-md-8" if has_due_date) }
.issuable-form-select-holder.selectbox
- issuable.reviewers.each do |reviewer|
= hidden_field_tag "#{issuable.to_ability_name}[reviewer_ids][]", reviewer.id, id: nil, data: { meta: reviewer.name, avatar_url: reviewer.avatar_url, name: reviewer.name, username: reviewer.username }
- if issuable.reviewers.empty?
= hidden_field_tag "#{issuable.to_ability_name}[reviewer_ids][]", 0, id: nil, data: { meta: '' }
= dropdown_tag(users_dropdown_label(issuable.reviewers), options: reviewers_dropdown_options(issuable.to_ability_name))

View File

@ -0,0 +1,5 @@
---
title: Use the correct start time when polling for updated notes
merge_request: 42124
author:
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Add admin setting of Elasticsearch client request timeout
merge_request: 41470
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Add Issue actions to UsageData
merge_request: 40904
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Replace bootstrap alerts in app/views/shared/_no_password.html.haml
merge_request: 41397
author: Gilang Gumilar
type: changed

View File

@ -0,0 +1,5 @@
---
title: Added EWM work item tracker integration
merge_request: 36662
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Make Pipeline ID's always a link for downstream/upstream pipelines
merge_request: 42107
author:
type: added

View File

@ -0,0 +1,5 @@
---
title: Remove frontend unit test report test case sorting
merge_request: 40885
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Replace notification icons with Gitlab SVGs
merge_request: 40709
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Remove duplicated container scanning findings
merge_request: 42041
author:
type: other

View File

@ -0,0 +1,5 @@
---
title: Present complete alert payload in detail and incident views
merge_request: 42140
author:
type: changed

View File

@ -0,0 +1,5 @@
---
title: Exclude tmp dirs from backups
merge_request: 41706
author:
type: fixed

View File

@ -0,0 +1,7 @@
---
name: track_issue_activity_actions
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/40904
rollout_issue_url:
group: group::project_management
type: development
default_enabled: false

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
# See https://docs.gitlab.com/ee/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.
class AddElasticsearchClientTimeout < ActiveRecord::Migration[6.0]
DOWNTIME = false
def change
add_column :application_settings, :elasticsearch_client_request_timeout, :integer, null: false, default: 0
end
end

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class TmpIndexForFixingInconsistentVulnerabilityOccurrences < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
INDEX_NAME = 'tmp_index_for_fixing_inconsistent_vulnerability_occurrences'
disable_ddl_transaction!
def up
# report_type: 2 container scanning
add_concurrent_index(:vulnerability_occurrences, :id,
where: "LENGTH(location_fingerprint) = 40 AND report_type = 2",
name: INDEX_NAME)
end
def down
remove_concurrent_index_by_name(:vulnerability_occurrences, INDEX_NAME)
end
end

View File

@ -0,0 +1,31 @@
# frozen_string_literal: true
class RemoveDuplicatedCsFindings < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
BATCH_SIZE = 1_000
INTERVAL = 2.minutes
# 23_893 records will be updated
# 23_893 records will be deleted
def up
return unless Gitlab.com?
migration = Gitlab::BackgroundMigration::RemoveDuplicateCsFindings
migration_name = migration.to_s.demodulize
relation = migration::Finding.container_scanning.where("LENGTH(location_fingerprint) = 40")
queue_background_migration_jobs_by_range_at_intervals(relation,
migration_name,
INTERVAL,
batch_size: BATCH_SIZE)
end
def down
# no-op
# intentionally blank
end
end

View File

@ -0,0 +1 @@
f9aa112661a55c9eeed1a6aa05dd4c28d6f88971dc14bb606e677d4b4a4e5947

View File

@ -0,0 +1 @@
205580c1ba38fd03ce025dfd1d9be67756ade4fd28ba957bb71cd9e5e89ef190

View File

@ -0,0 +1 @@
ba431f19818b93da91c4ed2c3f25dc8e2f62c6d9ac07b15f6d01f21f085c1730

View File

@ -9271,6 +9271,7 @@ CREATE TABLE public.application_settings (
elasticsearch_indexed_file_size_limit_kb integer DEFAULT 1024 NOT NULL,
enforce_namespace_storage_limit boolean DEFAULT false NOT NULL,
container_registry_delete_tags_service_timeout integer DEFAULT 250 NOT NULL,
elasticsearch_client_request_timeout integer DEFAULT 0 NOT NULL,
CONSTRAINT check_51700b31b5 CHECK ((char_length(default_branch_name) <= 255)),
CONSTRAINT check_9c6c447a13 CHECK ((char_length(maintenance_mode_message) <= 255)),
CONSTRAINT check_d03919528d CHECK ((char_length(container_registry_vendor) <= 255)),
@ -21400,6 +21401,8 @@ CREATE INDEX tmp_build_stage_position_index ON public.ci_builds USING btree (sta
CREATE INDEX tmp_index_for_email_unconfirmation_migration ON public.emails USING btree (id) WHERE (confirmed_at IS NOT NULL);
CREATE INDEX tmp_index_for_fixing_inconsistent_vulnerability_occurrences ON public.vulnerability_occurrences USING btree (id) WHERE ((length(location_fingerprint) = 40) AND (report_type = 2));
CREATE UNIQUE INDEX unique_merge_request_metrics_by_merge_request_id ON public.merge_request_metrics USING btree (merge_request_id);
CREATE UNIQUE INDEX users_security_dashboard_projects_unique_index ON public.users_security_dashboard_projects USING btree (project_id, user_id);

Some files were not shown because too many files have changed in this diff Show More