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
path: root/app
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-06-14 15:08:53 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-06-14 15:08:53 +0300
commit7a124e225ea58c2a432dd29f82ba682963886383 (patch)
tree4ad5eefec173bdc56aaacc81e4dfb66a8fb9e254 /app
parent067b3d04573d1473dbc6c81ef775d70c6636ff3f (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'app')
-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
-rw-r--r--app/assets/stylesheets/framework/buttons.scss8
-rw-r--r--app/assets/stylesheets/framework/secondary_navigation_elements.scss23
-rw-r--r--app/assets/stylesheets/framework/variables.scss1
-rw-r--r--app/assets/stylesheets/page_bundles/merge_requests.scss2
-rw-r--r--app/assets/stylesheets/pages/groups.scss4
-rw-r--r--app/assets/stylesheets/pages/issuable.scss55
-rw-r--r--app/assets/stylesheets/pages/merge_requests.scss5
-rw-r--r--app/assets/stylesheets/themes/_dark.scss1
-rw-r--r--app/models/key.rb22
-rw-r--r--app/models/project.rb11
-rw-r--r--app/uploaders/metric_image_uploader.rb4
-rw-r--r--app/views/admin/application_settings/_account_and_limit.html.haml2
-rw-r--r--app/views/admin/application_settings/_ci_cd.html.haml4
-rw-r--r--app/views/admin/application_settings/_floc.html.haml2
-rw-r--r--app/views/admin/application_settings/_kroki.html.haml2
-rw-r--r--app/views/admin/application_settings/_package_registry.html.haml2
-rw-r--r--app/views/admin/application_settings/_signin.html.haml2
-rw-r--r--app/views/admin/application_settings/_sourcegraph.html.haml2
-rw-r--r--app/views/admin/application_settings/_terms.html.haml2
-rw-r--r--app/views/admin/application_settings/service_usage_data.html.haml12
-rw-r--r--app/views/admin/dashboard/index.html.haml1
-rw-r--r--app/views/admin/jobs/index.html.haml11
-rw-r--r--app/views/admin/projects/index.html.haml18
-rw-r--r--app/views/dashboard/_projects_head.html.haml9
-rw-r--r--app/views/dashboard/_projects_nav.html.haml2
-rw-r--r--app/views/explore/topics/_head.html.haml9
-rw-r--r--app/views/kaminari/gitlab/_next_page.html.haml2
-rw-r--r--app/views/kaminari/gitlab/_prev_page.html.haml2
-rw-r--r--app/views/projects/commits/_commits.html.haml4
-rw-r--r--app/views/projects/merge_requests/creations/_new_compare.html.haml26
-rw-r--r--app/views/shared/_label.html.haml10
-rw-r--r--app/views/shared/builds/_tabs.html.haml2
-rw-r--r--app/views/shared/issue_type/_details_content.html.haml2
57 files changed, 539 insertions, 145 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>
diff --git a/app/assets/stylesheets/framework/buttons.scss b/app/assets/stylesheets/framework/buttons.scss
index 13db3677cab..5fa1923af7c 100644
--- a/app/assets/stylesheets/framework/buttons.scss
+++ b/app/assets/stylesheets/framework/buttons.scss
@@ -175,10 +175,6 @@
@include btn-outline($white, $red-500, $red-500, $red-100, $red-700, $red-500, $red-200, $red-600, $red-800);
}
- &.btn-warning {
- @include btn-outline($white, $orange-500, $orange-500, $orange-50, $orange-600, $orange-600, $orange-100, $orange-700, $orange-700);
- }
-
&.btn-primary,
&.btn-info {
@include btn-outline($white, $blue-500, $blue-500, $blue-100, $blue-700, $blue-500, $blue-200, $blue-600, $blue-800);
@@ -190,10 +186,6 @@
@include btn-blue;
}
- &.btn-warning {
- @include btn-orange;
- }
-
&.btn-danger {
@include btn-red;
}
diff --git a/app/assets/stylesheets/framework/secondary_navigation_elements.scss b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
index 549b61aedae..74aed1bd984 100644
--- a/app/assets/stylesheets/framework/secondary_navigation_elements.scss
+++ b/app/assets/stylesheets/framework/secondary_navigation_elements.scss
@@ -273,6 +273,18 @@
@include scrolling-links();
}
+ .fade-left::after,
+ .fade-right::after {
+ content: '';
+ pointer-events: none;
+ z-index: -1;
+ display: block;
+ width: 16px;
+ height: 100%;
+ position: absolute;
+ top: 0;
+ }
+
.fade-right {
@include fade(left, $gray-light);
right: -5px;
@@ -280,6 +292,11 @@
svg {
right: -7px;
}
+
+ &::after {
+ right: 0;
+ background: linear-gradient(270deg, $white, transparent);
+ }
}
.fade-left {
@@ -290,6 +307,11 @@
svg {
left: -7px;
}
+
+ &::after {
+ left: 0;
+ background: linear-gradient(90deg, $white, transparent);
+ }
}
}
@@ -316,7 +338,6 @@
.fade-right,
.fade-left {
- bottom: $gl-padding;
top: auto;
}
diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss
index 715ba48ab6d..c9bc1c9189e 100644
--- a/app/assets/stylesheets/framework/variables.scss
+++ b/app/assets/stylesheets/framework/variables.scss
@@ -428,7 +428,6 @@ $gl-padding-12: 12px;
$gl-padding: 16px;
$gl-padding-24: 24px;
$gl-padding-32: 32px;
-$gl-padding-50: 50px;
$gl-input-padding: 10px;
$gl-vert-padding: 6px;
$gl-padding-top: 10px;
diff --git a/app/assets/stylesheets/page_bundles/merge_requests.scss b/app/assets/stylesheets/page_bundles/merge_requests.scss
index 76f84331790..3356285dd41 100644
--- a/app/assets/stylesheets/page_bundles/merge_requests.scss
+++ b/app/assets/stylesheets/page_bundles/merge_requests.scss
@@ -315,7 +315,7 @@ $tabs-holder-z-index: 250;
}
.mr-fast-forward-message {
- padding-left: $gl-padding-50;
+ padding-left: $gl-spacing-scale-9;
padding-bottom: $gl-padding;
}
diff --git a/app/assets/stylesheets/pages/groups.scss b/app/assets/stylesheets/pages/groups.scss
index 7ac3ef2221f..9106ecaa81d 100644
--- a/app/assets/stylesheets/pages/groups.scss
+++ b/app/assets/stylesheets/pages/groups.scss
@@ -40,8 +40,8 @@
}
.save-group-loader {
- margin-top: $gl-padding-50;
- margin-bottom: $gl-padding-50;
+ margin-top: $gl-spacing-scale-9;
+ margin-bottom: $gl-spacing-scale-9;
color: $gray-700;
}
diff --git a/app/assets/stylesheets/pages/issuable.scss b/app/assets/stylesheets/pages/issuable.scss
index 387970e06ae..f3182af3047 100644
--- a/app/assets/stylesheets/pages/issuable.scss
+++ b/app/assets/stylesheets/pages/issuable.scss
@@ -937,3 +937,58 @@
margin-right: -7px;
z-index: 1;
}
+
+.issuable-discussion.incident-timeline-events {
+ .main-notes-list::before {
+ content: none;
+ }
+
+ .timeline-event-note {
+ p {
+ margin-bottom: 0;
+ }
+ }
+}
+
+/**
+ * We have a very specific design proposal where we cannot
+ * use `vertical-line` mixin as it is and have to use
+ * custom styles, see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/81284#note_904867444
+ */
+.timeline-entry-vertical-line {
+ &::before,
+ &::after {
+ content: '';
+ border-left: 2px solid $gray-50;
+ position: absolute;
+ left: 39px;
+ height: 80%;
+ }
+
+ &:first-child::before,
+ &:last-child::after {
+ content: none;
+ }
+
+ &:first-child {
+ &::after {
+ top: 50%;
+ }
+ }
+
+ &:last-child {
+ &::before {
+ bottom: 50%;
+ }
+ }
+
+ &:not(:first-child):not(:last-child) {
+ &::before {
+ top: -10%;
+ }
+
+ &::after {
+ bottom: -10%;
+ }
+ }
+}
diff --git a/app/assets/stylesheets/pages/merge_requests.scss b/app/assets/stylesheets/pages/merge_requests.scss
index b63fd941a9b..a3fbedd87a9 100644
--- a/app/assets/stylesheets/pages/merge_requests.scss
+++ b/app/assets/stylesheets/pages/merge_requests.scss
@@ -3,6 +3,7 @@
*
*/
$tabs-holder-z-index: 250;
+$comparison-empty-state-height: 62px;
.space-children {
@include clearfix;
@@ -70,6 +71,10 @@ $tabs-holder-z-index: 250;
}
}
+.compare-commit-empty {
+ min-height: $comparison-empty-state-height;
+}
+
.commits-empty {
text-align: center;
diff --git a/app/assets/stylesheets/themes/_dark.scss b/app/assets/stylesheets/themes/_dark.scss
index 6a9e96c3ac5..fe8a5aec1b3 100644
--- a/app/assets/stylesheets/themes/_dark.scss
+++ b/app/assets/stylesheets/themes/_dark.scss
@@ -209,7 +209,6 @@ body.gl-dark {
&.btn-info,
&.btn-success,
&.btn-danger,
- &.btn-warning,
&.btn-confirm {
&-tertiary {
mix-blend-mode: screen;
diff --git a/app/models/key.rb b/app/models/key.rb
index 621343cab10..5268ce2e040 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -28,6 +28,7 @@ class Key < ApplicationRecord
validate :key_meets_restrictions
validate :expiration, on: :create
+ validate :banned_key, if: :should_check_for_banned_key?
delegate :name, :email, to: :user, prefix: true
@@ -142,6 +143,27 @@ class Key < ApplicationRecord
end
end
+ def should_check_for_banned_key?
+ return false unless user
+
+ key_changed? && Feature.enabled?(:ssh_banned_key, user)
+ end
+
+ def banned_key
+ return unless public_key.banned?
+
+ help_page_url = Rails.application.routes.url_helpers.help_page_url(
+ 'security/ssh_keys_restrictions',
+ anchor: 'block-banned-or-compromised-keys'
+ )
+
+ errors.add(
+ :key,
+ _('cannot be used because it belongs to a compromised private key. Stop using this key and generate a new one.'),
+ help_page_url: help_page_url
+ )
+ end
+
def forbidden_key_type_message
allowed_types = Gitlab::CurrentSettings.allowed_key_types.map(&:upcase)
diff --git a/app/models/project.rb b/app/models/project.rb
index aeed681fc6f..4c99809f819 100644
--- a/app/models/project.rb
+++ b/app/models/project.rb
@@ -2585,16 +2585,7 @@ class Project < ApplicationRecord
end
def access_request_approvers_to_be_notified
- # For a personal project:
- # The creator is added as a member with `Owner` access level, starting from GitLab 14.8
- # The creator was added as a member with `Maintainer` access level, before GitLab 14.8
- # So, to make sure access requests for all personal projects work as expected,
- # we need to filter members with the scope `owners_and_maintainers`.
- access_request_approvers = if personal?
- members.owners_and_maintainers
- else
- members.maintainers
- end
+ access_request_approvers = members.owners_and_maintainers
access_request_approvers.connected_to_user.order_recent_sign_in.limit(Member::ACCESS_REQUEST_APPROVERS_TO_BE_NOTIFIED_LIMIT)
end
diff --git a/app/uploaders/metric_image_uploader.rb b/app/uploaders/metric_image_uploader.rb
index 0826bb251e4..d7d70518565 100644
--- a/app/uploaders/metric_image_uploader.rb
+++ b/app/uploaders/metric_image_uploader.rb
@@ -6,6 +6,10 @@ class MetricImageUploader < GitlabUploader # rubocop:disable Gitlab/NamespacedCl
prepend ObjectStorage::Extension::RecordsUploads
include UploaderHelper
+ def self.workhorse_local_upload_path
+ File.join(options.storage_path, 'uploads', TMP_UPLOAD_PATH)
+ end
+
private
def dynamic_segment
diff --git a/app/views/admin/application_settings/_account_and_limit.html.haml b/app/views/admin/application_settings/_account_and_limit.html.haml
index f914de138a9..e7204f635e6 100644
--- a/app/views/admin/application_settings/_account_and_limit.html.haml
+++ b/app/views/admin/application_settings/_account_and_limit.html.haml
@@ -1,5 +1,5 @@
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-account-settings'), html: { class: 'fieldset-form', id: 'account-settings' } do |f|
- = form_errors(@application_setting)
+ = form_errors(@application_setting, pajamas_alert: true)
%fieldset
.form-group
diff --git a/app/views/admin/application_settings/_ci_cd.html.haml b/app/views/admin/application_settings/_ci_cd.html.haml
index 201ca830ba4..ba2a2f34d63 100644
--- a/app/views/admin/application_settings/_ci_cd.html.haml
+++ b/app/views/admin/application_settings/_ci_cd.html.haml
@@ -1,6 +1,6 @@
.settings-content
= gitlab_ui_form_for @application_setting, url: ci_cd_admin_application_settings_path(anchor: 'js-ci-cd-settings'), html: { class: 'fieldset-form' } do |f|
- = form_errors(@application_setting)
+ = form_errors(@application_setting, pajamas_alert: true )
%fieldset
.form-group
@@ -72,7 +72,7 @@
- @plans.each_with_index do |plan, index|
.tab-pane{ :id => "plan#{index}", class: index == 0 ? 'active': '' }
= form_for plan.actual_limits, url: admin_plan_limits_path(anchor: 'js-ci-cd-settings'), html: { class: 'fieldset-form' }, method: :post do |f|
- = form_errors(plan)
+ = form_errors(plan, pajamas_alert: true)
%fieldset
= f.hidden_field(:plan_id, value: plan.id)
.form-group
diff --git a/app/views/admin/application_settings/_floc.html.haml b/app/views/admin/application_settings/_floc.html.haml
index 125ed569463..b5a63aa0847 100644
--- a/app/views/admin/application_settings/_floc.html.haml
+++ b/app/views/admin/application_settings/_floc.html.haml
@@ -12,7 +12,7 @@
.settings-content
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-floc-settings'), html: { class: 'fieldset-form', id: 'floc-settings' } do |f|
- = form_errors(@application_setting)
+ = form_errors(@application_setting, pajamas_alert: true)
%fieldset
.form-group
diff --git a/app/views/admin/application_settings/_kroki.html.haml b/app/views/admin/application_settings/_kroki.html.haml
index ad9e7ca5fea..b1dd8a282ec 100644
--- a/app/views/admin/application_settings/_kroki.html.haml
+++ b/app/views/admin/application_settings/_kroki.html.haml
@@ -10,7 +10,7 @@
= link_to _('Learn more.'), help_page_path('administration/integration/kroki.md'), target: '_blank', rel: 'noopener noreferrer'
.settings-content
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-kroki-settings'), html: { class: 'fieldset-form', id: 'kroki-settings' } do |f|
- = form_errors(@application_setting) if expanded
+ = form_errors(@application_setting, pajamas_alert: true) if expanded
%fieldset
.form-group
diff --git a/app/views/admin/application_settings/_package_registry.html.haml b/app/views/admin/application_settings/_package_registry.html.haml
index 4858353f3b6..c0fabb1d42e 100644
--- a/app/views/admin/application_settings/_package_registry.html.haml
+++ b/app/views/admin/application_settings/_package_registry.html.haml
@@ -26,7 +26,7 @@
- @plans.each_with_index do |plan, index|
.tab-pane{ :id => "plan#{index}", class: index == 0 ? 'active': '' }
= form_for plan.actual_limits, url: admin_plan_limits_path(anchor: 'js-package-settings'), html: { class: 'fieldset-form' }, method: :post do |f|
- = form_errors(plan)
+ = form_errors(plan, pajamas_alert: true)
%fieldset
= f.hidden_field(:plan_id, value: plan.id)
.form-group
diff --git a/app/views/admin/application_settings/_signin.html.haml b/app/views/admin/application_settings/_signin.html.haml
index 48f0b9b2c31..870bfbf4184 100644
--- a/app/views/admin/application_settings/_signin.html.haml
+++ b/app/views/admin/application_settings/_signin.html.haml
@@ -1,5 +1,5 @@
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-signin-settings'), html: { class: 'fieldset-form', id: 'signin-settings' } do |f|
- = form_errors(@application_setting)
+ = form_errors(@application_setting, pajamas_alert: true)
%fieldset
.form-group
diff --git a/app/views/admin/application_settings/_sourcegraph.html.haml b/app/views/admin/application_settings/_sourcegraph.html.haml
index 7aff7309e07..a0cbbecb943 100644
--- a/app/views/admin/application_settings/_sourcegraph.html.haml
+++ b/app/views/admin/application_settings/_sourcegraph.html.haml
@@ -17,7 +17,7 @@
.settings-content
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-sourcegraph-settings'), html: { class: 'fieldset-form', id: 'sourcegraph-settings' } do |f|
- = form_errors(@application_setting)
+ = form_errors(@application_setting, pajamas_alert: true)
%fieldset
.form-group
diff --git a/app/views/admin/application_settings/_terms.html.haml b/app/views/admin/application_settings/_terms.html.haml
index a4b6e061c43..c5387db59ef 100644
--- a/app/views/admin/application_settings/_terms.html.haml
+++ b/app/views/admin/application_settings/_terms.html.haml
@@ -1,5 +1,5 @@
= gitlab_ui_form_for @application_setting, url: general_admin_application_settings_path(anchor: 'js-terms-settings'), html: { class: 'fieldset-form', id: 'terms-settings' } do |f|
- = form_errors(@application_setting)
+ = form_errors(@application_setting, pajamas_alert: true)
%fieldset
.form-group
diff --git a/app/views/admin/application_settings/service_usage_data.html.haml b/app/views/admin/application_settings/service_usage_data.html.haml
index 55c25ca32d5..25c8bd12345 100644
--- a/app/views/admin/application_settings/service_usage_data.html.haml
+++ b/app/views/admin/application_settings/service_usage_data.html.haml
@@ -8,12 +8,12 @@
%h3= name
- if @service_ping_data_present
- %button.gl-button.btn.btn-default.js-payload-preview-trigger{ type: 'button', data: { payload_selector: ".#{payload_class}" } }
- = gl_loading_icon(css_class: 'js-spinner gl-display-none gl-mr-2')
- .js-text.gl-display-inline= _('Preview payload')
- %button.gl-button.btn.btn-default.js-payload-download-trigger{ type: 'button', data: { endpoint: usage_data_admin_application_settings_path(format: :json) } }
- = gl_loading_icon(css_class: 'js-spinner gl-display-none gl-mr-2')
- .js-text.d-inline= _('Download payload')
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-payload-preview-trigger gl-mr-2', data: { payload_selector: ".#{payload_class}" } } ) do
+ = gl_loading_icon(css_class: 'js-spinner gl-display-none', inline: true)
+ %span.js-text.gl-display-inline= _('Preview payload')
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'js-payload-download-trigger gl-mr-2', data: { endpoint: usage_data_admin_application_settings_path(format: :json) } } ) do
+ = gl_loading_icon(css_class: 'js-spinner gl-display-none', inline: true)
+ %span.js-text.gl-display-inline= _('Download payload')
%pre.js-syntax-highlight.code.highlight.gl-mt-2.gl-display-none{ class: payload_class, data: { endpoint: usage_data_admin_application_settings_path(format: :html) } }
- else
= render Pajamas::AlertComponent.new(variant: :warning,
diff --git a/app/views/admin/dashboard/index.html.haml b/app/views/admin/dashboard/index.html.haml
index 3cb9cd967dc..88fbbb28201 100644
--- a/app/views/admin/dashboard/index.html.haml
+++ b/app/views/admin/dashboard/index.html.haml
@@ -3,7 +3,6 @@
- billable_users_url = help_page_path('subscriptions/self_managed/index', anchor: 'billable-users')
- billable_users_link_start = '<a href="%{url}" target="_blank" rel="noopener noreferrer nofollow">'.html_safe % { url: billable_users_url }
-= render_if_exists 'shared/manual_renewal_banner'
= render_if_exists 'shared/manual_quarterly_reconciliation_banner'
= render_if_exists 'shared/submit_license_usage_data_banner'
= render_if_exists 'shared/qrtly_reconciliation_alert'
diff --git a/app/views/admin/jobs/index.html.haml b/app/views/admin/jobs/index.html.haml
index 670628f7463..667c90f0228 100644
--- a/app/views/admin/jobs/index.html.haml
+++ b/app/views/admin/jobs/index.html.haml
@@ -4,14 +4,17 @@
- breadcrumb_title _("Jobs")
- page_title _("Jobs")
-.top-area.scrolling-tabs-container.inner-page-scroll-tabs
- - build_path_proc = ->(scope) { admin_jobs_path(scope: scope) }
- = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
+.top-area
+ .scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
+ .fade-left= sprite_icon('chevron-lg-left', size: 12)
+ .fade-right= sprite_icon('chevron-lg-right', size: 12)
+ - build_path_proc = ->(scope) { admin_jobs_path(scope: scope) }
+ = render "shared/builds/tabs", build_path_proc: build_path_proc, all_builds: @all_builds, scope: @scope
- if @all_builds.running_or_pending.any?
#js-stop-jobs-modal
.nav-controls
- %button#js-stop-jobs-button.btn.gl-button.btn-danger{ data: { url: cancel_all_admin_jobs_path } }
+ = render Pajamas::ButtonComponent.new(variant: :danger, button_options: { id: 'js-stop-jobs-button', data: { url: cancel_all_admin_jobs_path } }) do
= s_('AdminArea|Stop all jobs')
.row-content-block.second-block
diff --git a/app/views/admin/projects/index.html.haml b/app/views/admin/projects/index.html.haml
index 0fae92610f6..f23a688dd48 100644
--- a/app/views/admin/projects/index.html.haml
+++ b/app/views/admin/projects/index.html.haml
@@ -1,14 +1,18 @@
- page_title _('Projects')
- params[:visibility_level] ||= []
-.top-area.scrolling-tabs-container.inner-page-scroll-tabs
- = gl_tabs_nav({ class: 'gl-border-b-0 gl-overflow-x-auto gl-flex-grow-1 gl-flex-nowrap gl-webkit-scrollbar-display-none' }) do
- = gl_tab_link_to _('All'), admin_projects_path(visibility_level: nil), { item_active: params[:visibility_level].empty? }
- = gl_tab_link_to _('Private'), admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
- = gl_tab_link_to _('Internal'), admin_projects_path(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
- = gl_tab_link_to _('Public'), admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
+.top-area
+ .scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
+ .fade-left= sprite_icon('chevron-lg-left', size: 12)
+ .fade-right= sprite_icon('chevron-lg-right', size: 12)
+ = gl_tabs_nav({ class: 'scrolling-tabs nav-links gl-display-flex gl-flex-grow-1 gl-w-full nav gl-tabs-nav nav gl-tabs-nav' }) do
+ = gl_tab_link_to _('All'), admin_projects_path(visibility_level: nil), { item_active: params[:visibility_level].empty? }
+ = gl_tab_link_to _('Private'), admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PRIVATE)
+ = gl_tab_link_to _('Internal'), admin_projects_path(visibility_level: Gitlab::VisibilityLevel::INTERNAL)
+ = gl_tab_link_to _('Public'), admin_projects_path(visibility_level: Gitlab::VisibilityLevel::PUBLIC)
- .nav-controls
+
+ .nav-controls.gl-pl-2
.search-holder
= render 'shared/projects/search_form', autofocus: true, admin_view: true
- current_namespace = _('Namespace')
diff --git a/app/views/dashboard/_projects_head.html.haml b/app/views/dashboard/_projects_head.html.haml
index 028edefe821..9c492a0da34 100644
--- a/app/views/dashboard/_projects_head.html.haml
+++ b/app/views/dashboard/_projects_head.html.haml
@@ -11,10 +11,11 @@
.page-title-controls
= link_to _("New project"), new_project_path, class: "gl-button btn btn-confirm", data: { qa_selector: 'new_project_button' }
-.top-area.scrolling-tabs-container.inner-page-scroll-tabs
- .fade-left= sprite_icon('chevron-lg-left', size: 12)
- .fade-right= sprite_icon('chevron-lg-right', size: 12)
- = render 'dashboard/projects_nav'
+.top-area
+ .scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
+ .fade-left= sprite_icon('chevron-lg-left', size: 12)
+ .fade-right= sprite_icon('chevron-lg-right', size: 12)
+ = render 'dashboard/projects_nav'
- unless feature_project_list_filter_bar
.nav-controls
= render 'shared/projects/search_form'
diff --git a/app/views/dashboard/_projects_nav.html.haml b/app/views/dashboard/_projects_nav.html.haml
index 90b40f3c7b7..29c820ddc58 100644
--- a/app/views/dashboard/_projects_nav.html.haml
+++ b/app/views/dashboard/_projects_nav.html.haml
@@ -1,7 +1,7 @@
- is_your_projects_path = current_page?(dashboard_projects_path) || current_page?(root_path)
- is_explore_projects_path = current_page?(explore_root_path) || current_page?(trending_explore_projects_path) || current_page?(starred_explore_projects_path) || current_page?(explore_projects_path)
-= gl_tabs_nav({ class: 'scrolling-tabs nav-links gl-display-flex gl-flex-grow-1 gl-flex-nowrap gl-border-0' }) do
+= gl_tabs_nav({ class: 'scrolling-tabs nav-links gl-display-flex gl-flex-grow-1 gl-w-full nav gl-tabs-nav' }) do
= gl_tab_link_to dashboard_projects_path, { item_active: is_your_projects_path, class: 'shortcuts-activity', data: { placement: 'right' } } do
= _("Your projects")
= gl_tab_counter_badge(limited_counter_with_delimiter(@total_user_projects_count))
diff --git a/app/views/explore/topics/_head.html.haml b/app/views/explore/topics/_head.html.haml
index 2a96c6c97c6..f7d80d63c45 100644
--- a/app/views/explore/topics/_head.html.haml
+++ b/app/views/explore/topics/_head.html.haml
@@ -1,9 +1,10 @@
.page-title-holder.d-flex.align-items-center
%h1.page-title.gl-font-size-h-display= _('Projects')
-.top-area.scrolling-tabs-container.inner-page-scroll-tabs
- .fade-left= sprite_icon('chevron-lg-left', size: 12)
- .fade-right= sprite_icon('chevron-lg-right', size: 12)
- = render 'dashboard/projects_nav'
+.top-area
+ .scrolling-tabs-container.inner-page-scroll-tabs.gl-flex-grow-1.gl-min-w-0.gl-w-full
+ .fade-left= sprite_icon('chevron-lg-left', size: 12)
+ .fade-right= sprite_icon('chevron-lg-right', size: 12)
+ = render 'dashboard/projects_nav'
.nav-controls
= render 'shared/topics/search_form'
diff --git a/app/views/kaminari/gitlab/_next_page.html.haml b/app/views/kaminari/gitlab/_next_page.html.haml
index 9572dd91330..3ddd9fe655f 100644
--- a/app/views/kaminari/gitlab/_next_page.html.haml
+++ b/app/views/kaminari/gitlab/_next_page.html.haml
@@ -11,4 +11,4 @@
%li.page-item.js-next-button{ class: ('disabled' if current_page.last?) }
= link_to page_url, rel: 'next', remote: remote, class: 'page-link' do
= s_('Pagination|Next')
- = sprite_icon('angle-right', size: 8)
+ = sprite_icon('chevron-lg-right', size: 8)
diff --git a/app/views/kaminari/gitlab/_prev_page.html.haml b/app/views/kaminari/gitlab/_prev_page.html.haml
index 4ba7ab6488a..5fb11c975de 100644
--- a/app/views/kaminari/gitlab/_prev_page.html.haml
+++ b/app/views/kaminari/gitlab/_prev_page.html.haml
@@ -10,5 +10,5 @@
%li.page-item.js-previous-button{ class: ('disabled' if current_page.first?) }
= link_to page_url, rel: 'prev', remote: remote, class: 'page-link' do
- = sprite_icon('angle-left', size: 8)
+ = sprite_icon('chevron-lg-left', size: 8)
= s_('Pagination|Prev')
diff --git a/app/views/projects/commits/_commits.html.haml b/app/views/projects/commits/_commits.html.haml
index c6fb3bcd559..764ddace0ad 100644
--- a/app/views/projects/commits/_commits.html.haml
+++ b/app/views/projects/commits/_commits.html.haml
@@ -23,7 +23,7 @@
%li.commit-header.js-commit-header
%span.font-weight-bold= n_("%d previously merged commit", "%d previously merged commits", context_commits.count) % context_commits.count
- if can_update_merge_request
- %button.gl-button.btn.btn-default.ml-3.add-review-item-modal-trigger{ type: "button", data: { context_commits_empty: 'false' } }
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'gl-ml-3 add-review-item-modal-trigger', data: { context_commits_empty: 'false' } }) do
= _('Add/remove')
%li.commits-row
@@ -41,7 +41,7 @@
= n_('%s additional commit has been omitted to prevent performance issues.', '%s additional commits have been omitted to prevent performance issues.', hidden) % number_with_delimiter(hidden)
- if can_update_merge_request && context_commits&.empty?
- %button.gl-button.btn.btn-default.mt-3.add-review-item-modal-trigger{ type: "button", data: { context_commits_empty: 'true' } }
+ = render Pajamas::ButtonComponent.new(button_options: { class: 'gl-mt-5', data: { context_commits_empty: 'true' } }) do
= _('Add previously merged commits')
- if commits.size == 0 && context_commits.nil?
diff --git a/app/views/projects/merge_requests/creations/_new_compare.html.haml b/app/views/projects/merge_requests/creations/_new_compare.html.haml
index 9513b904804..8cd0d2f9e32 100644
--- a/app/views/projects/merge_requests/creations/_new_compare.html.haml
+++ b/app/views/projects/merge_requests/creations/_new_compare.html.haml
@@ -12,24 +12,27 @@
.clearfix
.merge-request-select.dropdown
= f.hidden_field :source_project_id
- = dropdown_toggle @merge_request.source_project_path, { toggle: "dropdown", 'field-name': "#{f.object_name}[source_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-source-project" }
+ = dropdown_toggle @merge_request.source_project_path, { toggle: "dropdown", 'field-name': "#{f.object_name}[source_project_id]", disabled: @merge_request.persisted?, default_text: _("Select source project") }, { toggle_class: "js-compare-dropdown js-source-project" }
.dropdown-menu.dropdown-menu-selectable.dropdown-source-project
- = dropdown_title("Select source project")
- = dropdown_filter("Search projects")
+ = dropdown_title(_("Select source project"))
+ = dropdown_filter(_("Search projects"))
= dropdown_content do
= render 'projects/merge_requests/dropdowns/project',
projects: [@merge_request.source_project],
selected: f.object.source_project_id
.merge-request-select.dropdown
= f.hidden_field :source_branch
- = dropdown_toggle f.object.source_branch.presence || _("Select source branch"), { toggle: "dropdown", 'field-name': "#{f.object_name}[source_branch]", 'refs-url': refs_project_path(@source_project), selected: f.object.source_branch, qa_selector: "source_branch_dropdown" }, { toggle_class: "js-compare-dropdown js-source-branch monospace" }
+ = dropdown_toggle f.object.source_branch.presence || _("Select source branch"), { toggle: "dropdown", 'field-name': "#{f.object_name}[source_branch]", 'refs-url': refs_project_path(@source_project), selected: f.object.source_branch, default_text: _("Select target branch"), qa_selector: "source_branch_dropdown" }, { toggle_class: "js-compare-dropdown js-source-branch monospace" }
.dropdown-menu.dropdown-menu-selectable.js-source-branch-dropdown.git-revision-dropdown
= dropdown_title(_("Select source branch"))
= dropdown_filter(_("Search branches"))
= dropdown_content
= dropdown_loading
.gl-bg-gray-50.gl-rounded-base.gl-mx-2.gl-my-4
- = gl_loading_icon(css_class: 'js-source-loading gl-my-3')
+ .compare-commit-empty.js-source-commit-empty.gl-display-flex.gl-align-items-center.gl-p-5{ style: 'display: none;' }
+ = sprite_icon('branch', size: 16, css_class: 'gl-mr-3')
+ = _('Select a branch to compare')
+ = gl_loading_icon(css_class: 'js-source-loading gl-py-3')
%ul.list-unstyled.mr_source_commit
.col-lg-6
@@ -40,24 +43,27 @@
- projects = target_projects(@project)
.merge-request-select.dropdown
= f.hidden_field :target_project_id
- = dropdown_toggle f.object.target_project.full_path, { toggle: "dropdown", 'field-name': "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted? }, { toggle_class: "js-compare-dropdown js-target-project" }
+ = dropdown_toggle f.object.target_project.full_path, { toggle: "dropdown", 'field-name': "#{f.object_name}[target_project_id]", disabled: @merge_request.persisted?, default_text: _("Select target project") }, { toggle_class: "js-compare-dropdown js-target-project" }
.dropdown-menu.dropdown-menu-selectable.dropdown-target-project
- = dropdown_title("Select target project")
- = dropdown_filter("Search projects")
+ = dropdown_title(_("Select target project"))
+ = dropdown_filter(_("Search projects"))
= dropdown_content do
= render 'projects/merge_requests/dropdowns/project',
projects: projects,
selected: f.object.target_project_id
.merge-request-select.dropdown
= f.hidden_field :target_branch
- = dropdown_toggle f.object.target_branch.presence || _("Select target branch"), { toggle: "dropdown", 'field-name': "#{f.object_name}[target_branch]", 'refs-url': refs_project_path(f.object.target_project), selected: f.object.target_branch }, { toggle_class: "js-compare-dropdown js-target-branch monospace" }
+ = dropdown_toggle f.object.target_branch.presence || _("Select target branch"), { toggle: "dropdown", 'field-name': "#{f.object_name}[target_branch]", 'refs-url': refs_project_path(f.object.target_project), selected: f.object.target_branch, default_text: _("Select target branch") }, { toggle_class: "js-compare-dropdown js-target-branch monospace" }
.dropdown-menu.dropdown-menu-selectable.js-target-branch-dropdown.git-revision-dropdown
= dropdown_title(_("Select target branch"))
= dropdown_filter(_("Search branches"))
= dropdown_content
= dropdown_loading
.gl-bg-gray-50.gl-rounded-base.gl-mx-2.gl-my-4
- = gl_loading_icon(css_class: 'js-target-loading gl-my-3')
+ .compare-commit-empty.js-target-commit-empty.gl-display-flex.gl-align-items-center.gl-p-5{ style: 'display: none;' }
+ = sprite_icon('branch', size: 16, css_class: 'gl-mr-3')
+ = _('Select a branch to compare')
+ = gl_loading_icon(css_class: 'js-target-loading gl-py-3')
%ul.list-unstyled.mr_target_commit
- if @merge_request.errors.any?
diff --git a/app/views/shared/_label.html.haml b/app/views/shared/_label.html.haml
index 83a27314552..74541222fbf 100644
--- a/app/views/shared/_label.html.haml
+++ b/app/views/shared/_label.html.haml
@@ -14,8 +14,9 @@
dom_id: dom_id(label), type: label.type } }
%button.add-priority.btn.gl-button.btn-default-tertiary.btn-sm.has-tooltip{ title: _('Prioritize'), type: 'button', data: { placement: 'bottom' }, aria_label: _('Prioritize label') }
= sprite_icon('star-o')
- %button.remove-priority.btn.gl-button.btn-default-tertiary.btn-sm.has-tooltip{ title: _('Remove priority'), type: 'button', data: { placement: 'bottom' }, aria_label: _('Deprioritize label') }
- = sprite_icon('star')
+ = render Pajamas::ButtonComponent.new(category: :tertiary,
+ icon: 'star',
+ button_options: { class: 'remove-priority has-tooltip', 'title': _('Remove priority'), 'aria_label': _('Deprioritize label'), data: { placement: 'bottom' } })
- if can?(current_user, :admin_label, label)
%li.gl-display-inline-block
= link_to label.edit_path, class: 'btn gl-button btn-default-tertiary btn-sm edit has-tooltip', title: _('Edit'), data: { placement: 'bottom' }, aria_label: _('Edit') do
@@ -23,8 +24,9 @@
- if can?(current_user, :admin_label, label)
%li.gl-display-inline-block
.dropdown
- %button{ type: 'button', class: 'btn gl-button btn-default-tertiary btn-sm js-label-options-dropdown', data: { toggle: 'dropdown' }, aria_label: _('Label actions dropdown') }
- = sprite_icon('ellipsis_v')
+ = render Pajamas::ButtonComponent.new(category: :tertiary,
+ icon: 'ellipsis_v',
+ button_options: { class: 'js-label-options-dropdown', 'aria_label': _('Label actions dropdown'), data: { toggle: 'dropdown' } })
.dropdown-menu.dropdown-open-left
%ul
- if label.project_label? && label.project.group && can?(current_user, :admin_label, label.project.group)
diff --git a/app/views/shared/builds/_tabs.html.haml b/app/views/shared/builds/_tabs.html.haml
index 3bbd7a32bda..8e4b8d6d428 100644
--- a/app/views/shared/builds/_tabs.html.haml
+++ b/app/views/shared/builds/_tabs.html.haml
@@ -1,6 +1,6 @@
- count_badge_classes = 'gl-display-none gl-sm-display-inline-flex'
-= gl_tabs_nav( {class: 'gl-border-b-0 gl-flex-grow-1', data: { testid: 'jobs-tabs' } } ) do
+= gl_tabs_nav( {class: 'scrolling-tabs nav-links gl-display-flex gl-flex-grow-1 gl-w-full nav gl-border-b-0', data: { testid: 'jobs-tabs' } } ) do
= gl_tab_link_to build_path_proc.call(nil), { item_active: scope.nil? } do
= _('All')
= gl_tab_counter_badge(limited_counter_with_delimiter(all_builds), { class: count_badge_classes })
diff --git a/app/views/shared/issue_type/_details_content.html.haml b/app/views/shared/issue_type/_details_content.html.haml
index 6a903dc3192..7c5b3fd4b3c 100644
--- a/app/views/shared/issue_type/_details_content.html.haml
+++ b/app/views/shared/issue_type/_details_content.html.haml
@@ -3,7 +3,7 @@
.issue-details.issuable-details.js-issue-details
.detail-page-description.content-block.js-detail-page-description
- #js-issuable-app{ data: { initial: issuable_initial_data(issuable).to_json, full_path: @project.full_path } }
+ #js-issuable-app{ data: { initial: issuable_initial_data(issuable).to_json, issuable_id: issuable.id, full_path: @project.full_path } }
.title-container
%h1.title.page-title.gl-font-size-h-display= markdown_field(issuable, :title)
- if issuable.description.present?