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:
Diffstat (limited to 'app/assets/javascripts')
-rw-r--r--app/assets/javascripts/boards/components/board_app.vue11
-rw-r--r--app/assets/javascripts/boards/components/boards_selector.vue28
-rw-r--r--app/assets/javascripts/boards/stores/actions.js7
-rw-r--r--app/assets/javascripts/boards/stores/mutation_types.js1
-rw-r--r--app/assets/javascripts/boards/stores/mutations.js6
-rw-r--r--app/assets/javascripts/boards/stores/state.js1
-rw-r--r--app/assets/javascripts/google_tag_manager/index.js8
-rw-r--r--app/assets/javascripts/ide/components/terminal/session.vue2
-rw-r--r--app/assets/javascripts/incidents_settings/components/pagerduty_form.vue24
-rw-r--r--app/assets/javascripts/issues/index.js2
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql21
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue73
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_list_item.vue71
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/timeline_events_tab.vue65
-rw-r--r--app/assets/javascripts/issues/show/components/incidents/utils.js18
-rw-r--r--app/assets/javascripts/issues/show/index.js2
-rw-r--r--app/assets/javascripts/monitoring/components/create_dashboard_modal.vue2
-rw-r--r--app/assets/javascripts/monitoring/components/dashboard_panel_builder.vue2
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/payload_downloader.js4
-rw-r--r--app/assets/javascripts/pages/admin/application_settings/payload_previewer.js6
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js9
-rw-r--r--app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js7
-rw-r--r--app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue30
-rw-r--r--app/assets/javascripts/runner/components/runner_details.vue20
24 files changed, 355 insertions, 65 deletions
diff --git a/app/assets/javascripts/boards/components/board_app.vue b/app/assets/javascripts/boards/components/board_app.vue
index 858aabb0f05..af753151be8 100644
--- a/app/assets/javascripts/boards/components/board_app.vue
+++ b/app/assets/javascripts/boards/components/board_app.vue
@@ -1,5 +1,6 @@
<script>
-import { mapActions, mapGetters } from 'vuex';
+import { mapGetters } from 'vuex';
+import { refreshCurrentPage } from '~/lib/utils/url_utility';
import BoardContent from '~/boards/components/board_content.vue';
import BoardSettingsSidebar from '~/boards/components/board_settings_sidebar.vue';
import BoardTopBar from '~/boards/components/board_top_bar.vue';
@@ -14,11 +15,11 @@ export default {
computed: {
...mapGetters(['isSidebarOpen']),
},
- mounted() {
- this.performSearch();
+ created() {
+ window.addEventListener('popstate', refreshCurrentPage);
},
- methods: {
- ...mapActions(['performSearch']),
+ destroyed() {
+ window.removeEventListener('popstate', refreshCurrentPage);
},
};
</script>
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue
index d7edaaa02d8..eaf3facb450 100644
--- a/app/assets/javascripts/boards/components/boards_selector.vue
+++ b/app/assets/javascripts/boards/components/boards_selector.vue
@@ -14,6 +14,8 @@ import { mapActions, mapGetters, mapState } from 'vuex';
import BoardForm from 'ee_else_ce/boards/components/board_form.vue';
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
+import { isMetaKey } from '~/lib/utils/common_utils';
+import { updateHistory } from '~/lib/utils/url_utility';
import { s__ } from '~/locale';
import eventHub from '../eventhub';
@@ -21,6 +23,7 @@ import groupBoardsQuery from '../graphql/group_boards.query.graphql';
import projectBoardsQuery from '../graphql/project_boards.query.graphql';
import groupRecentBoardsQuery from '../graphql/group_recent_boards.query.graphql';
import projectRecentBoardsQuery from '../graphql/project_recent_boards.query.graphql';
+import { fullBoardId } from '../boards_util';
const MIN_BOARDS_TO_VIEW_RECENT = 10;
@@ -112,6 +115,9 @@ export default {
this.scrollFadeInitialized = false;
this.$nextTick(this.setScrollFade);
},
+ board(newBoard) {
+ document.title = newBoard.name;
+ },
},
created() {
eventHub.$on('showBoardModal', this.showPage);
@@ -120,7 +126,7 @@ export default {
eventHub.$off('showBoardModal', this.showPage);
},
methods: {
- ...mapActions(['setError', 'setBoardConfig']),
+ ...mapActions(['setError', 'fetchBoard', 'unsetActiveId']),
showPage(page) {
this.currentPage = page;
},
@@ -196,6 +202,22 @@ export default {
this.hasScrollFade = this.isScrolledUp();
},
+ fetchCurrentBoard(boardId) {
+ this.fetchBoard({
+ fullPath: this.fullPath,
+ fullBoardId: fullBoardId(boardId),
+ boardType: this.boardType,
+ });
+ },
+ async switchBoard(boardId, e) {
+ if (isMetaKey(e)) {
+ window.open(`${this.boardBaseUrl}/${boardId}`, '_blank');
+ } else {
+ this.unsetActiveId();
+ this.fetchCurrentBoard(boardId);
+ updateHistory({ url: `${this.boardBaseUrl}/${boardId}` });
+ }
+ },
},
i18n: {
errorFetchingBoard: s__('Board|An error occurred while fetching the board, please try again.'),
@@ -242,8 +264,8 @@ export default {
<gl-dropdown-item
v-for="recentBoard in recentBoards"
:key="`recent-${recentBoard.id}`"
- :href="`${boardBaseUrl}/${recentBoard.id}`"
data-testid="dropdown-item"
+ @click.prevent="switchBoard(recentBoard.id, $event)"
>
{{ recentBoard.name }}
</gl-dropdown-item>
@@ -258,8 +280,8 @@ export default {
<gl-dropdown-item
v-for="otherBoard in filteredBoards"
:key="otherBoard.id"
- :href="`${boardBaseUrl}/${otherBoard.id}`"
data-testid="dropdown-item"
+ @click.prevent="switchBoard(otherBoard.id, $event)"
>
{{ otherBoard.name }}
</gl-dropdown-item>
diff --git a/app/assets/javascripts/boards/stores/actions.js b/app/assets/javascripts/boards/stores/actions.js
index d319e659ac0..791182af806 100644
--- a/app/assets/javascripts/boards/stores/actions.js
+++ b/app/assets/javascripts/boards/stores/actions.js
@@ -68,8 +68,7 @@ export default {
commit(types.RECEIVE_BOARD_FAILURE);
} else {
const board = data.workspace?.board;
- commit(types.RECEIVE_BOARD_SUCCESS, board);
- dispatch('setBoardConfig', board);
+ dispatch('setBoard', board);
}
})
.catch(() => commit(types.RECEIVE_BOARD_FAILURE));
@@ -420,9 +419,6 @@ export default {
fetchItemsForList: ({ state, commit }, { listId, fetchNext = false }) => {
if (!listId) return null;
- if (!fetchNext) {
- commit(types.RESET_ITEMS_FOR_LIST, listId);
- }
commit(types.REQUEST_ITEMS_FOR_LIST, { listId, fetchNext });
const { fullPath, fullBoardId, boardType, filterParams } = state;
@@ -444,6 +440,7 @@ export default {
isSingleRequest: true,
},
variables,
+ ...(!fetchNext ? { fetchPolicy: fetchPolicies.NO_CACHE } : {}),
})
.then(({ data }) => {
const { lists } = data[boardType].board;
diff --git a/app/assets/javascripts/boards/stores/mutation_types.js b/app/assets/javascripts/boards/stores/mutation_types.js
index 96ab302c98f..43268f21f96 100644
--- a/app/assets/javascripts/boards/stores/mutation_types.js
+++ b/app/assets/javascripts/boards/stores/mutation_types.js
@@ -18,7 +18,6 @@ export const MOVE_LISTS = 'MOVE_LISTS';
export const TOGGLE_LIST_COLLAPSED = 'TOGGLE_LIST_COLLAPSED';
export const REMOVE_LIST = 'REMOVE_LIST';
export const REMOVE_LIST_FAILURE = 'REMOVE_LIST_FAILURE';
-export const RESET_ITEMS_FOR_LIST = 'RESET_ITEMS_FOR_LIST';
export const REQUEST_ITEMS_FOR_LIST = 'REQUEST_ITEMS_FOR_LIST';
export const RECEIVE_ITEMS_FOR_LIST_FAILURE = 'RECEIVE_ITEMS_FOR_LIST_FAILURE';
export const RECEIVE_ITEMS_FOR_LIST_SUCCESS = 'RECEIVE_ITEMS_FOR_LIST_SUCCESS';
diff --git a/app/assets/javascripts/boards/stores/mutations.js b/app/assets/javascripts/boards/stores/mutations.js
index 6dda0e2af8b..04e7d3643e7 100644
--- a/app/assets/javascripts/boards/stores/mutations.js
+++ b/app/assets/javascripts/boards/stores/mutations.js
@@ -145,11 +145,6 @@ export default {
state.boardLists = listsBackup;
},
- [mutationTypes.RESET_ITEMS_FOR_LIST]: (state, listId) => {
- Vue.set(state, 'backupItemsList', state.boardItemsByListId[listId]);
- Vue.set(state.boardItemsByListId, listId, []);
- },
-
[mutationTypes.REQUEST_ITEMS_FOR_LIST]: (state, { listId, fetchNext }) => {
Vue.set(state.listsFlags, listId, { [fetchNext ? 'isLoadingMore' : 'isLoading']: true });
},
@@ -185,7 +180,6 @@ export default {
'Boards|An error occurred while fetching the board issues. Please reload the page.',
);
Vue.set(state.listsFlags, listId, { isLoading: false, isLoadingMore: false });
- Vue.set(state.boardItemsByListId, listId, state.backupItemsList);
},
[mutationTypes.RESET_ISSUES]: (state) => {
diff --git a/app/assets/javascripts/boards/stores/state.js b/app/assets/javascripts/boards/stores/state.js
index 02275e40703..b62c032b921 100644
--- a/app/assets/javascripts/boards/stores/state.js
+++ b/app/assets/javascripts/boards/stores/state.js
@@ -13,7 +13,6 @@ export default () => ({
boardLists: {},
listsFlags: {},
boardItemsByListId: {},
- backupItemsList: [],
isSettingAssignees: false,
pageInfoByListId: {},
boardItems: {},
diff --git a/app/assets/javascripts/google_tag_manager/index.js b/app/assets/javascripts/google_tag_manager/index.js
index a44a5b30e1e..2969121bf06 100644
--- a/app/assets/javascripts/google_tag_manager/index.js
+++ b/app/assets/javascripts/google_tag_manager/index.js
@@ -19,6 +19,7 @@ const PRODUCT_INFO = {
variant: 'SaaS',
},
};
+const EMPTY_NAMESPACE_ID_VALUE = 'not available';
const generateProductInfo = (sku, quantity) => {
const product = PRODUCT_INFO[sku];
@@ -200,6 +201,10 @@ export const trackCheckout = (selectedPlan, quantity) => {
pushEnhancedEcommerceEvent('EECCheckout', eventData);
};
+export const getNamespaceId = () => {
+ return window.gl.snowplowStandardContext?.data?.namespace_id || EMPTY_NAMESPACE_ID_VALUE;
+};
+
export const trackTransaction = (transactionDetails) => {
if (!isSupported()) {
return;
@@ -208,6 +213,7 @@ export const trackTransaction = (transactionDetails) => {
const transactionId = uuidv4();
const { paymentOption, revenue, tax, selectedPlan, quantity } = transactionDetails;
const product = generateProductInfo(selectedPlan, quantity);
+ const namespaceId = getNamespaceId();
if (Object.keys(product).length === 0) {
return;
@@ -224,7 +230,7 @@ export const trackTransaction = (transactionDetails) => {
revenue: revenue.toString(),
tax: tax.toString(),
},
- products: [product],
+ products: [{ ...product, dimension36: namespaceId }],
},
},
};
diff --git a/app/assets/javascripts/ide/components/terminal/session.vue b/app/assets/javascripts/ide/components/terminal/session.vue
index 3a4128b6207..384e27844c6 100644
--- a/app/assets/javascripts/ide/components/terminal/session.vue
+++ b/app/assets/javascripts/ide/components/terminal/session.vue
@@ -16,7 +16,7 @@ export default {
if (isEndingStatus(this.session.status)) {
return {
action: () => this.restartSession(),
- variant: 'info',
+ variant: 'confirm',
category: 'primary',
text: __('Restart Terminal'),
};
diff --git a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
index 866d2ff399e..e8c9aa53a7c 100644
--- a/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
+++ b/app/assets/javascripts/incidents_settings/components/pagerduty_form.vue
@@ -11,6 +11,7 @@ import {
GlModal,
GlModalDirective,
} from '@gitlab/ui';
+import { __ } from '~/locale';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import { I18N_PAGERDUTY_SETTINGS_FORM, CONFIGURE_PAGERDUTY_WEBHOOK_DOCS_LINK } from '../constants';
@@ -42,6 +43,21 @@ export default {
};
},
i18n: I18N_PAGERDUTY_SETTINGS_FORM,
+ modal: {
+ id: 'resetWebhookModal',
+ actionPrimary: {
+ text: I18N_PAGERDUTY_SETTINGS_FORM.webhookUrl.resetWebhookUrl,
+ attributes: {
+ variant: 'danger',
+ },
+ },
+ actionCancel: {
+ text: __('Cancel'),
+ attributes: {
+ variant: 'default',
+ },
+ },
+ },
CONFIGURE_PAGERDUTY_WEBHOOK_DOCS_LINK,
computed: {
formData() {
@@ -152,11 +168,11 @@ export default {
{{ $options.i18n.webhookUrl.resetWebhookUrl }}
</gl-button>
<gl-modal
- modal-id="resetWebhookModal"
+ :modal-id="$options.modal.id"
:title="$options.i18n.webhookUrl.resetWebhookUrl"
- :ok-title="$options.i18n.webhookUrl.resetWebhookUrl"
- ok-variant="danger"
- @ok="resetWebhookUrl"
+ :action-primary="$options.modal.actionPrimary"
+ :action-cancel="$options.modal.actionCancel"
+ @primary="resetWebhookUrl"
>
{{ $options.i18n.webhookUrl.restKeyInfo }}
</gl-modal>
diff --git a/app/assets/javascripts/issues/index.js b/app/assets/javascripts/issues/index.js
index 1b5e2824879..67c6c723dcc 100644
--- a/app/assets/javascripts/issues/index.js
+++ b/app/assets/javascripts/issues/index.js
@@ -57,7 +57,7 @@ export function initShow() {
const { issueType, ...issuableData } = parseIssuableData(el);
if (issueType === IssueType.Incident) {
- initIncidentApp(issuableData);
+ initIncidentApp({ ...issuableData, issuableId: el.dataset.issuableId });
initHeaderActions(store, IssueType.Incident);
initRelatedIssues(IssueType.Incident);
} else {
diff --git a/app/assets/javascripts/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql b/app/assets/javascripts/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql
new file mode 100644
index 00000000000..7e049d98c1a
--- /dev/null
+++ b/app/assets/javascripts/issues/show/components/incidents/graphql/queries/get_timeline_events.query.graphql
@@ -0,0 +1,21 @@
+query GetTimelineEvents($fullPath: ID!, $incidentId: IssueID!) {
+ project(fullPath: $fullPath) {
+ id
+ incidentManagementTimelineEvents(incidentId: $incidentId) {
+ nodes {
+ id
+ author {
+ id
+ name
+ username
+ }
+ note
+ noteHtml
+ action
+ occurredAt
+ createdAt
+ updatedAt
+ }
+ }
+ }
+}
diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue
new file mode 100644
index 00000000000..a6e58ee0bdc
--- /dev/null
+++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_list.vue
@@ -0,0 +1,73 @@
+<script>
+import { formatDate } from '~/lib/utils/datetime_utility';
+import IncidentTimelineEventListItem from './timeline_events_list_item.vue';
+
+export default {
+ name: 'IncidentTimelineEventList',
+ components: {
+ IncidentTimelineEventListItem,
+ },
+ props: {
+ timelineEventLoading: {
+ type: Boolean,
+ required: false,
+ default: true,
+ },
+ timelineEvents: {
+ type: Array,
+ required: true,
+ default: () => [],
+ },
+ },
+ computed: {
+ dateGroupedEvents() {
+ const groupedEvents = new Map();
+
+ this.timelineEvents.forEach((event) => {
+ const date = formatDate(event.occurredAt, 'isoDate', true);
+
+ if (groupedEvents.has(date)) {
+ groupedEvents.get(date).push(event);
+ } else {
+ groupedEvents.set(date, [event]);
+ }
+ });
+
+ return groupedEvents;
+ },
+ },
+ methods: {
+ isLastItem(groups, groupIndex, events, eventIndex) {
+ if (groupIndex < groups.size - 1) {
+ return false;
+ }
+ return eventIndex === events.length - 1;
+ },
+ },
+};
+</script>
+
+<template>
+ <div class="issuable-discussion incident-timeline-events">
+ <div
+ v-for="([eventDate, events], groupIndex) in dateGroupedEvents"
+ :key="eventDate"
+ data-testid="timeline-group"
+ >
+ <div class="gl-pb-3 gl-border-gray-50 gl-border-1 gl-border-b-solid">
+ <strong class="gl-font-size-h2" data-testid="event-date">{{ eventDate }}</strong>
+ </div>
+ <ul class="notes main-notes-list gl-pl-n3">
+ <incident-timeline-event-list-item
+ v-for="(event, eventIndex) in events"
+ :key="event.id"
+ :action="event.action"
+ :occurred-at="event.occurredAt"
+ :note-html="event.noteHtml"
+ :is-last-item="isLastItem(dateGroupedEvents, groupIndex, events, eventIndex)"
+ data-testid="timeline-event"
+ />
+ </ul>
+ </div>
+ </div>
+</template>
diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_list_item.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_list_item.vue
new file mode 100644
index 00000000000..fef9bf713b7
--- /dev/null
+++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_list_item.vue
@@ -0,0 +1,71 @@
+<script>
+import { GlIcon, GlSafeHtmlDirective, GlSprintf } from '@gitlab/ui';
+import { formatDate } from '~/lib/utils/datetime_utility';
+import { __ } from '~/locale';
+import { getEventIcon } from './utils';
+
+export default {
+ name: 'IncidentTimelineEventListItem',
+ i18n: {
+ timeUTC: __('%{time} UTC'),
+ },
+ components: {
+ GlIcon,
+ GlSprintf,
+ },
+ directives: {
+ SafeHtml: GlSafeHtmlDirective,
+ },
+ props: {
+ isLastItem: {
+ type: Boolean,
+ required: true,
+ },
+ occurredAt: {
+ type: String,
+ required: true,
+ },
+ action: {
+ type: String,
+ required: true,
+ },
+ noteHtml: {
+ type: String,
+ required: true,
+ },
+ },
+ computed: {
+ time() {
+ return formatDate(this.occurredAt, 'HH:MM', true);
+ },
+ },
+ methods: {
+ getEventIcon,
+ },
+};
+</script>
+<template>
+ <li
+ class="timeline-entry timeline-entry-vertical-line note system-note note-wrapper gl-my-2! gl-pr-0!"
+ >
+ <div class="gl-display-flex gl-align-items-center">
+ <div
+ class="gl-display-flex gl-align-items-center gl-justify-content-center gl-bg-white gl-text-gray-200 gl-border-gray-100 gl-border-1 gl-border-solid gl-rounded-full gl-mt-n2 gl-mr-3 gl-w-8 gl-h-8 gl-p-3 gl-z-index-1"
+ >
+ <gl-icon :name="getEventIcon(action)" class="note-icon" />
+ </div>
+ <div
+ class="timeline-event-note gl-w-full"
+ :class="{ 'gl-pb-3 gl-border-gray-50 gl-border-1 gl-border-b-solid': !isLastItem }"
+ data-testid="event-text-container"
+ >
+ <strong class="gl-font-lg" data-testid="event-time">
+ <gl-sprintf :message="$options.i18n.timeUTC">
+ <template #time>{{ time }}</template>
+ </gl-sprintf>
+ </strong>
+ <div v-safe-html="noteHtml"></div>
+ </div>
+ </div>
+ </li>
+</template>
diff --git a/app/assets/javascripts/issues/show/components/incidents/timeline_events_tab.vue b/app/assets/javascripts/issues/show/components/incidents/timeline_events_tab.vue
index ec101fd943f..400e1f0b725 100644
--- a/app/assets/javascripts/issues/show/components/incidents/timeline_events_tab.vue
+++ b/app/assets/javascripts/issues/show/components/incidents/timeline_events_tab.vue
@@ -1,21 +1,70 @@
<script>
-import { GlTab, GlButton } from '@gitlab/ui';
+import { GlEmptyState, GlLoadingIcon, GlTab } from '@gitlab/ui';
+import { convertToGraphQLId } from '~/graphql_shared/utils';
+import { TYPE_ISSUE } from '~/graphql_shared/constants';
+import { fetchPolicies } from '~/lib/graphql';
+import getTimelineEvents from './graphql/queries/get_timeline_events.query.graphql';
+import { displayAndLogError } from './utils';
+
+import IncidentTimelineEventsList from './timeline_events_list.vue';
export default {
components: {
+ GlEmptyState,
+ GlLoadingIcon,
GlTab,
- GlButton,
+ IncidentTimelineEventsList,
+ },
+ inject: ['fullPath', 'issuableId'],
+ data() {
+ return {
+ timelineEvents: [],
+ };
+ },
+ apollo: {
+ timelineEvents: {
+ fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
+ query: getTimelineEvents,
+ variables() {
+ return {
+ fullPath: this.fullPath,
+ incidentId: convertToGraphQLId(TYPE_ISSUE, this.issuableId),
+ };
+ },
+ update(data) {
+ return data.project.incidentManagementTimelineEvents.nodes;
+ },
+ error(error) {
+ displayAndLogError(error);
+ },
+ },
+ },
+ computed: {
+ timelineEventLoading() {
+ return this.$apollo.queries.timelineEvents.loading;
+ },
+ hasTimelineEvents() {
+ return Boolean(this.timelineEvents.length);
+ },
+ showEmptyState() {
+ return !this.timelineEventLoading && !this.hasTimelineEvents;
+ },
},
};
</script>
<template>
<gl-tab :title="s__('Incident|Timeline')">
- <div class="gl-my-4">
- <p>{{ s__('Incident|No timeline items have been added yet.') }}</p>
- </div>
- <gl-button class="gl-my-3">
- {{ s__('Incident|Add new timeline event') }}
- </gl-button>
+ <gl-loading-icon v-if="timelineEventLoading" size="lg" color="dark" class="gl-mt-5" />
+ <gl-empty-state
+ v-else-if="showEmptyState"
+ :compact="true"
+ :description="s__('Incident|No timeline items have been added yet.')"
+ />
+ <incident-timeline-events-list
+ v-if="hasTimelineEvents"
+ :timeline-event-loading="timelineEventLoading"
+ :timeline-events="timelineEvents"
+ />
</gl-tab>
</template>
diff --git a/app/assets/javascripts/issues/show/components/incidents/utils.js b/app/assets/javascripts/issues/show/components/incidents/utils.js
new file mode 100644
index 00000000000..8b5a2ec4031
--- /dev/null
+++ b/app/assets/javascripts/issues/show/components/incidents/utils.js
@@ -0,0 +1,18 @@
+import { createAlert } from '~/flash';
+import { s__ } from '~/locale';
+
+export const displayAndLogError = (error) =>
+ createAlert({
+ message: s__('Incident|Something went wrong while fetching incident timeline events.'),
+ captureError: true,
+ error,
+ });
+
+const EVENT_ICONS = {
+ comment: 'comment',
+ default: 'comment',
+};
+
+export const getEventIcon = (actionName) => {
+ return EVENT_ICONS[actionName] ?? EVENT_ICONS.default;
+};
diff --git a/app/assets/javascripts/issues/show/index.js b/app/assets/javascripts/issues/show/index.js
index 3f149e39c4e..5bdad010af7 100644
--- a/app/assets/javascripts/issues/show/index.js
+++ b/app/assets/javascripts/issues/show/index.js
@@ -33,6 +33,7 @@ export function initIncidentApp(issueData = {}) {
canCreateIncident,
canUpdate,
iid,
+ issuableId,
projectNamespace,
projectPath,
projectId,
@@ -53,6 +54,7 @@ export function initIncidentApp(issueData = {}) {
canUpdate,
fullPath,
iid,
+ issuableId,
projectId,
slaFeatureAvailable: parseBoolean(slaFeatureAvailable),
uploadMetricsFeatureAvailable: parseBoolean(uploadMetricsFeatureAvailable),
diff --git a/app/assets/javascripts/monitoring/components/create_dashboard_modal.vue b/app/assets/javascripts/monitoring/components/create_dashboard_modal.vue
index 288487d25a5..10178366db5 100644
--- a/app/assets/javascripts/monitoring/components/create_dashboard_modal.vue
+++ b/app/assets/javascripts/monitoring/components/create_dashboard_modal.vue
@@ -47,7 +47,7 @@ export default {
<gl-button category="secondary" @click="cancelHandler">{{ s__('Metrics|Cancel') }}</gl-button>
<gl-button
category="secondary"
- variant="info"
+ variant="confirm"
target="_blank"
:href="addDashboardDocumentationPath"
data-testid="create-dashboard-modal-docs-button"
diff --git a/app/assets/javascripts/monitoring/components/dashboard_panel_builder.vue b/app/assets/javascripts/monitoring/components/dashboard_panel_builder.vue
index ec35d8d3aca..8efea2bfc3e 100644
--- a/app/assets/javascripts/monitoring/components/dashboard_panel_builder.vue
+++ b/app/assets/javascripts/monitoring/components/dashboard_panel_builder.vue
@@ -162,7 +162,7 @@ export default {
ref="viewDocumentationBtn"
category="secondary"
class="gl-xs-w-full gl-xs-mb-3"
- variant="info"
+ variant="confirm"
target="_blank"
:href="addDashboardDocumentationPath"
>
diff --git a/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js b/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
index 7c81cf80dc6..8cecc1d3ef7 100644
--- a/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
+++ b/app/assets/javascripts/pages/admin/application_settings/payload_downloader.js
@@ -19,7 +19,7 @@ export default class PayloadDownloader {
}
requestPayload() {
- this.spinner.classList.add('d-inline-flex');
+ this.spinner.classList.add('gl-display-inline');
return axios
.get(this.trigger.dataset.endpoint, {
@@ -34,7 +34,7 @@ export default class PayloadDownloader {
});
})
.finally(() => {
- this.spinner.classList.remove('d-inline-flex');
+ this.spinner.classList.remove('gl-display-inline');
});
}
diff --git a/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js b/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
index ae08806fe4c..84027203783 100644
--- a/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
+++ b/app/assets/javascripts/pages/admin/application_settings/payload_previewer.js
@@ -29,7 +29,7 @@ export default class PayloadPreviewer {
requestPayload() {
if (this.isInserted) return this.showPayload();
- this.spinner.classList.add('gl-display-inline-flex');
+ this.spinner.classList.add('gl-display-inline');
const container = this.getContainer();
@@ -38,11 +38,11 @@ export default class PayloadPreviewer {
responseType: 'text',
})
.then(({ data }) => {
- this.spinner.classList.remove('gl-display-inline-flex');
+ this.spinner.classList.remove('gl-display-inline');
this.insertPayload(data);
})
.catch(() => {
- this.spinner.classList.remove('gl-display-inline-flex');
+ this.spinner.classList.remove('gl-display-inline');
createFlash({
message: __('Error fetching payload data.'),
});
diff --git a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js
index d61209f904d..2d26d3922bf 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare.js
@@ -4,7 +4,8 @@ import { localTimeAgo } from '~/lib/utils/datetime_utility';
import initCompareAutocomplete from './compare_autocomplete';
import initTargetProjectDropdown from './target_project_dropdown';
-const updateCommitList = (url, $loadingIndicator, $commitList, params) => {
+const updateCommitList = (url, $emptyState, $loadingIndicator, $commitList, params) => {
+ $emptyState.hide();
$loadingIndicator.show();
$commitList.empty();
@@ -16,6 +17,10 @@ const updateCommitList = (url, $loadingIndicator, $commitList, params) => {
$loadingIndicator.hide();
$commitList.html(data);
localTimeAgo($commitList.get(0).querySelectorAll('.js-timeago'));
+
+ if (!data) {
+ $emptyState.show();
+ }
});
};
@@ -26,6 +31,7 @@ export default (mrNewCompareNode) => {
const updateSourceBranchCommitList = () =>
updateCommitList(
sourceBranchUrl,
+ $(mrNewCompareNode).find('.js-source-commit-empty'),
$(mrNewCompareNode).find('.js-source-loading'),
$(mrNewCompareNode).find('.mr_source_commit'),
{
@@ -35,6 +41,7 @@ export default (mrNewCompareNode) => {
const updateTargetBranchCommitList = () =>
updateCommitList(
targetBranchUrl,
+ $(mrNewCompareNode).find('.js-target-commit-empty'),
$(mrNewCompareNode).find('.js-target-loading'),
$(mrNewCompareNode).find('.mr_target_commit'),
{
diff --git a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
index e5f97530c02..9a38c2cc765 100644
--- a/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
+++ b/app/assets/javascripts/pages/projects/merge_requests/creations/new/compare_autocomplete.js
@@ -12,6 +12,7 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = (
$('.js-compare-dropdown').each(function () {
const $dropdown = $(this);
const selected = $dropdown.data('selected');
+ const defaultText = $dropdown.data('defaultText').trim();
const $dropdownContainer = $dropdown.closest('.dropdown');
const $fieldInput = $(`input[name="${$dropdown.data('fieldName')}"]`, $dropdownContainer);
const $filterInput = $('input[type="search"]', $dropdownContainer);
@@ -63,7 +64,11 @@ export default function initCompareAutocomplete(limitTo = null, clickHandler = (
return $el.attr('data-ref');
},
toggleLabel(obj, $el) {
- return $el.text().trim();
+ if ($el.hasClass('is-active')) {
+ return $el.text().trim();
+ }
+
+ return defaultText;
},
clicked: () => clickHandler($dropdown),
});
diff --git a/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue b/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue
index c3f317b40b0..06a8eb790fc 100644
--- a/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue
+++ b/app/assets/javascripts/runner/admin_runner_show/admin_runner_show_app.vue
@@ -1,14 +1,16 @@
<script>
-import { GlTooltipDirective } from '@gitlab/ui';
+import { GlBadge, GlTab, GlTooltipDirective } from '@gitlab/ui';
import { createAlert, VARIANT_SUCCESS } from '~/flash';
import { TYPE_CI_RUNNER } from '~/graphql_shared/constants';
import { convertToGraphQLId } from '~/graphql_shared/utils';
import { redirectTo } from '~/lib/utils/url_utility';
+import { formatJobCount } from '../utils';
import RunnerDeleteButton from '../components/runner_delete_button.vue';
import RunnerEditButton from '../components/runner_edit_button.vue';
import RunnerPauseButton from '../components/runner_pause_button.vue';
import RunnerHeader from '../components/runner_header.vue';
import RunnerDetails from '../components/runner_details.vue';
+import RunnerJobs from '../components/runner_jobs.vue';
import { I18N_FETCH_ERROR } from '../constants';
import runnerQuery from '../graphql/show/runner.query.graphql';
import { captureException } from '../sentry_utils';
@@ -17,11 +19,14 @@ import { saveAlertToLocalStorage } from '../local_storage_alert/save_alert_to_lo
export default {
name: 'AdminRunnerShowApp',
components: {
+ GlBadge,
+ GlTab,
RunnerDeleteButton,
RunnerEditButton,
RunnerPauseButton,
RunnerHeader,
RunnerDetails,
+ RunnerJobs,
},
directives: {
GlTooltip: GlTooltipDirective,
@@ -63,6 +68,9 @@ export default {
canDelete() {
return this.runner.userPermissions?.deleteRunner;
},
+ jobCount() {
+ return formatJobCount(this.runner?.jobCount);
+ },
},
errorCaptured(error) {
this.reportToSentry(error);
@@ -88,6 +96,24 @@ export default {
</template>
</runner-header>
- <runner-details :runner="runner" />
+ <runner-details :runner="runner">
+ <template #jobs-tab>
+ <gl-tab>
+ <template #title>
+ {{ s__('Runners|Jobs') }}
+ <gl-badge
+ v-if="jobCount"
+ data-testid="job-count-badge"
+ class="gl-tab-counter-badge"
+ size="sm"
+ >
+ {{ jobCount }}
+ </gl-badge>
+ </template>
+
+ <runner-jobs v-if="runner" :runner="runner" />
+ </gl-tab>
+ </template>
+ </runner-details>
</div>
</template>
diff --git a/app/assets/javascripts/runner/components/runner_details.vue b/app/assets/javascripts/runner/components/runner_details.vue
index fbe08e93d71..75ddec6c716 100644
--- a/app/assets/javascripts/runner/components/runner_details.vue
+++ b/app/assets/javascripts/runner/components/runner_details.vue
@@ -1,19 +1,16 @@
<script>
-import { GlBadge, GlTabs, GlTab, GlIntersperse } from '@gitlab/ui';
+import { GlTabs, GlTab, GlIntersperse } from '@gitlab/ui';
import { s__ } from '~/locale';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
import { timeIntervalInWords } from '~/lib/utils/datetime_utility';
import { ACCESS_LEVEL_REF_PROTECTED, GROUP_TYPE, PROJECT_TYPE } from '../constants';
-import { formatJobCount } from '../utils';
import RunnerDetail from './runner_detail.vue';
import RunnerGroups from './runner_groups.vue';
import RunnerProjects from './runner_projects.vue';
-import RunnerJobs from './runner_jobs.vue';
import RunnerTags from './runner_tags.vue';
export default {
components: {
- GlBadge,
GlTabs,
GlTab,
GlIntersperse,
@@ -22,7 +19,6 @@ export default {
import('ee_component/runner/components/runner_maintenance_note_detail.vue'),
RunnerGroups,
RunnerProjects,
- RunnerJobs,
RunnerTags,
TimeAgo,
},
@@ -59,9 +55,6 @@ export default {
isProjectRunner() {
return this.runner?.runnerType === PROJECT_TYPE;
},
- jobCount() {
- return formatJobCount(this.runner?.jobCount);
- },
},
ACCESS_LEVEL_REF_PROTECTED,
};
@@ -120,15 +113,6 @@ export default {
<runner-projects v-if="isProjectRunner" :runner="runner" />
</template>
</gl-tab>
- <gl-tab>
- <template #title>
- {{ s__('Runners|Jobs') }}
- <gl-badge v-if="jobCount" data-testid="job-count-badge" class="gl-ml-1" size="sm">
- {{ jobCount }}
- </gl-badge>
- </template>
-
- <runner-jobs v-if="runner" :runner="runner" />
- </gl-tab>
+ <slot name="jobs-tab"></slot>
</gl-tabs>
</template>