Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-03-24 21:09:31 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2021-03-24 21:09:31 +0300
commit1d041b2968384605660d49c96a3fcd7a6c51875d (patch)
tree90ebe0d46183ea57be38273f36b93b2a2adcccf1 /app/assets
parent036de5f31f136a7482f9e2b1d1e98a9c4b45ea80 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app/assets')
-rw-r--r--app/assets/javascripts/alert_management/list.js4
-rw-r--r--app/assets/javascripts/boards/components/board_add_new_column.vue38
-rw-r--r--app/assets/javascripts/boards/components/board_add_new_column_form.vue119
-rw-r--r--app/assets/javascripts/boards/components/board_list_deprecated.vue7
-rw-r--r--app/assets/javascripts/performance_bar/components/detailed_metric.vue90
-rw-r--r--app/assets/javascripts/performance_bar/components/performance_bar_app.vue13
-rw-r--r--app/assets/javascripts/performance_bar/constants.js17
7 files changed, 202 insertions, 86 deletions
diff --git a/app/assets/javascripts/alert_management/list.js b/app/assets/javascripts/alert_management/list.js
index f5eac26431f..b23f8a8eba4 100644
--- a/app/assets/javascripts/alert_management/list.js
+++ b/app/assets/javascripts/alert_management/list.js
@@ -5,6 +5,7 @@ import createDefaultClient from '~/lib/graphql';
import { parseBoolean } from '~/lib/utils/common_utils';
import { PAGE_CONFIG } from '~/vue_shared/alert_details/constants';
import AlertManagementList from './components/alert_management_list_wrapper.vue';
+import alertsHelpUrlQuery from './graphql/queries/alert_help_url.query.graphql';
Vue.use(VueApollo);
@@ -41,7 +42,8 @@ export default () => {
),
});
- apolloProvider.clients.defaultClient.cache.writeData({
+ apolloProvider.clients.defaultClient.cache.writeQuery({
+ query: alertsHelpUrlQuery,
data: {
alertsHelpUrl,
},
diff --git a/app/assets/javascripts/boards/components/board_add_new_column.vue b/app/assets/javascripts/boards/components/board_add_new_column.vue
index 3c7c792b787..a77696b70cc 100644
--- a/app/assets/javascripts/boards/components/board_add_new_column.vue
+++ b/app/assets/javascripts/boards/components/board_add_new_column.vue
@@ -1,10 +1,5 @@
<script>
-import {
- GlFormRadio,
- GlFormRadioGroup,
- GlLabel,
- GlTooltipDirective as GlTooltip,
-} from '@gitlab/ui';
+import { GlFormRadio, GlFormRadioGroup, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex';
import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form.vue';
import { ListType } from '~/boards/constants';
@@ -17,7 +12,6 @@ export default {
BoardAddNewColumnForm,
GlFormRadio,
GlFormRadioGroup,
- GlLabel,
},
directives: {
GlTooltip,
@@ -99,25 +93,25 @@ export default {
<template>
<board-add-new-column-form
:loading="labelsLoading"
- :form-description="__('A label list displays issues with the selected label.')"
- :search-label="__('Select label')"
+ :none-selected="__('Select a label')"
:search-placeholder="__('Search labels')"
:selected-id="selectedId"
@filter-items="filterItems"
@add-list="addList"
>
- <template slot="selected">
- <gl-label
- v-if="selectedLabel"
- v-gl-tooltip
- :title="selectedLabel.title"
- :description="selectedLabel.description"
- :background-color="selectedLabel.color"
- :scoped="showScopedLabels(selectedLabel)"
- />
+ <template #selected>
+ <template v-if="selectedLabel">
+ <span
+ class="dropdown-label-box gl-top-0 gl-flex-shrink-0"
+ :style="{
+ backgroundColor: selectedLabel.color,
+ }"
+ ></span>
+ <div class="gl-text-truncate">{{ selectedLabel.title }}</div>
+ </template>
</template>
- <template slot="items">
+ <template #items>
<gl-form-radio-group
v-if="labels.length > 0"
v-model="selectedId"
@@ -126,11 +120,11 @@ export default {
<label
v-for="label in labels"
:key="label.id"
- class="gl-display-flex gl-flex-align-items-center gl-mb-5 gl-font-weight-normal"
+ class="gl-display-flex gl-mb-5 gl-font-weight-normal gl-overflow-break-word"
>
- <gl-form-radio :value="label.id" class="gl-mb-0" />
+ <gl-form-radio :value="label.id" />
<span
- class="dropdown-label-box gl-top-0"
+ class="dropdown-label-box gl-top-0 gl-flex-shrink-0"
:style="{
backgroundColor: label.color,
}"
diff --git a/app/assets/javascripts/boards/components/board_add_new_column_form.vue b/app/assets/javascripts/boards/components/board_add_new_column_form.vue
index d85343a5390..70ba90bb1d4 100644
--- a/app/assets/javascripts/boards/components/board_add_new_column_form.vue
+++ b/app/assets/javascripts/boards/components/board_add_new_column_form.vue
@@ -1,5 +1,12 @@
<script>
-import { GlButton, GlFormGroup, GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
+import {
+ GlButton,
+ GlDropdown,
+ GlFormGroup,
+ GlIcon,
+ GlSearchBoxByType,
+ GlSkeletonLoader,
+} from '@gitlab/ui';
import { mapActions } from 'vuex';
import { __ } from '~/locale';
@@ -8,13 +15,16 @@ export default {
add: __('Add to board'),
cancel: __('Cancel'),
newList: __('New list'),
- noneSelected: __('None'),
noResults: __('No matching results'),
+ scope: __('Scope'),
+ scopeDescription: __('Issues must match this scope to appear in this list.'),
selected: __('Selected'),
},
components: {
GlButton,
+ GlDropdown,
GlFormGroup,
+ GlIcon,
GlSearchBoxByType,
GlSkeletonLoader,
},
@@ -23,11 +33,12 @@ export default {
type: Boolean,
required: true,
},
- formDescription: {
+ searchLabel: {
type: String,
- required: true,
+ required: false,
+ default: null,
},
- searchLabel: {
+ noneSelected: {
type: String,
required: true,
},
@@ -46,8 +57,23 @@ export default {
searchValue: '',
};
},
+ watch: {
+ selectedId(val) {
+ if (val) {
+ this.$refs.dropdown.hide(true);
+ }
+ },
+ },
methods: {
...mapActions(['setAddColumnFormVisibility']),
+ setFocus() {
+ this.$refs.searchBox.focusInput();
+ },
+ onHide() {
+ this.searchValue = '';
+ this.$emit('filter-items', '');
+ this.$emit('hide');
+ },
},
};
</script>
@@ -62,51 +88,64 @@ export default {
class="board-inner gl-display-flex gl-flex-direction-column gl-relative gl-h-full gl-rounded-base gl-bg-white"
>
<h3
- class="gl-font-base gl-px-5 gl-py-5 gl-m-0 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
+ class="gl-font-size-h2 gl-px-5 gl-py-4 gl-m-0 gl-border-b-1 gl-border-b-solid gl-border-b-gray-100"
data-testid="board-add-column-form-title"
>
{{ $options.i18n.newList }}
</h3>
- <div class="gl-display-flex gl-flex-direction-column gl-h-full gl-overflow-hidden">
- <slot name="select-list-type">
- <div class="gl-mb-5"></div>
- </slot>
+ <div
+ class="gl-display-flex gl-flex-direction-column gl-h-full gl-overflow-y-auto gl-align-items-flex-start"
+ >
+ <div class="gl-px-5">
+ <h3 class="gl-font-lg gl-mt-5 gl-mb-2">
+ {{ $options.i18n.scope }}
+ </h3>
+ <p class="gl-mb-3">{{ $options.i18n.scopeDescription }}</p>
+ </div>
- <p class="gl-px-5">{{ formDescription }}</p>
+ <slot name="select-list-type"></slot>
- <div class="gl-px-5 gl-pb-4">
- <label class="gl-mb-2">{{ $options.i18n.selected }}</label>
- <slot name="selected">
- <div class="gl-text-gray-500">{{ $options.i18n.noneSelected }}</div>
- </slot>
- </div>
+ <gl-form-group class="gl-px-5 lg-mb-3 gl-max-w-full" :label="searchLabel">
+ <gl-dropdown
+ ref="dropdown"
+ class="gl-mb-3 gl-max-w-full"
+ toggle-class="gl-max-w-full gl-display-flex gl-align-items-center gl-text-trunate"
+ boundary="viewport"
+ @shown="setFocus"
+ @hide="onHide"
+ >
+ <template #button-content>
+ <slot name="selected">
+ <div>{{ noneSelected }}</div>
+ </slot>
+ <gl-icon class="dropdown-chevron gl-flex-shrink-0" name="chevron-down" />
+ </template>
- <gl-form-group
- class="gl-mx-5 gl-mb-3"
- :label="searchLabel"
- label-for="board-available-column-entities"
- >
- <gl-search-box-by-type
- id="board-available-column-entities"
- v-model="searchValue"
- debounce="250"
- :placeholder="searchPlaceholder"
- @input="$emit('filter-items', $event)"
- />
- </gl-form-group>
+ <template #header>
+ <gl-search-box-by-type
+ ref="searchBox"
+ v-model="searchValue"
+ debounce="250"
+ class="gl-mt-0!"
+ :placeholder="searchPlaceholder"
+ @input="$emit('filter-items', $event)"
+ />
+ </template>
- <div v-if="loading" class="gl-px-5">
- <gl-skeleton-loader :width="500" :height="172">
- <rect width="480" height="20" x="10" y="15" rx="4" />
- <rect width="380" height="20" x="10" y="50" rx="4" />
- <rect width="430" height="20" x="10" y="85" rx="4" />
- </gl-skeleton-loader>
- </div>
+ <div v-if="loading" class="gl-px-5">
+ <gl-skeleton-loader :width="400" :height="172">
+ <rect width="380" height="20" x="10" y="15" rx="4" />
+ <rect width="280" height="20" x="10" y="50" rx="4" />
+ <rect width="330" height="20" x="10" y="85" rx="4" />
+ </gl-skeleton-loader>
+ </div>
- <slot v-else name="items">
- <p class="gl-mx-5">{{ $options.i18n.noResults }}</p>
- </slot>
+ <slot v-else name="items">
+ <p class="gl-mx-5">{{ $options.i18n.noResults }}</p>
+ </slot>
+ </gl-dropdown>
+ </gl-form-group>
</div>
<div
class="gl-display-flex gl-p-3 gl-border-t-1 gl-border-t-solid gl-border-gray-100 gl-bg-gray-10 gl-rounded-bottom-left-base gl-rounded-bottom-right-base"
diff --git a/app/assets/javascripts/boards/components/board_list_deprecated.vue b/app/assets/javascripts/boards/components/board_list_deprecated.vue
index d59fbcc1b31..0534e027c86 100644
--- a/app/assets/javascripts/boards/components/board_list_deprecated.vue
+++ b/app/assets/javascripts/boards/components/board_list_deprecated.vue
@@ -134,9 +134,10 @@ export default {
e.target.closest('.js-board-list') || e.target.querySelector('.js-board-list');
const toBoardType = containerEl.dataset.boardType;
const cloneActions = {
- label: ['milestone', 'assignee'],
- assignee: ['milestone', 'label'],
- milestone: ['label', 'assignee'],
+ label: ['milestone', 'assignee', 'iteration'],
+ assignee: ['milestone', 'label', 'iteration'],
+ milestone: ['label', 'assignee', 'iteration'],
+ iteration: ['label', 'assignee', 'milestone'],
};
if (toBoardType) {
diff --git a/app/assets/javascripts/performance_bar/components/detailed_metric.vue b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
index 9bf77239a6b..57569340aa5 100644
--- a/app/assets/javascripts/performance_bar/components/detailed_metric.vue
+++ b/app/assets/javascripts/performance_bar/components/detailed_metric.vue
@@ -1,5 +1,8 @@
<script>
-import { GlButton, GlModal, GlModalDirective } from '@gitlab/ui';
+import { GlButton, GlModal, GlModalDirective, GlSegmentedControl } from '@gitlab/ui';
+
+import { s__ } from '~/locale';
+import { sortOrders, sortOrderOptions } from '../constants';
import RequestWarning from './request_warning.vue';
export default {
@@ -7,6 +10,7 @@ export default {
RequestWarning,
GlButton,
GlModal,
+ GlSegmentedControl,
},
directives: {
'gl-modal': GlModalDirective,
@@ -39,6 +43,7 @@ export default {
data() {
return {
openedBacktraces: [],
+ sortOrder: sortOrders.DURATION,
};
},
computed: {
@@ -48,13 +53,37 @@ export default {
metricDetails() {
return this.currentRequest.details[this.metric];
},
+ metricDetailsSummary() {
+ return {
+ [s__('Total')]: this.metricDetails.calls,
+ [s__('PerformanceBar|Total duration')]: this.metricDetails.duration,
+ ...(this.metricDetails.summary || {}),
+ };
+ },
metricDetailsLabel() {
- return this.metricDetails.duration
- ? `${this.metricDetails.duration} / ${this.metricDetails.calls}`
- : this.metricDetails.calls;
+ if (this.metricDetails.duration && this.metricDetails.calls) {
+ return `${this.metricDetails.duration} / ${this.metricDetails.calls}`;
+ } else if (this.metricDetails.calls) {
+ return this.metricDetails.calls;
+ }
+
+ return '0';
+ },
+ displaySortOrder() {
+ return (
+ this.metricDetails.details.length !== 0 &&
+ this.metricDetails.details.every((item) => item.start)
+ );
},
detailsList() {
- return this.metricDetails.details;
+ return this.metricDetails.details.map((item, index) => ({ ...item, id: index }));
+ },
+ sortedList() {
+ if (this.sortOrder === sortOrders.CHRONOLOGICAL) {
+ return this.detailsList.slice().sort(this.sortDetailChronologically);
+ }
+
+ return this.detailsList.slice().sort(this.sortDetailByDuration);
},
warnings() {
return this.metricDetails.warnings || [];
@@ -82,7 +111,17 @@ export default {
itemHasOpenedBacktrace(toggledIndex) {
return this.openedBacktraces.find((openedIndex) => openedIndex === toggledIndex) >= 0;
},
+ changeSortOrder(order) {
+ this.sortOrder = order;
+ },
+ sortDetailByDuration(a, b) {
+ return a.duration < b.duration ? 1 : -1;
+ },
+ sortDetailChronologically(a, b) {
+ return a.start < b.start ? -1 : 1;
+ },
},
+ sortOrderOptions,
};
</script>
<template>
@@ -93,18 +132,41 @@ export default {
data-qa-selector="detailed_metric_content"
>
<gl-button v-gl-modal="modalId" class="gl-mr-2" type="button" variant="link">
- <span class="gl-text-blue-300 gl-font-weight-bold">{{ metricDetailsLabel }}</span>
+ <span
+ class="gl-text-blue-300 gl-font-weight-bold"
+ data-testid="performance-bar-details-label"
+ >
+ {{ metricDetailsLabel }}
+ </span>
</gl-button>
<gl-modal :modal-id="modalId" :title="header" size="lg" footer-class="d-none" scrollable>
+ <div class="gl-display-flex gl-align-items-center gl-justify-content-space-between">
+ <div class="gl-display-flex gl-align-items-center" data-testid="performance-bar-summary">
+ <div v-for="(value, name) in metricDetailsSummary" :key="name" class="gl-pr-8">
+ <div v-if="value" data-testid="performance-bar-summary-item">
+ <div>{{ name }}</div>
+ <div class="gl-font-size-h1 gl-font-weight-bold">{{ value }}</div>
+ </div>
+ </div>
+ </div>
+ <gl-segmented-control
+ v-if="displaySortOrder"
+ data-testid="performance-bar-sort-order"
+ :options="$options.sortOrderOptions"
+ :checked="sortOrder"
+ @input="changeSortOrder"
+ />
+ </div>
+ <hr />
<table class="table gl-table">
- <template v-if="detailsList.length">
- <tr v-for="(item, index) in detailsList" :key="index">
- <td>
+ <template v-if="sortedList.length">
+ <tr v-for="item in sortedList" :key="item.id">
+ <td data-testid="performance-item-duration">
<span v-if="item.duration">{{
sprintf(__('%{duration}ms'), { duration: item.duration })
}}</span>
</td>
- <td>
+ <td data-testid="performance-item-content">
<div>
<div
v-for="(key, keyIndex) in keys"
@@ -121,12 +183,12 @@ export default {
variant="default"
icon="ellipsis_h"
size="small"
- :selected="itemHasOpenedBacktrace(index)"
+ :selected="itemHasOpenedBacktrace(item.id)"
:aria-label="__('Toggle backtrace')"
- @click="toggleBacktrace(index)"
+ @click="toggleBacktrace(item.id)"
/>
</div>
- <pre v-if="itemHasOpenedBacktrace(index)" class="backtrace-row mt-2">{{
+ <pre v-if="itemHasOpenedBacktrace(item.id)" class="backtrace-row gl-mt-3">{{
item.backtrace
}}</pre>
</div>
@@ -135,7 +197,7 @@ export default {
</template>
<template v-else>
<tr>
- <td>
+ <td data-testid="performance-bar-empty-detail-notice">
{{ sprintf(__('No %{header} for this request.'), { header: header.toLowerCase() }) }}
</td>
</tr>
diff --git a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
index 6b446eb6073..4f79d99a49b 100644
--- a/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
+++ b/app/assets/javascripts/performance_bar/components/performance_bar_app.vue
@@ -40,7 +40,7 @@ export default {
metric: 'active-record',
title: 'pg',
header: s__('PerformanceBar|SQL queries'),
- keys: ['sql', 'cached', 'db_role'],
+ keys: ['sql', 'cached', 'transaction', 'db_role'],
},
{
metric: 'bullet',
@@ -69,6 +69,7 @@ export default {
},
{
metric: 'external-http',
+ title: 'external',
header: s__('PerformanceBar|External Http calls'),
keys: ['label', 'code', 'proxy', 'error'],
},
@@ -157,15 +158,17 @@ export default {
class="view"
>
<a class="gl-text-blue-300" :href="currentRequest.details.tracing.tracing_url">{{
- s__('PerformanceBar|trace')
+ s__('PerformanceBar|Trace')
}}</a>
</div>
- <add-request v-on="$listeners" />
<div v-if="currentRequest.details" id="peek-download" class="view">
<a class="gl-text-blue-300" :download="downloadName" :href="downloadPath">{{
s__('PerformanceBar|Download')
}}</a>
</div>
+ <a v-if="statsUrl" class="gl-text-blue-300 view" :href="statsUrl">{{
+ s__('PerformanceBar|Stats')
+ }}</a>
<request-selector
v-if="currentRequest"
:current-request="currentRequest"
@@ -173,9 +176,7 @@ export default {
class="ml-auto"
@change-current-request="changeCurrentRequest"
/>
- <div v-if="statsUrl" id="peek-stats" class="view">
- <a class="gl-text-blue-300" :href="statsUrl">{{ s__('PerformanceBar|Stats') }}</a>
- </div>
+ <add-request v-on="$listeners" />
</div>
</div>
</template>
diff --git a/app/assets/javascripts/performance_bar/constants.js b/app/assets/javascripts/performance_bar/constants.js
new file mode 100644
index 00000000000..9659383edd9
--- /dev/null
+++ b/app/assets/javascripts/performance_bar/constants.js
@@ -0,0 +1,17 @@
+import { s__ } from '~/locale';
+
+export const sortOrders = {
+ DURATION: 'duration',
+ CHRONOLOGICAL: 'chronological',
+};
+
+export const sortOrderOptions = [
+ {
+ value: sortOrders.DURATION,
+ text: s__('PerformanceBar|Sort by duration'),
+ },
+ {
+ value: sortOrders.CHRONOLOGICAL,
+ text: s__('PerformanceBar|Sort chronologically'),
+ },
+];