Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
65f197cdb6
commit
711f859532
59 changed files with 371 additions and 114 deletions
|
@ -11,6 +11,7 @@ import {
|
|||
GlTabs,
|
||||
GlTab,
|
||||
GlBadge,
|
||||
GlPagination,
|
||||
} from '@gitlab/ui';
|
||||
import createFlash from '~/flash';
|
||||
import { s__ } from '~/locale';
|
||||
|
@ -22,6 +23,7 @@ import getAlertsCountByStatus from '../graphql/queries/get_count_by_status.query
|
|||
import {
|
||||
ALERTS_STATUS_TABS,
|
||||
ALERTS_SEVERITY_LABELS,
|
||||
DEFAULT_PAGE_SIZE,
|
||||
trackAlertListViewsOptions,
|
||||
trackAlertStatusUpdateOptions,
|
||||
} from '../constants';
|
||||
|
@ -34,6 +36,14 @@ const bodyTrClass =
|
|||
'gl-border-1 gl-border-t-solid gl-border-gray-100 gl-hover-bg-blue-50 gl-hover-cursor-pointer gl-hover-border-b-solid gl-hover-border-blue-200';
|
||||
const findDefaultSortColumn = () => document.querySelector('.js-started-at');
|
||||
|
||||
const initialPaginationState = {
|
||||
currentPage: 1,
|
||||
prevPageCursor: '',
|
||||
nextPageCursor: '',
|
||||
firstPageSize: DEFAULT_PAGE_SIZE,
|
||||
lastPageSize: null,
|
||||
};
|
||||
|
||||
export default {
|
||||
i18n: {
|
||||
noAlertsMsg: s__(
|
||||
|
@ -110,6 +120,7 @@ export default {
|
|||
GlTabs,
|
||||
GlTab,
|
||||
GlBadge,
|
||||
GlPagination,
|
||||
},
|
||||
props: {
|
||||
projectPath: {
|
||||
|
@ -142,10 +153,20 @@ export default {
|
|||
projectPath: this.projectPath,
|
||||
statuses: this.statusFilter,
|
||||
sort: this.sort,
|
||||
firstPageSize: this.pagination.firstPageSize,
|
||||
lastPageSize: this.pagination.lastPageSize,
|
||||
prevPageCursor: this.pagination.prevPageCursor,
|
||||
nextPageCursor: this.pagination.nextPageCursor,
|
||||
};
|
||||
},
|
||||
update(data) {
|
||||
return data.project?.alertManagementAlerts?.nodes;
|
||||
const { alertManagementAlerts: { nodes: list = [], pageInfo = {} } = {} } =
|
||||
data.project || {};
|
||||
|
||||
return {
|
||||
list,
|
||||
pageInfo,
|
||||
};
|
||||
},
|
||||
error() {
|
||||
this.errored = true;
|
||||
|
@ -169,7 +190,9 @@ export default {
|
|||
isAlertDismissed: false,
|
||||
isErrorAlertDismissed: false,
|
||||
sort: 'STARTED_AT_ASC',
|
||||
statusFilter: this.$options.statusTabs[4].filters,
|
||||
statusFilter: [],
|
||||
filteredByStatus: '',
|
||||
pagination: initialPaginationState,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
|
@ -185,19 +208,34 @@ export default {
|
|||
return this.$apollo.queries.alerts.loading;
|
||||
},
|
||||
hasAlerts() {
|
||||
return this.alerts?.length;
|
||||
return this.alerts?.list?.length;
|
||||
},
|
||||
tbodyTrClass() {
|
||||
return !this.loading && this.hasAlerts ? bodyTrClass : '';
|
||||
},
|
||||
showPaginationControls() {
|
||||
return Boolean(this.prevPage || this.nextPage);
|
||||
},
|
||||
alertsForCurrentTab() {
|
||||
return this.alertsCount ? this.alertsCount[this.filteredByStatus.toLowerCase()] : 0;
|
||||
},
|
||||
prevPage() {
|
||||
return Math.max(this.pagination.currentPage - 1, 0);
|
||||
},
|
||||
nextPage() {
|
||||
const nextPage = this.pagination.currentPage + 1;
|
||||
return nextPage > Math.ceil(this.alertsForCurrentTab / DEFAULT_PAGE_SIZE) ? null : nextPage;
|
||||
},
|
||||
},
|
||||
mounted() {
|
||||
findDefaultSortColumn().ariaSort = 'ascending';
|
||||
this.trackPageViews();
|
||||
},
|
||||
methods: {
|
||||
filterAlertsByStatus(tabIndex) {
|
||||
this.statusFilter = this.$options.statusTabs[tabIndex].filters;
|
||||
this.resetPagination();
|
||||
const { filters, status } = this.$options.statusTabs[tabIndex];
|
||||
this.statusFilter = filters;
|
||||
this.filteredByStatus = status;
|
||||
},
|
||||
fetchSortedData({ sortBy, sortDesc }) {
|
||||
const sortDirection = sortDesc ? 'DESC' : 'ASC';
|
||||
|
@ -206,6 +244,7 @@ export default {
|
|||
if (sortBy !== 'startedAt') {
|
||||
findDefaultSortColumn().ariaSort = 'none';
|
||||
}
|
||||
this.resetPagination();
|
||||
this.sort = `${sortColumn}_${sortDirection}`;
|
||||
},
|
||||
updateAlertStatus(status, iid) {
|
||||
|
@ -222,6 +261,7 @@ export default {
|
|||
this.trackStatusUpdate(status);
|
||||
this.$apollo.queries.alerts.refetch();
|
||||
this.$apollo.queries.alertsCount.refetch();
|
||||
this.resetPagination();
|
||||
})
|
||||
.catch(() => {
|
||||
createFlash(
|
||||
|
@ -246,6 +286,28 @@ export default {
|
|||
// TODO: Update to show list of assignee(s) after https://gitlab.com/gitlab-org/gitlab/-/issues/218405
|
||||
return assignees?.length > 0 ? assignees[0]?.username : s__('AlertManagement|Unassigned');
|
||||
},
|
||||
handlePageChange(page) {
|
||||
const { startCursor, endCursor } = this.alerts.pageInfo;
|
||||
|
||||
if (page > this.pagination.currentPage) {
|
||||
this.pagination = {
|
||||
...initialPaginationState,
|
||||
nextPageCursor: endCursor,
|
||||
currentPage: page,
|
||||
};
|
||||
} else {
|
||||
this.pagination = {
|
||||
lastPageSize: DEFAULT_PAGE_SIZE,
|
||||
firstPageSize: null,
|
||||
prevPageCursor: startCursor,
|
||||
nextPageCursor: '',
|
||||
currentPage: page,
|
||||
};
|
||||
}
|
||||
},
|
||||
resetPagination() {
|
||||
this.pagination = initialPaginationState;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -275,7 +337,7 @@ export default {
|
|||
</h4>
|
||||
<gl-table
|
||||
class="alert-management-table mt-3"
|
||||
:items="alerts"
|
||||
:items="alerts ? alerts.list : []"
|
||||
:fields="$options.fields"
|
||||
:show-empty="true"
|
||||
:busy="loading"
|
||||
|
@ -283,6 +345,7 @@ export default {
|
|||
:tbody-tr-class="tbodyTrClass"
|
||||
:no-local-sorting="true"
|
||||
sort-icon-left
|
||||
sort-by="startedAt"
|
||||
@row-clicked="navigateToAlertDetails"
|
||||
@sort-changed="fetchSortedData"
|
||||
>
|
||||
|
@ -350,6 +413,16 @@ export default {
|
|||
<gl-loading-icon size="lg" color="dark" class="mt-3" />
|
||||
</template>
|
||||
</gl-table>
|
||||
|
||||
<gl-pagination
|
||||
v-if="showPaginationControls"
|
||||
:value="pagination.currentPage"
|
||||
:prev-page="prevPage"
|
||||
:next-page="nextPage"
|
||||
align="center"
|
||||
class="gl-pagination prepend-top-default"
|
||||
@input="handlePageChange"
|
||||
/>
|
||||
</div>
|
||||
<gl-empty-state
|
||||
v-else
|
||||
|
|
|
@ -63,3 +63,5 @@ export const trackAlertStatusUpdateOptions = {
|
|||
action: 'update_alert_status',
|
||||
label: 'Status',
|
||||
};
|
||||
|
||||
export const DEFAULT_PAGE_SIZE = 10;
|
||||
|
|
|
@ -1,11 +1,32 @@
|
|||
#import "../fragments/list_item.fragment.graphql"
|
||||
|
||||
query getAlerts($projectPath: ID!, $statuses: [AlertManagementStatus!], $sort: AlertManagementAlertSort ) {
|
||||
project(fullPath: $projectPath) {
|
||||
alertManagementAlerts(statuses: $statuses, sort: $sort) {
|
||||
nodes {
|
||||
...AlertListItem
|
||||
}
|
||||
query getAlerts(
|
||||
$projectPath: ID!,
|
||||
$statuses: [AlertManagementStatus!],
|
||||
$sort: AlertManagementAlertSort,
|
||||
$firstPageSize: Int,
|
||||
$lastPageSize: Int,
|
||||
$prevPageCursor: String = ""
|
||||
$nextPageCursor: String = ""
|
||||
) {
|
||||
project(fullPath: $projectPath, ) {
|
||||
alertManagementAlerts(
|
||||
statuses: $statuses,
|
||||
sort: $sort,
|
||||
first: $firstPageSize
|
||||
last: $lastPageSize,
|
||||
after: $nextPageCursor,
|
||||
before: $prevPageCursor
|
||||
) {
|
||||
nodes {
|
||||
...AlertListItem
|
||||
},
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
endCursor
|
||||
hasPreviousPage
|
||||
startCursor
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,10 +84,10 @@ export default {
|
|||
|
||||
<div v-show="hasError" class="btn-group">
|
||||
<div class="btn btn-default btn-sm disabled">
|
||||
<icon :size="16" class="gl-ml-3 append-right-8" name="doc-image" aria-hidden="true" />
|
||||
<icon :size="16" class="gl-ml-3 gl-mr-3" name="doc-image" aria-hidden="true" />
|
||||
</div>
|
||||
<div class="btn btn-default btn-sm disabled">
|
||||
<span class="gl-ml-3 append-right-8">{{ s__('Badges|No badge image') }}</span>
|
||||
<span class="gl-ml-3 gl-mr-3">{{ s__('Badges|No badge image') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ export default {
|
|||
<div v-if="canEditBadge" class="table-action-buttons">
|
||||
<button
|
||||
:disabled="badge.isDeleting"
|
||||
class="btn btn-default append-right-8"
|
||||
class="btn btn-default gl-mr-3"
|
||||
type="button"
|
||||
@click="editBadge(badge)"
|
||||
>
|
||||
|
|
|
@ -86,7 +86,7 @@ export default {
|
|||
<publish-button
|
||||
:show-count="true"
|
||||
:should-publish="false"
|
||||
class="btn btn-success btn-inverted append-right-8"
|
||||
class="btn btn-success btn-inverted gl-mr-3"
|
||||
/>
|
||||
<loading-button
|
||||
ref="publishNowButton"
|
||||
|
|
|
@ -103,7 +103,7 @@ export default {
|
|||
:show-count="false"
|
||||
:should-publish="true"
|
||||
:label="__('Submit review')"
|
||||
class="float-right append-right-8"
|
||||
class="float-right gl-mr-3"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -83,7 +83,7 @@ export default {
|
|||
@click="scrollToDraft(draft)"
|
||||
>
|
||||
<span class="review-preview-item-header">
|
||||
<icon class="append-right-8 flex-shrink-0" :name="iconName" />
|
||||
<icon class="gl-mr-3 flex-shrink-0" :name="iconName" />
|
||||
<span class="bold text-nowrap">
|
||||
<span class="review-preview-item-header-text block-truncated"> {{ titleText }} </span>
|
||||
<template v-if="showLinePosition">
|
||||
|
@ -98,7 +98,7 @@ export default {
|
|||
v-if="draft.discussion_id && resolvedStatusMessage"
|
||||
class="review-preview-item-footer draft-note-resolution p-0"
|
||||
>
|
||||
<icon class="append-right-8" name="status_success" /> {{ resolvedStatusMessage }}
|
||||
<icon class="gl-mr-3" name="status_success" /> {{ resolvedStatusMessage }}
|
||||
</span>
|
||||
</button>
|
||||
</template>
|
||||
|
|
|
@ -188,7 +188,7 @@ export default {
|
|||
>
|
||||
<span
|
||||
v-if="issue.referencePath"
|
||||
class="board-card-number overflow-hidden d-flex append-right-8 gl-mt-3"
|
||||
class="board-card-number overflow-hidden d-flex gl-mr-3 gl-mt-3"
|
||||
>
|
||||
<tooltip-on-truncate
|
||||
v-if="issueReferencePath"
|
||||
|
|
|
@ -170,7 +170,7 @@ export default {
|
|||
v-if="tableIsNotEmpty"
|
||||
ref="secret-value-reveal-button"
|
||||
data-qa-selector="reveal_ci_variable_value_button"
|
||||
class="append-right-8"
|
||||
class="gl-mr-3"
|
||||
@click="toggleValues(!valuesHidden)"
|
||||
>{{ valuesButtonText }}</gl-deprecated-button
|
||||
>
|
||||
|
|
|
@ -313,7 +313,7 @@ export default {
|
|||
:data-qa-selector="id"
|
||||
>
|
||||
<div class="gl-responsive-table-row-layout" role="row">
|
||||
<div class="table-section append-right-8 section-align-top" role="gridcell">
|
||||
<div class="table-section gl-mr-3 section-align-top" role="gridcell">
|
||||
<img
|
||||
v-if="hasLogo"
|
||||
:src="logoUrl"
|
||||
|
|
|
@ -168,7 +168,7 @@ export default {
|
|||
}}
|
||||
</gl-alert>
|
||||
<div class="gl-responsive-table-row-layout" role="row">
|
||||
<div class="table-section append-right-8 section-align-top" role="gridcell">
|
||||
<div class="table-section gl-mr-3 section-align-top" role="gridcell">
|
||||
<img
|
||||
:src="modSecurityLogo"
|
||||
:alt="`${$options.title} logo`"
|
||||
|
|
|
@ -86,7 +86,7 @@ export default {
|
|||
<button
|
||||
v-gl-tooltip.hover
|
||||
type="button"
|
||||
class="btn btn-default append-right-8 js-toggle-tree-list"
|
||||
class="btn btn-default gl-mr-3 js-toggle-tree-list"
|
||||
:class="{
|
||||
active: showTreeList,
|
||||
}"
|
||||
|
@ -126,15 +126,11 @@ export default {
|
|||
<gl-deprecated-button
|
||||
v-if="commit || startVersion"
|
||||
:href="latestVersionPath"
|
||||
class="append-right-8 js-latest-version"
|
||||
class="gl-mr-3 js-latest-version"
|
||||
>
|
||||
{{ __('Show latest version') }}
|
||||
</gl-deprecated-button>
|
||||
<gl-deprecated-button
|
||||
v-show="hasCollapsedFile"
|
||||
class="append-right-8"
|
||||
@click="expandAllFiles"
|
||||
>
|
||||
<gl-deprecated-button v-show="hasCollapsedFile" class="gl-mr-3" @click="expandAllFiles">
|
||||
{{ __('Expand all') }}
|
||||
</gl-deprecated-button>
|
||||
<settings-dropdown />
|
||||
|
|
|
@ -104,7 +104,7 @@ export default {
|
|||
<gl-loading-icon
|
||||
v-if="group.isChildrenLoading"
|
||||
size="lg"
|
||||
class="d-none d-sm-inline-flex flex-shrink-0 append-right-8"
|
||||
class="d-none d-sm-inline-flex flex-shrink-0 gl-mr-3"
|
||||
/>
|
||||
<div
|
||||
:class="{ 'd-sm-flex': !group.isChildrenLoading }"
|
||||
|
@ -117,12 +117,12 @@ export default {
|
|||
</div>
|
||||
<div class="group-text-container d-flex flex-fill align-items-center">
|
||||
<div class="group-text flex-grow-1 flex-shrink-1">
|
||||
<div class="d-flex align-items-center flex-wrap title namespace-title append-right-8">
|
||||
<div class="d-flex align-items-center flex-wrap title namespace-title gl-mr-3">
|
||||
<a
|
||||
v-tooltip
|
||||
:href="group.relativePath"
|
||||
:title="group.fullName"
|
||||
class="no-expand gl-mt-3 append-right-8"
|
||||
class="no-expand gl-mt-3 gl-mr-3"
|
||||
data-placement="bottom"
|
||||
>{{
|
||||
// ending bracket must be by closing tag to prevent
|
||||
|
|
|
@ -56,7 +56,7 @@ export default {
|
|||
v-if="canDiscard"
|
||||
ref="discardButton"
|
||||
type="button"
|
||||
class="btn btn-remove btn-inverted append-right-8"
|
||||
class="btn btn-remove btn-inverted gl-mr-3"
|
||||
@click="showDiscardModal"
|
||||
>
|
||||
{{ __('Discard changes') }}
|
||||
|
|
|
@ -74,7 +74,7 @@ export default {
|
|||
<div class="ide-commit-list-container">
|
||||
<header class="multi-file-commit-panel-header d-flex mb-0">
|
||||
<div class="d-flex align-items-center flex-fill">
|
||||
<icon v-once :name="iconName" :size="18" class="append-right-8" />
|
||||
<icon v-once :name="iconName" :size="18" class="gl-mr-3" />
|
||||
<strong> {{ titleText }} </strong>
|
||||
<div class="d-flex ml-auto">
|
||||
<button
|
||||
|
|
|
@ -87,7 +87,7 @@ export default {
|
|||
@click="openFileInEditor"
|
||||
>
|
||||
<span class="multi-file-commit-list-file-path d-flex align-items-center">
|
||||
<file-icon :file-name="file.name" class="append-right-8" />
|
||||
<file-icon :file-name="file.name" class="gl-mr-3" />
|
||||
<template v-if="file.prevName && file.prevName !== file.name">
|
||||
{{ file.prevName }} →
|
||||
</template>
|
||||
|
|
|
@ -75,7 +75,7 @@ export default {
|
|||
>
|
||||
{{ stage.name }}
|
||||
</strong>
|
||||
<div v-if="!stage.isLoading || stage.jobs.length" class="append-right-8 gl-ml-2">
|
||||
<div v-if="!stage.isLoading || stage.jobs.length" class="gl-mr-3 gl-ml-2">
|
||||
<span class="badge badge-pill"> {{ jobsCount }} </span>
|
||||
</div>
|
||||
<icon :name="collapseIcon" class="ide-stage-collapse-icon" />
|
||||
|
|
|
@ -18,6 +18,6 @@ export default {
|
|||
:title="__('Part of merge request changes')"
|
||||
:size="12"
|
||||
name="git-merge"
|
||||
class="append-right-8"
|
||||
class="gl-mr-3"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
@ -285,7 +285,7 @@ export default {
|
|||
<slot name="topLeft"></slot>
|
||||
<h5
|
||||
ref="graphTitle"
|
||||
class="prometheus-graph-title gl-font-lg font-weight-bold text-truncate append-right-8"
|
||||
class="prometheus-graph-title gl-font-lg font-weight-bold text-truncate gl-mr-3"
|
||||
tabindex="0"
|
||||
>
|
||||
{{ title }}
|
||||
|
|
|
@ -71,7 +71,7 @@ export default {
|
|||
:download="evidenceTitle(index)"
|
||||
:href="evidenceUrl(index)"
|
||||
>
|
||||
<gl-icon name="review-list" class="align-middle append-right-8" />
|
||||
<gl-icon name="review-list" class="align-middle gl-mr-3" />
|
||||
<span>{{ evidenceTitle(index) }}</span>
|
||||
</gl-link>
|
||||
|
||||
|
@ -96,7 +96,7 @@ export default {
|
|||
<gl-icon
|
||||
v-gl-tooltip
|
||||
name="clock"
|
||||
class="align-middle append-right-8"
|
||||
class="align-middle gl-mr-3"
|
||||
:title="collectedAt(index)"
|
||||
/>
|
||||
<span>{{ timeSummary(index) }}</span>
|
||||
|
|
|
@ -57,7 +57,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div class="card-subtitle d-flex flex-wrap text-secondary">
|
||||
<div class="append-right-8">
|
||||
<div class="gl-mr-3">
|
||||
<icon name="commit" class="align-middle" />
|
||||
<gl-link v-if="commitUrl" v-gl-tooltip.bottom :title="commit.title" :href="commitUrl">
|
||||
{{ commit.shortId }}
|
||||
|
@ -65,7 +65,7 @@ export default {
|
|||
<span v-else v-gl-tooltip.bottom :title="commit.title">{{ commit.shortId }}</span>
|
||||
</div>
|
||||
|
||||
<div class="append-right-8">
|
||||
<div class="gl-mr-3">
|
||||
<icon name="tag" class="align-middle" />
|
||||
<gl-link v-if="tagUrl" v-gl-tooltip.bottom :title="__('Tag')" :href="tagUrl">
|
||||
{{ release.tagName }}
|
||||
|
|
|
@ -117,7 +117,7 @@ export default {
|
|||
:href="webIdePath"
|
||||
:title="ideButtonTitle"
|
||||
:class="{ disabled: !mr.canPushToSourceBranch }"
|
||||
class="btn btn-default js-web-ide d-none d-md-inline-block append-right-8"
|
||||
class="btn btn-default js-web-ide d-none d-md-inline-block gl-mr-3"
|
||||
data-placement="bottom"
|
||||
tabindex="0"
|
||||
role="button"
|
||||
|
@ -129,7 +129,7 @@ export default {
|
|||
:disabled="mr.sourceBranchRemoved"
|
||||
data-target="#modal_merge_info"
|
||||
data-toggle="modal"
|
||||
class="btn btn-default js-check-out-branch append-right-8"
|
||||
class="btn btn-default js-check-out-branch gl-mr-3"
|
||||
type="button"
|
||||
>
|
||||
{{ s__('mrWidget|Check out branch') }}
|
||||
|
|
|
@ -52,7 +52,7 @@ export default {
|
|||
:download="fileName"
|
||||
target="_blank"
|
||||
>
|
||||
<icon :size="16" name="download" class="float-left append-right-8" />
|
||||
<icon :size="16" name="download" class="float-left gl-mr-3" />
|
||||
{{ __('Download') }}
|
||||
</gl-link>
|
||||
</div>
|
||||
|
|
|
@ -75,12 +75,8 @@ export default {
|
|||
@mouseover="mouseOverRow"
|
||||
@mousemove="mouseMove"
|
||||
>
|
||||
<file-icon
|
||||
:file-name="file.name"
|
||||
:size="16"
|
||||
css-classes="diff-file-changed-icon append-right-8"
|
||||
/>
|
||||
<span class="diff-changed-file-content append-right-8">
|
||||
<file-icon :file-name="file.name" :size="16" css-classes="diff-file-changed-icon gl-mr-3" />
|
||||
<span class="diff-changed-file-content gl-mr-3">
|
||||
<strong class="diff-changed-file-name">
|
||||
<span
|
||||
v-for="(char, charIndex) in file.name.split('')"
|
||||
|
|
|
@ -414,7 +414,6 @@ img.emoji {
|
|||
.append-right-2 { margin-right: 2px; }
|
||||
.append-right-4 { margin-right: 4px; }
|
||||
.append-right-5 { margin-right: 5px; }
|
||||
.append-right-8 { margin-right: 8px; }
|
||||
.append-right-10 { margin-right: 10px; }
|
||||
.append-right-15 { margin-right: 15px; }
|
||||
.append-right-default { margin-right: $gl-padding; }
|
||||
|
|
|
@ -920,7 +920,7 @@ button.mini-pipeline-graph-dropdown-toggle {
|
|||
|
||||
|
||||
.ci-status-icon {
|
||||
@extend .append-right-8;
|
||||
@include gl-mr-3;
|
||||
|
||||
position: relative;
|
||||
|
||||
|
|
|
@ -14,6 +14,13 @@ module Releases
|
|||
|
||||
scope :sorted, -> { order(created_at: :desc) }
|
||||
|
||||
enum link_type: {
|
||||
other: 0,
|
||||
runbook: 1,
|
||||
package: 2,
|
||||
image: 3
|
||||
}
|
||||
|
||||
def internal?
|
||||
url.start_with?(release.project.web_url)
|
||||
end
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
= form_for @hook, as: :hook, url: admin_hook_path do |f|
|
||||
= render partial: 'form', locals: { form: f, hook: @hook }
|
||||
.form-actions
|
||||
%span>= f.submit _('Save changes'), class: 'btn btn-success append-right-8'
|
||||
%span>= f.submit _('Save changes'), class: 'btn btn-success gl-mr-3'
|
||||
= render 'shared/web_hooks/test_button', hook: @hook
|
||||
= link_to _('Delete'), admin_hook_path(@hook), method: :delete, class: 'btn btn-remove float-right', data: { confirm: _('Are you sure?') }
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
.bs-callout.gcp-signup-offer.alert.alert-block.alert-dismissable.prepend-top-default.append-bottom-default{ role: 'alert', data: { feature_id: UserCalloutsHelper::GCP_SIGNUP_OFFER, dismiss_endpoint: user_callouts_path } }
|
||||
%button.close.js-close{ type: "button" } ×
|
||||
.gcp-signup-offer--content
|
||||
.gcp-signup-offer--icon.append-right-8
|
||||
.gcp-signup-offer--icon.gl-mr-3
|
||||
= sprite_icon("information", size: 16)
|
||||
.gcp-signup-offer--copy
|
||||
%h4= s_('ClusterIntegration|Did you know?')
|
||||
|
|
|
@ -13,14 +13,14 @@
|
|||
.form-group.row
|
||||
= label_tag :bitbucket_server_url, 'Bitbucket Server URL', class: 'col-form-label col-md-2'
|
||||
.col-md-4
|
||||
= text_field_tag :bitbucket_server_url, '', class: 'form-control append-right-8', placeholder: _('https://your-bitbucket-server'), size: 40
|
||||
= text_field_tag :bitbucket_server_url, '', class: 'form-control gl-mr-3', placeholder: _('https://your-bitbucket-server'), size: 40
|
||||
.form-group.row
|
||||
= label_tag :bitbucket_server_url, 'Username', class: 'col-form-label col-md-2'
|
||||
.col-md-4
|
||||
= text_field_tag :bitbucket_username, '', class: 'form-control append-right-8', placeholder: _('username'), size: 40
|
||||
= text_field_tag :bitbucket_username, '', class: 'form-control gl-mr-3', placeholder: _('username'), size: 40
|
||||
.form-group.row
|
||||
= label_tag :personal_access_token, 'Password/Personal Access Token', class: 'col-form-label col-md-2'
|
||||
.col-md-4
|
||||
= password_field_tag :personal_access_token, '', class: 'form-control append-right-8', placeholder: _('Personal Access Token'), size: 40
|
||||
= password_field_tag :personal_access_token, '', class: 'form-control gl-mr-3', placeholder: _('Personal Access Token'), size: 40
|
||||
.form-actions
|
||||
= submit_tag _('List your Bitbucket Server repositories'), class: 'btn btn-success'
|
||||
|
|
|
@ -16,10 +16,10 @@
|
|||
.form-group.row
|
||||
= label_tag :phabricator_server_url, _('Phabricator Server URL'), class: 'col-form-label col-md-2'
|
||||
.col-md-4
|
||||
= text_field_tag :phabricator_server_url, params[:phabricator_server_url], class: 'form-control append-right-8', placeholder: 'https://your-phabricator-server', size: 40
|
||||
= text_field_tag :phabricator_server_url, params[:phabricator_server_url], class: 'form-control gl-mr-3', placeholder: 'https://your-phabricator-server', size: 40
|
||||
.form-group.row
|
||||
= label_tag :api_token, _('API Token'), class: 'col-form-label col-md-2'
|
||||
.col-md-4
|
||||
= password_field_tag :api_token, params[:api_token], class: 'form-control append-right-8', placeholder: _('Personal Access Token'), size: 40
|
||||
= password_field_tag :api_token, params[:api_token], class: 'form-control gl-mr-3', placeholder: _('Personal Access Token'), size: 40
|
||||
.form-actions
|
||||
= submit_tag _('Import tasks'), class: 'btn btn-success'
|
||||
|
|
|
@ -80,7 +80,7 @@
|
|||
- if @project.badges.present?
|
||||
.project-badges.mb-2
|
||||
- @project.badges.each do |badge|
|
||||
%a.append-right-8{ href: badge.rendered_link_url(@project),
|
||||
%a.gl-mr-3{ href: badge.rendered_link_url(@project),
|
||||
target: '_blank',
|
||||
rel: 'noopener noreferrer' }>
|
||||
%img.project-badge{ src: badge.rendered_image_url(@project),
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
- unless @project.empty_repo?
|
||||
- if current_user && can?(current_user, :fork_project, @project)
|
||||
.count-badge.d-inline-flex.align-item-stretch.append-right-8
|
||||
.count-badge.d-inline-flex.align-item-stretch.gl-mr-3
|
||||
- if current_user.already_forked?(@project) && current_user.manageable_namespaces.size < 2
|
||||
= link_to namespace_project_path(current_user, current_user.fork_of(@project)), title: s_('ProjectOverview|Go to your fork'), class: 'btn btn-default has-tooltip count-badge-button d-flex align-items-center fork-btn' do
|
||||
= sprite_icon('fork', { css_class: 'icon' })
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
- if current_user
|
||||
.count-badge.d-inline-flex.align-item-stretch.append-right-8
|
||||
.count-badge.d-inline-flex.align-item-stretch.gl-mr-3
|
||||
%button.count-badge-button.btn.btn-default.btn-xs.d-flex.align-items-center.star-btn.toggle-star{ type: "button", data: { endpoint: toggle_star_project_path(@project, :json) } }
|
||||
- if current_user.starred?(@project)
|
||||
= sprite_icon('star', { css_class: 'icon' })
|
||||
|
@ -12,7 +12,7 @@
|
|||
= @project.star_count
|
||||
|
||||
- else
|
||||
.count-badge.d-inline-flex.align-item-stretch.append-right-8
|
||||
.count-badge.d-inline-flex.align-item-stretch.gl-mr-3
|
||||
= link_to new_user_session_path, class: 'btn btn-default btn-xs has-tooltip count-badge-button d-flex align-items-center star-btn', title: s_('ProjectOverview|You must sign in to star a project') do
|
||||
= sprite_icon('star-o', { css_class: 'icon' })
|
||||
%span= s_('ProjectOverview|Star')
|
||||
|
|
|
@ -22,8 +22,8 @@
|
|||
- diff_files.each do |diff_file|
|
||||
%li
|
||||
%a.diff-changed-file{ href: "##{hexdigest(diff_file.file_path)}", title: diff_file.new_path }
|
||||
= sprite_icon(diff_file_changed_icon(diff_file), size: 16, css_class: "#{diff_file_changed_icon_color(diff_file)} diff-file-changed-icon append-right-8")
|
||||
%span.diff-changed-file-content.append-right-8
|
||||
= sprite_icon(diff_file_changed_icon(diff_file), size: 16, css_class: "#{diff_file_changed_icon_color(diff_file)} diff-file-changed-icon gl-mr-3")
|
||||
%span.diff-changed-file-content.gl-mr-3
|
||||
- if diff_file.file_path
|
||||
%strong.diff-changed-file-name
|
||||
= diff_file.file_path
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
= form_for [@project.namespace.becomes(Namespace), @project, @hook], as: :hook, url: project_hook_path(@project, @hook) do |f|
|
||||
= render partial: 'shared/web_hooks/form', locals: { form: f, hook: @hook }
|
||||
|
||||
%span>= f.submit 'Save changes', class: 'btn btn-success append-right-8'
|
||||
%span>= f.submit 'Save changes', class: 'btn btn-success gl-mr-3'
|
||||
= render 'shared/web_hooks/test_button', hook: @hook
|
||||
= link_to _('Delete'), project_hook_path(@project, @hook), method: :delete, class: 'btn btn-remove float-right', data: { confirm: _('Are you sure?') }
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@
|
|||
= _('Create branch')
|
||||
%li.divider.droplab-item-ignore
|
||||
|
||||
%li.droplab-item-ignore.gl-ml-3.append-right-8.prepend-top-16
|
||||
%li.droplab-item-ignore.gl-ml-3.gl-mr-3.prepend-top-16
|
||||
- if can_create_confidential_merge_request?
|
||||
#js-forked-project{ data: { namespace_path: @project.namespace.full_path, project_path: @project.full_path, new_fork_path: new_project_fork_path(@project), help_page_path: help_page_path('user/project/merge_requests') } }
|
||||
.form-group
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
- else
|
||||
- button_title = _("Notification setting - %{notification_title}") % { notification_title: notification_title(notification_setting.level) }
|
||||
|
||||
.js-notification-dropdown.notification-dropdown.home-panel-action-button.prepend-top-default.append-right-8.dropdown.inline
|
||||
.js-notification-dropdown.notification-dropdown.home-panel-action-button.prepend-top-default.gl-mr-3.dropdown.inline
|
||||
= form_for notification_setting, remote: true, html: { class: "inline notification-form no-label" } do |f|
|
||||
= hidden_setting_source_input(notification_setting)
|
||||
= hidden_field_tag "hide_label", true
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
.d-flex.align-items-center.flex-wrap.project-title
|
||||
%h2.d-flex.gl-mt-3
|
||||
= link_to project_path(project), class: 'text-plain' do
|
||||
%span.project-full-name.append-right-8><
|
||||
%span.project-full-name.gl-mr-3><
|
||||
%span.namespace-name
|
||||
- if project.namespace && !skip_namespace
|
||||
= project.namespace.human_name
|
||||
|
|
|
@ -11,6 +11,6 @@
|
|||
= hook.enable_ssl_verification ? _('enabled') : _('disabled')
|
||||
|
||||
.col-md-4.col-lg-5.text-right-md.prepend-top-5
|
||||
%span>= render 'shared/web_hooks/test_button', hook: hook, button_class: 'btn-sm append-right-8'
|
||||
%span>= link_to _('Edit'), edit_hook_path(hook), class: 'btn btn-sm append-right-8'
|
||||
%span>= render 'shared/web_hooks/test_button', hook: hook, button_class: 'btn-sm gl-mr-3'
|
||||
%span>= link_to _('Edit'), edit_hook_path(hook), class: 'btn btn-sm gl-mr-3'
|
||||
= link_to _('Delete'), destroy_hook_path(hook), data: { confirm: _('Are you sure?') }, method: :delete, class: 'btn btn-sm'
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Add link_type column to release_links table
|
||||
merge_request: 33156
|
||||
author:
|
||||
type: changed
|
5
changelogs/unreleased/213881-alerts-list-pagination.yml
Normal file
5
changelogs/unreleased/213881-alerts-list-pagination.yml
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Alerts list pagination
|
||||
merge_request: 33073
|
||||
author:
|
||||
type: added
|
19
db/migrate/20200527092027_add_link_type_to_release_links.rb
Normal file
19
db/migrate/20200527092027_add_link_type_to_release_links.rb
Normal file
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class AddLinkTypeToReleaseLinks < ActiveRecord::Migration[6.0]
|
||||
include Gitlab::Database::MigrationHelpers
|
||||
|
||||
DOWNTIME = false
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
add_column :release_links, :link_type, :integer, limit: 2, default: 0
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
with_lock_retries do
|
||||
remove_column :release_links, :link_type
|
||||
end
|
||||
end
|
||||
end
|
|
@ -5730,7 +5730,8 @@ CREATE TABLE public.release_links (
|
|||
name character varying NOT NULL,
|
||||
created_at timestamp with time zone NOT NULL,
|
||||
updated_at timestamp with time zone NOT NULL,
|
||||
filepath character varying(128)
|
||||
filepath character varying(128),
|
||||
link_type smallint DEFAULT 0
|
||||
);
|
||||
|
||||
CREATE SEQUENCE public.release_links_id_seq
|
||||
|
@ -14031,6 +14032,7 @@ COPY "schema_migrations" (version) FROM STDIN;
|
|||
20200526153844
|
||||
20200526164946
|
||||
20200526164947
|
||||
20200527092027
|
||||
20200527094322
|
||||
20200527095401
|
||||
20200527151413
|
||||
|
|
|
@ -126,10 +126,12 @@ configuration option in `gitlab.yml`. These metrics are served from the
|
|||
| `sidekiq_jobs_db_seconds` | Histogram | 12.9 | Seconds of DB time to run Sidekiq job | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency` |
|
||||
| `sidekiq_jobs_gitaly_seconds` | Histogram | 12.9 | Seconds of Gitaly time to run Sidekiq job | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency` |
|
||||
| `sidekiq_redis_requests_duration_seconds` | Histogram | 13.1 | Duration in seconds that a Sidekiq job spent querying a Redis server | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency` |
|
||||
| `sidekiq_elasticsearch_requests_duration_seconds` | Histogram | 13.1 | Duration in seconds that a Sidekiq job spent in requests to an Elasticsearch server | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency` |
|
||||
| `sidekiq_jobs_queue_duration_seconds` | Histogram | 12.5 | Duration in seconds that a Sidekiq job was queued before being executed | `queue`, `boundary`, `external_dependencies`, `feature_category`, `urgency` |
|
||||
| `sidekiq_jobs_failed_total` | Counter | 12.2 | Sidekiq jobs failed | `queue`, `boundary`, `external_dependencies`, `feature_category`, `urgency` |
|
||||
| `sidekiq_jobs_retried_total` | Counter | 12.2 | Sidekiq jobs retried | `queue`, `boundary`, `external_dependencies`, `feature_category`, `urgency` |
|
||||
| `sidekiq_redis_requests_total` | Counter | 13.1 | Redis requests during a Sidekiq job execution | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency` |
|
||||
| `sidekiq_elasticsearch_requests_total` | Counter | 13.1 | Elasticsearch requests during a Sidekiq job execution | `queue`, `boundary`, `external_dependencies`, `feature_category`, `job_status`, `urgency` |
|
||||
| `sidekiq_running_jobs` | Gauge | 12.2 | Number of Sidekiq jobs running | `queue`, `boundary`, `external_dependencies`, `feature_category`, `urgency` |
|
||||
| `sidekiq_concurrency` | Gauge | 12.5 | Maximum number of Sidekiq jobs | |
|
||||
| `geo_db_replication_lag_seconds` | Gauge | 10.2 | Database replication lag (seconds) | `url` |
|
||||
|
|
|
@ -4,29 +4,31 @@ 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 and merge requests
|
||||
# Bulk editing issues, epics, and merge requests
|
||||
|
||||
> **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.
|
||||
|
||||
Attributes can be updated simultaneously across multiple issues or merge requests
|
||||
Attributes can be updated simultaneously across multiple issues, epics, or merge requests
|
||||
by using the bulk editing feature.
|
||||
|
||||
![Bulk editing](img/bulk-editing.png)
|
||||
|
||||
NOTE: **Note:**
|
||||
Bulk editing issues and merge requests is also available at the group level.
|
||||
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).
|
||||
|
||||
To update multiple project issues or merge requests at the same time:
|
||||
To update multiple project issues, epics, or merge requests at the same time:
|
||||
|
||||
1. Navigate to their respective list.
|
||||
|
||||
1. Click **Edit issues** or **Edit merge requests**.
|
||||
1. Click either **Edit issues**, **Edit epics**, or **Edit merge requests**.
|
||||
|
||||
- This will open a sidebar on the right-hand side of your screen
|
||||
where editable fields will be displayed.
|
||||
|
|
|
@ -6,6 +6,7 @@ module Gitlab
|
|||
class BaseFormatter
|
||||
attr_reader :old_path
|
||||
attr_reader :new_path
|
||||
attr_reader :file_identifier_hash
|
||||
attr_reader :base_sha
|
||||
attr_reader :start_sha
|
||||
attr_reader :head_sha
|
||||
|
@ -16,6 +17,7 @@ module Gitlab
|
|||
attrs[:diff_refs] = diff_file.diff_refs
|
||||
attrs[:old_path] = diff_file.old_path
|
||||
attrs[:new_path] = diff_file.new_path
|
||||
attrs[:file_identifier_hash] = diff_file.file_identifier_hash
|
||||
end
|
||||
|
||||
if diff_refs = attrs[:diff_refs]
|
||||
|
@ -26,6 +28,7 @@ module Gitlab
|
|||
|
||||
@old_path = attrs[:old_path]
|
||||
@new_path = attrs[:new_path]
|
||||
@file_identifier_hash = attrs[:file_identifier_hash]
|
||||
@base_sha = attrs[:base_sha]
|
||||
@start_sha = attrs[:start_sha]
|
||||
@head_sha = attrs[:head_sha]
|
||||
|
@ -36,7 +39,7 @@ module Gitlab
|
|||
end
|
||||
|
||||
def to_h
|
||||
{
|
||||
out = {
|
||||
base_sha: base_sha,
|
||||
start_sha: start_sha,
|
||||
head_sha: head_sha,
|
||||
|
@ -44,6 +47,12 @@ module Gitlab
|
|||
new_path: new_path,
|
||||
position_type: position_type
|
||||
}
|
||||
|
||||
if Feature.enabled?(:file_identifier_hash)
|
||||
out[:file_identifier_hash] = file_identifier_hash
|
||||
end
|
||||
|
||||
out
|
||||
end
|
||||
|
||||
def position_type
|
||||
|
|
|
@ -9,6 +9,7 @@ module Gitlab
|
|||
|
||||
delegate :old_path,
|
||||
:new_path,
|
||||
:file_identifier_hash,
|
||||
:base_sha,
|
||||
:start_sha,
|
||||
:head_sha,
|
||||
|
|
|
@ -49,6 +49,8 @@ module Gitlab
|
|||
@metrics[:sidekiq_jobs_gitaly_seconds].observe(labels, get_gitaly_time(job))
|
||||
@metrics[:sidekiq_redis_requests_total].increment(labels, get_redis_calls(job))
|
||||
@metrics[:sidekiq_redis_requests_duration_seconds].observe(labels, get_redis_time(job))
|
||||
@metrics[:sidekiq_elasticsearch_requests_total].increment(labels, get_elasticsearch_calls(job))
|
||||
@metrics[:sidekiq_elasticsearch_requests_duration_seconds].observe(labels, get_elasticsearch_time(job))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -62,9 +64,11 @@ module Gitlab
|
|||
sidekiq_jobs_gitaly_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_gitaly_seconds, 'Seconds of Gitaly time to run Sidekiq job', {}, SIDEKIQ_LATENCY_BUCKETS),
|
||||
sidekiq_jobs_queue_duration_seconds: ::Gitlab::Metrics.histogram(:sidekiq_jobs_queue_duration_seconds, 'Duration in seconds that a Sidekiq job was queued before being executed', {}, SIDEKIQ_LATENCY_BUCKETS),
|
||||
sidekiq_redis_requests_duration_seconds: ::Gitlab::Metrics.histogram(:sidekiq_redis_requests_duration_seconds, 'Duration in seconds that a Sidekiq job spent requests a Redis server', {}, Gitlab::Instrumentation::Redis::QUERY_TIME_BUCKETS),
|
||||
sidekiq_elasticsearch_requests_duration_seconds: ::Gitlab::Metrics.histogram(:sidekiq_elasticsearch_requests_duration_seconds, 'Duration in seconds that a Sidekiq job spent in requests to an Elasticsearch server', {}, SIDEKIQ_LATENCY_BUCKETS),
|
||||
sidekiq_jobs_failed_total: ::Gitlab::Metrics.counter(:sidekiq_jobs_failed_total, 'Sidekiq jobs failed'),
|
||||
sidekiq_jobs_retried_total: ::Gitlab::Metrics.counter(:sidekiq_jobs_retried_total, 'Sidekiq jobs retried'),
|
||||
sidekiq_redis_requests_total: ::Gitlab::Metrics.counter(:sidekiq_redis_requests_total, 'Redis requests during a Sidekiq job execution'),
|
||||
sidekiq_elasticsearch_requests_total: ::Gitlab::Metrics.counter(:sidekiq_elasticsearch_requests_total, 'Elasticsearch requests during a Sidekiq job execution'),
|
||||
sidekiq_running_jobs: ::Gitlab::Metrics.gauge(:sidekiq_running_jobs, 'Number of Sidekiq jobs running', {}, :all),
|
||||
sidekiq_concurrency: ::Gitlab::Metrics.gauge(:sidekiq_concurrency, 'Maximum number of Sidekiq jobs', {}, :all)
|
||||
}
|
||||
|
@ -82,6 +86,14 @@ module Gitlab
|
|||
job.fetch(:redis_calls, 0)
|
||||
end
|
||||
|
||||
def get_elasticsearch_time(job)
|
||||
job.fetch(:elasticsearch_duration_s, 0)
|
||||
end
|
||||
|
||||
def get_elasticsearch_calls(job)
|
||||
job.fetch(:elasticsearch_calls, 0)
|
||||
end
|
||||
|
||||
def get_gitaly_time(job)
|
||||
job.fetch(:gitaly_duration_s, 0)
|
||||
end
|
||||
|
|
|
@ -7,8 +7,10 @@ import {
|
|||
GlDropdown,
|
||||
GlDropdownItem,
|
||||
GlIcon,
|
||||
GlTabs,
|
||||
GlTab,
|
||||
GlBadge,
|
||||
GlPagination,
|
||||
} from '@gitlab/ui';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
|
||||
|
@ -39,19 +41,21 @@ describe('AlertManagementList', () => {
|
|||
const findLoader = () => wrapper.find(GlLoadingIcon);
|
||||
const findStatusDropdown = () => wrapper.find(GlDropdown);
|
||||
const findStatusFilterTabs = () => wrapper.findAll(GlTab);
|
||||
const findStatusTabs = () => wrapper.find(GlTabs);
|
||||
const findStatusFilterBadge = () => wrapper.findAll(GlBadge);
|
||||
const findDateFields = () => wrapper.findAll(TimeAgo);
|
||||
const findFirstStatusOption = () => findStatusDropdown().find(GlDropdownItem);
|
||||
const findAssignees = () => wrapper.findAll('[data-testid="assigneesField"]');
|
||||
const findSeverityFields = () => wrapper.findAll('[data-testid="severityField"]');
|
||||
const findSeverityColumnHeader = () => wrapper.findAll('th').at(0);
|
||||
|
||||
const findStartTimeColumnHeader = () => wrapper.findAll('th').at(1);
|
||||
const findPagination = () => wrapper.find(GlPagination);
|
||||
const alertsCount = {
|
||||
acknowledged: 6,
|
||||
all: 16,
|
||||
open: 14,
|
||||
resolved: 2,
|
||||
triggered: 10,
|
||||
acknowledged: 6,
|
||||
resolved: 1,
|
||||
all: 16,
|
||||
};
|
||||
|
||||
function mountComponent({
|
||||
|
@ -76,6 +80,7 @@ describe('AlertManagementList', () => {
|
|||
mocks: {
|
||||
$apollo: {
|
||||
mutate: jest.fn(),
|
||||
query: jest.fn(),
|
||||
queries: {
|
||||
alerts: {
|
||||
loading,
|
||||
|
@ -134,7 +139,7 @@ describe('AlertManagementList', () => {
|
|||
it('loading state', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: null, alertsCount: null },
|
||||
data: { alerts: {}, alertsCount: null },
|
||||
loading: true,
|
||||
});
|
||||
expect(findAlertsTable().exists()).toBe(true);
|
||||
|
@ -149,7 +154,7 @@ describe('AlertManagementList', () => {
|
|||
it('error state', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: null, alertsCount: null, errored: true },
|
||||
data: { alerts: { errors: ['error'] }, alertsCount: null, errored: true },
|
||||
loading: false,
|
||||
});
|
||||
expect(findAlertsTable().exists()).toBe(true);
|
||||
|
@ -166,7 +171,7 @@ describe('AlertManagementList', () => {
|
|||
it('empty state', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: [], alertsCount: { all: 0 }, errored: false },
|
||||
data: { alerts: { list: [], pageInfo: {} }, alertsCount: { all: 0 }, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
expect(findAlertsTable().exists()).toBe(true);
|
||||
|
@ -183,7 +188,7 @@ describe('AlertManagementList', () => {
|
|||
it('has data state', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount, errored: false },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
expect(findLoader().exists()).toBe(false);
|
||||
|
@ -199,7 +204,7 @@ describe('AlertManagementList', () => {
|
|||
it('displays status dropdown', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount, errored: false },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
expect(findStatusDropdown().exists()).toBe(true);
|
||||
|
@ -208,7 +213,7 @@ describe('AlertManagementList', () => {
|
|||
it('shows correct severity icons', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount, errored: false },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
|
||||
|
@ -225,7 +230,7 @@ describe('AlertManagementList', () => {
|
|||
it('renders severity text', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount, errored: false },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
|
||||
|
@ -239,7 +244,7 @@ describe('AlertManagementList', () => {
|
|||
it('renders Unassigned when no assignee(s) present', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount, errored: false },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
|
||||
|
@ -253,7 +258,7 @@ describe('AlertManagementList', () => {
|
|||
it('renders username(s) when assignee(s) present', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount, errored: false },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
|
||||
|
@ -267,7 +272,7 @@ describe('AlertManagementList', () => {
|
|||
it('navigates to the detail page when alert row is clicked', () => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount, errored: false },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
|
||||
|
@ -282,15 +287,17 @@ describe('AlertManagementList', () => {
|
|||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: {
|
||||
alerts: [
|
||||
{
|
||||
iid: 1,
|
||||
status: 'acknowledged',
|
||||
startedAt: '2020-03-17T23:18:14.996Z',
|
||||
endedAt: '2020-04-17T23:18:14.996Z',
|
||||
severity: 'high',
|
||||
},
|
||||
],
|
||||
alerts: {
|
||||
list: [
|
||||
{
|
||||
iid: 1,
|
||||
status: 'acknowledged',
|
||||
startedAt: '2020-03-17T23:18:14.996Z',
|
||||
endedAt: '2020-04-17T23:18:14.996Z',
|
||||
severity: 'high',
|
||||
},
|
||||
],
|
||||
},
|
||||
alertsCount,
|
||||
errored: false,
|
||||
},
|
||||
|
@ -326,27 +333,31 @@ describe('AlertManagementList', () => {
|
|||
beforeEach(() => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, errored: false, sort: 'STARTED_AT_ASC', alertsCount },
|
||||
data: { alerts: { list: mockAlerts }, errored: false, sort: 'STARTED_AT_ASC', alertsCount },
|
||||
loading: false,
|
||||
stubs: { GlTable },
|
||||
});
|
||||
});
|
||||
|
||||
it('updates sort with new direction and column key', () => {
|
||||
findSeverityColumnHeader().trigger('click');
|
||||
|
||||
expect(wrapper.vm.$data.sort).toEqual('SEVERITY_ASC');
|
||||
expect(wrapper.vm.$data.sort).toBe('SEVERITY_ASC');
|
||||
|
||||
findSeverityColumnHeader().trigger('click');
|
||||
|
||||
expect(wrapper.vm.$data.sort).toEqual('SEVERITY_DESC');
|
||||
expect(wrapper.vm.$data.sort).toBe('SEVERITY_DESC');
|
||||
});
|
||||
|
||||
it('updates the `ariaSort` attribute so the sort icon appears in the proper column', () => {
|
||||
expect(mockStartedAtCol.ariaSort).toEqual('ascending');
|
||||
expect(findStartTimeColumnHeader().attributes('aria-sort')).toBe('ascending');
|
||||
|
||||
findSeverityColumnHeader().trigger('click');
|
||||
|
||||
expect(mockStartedAtCol.ariaSort).toEqual('none');
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(findStartTimeColumnHeader().attributes('aria-sort')).toBe('none');
|
||||
expect(findSeverityColumnHeader().attributes('aria-sort')).toBe('ascending');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -367,7 +378,7 @@ describe('AlertManagementList', () => {
|
|||
beforeEach(() => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount, errored: false },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
|
@ -403,7 +414,7 @@ describe('AlertManagementList', () => {
|
|||
jest.spyOn(Tracking, 'event');
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: mockAlerts, alertsCount },
|
||||
data: { alerts: { list: mockAlerts }, alertsCount },
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
|
@ -424,4 +435,64 @@ describe('AlertManagementList', () => {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Pagination', () => {
|
||||
beforeEach(() => {
|
||||
mountComponent({
|
||||
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
|
||||
data: { alerts: { list: mockAlerts, pageInfo: {} }, alertsCount, errored: false },
|
||||
loading: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('does NOT show pagination control when list is smaller than default page size', () => {
|
||||
findStatusTabs().vm.$emit('input', 3);
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(findPagination().exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
it('shows pagination control when list is larger than default page size', () => {
|
||||
findStatusTabs().vm.$emit('input', 0);
|
||||
wrapper.vm.$nextTick(() => {
|
||||
expect(findPagination().exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('prevPage', () => {
|
||||
it('returns prevPage number', () => {
|
||||
findPagination().vm.$emit('input', 3);
|
||||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(wrapper.vm.prevPage).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 0 when it is the first page', () => {
|
||||
findPagination().vm.$emit('input', 1);
|
||||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(wrapper.vm.prevPage).toBe(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('nextPage', () => {
|
||||
it('returns nextPage number', () => {
|
||||
findPagination().vm.$emit('input', 1);
|
||||
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(wrapper.vm.nextPage).toBe(2);
|
||||
});
|
||||
});
|
||||
|
||||
it('returns `null` when currentPage is already last page', () => {
|
||||
findStatusTabs().vm.$emit('input', 3);
|
||||
findPagination().vm.$emit('input', 1);
|
||||
return wrapper.vm.$nextTick(() => {
|
||||
expect(wrapper.vm.nextPage).toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -25,7 +25,7 @@ exports[`IDE pipeline stage renders stage details & icon 1`] = `
|
|||
</strong>
|
||||
|
||||
<div
|
||||
class="append-right-8 gl-ml-2"
|
||||
class="gl-mr-3 gl-ml-2"
|
||||
>
|
||||
<span
|
||||
class="badge badge-pill"
|
||||
|
|
|
@ -10,7 +10,7 @@ describe('Job Log', () => {
|
|||
let vm;
|
||||
|
||||
const trace =
|
||||
'<span>Running with gitlab-runner 12.1.0 (de7731dd)<br/></span><span> on docker-auto-scale-com d5ae8d25<br/></span><div class="append-right-8" data-timestamp="1565502765" data-section="prepare-executor" role="button"></div><span class="section section-header js-s-prepare-executor">Using Docker executor with image ruby:2.6 ...<br/></span>';
|
||||
'<span>Running with gitlab-runner 12.1.0 (de7731dd)<br/></span><span> on docker-auto-scale-com d5ae8d25<br/></span><div class="gl-mr-3" data-timestamp="1565502765" data-section="prepare-executor" role="button"></div><span class="section section-header js-s-prepare-executor">Using Docker executor with image ruby:2.6 ...<br/></span>';
|
||||
|
||||
beforeEach(() => {
|
||||
store = createStore();
|
||||
|
|
|
@ -10,6 +10,7 @@ describe Gitlab::Diff::Formatters::ImageFormatter do
|
|||
head_sha: 789,
|
||||
old_path: 'old_image.png',
|
||||
new_path: 'new_image.png',
|
||||
file_identifier_hash: '777',
|
||||
position_type: 'image'
|
||||
}
|
||||
end
|
||||
|
|
|
@ -10,6 +10,7 @@ describe Gitlab::Diff::Formatters::TextFormatter do
|
|||
head_sha: 789,
|
||||
old_path: 'old_path.txt',
|
||||
new_path: 'new_path.txt',
|
||||
file_identifier_hash: '777',
|
||||
line_range: nil
|
||||
}
|
||||
end
|
||||
|
|
|
@ -144,6 +144,7 @@ Releases::Link:
|
|||
- url
|
||||
- name
|
||||
- filepath
|
||||
- link_type
|
||||
- created_at
|
||||
- updated_at
|
||||
ProjectMember:
|
||||
|
|
|
@ -34,6 +34,8 @@ describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
|||
let(:redis_requests_total) { double('redis calls total metric') }
|
||||
let(:running_jobs_metric) { double('running jobs metric') }
|
||||
let(:redis_seconds_metric) { double('redis seconds metric') }
|
||||
let(:elasticsearch_seconds_metric) { double('elasticsearch seconds metric') }
|
||||
let(:elasticsearch_requests_total) { double('elasticsearch calls total metric') }
|
||||
|
||||
before do
|
||||
allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_queue_duration_seconds, anything, anything, anything).and_return(queue_duration_seconds)
|
||||
|
@ -42,9 +44,11 @@ describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
|||
allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_db_seconds, anything, anything, anything).and_return(db_seconds_metric)
|
||||
allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_jobs_gitaly_seconds, anything, anything, anything).and_return(gitaly_seconds_metric)
|
||||
allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_redis_requests_duration_seconds, anything, anything, anything).and_return(redis_seconds_metric)
|
||||
allow(Gitlab::Metrics).to receive(:histogram).with(:sidekiq_elasticsearch_requests_duration_seconds, anything, anything, anything).and_return(elasticsearch_seconds_metric)
|
||||
allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_jobs_failed_total, anything).and_return(failed_total_metric)
|
||||
allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_jobs_retried_total, anything).and_return(retried_total_metric)
|
||||
allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_redis_requests_total, anything).and_return(redis_requests_total)
|
||||
allow(Gitlab::Metrics).to receive(:counter).with(:sidekiq_elasticsearch_requests_total, anything).and_return(elasticsearch_requests_total)
|
||||
allow(Gitlab::Metrics).to receive(:gauge).with(:sidekiq_running_jobs, anything, {}, :all).and_return(running_jobs_metric)
|
||||
allow(Gitlab::Metrics).to receive(:gauge).with(:sidekiq_concurrency, anything, {}, :all).and_return(concurrency_metric)
|
||||
|
||||
|
@ -76,6 +80,9 @@ describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
|||
let(:redis_calls) { 2 }
|
||||
let(:redis_duration) { 0.01 }
|
||||
|
||||
let(:elasticsearch_calls) { 8 }
|
||||
let(:elasticsearch_duration) { 0.54 }
|
||||
|
||||
before do
|
||||
allow(subject).to receive(:get_thread_cputime).and_return(thread_cputime_before, thread_cputime_after)
|
||||
allow(Gitlab::Metrics::System).to receive(:monotonic_time).and_return(monotonic_time_before, monotonic_time_after)
|
||||
|
@ -86,14 +93,19 @@ describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
|||
job[:redis_calls] = redis_calls
|
||||
job[:redis_duration_s] = redis_duration
|
||||
|
||||
job[:elasticsearch_calls] = elasticsearch_calls
|
||||
job[:elasticsearch_duration_s] = elasticsearch_duration
|
||||
|
||||
allow(running_jobs_metric).to receive(:increment)
|
||||
allow(redis_requests_total).to receive(:increment)
|
||||
allow(elasticsearch_requests_total).to receive(:increment)
|
||||
allow(queue_duration_seconds).to receive(:observe)
|
||||
allow(user_execution_seconds_metric).to receive(:observe)
|
||||
allow(db_seconds_metric).to receive(:observe)
|
||||
allow(gitaly_seconds_metric).to receive(:observe)
|
||||
allow(completion_seconds_metric).to receive(:observe)
|
||||
allow(redis_seconds_metric).to receive(:observe)
|
||||
allow(elasticsearch_seconds_metric).to receive(:observe)
|
||||
end
|
||||
|
||||
it 'yields block' do
|
||||
|
@ -109,7 +121,9 @@ describe Gitlab::SidekiqMiddleware::ServerMetrics do
|
|||
expect(gitaly_seconds_metric).to receive(:observe).with(labels_with_job_status, gitaly_duration)
|
||||
expect(completion_seconds_metric).to receive(:observe).with(labels_with_job_status, monotonic_time_duration)
|
||||
expect(redis_seconds_metric).to receive(:observe).with(labels_with_job_status, redis_duration)
|
||||
expect(elasticsearch_seconds_metric).to receive(:observe).with(labels_with_job_status, elasticsearch_duration)
|
||||
expect(redis_requests_total).to receive(:increment).with(labels_with_job_status, redis_calls)
|
||||
expect(elasticsearch_requests_total).to receive(:increment).with(labels_with_job_status, elasticsearch_calls)
|
||||
|
||||
subject.call(worker, job, :test) { nil }
|
||||
end
|
||||
|
|
|
@ -195,6 +195,10 @@ RSpec.configure do |config|
|
|||
stub_feature_flags(flag => enable_rugged)
|
||||
end
|
||||
|
||||
# Disable the usage of file_identifier_hash by default until it is ready
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/33867
|
||||
stub_feature_flags(file_identifier_hash: false)
|
||||
|
||||
allow(Gitlab::GitalyClient).to receive(:can_use_disk?).and_return(enable_rugged)
|
||||
end
|
||||
|
||||
|
|
|
@ -32,7 +32,21 @@ RSpec.shared_examples "position formatter" do
|
|||
|
||||
subject { formatter.to_h }
|
||||
|
||||
it { is_expected.to eq(formatter_hash) }
|
||||
context 'when file_identifier_hash is disabled' do
|
||||
before do
|
||||
stub_feature_flags(file_identifier_hash: false)
|
||||
end
|
||||
|
||||
it { is_expected.to eq(formatter_hash.except(:file_identifier_hash)) }
|
||||
end
|
||||
|
||||
context 'when file_identifier_hash is enabled' do
|
||||
before do
|
||||
stub_feature_flags(file_identifier_hash: true)
|
||||
end
|
||||
|
||||
it { is_expected.to eq(formatter_hash) }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#==' do
|
||||
|
|
Loading…
Reference in a new issue