diff options
Diffstat (limited to 'app')
60 files changed, 305 insertions, 149 deletions
diff --git a/app/assets/javascripts/boards/components/boards_selector.vue b/app/assets/javascripts/boards/components/boards_selector.vue index 80db9930259..dbe3e0790f6 100644 --- a/app/assets/javascripts/boards/components/boards_selector.vue +++ b/app/assets/javascripts/boards/components/boards_selector.vue @@ -233,7 +233,7 @@ export default { </script> <template> - <div class="boards-switcher js-boards-selector append-right-10"> + <div class="boards-switcher js-boards-selector gl-mr-3"> <span class="boards-selector-wrapper js-boards-selector-wrapper"> <gl-dropdown data-qa-selector="boards_dropdown" diff --git a/app/assets/javascripts/jobs/components/manual_variables_form.vue b/app/assets/javascripts/jobs/components/manual_variables_form.vue index 9163e7a87f1..d83c598dd48 100644 --- a/app/assets/javascripts/jobs/components/manual_variables_form.vue +++ b/app/assets/javascripts/jobs/components/manual_variables_form.vue @@ -112,7 +112,7 @@ export default { <div v-for="variable in variables" :key="variable.id" class="gl-responsive-table-row"> <div class="table-section section-50"> <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div> - <div class="table-mobile-content append-right-10"> + <div class="table-mobile-content gl-mr-3"> <input :ref="`${$options.inputTypes.key}-${variable.id}`" v-model="variable.key" @@ -124,7 +124,7 @@ export default { <div class="table-section section-50"> <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Value') }}</div> - <div class="table-mobile-content append-right-10"> + <div class="table-mobile-content gl-mr-3"> <input :ref="`${$options.inputTypes.value}-${variable.id}`" v-model="variable.secret_value" @@ -149,7 +149,7 @@ export default { <div class="gl-responsive-table-row"> <div class="table-section section-50"> <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Key') }}</div> - <div class="table-mobile-content append-right-10"> + <div class="table-mobile-content gl-mr-3"> <input ref="inputKey" v-model="key" @@ -161,7 +161,7 @@ export default { <div class="table-section section-50"> <div class="table-mobile-header" role="rowheader">{{ s__('Pipeline|Value') }}</div> - <div class="table-mobile-content append-right-10"> + <div class="table-mobile-content gl-mr-3"> <input ref="inputSecretValue" v-model="secretValue" diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index f685d67751c..bde62275797 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -161,7 +161,6 @@ export default { ...mapState('monitoringDashboard', [ 'dashboard', 'emptyState', - 'showEmptyState', 'expandedPanel', 'variables', 'links', @@ -169,6 +168,9 @@ export default { 'hasDashboardValidationWarnings', ]), ...mapGetters('monitoringDashboard', ['selectedDashboard', 'getMetricStates']), + shouldShowEmptyState() { + return Boolean(this.emptyState); + }, shouldShowVariablesSection() { return Boolean(this.variables.length); }, @@ -278,6 +280,14 @@ export default { return null; }, /** + * Return true if the entire group is loading. + * @param {String} groupKey - Identifier for group + * @returns {boolean} + */ + isGroupLoading(groupKey) { + return this.groupSingleEmptyState(groupKey) === metricStates.LOADING; + }, + /** * A group should be not collapsed if any metric is loaded (OK) * * @param {String} groupKey - Identifier for group @@ -412,9 +422,9 @@ export default { @dateTimePickerInvalid="onDateTimePickerInvalid" @setRearrangingPanels="onSetRearrangingPanels" /> - <variables-section v-if="shouldShowVariablesSection && !showEmptyState" /> - <links-section v-if="shouldShowLinksSection && !showEmptyState" /> - <div v-if="!showEmptyState"> + <template v-if="!shouldShowEmptyState"> + <variables-section v-if="shouldShowVariablesSection" /> + <links-section v-if="shouldShowLinksSection" /> <dashboard-panel v-show="expandedPanel.panel" ref="expandedPanel" @@ -449,6 +459,7 @@ export default { :key="`${groupData.group}.${groupData.priority}`" :name="groupData.group" :show-panels="showPanels" + :is-loading="isGroupLoading(groupData.key)" :collapse-group="collapseGroup(groupData.key)" > <vue-draggable @@ -506,7 +517,7 @@ export default { </div> </graph-group> </div> - </div> + </template> <empty-state v-else :selected-state="emptyState" diff --git a/app/assets/javascripts/monitoring/components/dashboard_header.vue b/app/assets/javascripts/monitoring/components/dashboard_header.vue index 1d929b3b558..ae8c586ff8c 100644 --- a/app/assets/javascripts/monitoring/components/dashboard_header.vue +++ b/app/assets/javascripts/monitoring/components/dashboard_header.vue @@ -119,10 +119,10 @@ export default { }, computed: { ...mapState('monitoringDashboard', [ + 'emptyState', 'environmentsLoading', 'currentEnvironmentName', 'isUpdatingStarredValue', - 'showEmptyState', 'dashboardTimezone', 'projectPath', 'canAccessOperationsSettings', @@ -132,13 +132,16 @@ export default { isOutOfTheBoxDashboard() { return this.selectedDashboard?.out_of_the_box_dashboard; }, + shouldShowEmptyState() { + return Boolean(this.emptyState); + }, shouldShowEnvironmentsDropdownNoMatchedMsg() { return !this.environmentsLoading && this.filteredEnvironments.length === 0; }, addingMetricsAvailable() { return ( this.customMetricsAvailable && - !this.showEmptyState && + !this.shouldShowEmptyState && // Custom metrics only avaialble on system dashboards because // they are stored in the database. This can be improved. See: // https://gitlab.com/gitlab-org/gitlab/-/issues/28241 @@ -146,7 +149,7 @@ export default { ); }, showRearrangePanelsBtn() { - return !this.showEmptyState && this.rearrangePanelsAvailable; + return !this.shouldShowEmptyState && this.rearrangePanelsAvailable; }, displayUtc() { return this.dashboardTimezone === timezones.UTC; diff --git a/app/assets/javascripts/monitoring/components/empty_state.vue b/app/assets/javascripts/monitoring/components/empty_state.vue index 000420e2662..5e7c9b5d906 100644 --- a/app/assets/javascripts/monitoring/components/empty_state.vue +++ b/app/assets/javascripts/monitoring/components/empty_state.vue @@ -1,13 +1,19 @@ <script> -import { GlEmptyState } from '@gitlab/ui'; +import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui'; import { __ } from '~/locale'; import { dashboardEmptyStates } from '../constants'; export default { components: { + GlLoadingIcon, GlEmptyState, }, props: { + selectedState: { + type: String, + required: true, + validator: state => Object.values(dashboardEmptyStates).includes(state), + }, documentationPath: { type: String, required: true, @@ -22,10 +28,6 @@ export default { required: false, default: '', }, - selectedState: { - type: String, - required: true, - }, emptyGettingStartedSvgPath: { type: String, required: true, @@ -54,52 +56,49 @@ export default { }, data() { return { + /** + * Possible empty states. + * Keys in each state must match GlEmptyState props + */ states: { [dashboardEmptyStates.GETTING_STARTED]: { - svgUrl: this.emptyGettingStartedSvgPath, + svgPath: this.emptyGettingStartedSvgPath, title: __('Get started with performance monitoring'), description: __(`Stay updated about the performance and health of your environment by configuring Prometheus to monitor your deployments.`), - buttonText: __('Install on clusters'), - buttonPath: this.clustersPath, + primaryButtonText: __('Install on clusters'), + primaryButtonLink: this.clustersPath, secondaryButtonText: __('Configure existing installation'), - secondaryButtonPath: this.settingsPath, - }, - [dashboardEmptyStates.LOADING]: { - svgUrl: this.emptyLoadingSvgPath, - title: __('Waiting for performance data'), - description: __(`Creating graphs uses the data from the Prometheus server. - If this takes a long time, ensure that data is available.`), - buttonText: __('View documentation'), - buttonPath: this.documentationPath, - secondaryButtonText: '', - secondaryButtonPath: '', + secondaryButtonLink: this.settingsPath, }, [dashboardEmptyStates.NO_DATA]: { - svgUrl: this.emptyNoDataSvgPath, + svgPath: this.emptyNoDataSvgPath, title: __('No data found'), description: __(`You are connected to the Prometheus server, but there is currently no data to display.`), - buttonText: __('Configure Prometheus'), - buttonPath: this.settingsPath, + primaryButtonText: __('Configure Prometheus'), + primaryButtonLink: this.settingsPath, secondaryButtonText: '', - secondaryButtonPath: '', + secondaryButtonLink: '', }, [dashboardEmptyStates.UNABLE_TO_CONNECT]: { - svgUrl: this.emptyUnableToConnectSvgPath, + svgPath: this.emptyUnableToConnectSvgPath, title: __('Unable to connect to Prometheus server'), description: __( 'Ensure connectivity is available from the GitLab server to the Prometheus server', ), - buttonText: __('View documentation'), - buttonPath: this.documentationPath, + primaryButtonText: __('View documentation'), + primaryButtonLink: this.documentationPath, secondaryButtonText: __('Configure Prometheus'), - secondaryButtonPath: this.settingsPath, + secondaryButtonLink: this.settingsPath, }, }, }; }, computed: { + isLoading() { + return this.selectedState === dashboardEmptyStates.LOADING; + }, currentState() { return this.states[this.selectedState]; }, @@ -108,14 +107,8 @@ export default { </script> <template> - <gl-empty-state - :title="currentState.title" - :description="currentState.description" - :primary-button-text="currentState.buttonText" - :primary-button-link="currentState.buttonPath" - :secondary-button-text="currentState.secondaryButtonText" - :secondary-button-link="currentState.secondaryButtonPath" - :svg-path="currentState.svgUrl" - :compact="compact" - /> + <div> + <gl-loading-icon v-if="isLoading" size="xl" class="gl-my-9" /> + <gl-empty-state v-if="currentState" v-bind="currentState" :compact="compact" /> + </div> </template> diff --git a/app/assets/javascripts/monitoring/components/graph_group.vue b/app/assets/javascripts/monitoring/components/graph_group.vue index 2d3a839d826..ecb8ef4a0d0 100644 --- a/app/assets/javascripts/monitoring/components/graph_group.vue +++ b/app/assets/javascripts/monitoring/components/graph_group.vue @@ -1,9 +1,10 @@ <script> -import Icon from '~/vue_shared/components/icon.vue'; +import { GlLoadingIcon, GlIcon } from '@gitlab/ui'; export default { components: { - Icon, + GlLoadingIcon, + GlIcon, }, props: { name: { @@ -15,6 +16,11 @@ export default { required: false, default: true, }, + isLoading: { + type: Boolean, + required: false, + default: false, + }, /** * Initial value of collapse on mount. */ @@ -55,15 +61,18 @@ export default { <div v-if="showPanels" ref="graph-group" class="card prometheus-panel"> <div class="card-header d-flex align-items-center"> <h4 class="flex-grow-1">{{ name }}</h4> + <gl-loading-icon v-if="isLoading" name="loading" /> <a data-testid="group-toggle-button" + :aria-label="__('Toggle collapse')" + :icon="caretIcon" role="button" - class="js-graph-group-toggle gl-text-gray-900" + class="js-graph-group-toggle gl-display-flex gl-ml-2 gl-text-gray-900" tabindex="0" @click="collapse" @keyup.enter="collapse" > - <icon :size="16" :aria-label="__('Toggle collapse')" :name="caretIcon" /> + <gl-icon :name="caretIcon" /> </a> </div> <div diff --git a/app/assets/javascripts/monitoring/stores/mutation_types.js b/app/assets/javascripts/monitoring/stores/mutation_types.js index 72b48c251ae..e1fa037c5bb 100644 --- a/app/assets/javascripts/monitoring/stores/mutation_types.js +++ b/app/assets/javascripts/monitoring/stores/mutation_types.js @@ -40,7 +40,6 @@ export const SET_ALL_DASHBOARDS = 'SET_ALL_DASHBOARDS'; export const SET_ENDPOINTS = 'SET_ENDPOINTS'; export const SET_INITIAL_STATE = 'SET_INITIAL_STATE'; export const SET_GETTING_STARTED_EMPTY_STATE = 'SET_GETTING_STARTED_EMPTY_STATE'; -export const SET_NO_DATA_EMPTY_STATE = 'SET_NO_DATA_EMPTY_STATE'; export const SET_SHOW_ERROR_BANNER = 'SET_SHOW_ERROR_BANNER'; export const SET_PANEL_GROUP_METRICS = 'SET_PANEL_GROUP_METRICS'; export const SET_ENVIRONMENTS_FILTER = 'SET_ENVIRONMENTS_FILTER'; diff --git a/app/assets/javascripts/monitoring/stores/mutations.js b/app/assets/javascripts/monitoring/stores/mutations.js index 73d95f6638d..28c6b14a029 100644 --- a/app/assets/javascripts/monitoring/stores/mutations.js +++ b/app/assets/javascripts/monitoring/stores/mutations.js @@ -59,7 +59,6 @@ export default { */ [types.REQUEST_METRICS_DASHBOARD](state) { state.emptyState = dashboardEmptyStates.LOADING; - state.showEmptyState = true; }, [types.RECEIVE_METRICS_DASHBOARD_SUCCESS](state, dashboardYML) { const { dashboard, panelGroups, variables, links } = mapToDashboardViewModel(dashboardYML); @@ -72,13 +71,14 @@ export default { if (!state.dashboard.panelGroups.length) { state.emptyState = dashboardEmptyStates.NO_DATA; + } else { + state.emptyState = null; } }, [types.RECEIVE_METRICS_DASHBOARD_FAILURE](state, error) { state.emptyState = error ? dashboardEmptyStates.UNABLE_TO_CONNECT : dashboardEmptyStates.NO_DATA; - state.showEmptyState = true; }, [types.REQUEST_DASHBOARD_STARRING](state) { @@ -152,9 +152,6 @@ export default { const metric = findMetricInDashboard(metricId, state.dashboard); metric.loading = false; - state.showEmptyState = false; - state.emptyState = null; - if (!data.result || data.result.length === 0) { metric.state = metricStates.NO_DATA; metric.result = null; @@ -184,13 +181,8 @@ export default { state.timeRange = timeRange; }, [types.SET_GETTING_STARTED_EMPTY_STATE](state) { - state.showEmptyState = true; state.emptyState = dashboardEmptyStates.GETTING_STARTED; }, - [types.SET_NO_DATA_EMPTY_STATE](state) { - state.showEmptyState = true; - state.emptyState = dashboardEmptyStates.NO_DATA; - }, [types.SET_ALL_DASHBOARDS](state, dashboards) { state.allDashboards = dashboards || []; }, diff --git a/app/assets/javascripts/monitoring/stores/state.js b/app/assets/javascripts/monitoring/stores/state.js index a7f07234287..89738756ffe 100644 --- a/app/assets/javascripts/monitoring/stores/state.js +++ b/app/assets/javascripts/monitoring/stores/state.js @@ -21,8 +21,13 @@ export default () => ({ // Dashboard data hasDashboardValidationWarnings: false, + + /** + * {?String} If set, dashboard should display a global + * empty state, there is no way to interact (yet) + * with the dashboard. + */ emptyState: dashboardEmptyStates.GETTING_STARTED, - showEmptyState: true, showErrorBanner: true, isUpdatingStarredValue: false, dashboard: { diff --git a/app/assets/javascripts/notes/components/comment_form.vue b/app/assets/javascripts/notes/components/comment_form.vue index 679b81ce583..ac93d3df654 100644 --- a/app/assets/javascripts/notes/components/comment_form.vue +++ b/app/assets/javascripts/notes/components/comment_form.vue @@ -419,7 +419,7 @@ export default { </gl-alert> <div class="note-form-actions"> <div - class="btn-group append-right-10 comment-type-dropdown js-comment-type-dropdown droplab-dropdown" + class="btn-group gl-mr-3 comment-type-dropdown js-comment-type-dropdown droplab-dropdown" > <button :disabled="isSubmitButtonDisabled" diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index f0c3bd9d874..24227d55ebf 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -410,7 +410,7 @@ export default { </button> <button v-if="discussion.resolvable" - class="btn btn-nr btn-default append-right-10 js-comment-resolve-button" + class="btn btn-nr btn-default gl-mr-3 js-comment-resolve-button" @click.prevent="handleUpdate(true)" > {{ resolveButtonTitle }} diff --git a/app/assets/javascripts/releases/components/release_block_header.vue b/app/assets/javascripts/releases/components/release_block_header.vue index ed49841757a..310fba0fe76 100644 --- a/app/assets/javascripts/releases/components/release_block_header.vue +++ b/app/assets/javascripts/releases/components/release_block_header.vue @@ -56,7 +56,7 @@ export default { v-gl-tooltip category="primary" variant="default" - class="append-right-10 js-edit-button ml-2 pb-2" + class="gl-mr-3 js-edit-button ml-2 pb-2" :title="__('Edit this release')" :href="editLink" > diff --git a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue index b28a847e751..b8a8cb940e7 100644 --- a/app/assets/javascripts/reports/components/grouped_test_reports_app.vue +++ b/app/assets/javascripts/reports/components/grouped_test_reports_app.vue @@ -114,7 +114,12 @@ export default { class="mr-widget-section grouped-security-reports mr-report" > <template v-if="showViewFullReport" #actionButtons> - <gl-button :href="testTabURL" icon="external-link" data-testid="group-test-reports-full-link"> + <gl-button + :href="testTabURL" + icon="external-link" + data-testid="group-test-reports-full-link" + class="gl-mr-3" + > {{ s__('ciReport|View full report') }} </gl-button> </template> diff --git a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue index 32b142a3346..80928649a03 100644 --- a/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue +++ b/app/assets/javascripts/sidebar/components/confidential/edit_form_buttons.vue @@ -62,7 +62,7 @@ export default { <template> <div class="sidebar-item-warning-message-actions"> - <button type="button" class="btn btn-default append-right-10" @click="closeForm"> + <button type="button" class="btn btn-default gl-mr-3" @click="closeForm"> {{ __('Cancel') }} </button> <button diff --git a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue index f88bde624b4..2e85ded8ade 100644 --- a/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue +++ b/app/assets/javascripts/sidebar/components/lock/edit_form_buttons.vue @@ -41,7 +41,7 @@ export default { <template> <div class="sidebar-item-warning-message-actions"> - <button type="button" class="btn btn-default append-right-10" @click="closeForm"> + <button type="button" class="btn btn-default gl-mr-3" @click="closeForm"> {{ __('Cancel') }} </button> diff --git a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue index 92848e86e76..f02e0ac84da 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/states/mr_widget_auto_merge_enabled.vue @@ -87,7 +87,7 @@ export default { <status-icon status="success" /> <div class="media-body"> <h4 class="d-flex align-items-start"> - <span class="append-right-10"> + <span class="gl-mr-3"> <span class="js-status-text-before-author">{{ statusTextBeforeAuthor }}</span> <mr-widget-author :author="mr.setToAutoMergeBy" /> <span class="js-status-text-after-author">{{ statusTextAfterAuthor }}</span> @@ -113,9 +113,7 @@ export default { {{ s__('mrWidget|The source branch will be deleted') }} </p> <p v-else class="d-flex align-items-start"> - <span class="append-right-10">{{ - s__('mrWidget|The source branch will not be deleted') - }}</span> + <span class="gl-mr-3">{{ s__('mrWidget|The source branch will not be deleted') }}</span> <a v-if="canRemoveSourceBranch" :disabled="isRemovingSourceBranch" diff --git a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue index a28936456ff..fdcbcdce51b 100644 --- a/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue +++ b/app/assets/javascripts/vue_merge_request_widget/mr_widget_options.vue @@ -384,7 +384,7 @@ export default { v-if="mr.testResultsPath" class="js-reports-container" :endpoint="mr.testResultsPath" - :pipeline-path="mr.mergeRequestAddCiConfigPath" + :pipeline-path="mr.pipeline.path" /> <terraform-plan v-if="mr.terraformReportsPath" :endpoint="mr.terraformReportsPath" /> diff --git a/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue b/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue index 1cee800de44..8c6d795f4a6 100644 --- a/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue +++ b/app/assets/javascripts/vue_shared/components/project_selector/project_list_item.vue @@ -56,7 +56,7 @@ export default { @click="onClick" > <icon - class="prepend-left-10 append-right-10 flex-shrink-0 position-top-0 js-selected-icon" + class="prepend-left-10 gl-mr-3 flex-shrink-0 position-top-0 js-selected-icon" :class="{ 'js-selected visible': selected, 'js-unselected invisible': !selected }" name="mobile-issue-close" /> diff --git a/app/assets/stylesheets/framework/common.scss b/app/assets/stylesheets/framework/common.scss index fe48381d9c3..f2ff8b74790 100644 --- a/app/assets/stylesheets/framework/common.scss +++ b/app/assets/stylesheets/framework/common.scss @@ -404,7 +404,6 @@ img.emoji { .prepend-left-15 { margin-left: 15px; } .prepend-left-20 { margin-left: 20px; } .prepend-left-64 { margin-left: 64px; } -.append-right-10 { margin-right: 10px; } .append-right-15 { margin-right: 15px; } .append-right-20 { margin-right: 20px; } .append-bottom-10 { margin-bottom: 10px; } diff --git a/app/assets/stylesheets/framework/variables.scss b/app/assets/stylesheets/framework/variables.scss index 79f9cf5941f..265dceb3c61 100644 --- a/app/assets/stylesheets/framework/variables.scss +++ b/app/assets/stylesheets/framework/variables.scss @@ -171,7 +171,7 @@ $gray-500: #a7a7a7 !default; $gray-600: #919191 !default; $gray-700: #707070 !default; $gray-800: #4f4f4f !default; -$gray-900: #2e2e2e !default; +$gray-900: #303030 !default; $gray-950: #1f1f1f !default; $greens: ( diff --git a/app/assets/stylesheets/pages/runners.scss b/app/assets/stylesheets/pages/runners.scss index dc3811bab65..66d2f76c558 100644 --- a/app/assets/stylesheets/pages/runners.scss +++ b/app/assets/stylesheets/pages/runners.scss @@ -45,8 +45,7 @@ color: $gl-text-color-secondary; } - .fa-pause, - .fa-play { + .fa-pause { font-size: 11px; } } diff --git a/app/graphql/mutations/notes/create/base.rb b/app/graphql/mutations/notes/create/base.rb index cf9f74a63d8..f081eac368e 100644 --- a/app/graphql/mutations/notes/create/base.rb +++ b/app/graphql/mutations/notes/create/base.rb @@ -18,6 +18,11 @@ module Mutations required: true, description: copy_field_description(Types::Notes::NoteType, :body) + argument :confidential, + GraphQL::BOOLEAN_TYPE, + required: false, + description: 'The confidentiality flag of a note. Default is false.' + def resolve(args) noteable = authorized_find!(id: args[:noteable_id]) @@ -40,7 +45,8 @@ module Mutations def create_note_params(noteable, args) { noteable: noteable, - note: args[:body] + note: args[:body], + confidential: args[:confidential] } end end diff --git a/app/graphql/mutations/snippets/create.rb b/app/graphql/mutations/snippets/create.rb index 1545fd70290..89c21486a74 100644 --- a/app/graphql/mutations/snippets/create.rb +++ b/app/graphql/mutations/snippets/create.rb @@ -85,9 +85,9 @@ module Mutations def create_params(args) args.tap do |create_args| - # We need to rename `files` into `snippet_files` because + # We need to rename `files` into `snippet_actions` because # it's the expected key param - create_args[:snippet_files] = create_args.delete(:files)&.map(&:to_h) + create_args[:snippet_actions] = create_args.delete(:files)&.map(&:to_h) # We need to rename `uploaded_files` into `files` because # it's the expected key param diff --git a/app/graphql/mutations/snippets/update.rb b/app/graphql/mutations/snippets/update.rb index f0a22ebaa9d..8890158b0df 100644 --- a/app/graphql/mutations/snippets/update.rb +++ b/app/graphql/mutations/snippets/update.rb @@ -56,9 +56,9 @@ module Mutations def update_params(args) args.tap do |update_args| - # We need to rename `files` into `snippet_files` because + # We need to rename `files` into `snippet_actions` because # it's the expected key param - update_args[:snippet_files] = update_args.delete(:files)&.map(&:to_h) + update_args[:snippet_actions] = update_args.delete(:files)&.map(&:to_h) end end end diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 90ebab731ea..b522a9dfb4f 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -24,7 +24,7 @@ module EnvironmentsHelper def metrics_data(project, environment) metrics_data = {} metrics_data.merge!(project_metrics_data(project)) if project - metrics_data.merge!(environment_metrics_data(environment)) if environment + metrics_data.merge!(environment_metrics_data(environment, project)) if environment metrics_data.merge!(project_and_environment_metrics_data(project, environment)) if project && environment metrics_data.merge!(static_metrics_data) @@ -66,11 +66,11 @@ module EnvironmentsHelper } end - def environment_metrics_data(environment) + def environment_metrics_data(environment, project = nil) return {} unless environment { - 'metrics-dashboard-base-path' => environment_metrics_path(environment), + 'metrics-dashboard-base-path' => metrics_dashboard_base_path(environment, project), 'current-environment-name' => environment.name, 'has-metrics' => "#{environment.has_metrics?}", 'prometheus-status' => "#{environment.prometheus_status}", @@ -78,6 +78,17 @@ module EnvironmentsHelper } end + def metrics_dashboard_base_path(environment, project) + # This is needed to support our transition from environment scoped metric paths to project scoped. + if project + path = project_metrics_dashboard_path(project) + + return path if request.path.include?(path) + end + + environment_metrics_path(environment) + end + def project_and_environment_metrics_data(project, environment) return {} unless project && environment diff --git a/app/presenters/clusters/cluster_presenter.rb b/app/presenters/clusters/cluster_presenter.rb index 3dfa9626a79..6185f5cb4e5 100644 --- a/app/presenters/clusters/cluster_presenter.rb +++ b/app/presenters/clusters/cluster_presenter.rb @@ -76,9 +76,11 @@ module Clusters 'clusters-path': clusterable.index_path, 'dashboard-endpoint': clusterable.metrics_dashboard_path(cluster), 'documentation-path': help_page_path('user/project/clusters/index', anchor: 'monitoring-your-kubernetes-cluster-ultimate'), + 'add-dashboard-documentation-path': help_page_path('user/project/integrations/prometheus.md', anchor: 'adding-a-new-dashboard-to-your-project'), 'empty-getting-started-svg-path': image_path('illustrations/monitoring/getting_started.svg'), 'empty-loading-svg-path': image_path('illustrations/monitoring/loading.svg'), 'empty-no-data-svg-path': image_path('illustrations/monitoring/no_data.svg'), + 'empty-no-data-small-svg-path': image_path('illustrations/chart-empty-state-small.svg'), 'empty-unable-to-connect-svg-path': image_path('illustrations/monitoring/unable_to_connect.svg'), 'settings-path': '', 'project-path': '', diff --git a/app/services/concerns/incident_management/settings.rb b/app/services/concerns/incident_management/settings.rb index 5f56d6e7f53..491bd4fa6bf 100644 --- a/app/services/concerns/incident_management/settings.rb +++ b/app/services/concerns/incident_management/settings.rb @@ -1,6 +1,8 @@ # frozen_string_literal: true module IncidentManagement module Settings + include Gitlab::Utils::StrongMemoize + def incident_management_setting strong_memoize(:incident_management_setting) do project.incident_management_setting || diff --git a/app/services/incident_management/pager_duty/create_incident_issue_service.rb b/app/services/incident_management/pager_duty/create_incident_issue_service.rb new file mode 100644 index 00000000000..ee0feb49e0d --- /dev/null +++ b/app/services/incident_management/pager_duty/create_incident_issue_service.rb @@ -0,0 +1,72 @@ +# frozen_string_literal: true + +module IncidentManagement + module PagerDuty + class CreateIncidentIssueService < BaseService + include IncidentManagement::Settings + + def initialize(project, incident_payload) + super(project, User.alert_bot, incident_payload) + end + + def execute + return forbidden unless webhook_available? + + issue = create_issue + return error(issue.errors.full_messages.to_sentence, issue) unless issue.valid? + + success(issue) + end + + private + + alias_method :incident_payload, :params + + def create_issue + label_result = find_or_create_incident_label + + # Create an unlabelled issue if we couldn't create the label + # due to a race condition. + # See https://gitlab.com/gitlab-org/gitlab-foss/issues/65042 + extra_params = label_result.success? ? { label_ids: [label_result.payload[:label].id] } : {} + + Issues::CreateService.new( + project, + current_user, + title: issue_title, + description: issue_description, + **extra_params + ).execute + end + + def webhook_available? + Feature.enabled?(:pagerduty_webhook, project) && + incident_management_setting.pagerduty_active? + end + + def forbidden + ServiceResponse.error(message: 'Forbidden', http_status: :forbidden) + end + + def find_or_create_incident_label + ::IncidentManagement::CreateIncidentLabelService.new(project, current_user).execute + end + + def issue_title + incident_payload['title'] + end + + def issue_description + Gitlab::IncidentManagement::PagerDuty::IncidentIssueDescription.new(incident_payload).to_s + end + + def success(issue) + ServiceResponse.success(payload: { issue: issue }) + end + + def error(message, issue = nil) + ServiceResponse.error(payload: { issue: issue }, message: message) + end + end + end +end diff --git a/app/services/snippets/base_service.rb b/app/services/snippets/base_service.rb index 1985ced9dd0..d9e8326f159 100644 --- a/app/services/snippets/base_service.rb +++ b/app/services/snippets/base_service.rb @@ -6,15 +6,15 @@ module Snippets CreateRepositoryError = Class.new(StandardError) - attr_reader :uploaded_assets, :snippet_files + attr_reader :uploaded_assets, :snippet_actions def initialize(project, user = nil, params = {}) super @uploaded_assets = Array(@params.delete(:files).presence) - input_actions = Array(@params.delete(:snippet_files).presence) - @snippet_files = SnippetInputActionCollection.new(input_actions, allowed_actions: restricted_files_actions) + input_actions = Array(@params.delete(:snippet_actions).presence) + @snippet_actions = SnippetInputActionCollection.new(input_actions, allowed_actions: restricted_files_actions) filter_spam_check_params end @@ -32,18 +32,18 @@ module Snippets end def valid_params? - return true if snippet_files.empty? + return true if snippet_actions.empty? - (params.keys & [:content, :file_name]).none? && snippet_files.valid? + (params.keys & [:content, :file_name]).none? && snippet_actions.valid? end def invalid_params_error(snippet) - if snippet_files.valid? + if snippet_actions.valid? [:content, :file_name].each do |key| snippet.errors.add(key, 'and snippet files cannot be used together') if params.key?(key) end else - snippet.errors.add(:snippet_files, 'have invalid data') + snippet.errors.add(:snippet_actions, 'have invalid data') end snippet_error_response(snippet, 403) @@ -75,7 +75,7 @@ module Snippets end def files_to_commit(snippet) - snippet_files.to_commit_actions.presence || build_actions_from_params(snippet) + snippet_actions.to_commit_actions.presence || build_actions_from_params(snippet) end def build_actions_from_params(snippet) diff --git a/app/services/snippets/create_service.rb b/app/services/snippets/create_service.rb index 6039ca2e501..dab47de8a36 100644 --- a/app/services/snippets/create_service.rb +++ b/app/services/snippets/create_service.rb @@ -37,13 +37,13 @@ module Snippets end end - # If the snippet_files param is present + # If the snippet_actions param is present # we need to fill content and file_name from # the model def create_params - return params if snippet_files.empty? + return params if snippet_actions.empty? - params.merge(content: snippet_files[0].content, file_name: snippet_files[0].file_path) + params.merge(content: snippet_actions[0].content, file_name: snippet_actions[0].file_path) end def save_and_commit diff --git a/app/services/snippets/update_service.rb b/app/services/snippets/update_service.rb index 1c097ed447a..00146389e22 100644 --- a/app/services/snippets/update_service.rb +++ b/app/services/snippets/update_service.rb @@ -37,9 +37,9 @@ module Snippets # is implemented. # Once we can perform different operations through this service # we won't need to keep track of the `content` and `file_name` fields - if snippet_files.any? - params[:content] = snippet_files[0].content if snippet_files[0].content - params[:file_name] = snippet_files[0].file_path + if snippet_actions.any? + params[:content] = snippet_actions[0].content if snippet_actions[0].content + params[:file_name] = snippet_actions[0].file_path end snippet.assign_attributes(params) @@ -109,7 +109,7 @@ module Snippets end def committable_attributes? - (params.stringify_keys.keys & COMMITTABLE_ATTRIBUTES).present? || snippet_files.any? + (params.stringify_keys.keys & COMMITTABLE_ATTRIBUTES).present? || snippet_actions.any? end def build_actions_from_params(snippet) diff --git a/app/views/admin/runners/_runner.html.haml b/app/views/admin/runners/_runner.html.haml index 423472324fe..5c834c2125f 100644 --- a/app/views/admin/runners/_runner.html.haml +++ b/app/views/admin/runners/_runner.html.haml @@ -72,8 +72,8 @@ = link_to [:pause, :admin, runner], method: :get, class: 'btn btn-default has-tooltip', title: _('Pause'), ref: 'tooltip', aria: { label: _('Pause') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do = icon('pause') - else - = link_to [:resume, :admin, runner], method: :get, class: 'btn btn-default has-tooltip', title: _('Resume'), ref: 'tooltip', aria: { label: _('Resume') }, data: { placement: 'top', container: 'body'} do - = icon('play') + = link_to [:resume, :admin, runner], method: :get, class: 'btn btn-default has-tooltip gl-px-3', title: _('Resume'), ref: 'tooltip', aria: { label: _('Resume') }, data: { placement: 'top', container: 'body'} do + = sprite_icon('play') .btn-group = link_to [:admin, runner], method: :delete, class: 'btn btn-danger has-tooltip', title: _('Remove'), ref: 'tooltip', aria: { label: _('Remove') }, data: { placement: 'top', container: 'body', confirm: _('Are you sure?') } do = icon('remove') diff --git a/app/views/ci/group_variables/_index.html.haml b/app/views/ci/group_variables/_index.html.haml index c350ba5caf7..84bcd42e07c 100644 --- a/app/views/ci/group_variables/_index.html.haml +++ b/app/views/ci/group_variables/_index.html.haml @@ -6,8 +6,8 @@ = render 'ci/group_variables/variable_header' - variables.each do |variable| .group-variable-row.d-flex.w-100.border-bottom.pt-2.pb-2 - .table-section.section-40.append-right-10.key + .table-section.section-40.gl-mr-3.key = variable.key - .table-section.section-40.append-right-10 + .table-section.section-40.gl-mr-3 %a.group-origin-link{ href: group_settings_ci_cd_path(variable.group) } = variable.group.name diff --git a/app/views/ci/group_variables/_variable_header.html.haml b/app/views/ci/group_variables/_variable_header.html.haml index 1a3168cf781..a8d533da0e0 100644 --- a/app/views/ci/group_variables/_variable_header.html.haml +++ b/app/views/ci/group_variables/_variable_header.html.haml @@ -1,5 +1,5 @@ .group-variable-keys.d-flex.w-100.align-items-center.pb-2.border-bottom - .bold.table-section.section-40.append-right-10 + .bold.table-section.section-40.gl-mr-3 = s_('Key') - .bold.table-section.section-40.append-right-10 + .bold.table-section.section-40.gl-mr-3 = s_('Origin') diff --git a/app/views/ci/variables/_environment_scope_header.html.haml b/app/views/ci/variables/_environment_scope_header.html.haml index 4ba4ceec16c..fc3b7f925fc 100644 --- a/app/views/ci/variables/_environment_scope_header.html.haml +++ b/app/views/ci/variables/_environment_scope_header.html.haml @@ -1,2 +1,2 @@ -.bold.table-section.section-15.append-right-10 +.bold.table-section.section-15.gl-mr-3 = s_('CiVariables|Scope') diff --git a/app/views/ci/variables/_variable_header.html.haml b/app/views/ci/variables/_variable_header.html.haml index d3b7a5ae883..65cea00a0c4 100644 --- a/app/views/ci/variables/_variable_header.html.haml +++ b/app/views/ci/variables/_variable_header.html.haml @@ -2,11 +2,11 @@ %li.ci-variable-row.m-0.d-none.d-sm-block .d-flex.w-100.align-items-center.pb-2 - .bold.table-section.section-15.append-right-10 + .bold.table-section.section-15.gl-mr-3 = s_('CiVariables|Type') - .bold.table-section.section-15.append-right-10 + .bold.table-section.section-15.gl-mr-3 = s_('CiVariables|Key') - .bold.table-section.section-15.append-right-10 + .bold.table-section.section-15.gl-mr-3 = s_('CiVariables|Value') - unless only_key_value .bold.table-section.section-20 diff --git a/app/views/profiles/active_sessions/_active_session.html.haml b/app/views/profiles/active_sessions/_active_session.html.haml index f3ad0c4c8ad..68f5460e599 100644 --- a/app/views/profiles/active_sessions/_active_session.html.haml +++ b/app/views/profiles/active_sessions/_active_session.html.haml @@ -1,7 +1,7 @@ - is_current_session = active_session.current?(session) %li.list-group-item - .float-left.append-right-10{ data: { toggle: 'tooltip' }, title: active_session.human_device_type } + .float-left.gl-mr-3{ data: { toggle: 'tooltip' }, title: active_session.human_device_type } = active_session_device_type_icon(active_session) .description.float-left diff --git a/app/views/profiles/gpg_keys/_key.html.haml b/app/views/profiles/gpg_keys/_key.html.haml index 2de5cf2f506..7a10b24c312 100644 --- a/app/views/profiles/gpg_keys/_key.html.haml +++ b/app/views/profiles/gpg_keys/_key.html.haml @@ -1,5 +1,5 @@ %li.key-list-item - .float-left.append-right-10 + .float-left.gl-mr-3 = icon 'key', class: "settings-list-icon d-none d-sm-block" .key-list-item-info - key.emails_with_verified_status.map do |email, verified| diff --git a/app/views/profiles/keys/_key.html.haml b/app/views/profiles/keys/_key.html.haml index b227041c9de..c02711e31ae 100644 --- a/app/views/profiles/keys/_key.html.haml +++ b/app/views/profiles/keys/_key.html.haml @@ -1,5 +1,5 @@ %li.d-flex.align-items-center.key-list-item - .append-right-10 + .gl-mr-3 - if key.valid? - if key.expired? %span.d-inline-block.has-tooltip{ title: s_('Profiles|Your key has expired') } @@ -17,10 +17,10 @@ = key.fingerprint .key-list-item-dates.d-flex.align-items-start.justify-content-between - %span.last-used-at.append-right-10 + %span.last-used-at.gl-mr-3 = s_('Profiles|Last used:') = key.last_used_at ? time_ago_with_tooltip(key.last_used_at) : _('Never') - %span.expires.append-right-10 + %span.expires.gl-mr-3 = s_('Profiles|Expires:') = key.expires_at ? key.expires_at.to_date : _('Never') %span.key-created-at diff --git a/app/views/profiles/passwords/edit.html.haml b/app/views/profiles/passwords/edit.html.haml index d21db0a6511..fe16c2e2f28 100644 --- a/app/views/profiles/passwords/edit.html.haml +++ b/app/views/profiles/passwords/edit.html.haml @@ -30,6 +30,6 @@ = f.label :password_confirmation, _('Password confirmation'), class: 'label-bold' = f.password_field :password_confirmation, required: true, class: 'form-control', data: { qa_selector: 'confirm_password_field' } .gl-mt-3.gl-mb-3 - = f.submit _('Save password'), class: "btn btn-success append-right-10", data: { qa_selector: 'save_password_button' } + = f.submit _('Save password'), class: "btn btn-success gl-mr-3", data: { qa_selector: 'save_password_button' } - unless @user.password_automatically_set? = link_to _('I forgot my password'), reset_profile_password_path, method: :put diff --git a/app/views/profiles/two_factor_auths/_codes.html.haml b/app/views/profiles/two_factor_auths/_codes.html.haml index 94fd40ed669..68cd4875a33 100644 --- a/app/views/profiles/two_factor_auths/_codes.html.haml +++ b/app/views/profiles/two_factor_auths/_codes.html.haml @@ -9,5 +9,5 @@ %span.monospace= code .d-flex - = link_to _('Proceed'), profile_account_path, class: 'btn btn-success append-right-10', data: { qa_selector: 'proceed_button' } + = link_to _('Proceed'), profile_account_path, class: 'btn btn-success gl-mr-3', data: { qa_selector: 'proceed_button' } = link_to _('Download codes'), "data:text/plain;charset=utf-8,#{CGI.escape(@codes.join("\n"))}", download: "gitlab-recovery-codes.txt", class: 'btn btn-default' diff --git a/app/views/profiles/two_factor_auths/show.html.haml b/app/views/profiles/two_factor_auths/show.html.haml index b8c5d626d17..0fde3e5fb10 100644 --- a/app/views/profiles/two_factor_auths/show.html.haml +++ b/app/views/profiles/two_factor_auths/show.html.haml @@ -19,7 +19,7 @@ = link_to _('Disable two-factor authentication'), profile_two_factor_auth_path, method: :delete, data: { confirm: _('Are you sure? This will invalidate your registered applications and U2F devices.') }, - class: 'btn btn-danger append-right-10' + class: 'btn btn-danger gl-mr-3' = form_tag codes_profile_two_factor_auth_path, {style: 'display: inline-block', method: :post} do |f| = submit_tag _('Regenerate recovery codes'), class: 'btn' diff --git a/app/views/projects/blob/_editor.html.haml b/app/views/projects/blob/_editor.html.haml index 1e9cf68f3a5..b06ae31e73f 100644 --- a/app/views/projects/blob/_editor.html.haml +++ b/app/views/projects/blob/_editor.html.haml @@ -8,13 +8,13 @@ = sprite_icon('fork', size: 12) = ref - if current_action?(:edit) || current_action?(:update) - %span.pull-left.append-right-10 + %span.pull-left.gl-mr-3 = text_field_tag 'file_path', (params[:file_path] || @path), class: 'form-control new-file-path js-file-path-name-input' = render 'template_selectors' - if current_action?(:new) || current_action?(:create) - %span.pull-left.append-right-10 + %span.pull-left.gl-mr-3 \/ = text_field_tag 'file_name', params[:file_name], placeholder: "File name", required: true, class: 'form-control new-file-name js-file-path-name-input', value: params[:file_name] || (should_suggest_gitlab_ci_yml? ? '.gitlab-ci.yml' : '') diff --git a/app/views/projects/commit/_commit_box.html.haml b/app/views/projects/commit/_commit_box.html.haml index 4442bdcdf1d..71cf6ca6922 100644 --- a/app/views/projects/commit/_commit_box.html.haml +++ b/app/views/projects/commit/_commit_box.html.haml @@ -22,10 +22,10 @@ .header-action-buttons - if defined?(@notes_count) && @notes_count > 0 - %span.btn.disabled.btn-grouped.d-none.d-sm-block.append-right-10.has-tooltip{ title: n_("%d comment on this commit", "%d comments on this commit", @notes_count) % @notes_count } + %span.btn.disabled.btn-grouped.d-none.d-sm-block.gl-mr-3.has-tooltip{ title: n_("%d comment on this commit", "%d comments on this commit", @notes_count) % @notes_count } = sprite_icon('comment') = @notes_count - = link_to project_tree_path(@project, @commit), class: "btn btn-default append-right-10 d-none d-sm-none d-md-inline" do + = link_to project_tree_path(@project, @commit), class: "btn btn-default gl-mr-3 d-none d-sm-none d-md-inline" do #{ _('Browse files') } .dropdown.inline %a.btn.btn-default.dropdown-toggle.qa-options-button.d-md-inline{ data: { toggle: "dropdown" } } diff --git a/app/views/projects/issues/_nav_btns.html.haml b/app/views/projects/issues/_nav_btns.html.haml index 71c9bb36936..cc6ca4aca4a 100644 --- a/app/views/projects/issues/_nav_btns.html.haml +++ b/app/views/projects/issues/_nav_btns.html.haml @@ -14,7 +14,7 @@ = render 'projects/issues/import_csv/button' - if @can_bulk_update - = button_tag _("Edit issues"), class: "btn btn-default append-right-10 js-bulk-update-toggle" + = button_tag _("Edit issues"), class: "btn btn-default gl-mr-3 js-bulk-update-toggle" - if show_new_issue_link?(@project) = link_to _("New issue"), new_project_issue_path(@project, issue: { assignee_id: finder.assignee.try(:id), diff --git a/app/views/projects/merge_requests/_discussion.html.haml b/app/views/projects/merge_requests/_discussion.html.haml index 3303aa72604..ecb51aca847 100644 --- a/app/views/projects/merge_requests/_discussion.html.haml +++ b/app/views/projects/merge_requests/_discussion.html.haml @@ -5,7 +5,7 @@ - if @merge_request.reopenable? = link_to 'Reopen merge request', merge_request_path(@merge_request, merge_request: { state_event: :reopen }), method: :put, class: "btn btn-nr btn-comment btn-reopen reopen-mr-link js-note-target-close js-note-target-reopen", title: "Reopen merge request", data: { original_text: "Reopen merge request", alternative_text: "Comment & reopen merge request"} %comment-and-resolve-btn{ "inline-template" => true } - %button.btn.btn-nr.btn-default.append-right-10.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { project_path: "#{project_path(@merge_request.project)}" } } + %button.btn.btn-nr.btn-default.gl-mr-3.js-comment-resolve-button{ "v-if" => "showButton", type: "submit", data: { project_path: "#{project_path(@merge_request.project)}" } } {{ buttonText }} #notes= render "shared/notes/notes_with_form", :autocomplete => true diff --git a/app/views/projects/merge_requests/_nav_btns.html.haml b/app/views/projects/merge_requests/_nav_btns.html.haml index b7498216334..2ef10365c18 100644 --- a/app/views/projects/merge_requests/_nav_btns.html.haml +++ b/app/views/projects/merge_requests/_nav_btns.html.haml @@ -1,5 +1,5 @@ - if @can_bulk_update - = button_tag "Edit merge requests", class: "btn append-right-10 js-bulk-update-toggle" + = button_tag "Edit merge requests", class: "btn gl-mr-3 js-bulk-update-toggle" - if merge_project = link_to new_merge_request_path, class: "btn btn-success", title: "New merge request" do New merge request diff --git a/app/views/projects/mirrors/_ssh_host_keys.html.haml b/app/views/projects/mirrors/_ssh_host_keys.html.haml index ca8ed417255..236ede32d31 100644 --- a/app/views/projects/mirrors/_ssh_host_keys.html.haml +++ b/app/views/projects/mirrors/_ssh_host_keys.html.haml @@ -3,7 +3,7 @@ - verified_at = mirror.ssh_known_hosts_verified_at .form-group.js-ssh-host-keys-section{ class: ('collapse' unless mirror.ssh_mirror_url?) } - %button.btn.btn-inverted.btn-secondary.inline.js-detect-host-keys.append-right-10{ type: 'button', data: { qa_selector: 'detect_host_keys' } } + %button.btn.btn-inverted.btn-secondary.inline.js-detect-host-keys.gl-mr-3{ type: 'button', data: { qa_selector: 'detect_host_keys' } } .js-spinner.d-none.spinner.mr-1 = _('Detect host keys') .fingerprint-ssh-info.js-fingerprint-ssh-info.prepend-top-10.append-bottom-10{ class: ('collapse' unless mirror.ssh_mirror_url?) } diff --git a/app/views/projects/no_repo.html.haml b/app/views/projects/no_repo.html.haml index 7748aadf44d..3a9e9108256 100644 --- a/app/views/projects/no_repo.html.haml +++ b/app/views/projects/no_repo.html.haml @@ -15,7 +15,7 @@ = link_to project_repository_path(@project), method: :post, class: 'btn btn-primary' do #{ _('Create empty repository') } - %strong.prepend-left-10.append-right-10 or + %strong.prepend-left-10.gl-mr-3 or = link_to new_project_import_path(@project), class: 'btn' do #{ _('Import repository') } diff --git a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml index 8d88f0be083..f48763cb544 100644 --- a/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml +++ b/app/views/projects/pipeline_schedules/_pipeline_schedule.html.haml @@ -27,8 +27,8 @@ %td .float-right.btn-group - if can?(current_user, :play_pipeline_schedule, pipeline_schedule) - = link_to play_pipeline_schedule_path(pipeline_schedule), method: :post, title: s_('Play'), class: 'btn' do - = icon('play') + = link_to play_pipeline_schedule_path(pipeline_schedule), method: :post, title: s_('Play'), class: 'btn btn-svg gl-display-flex gl-align-items-center gl-justify-content-center' do + = sprite_icon('play') - if can?(current_user, :take_ownership_pipeline_schedule, pipeline_schedule) = link_to take_ownership_pipeline_schedule_path(pipeline_schedule), method: :post, title: s_('PipelineSchedules|Take ownership'), class: 'btn' do = s_('PipelineSchedules|Take ownership') diff --git a/app/views/projects/project_templates/_built_in_templates.html.haml b/app/views/projects/project_templates/_built_in_templates.html.haml index eb41a3e0785..43352952b37 100644 --- a/app/views/projects/project_templates/_built_in_templates.html.haml +++ b/app/views/projects/project_templates/_built_in_templates.html.haml @@ -1,6 +1,6 @@ - Gitlab::ProjectTemplate.all.each do |template| .template-option.d-flex.align-items-center{ data: { qa_selector: 'template_option_row' } } - .logo.append-right-10.px-1 + .logo.gl-mr-3.px-1 = image_tag template.logo, size: 32, class: "btn-template-icon icon-#{template.name}" .description %strong @@ -9,7 +9,7 @@ .text-muted = template.description .controls.d-flex.align-items-center - %a.btn.btn-default.append-right-10{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } } + %a.btn.btn-default.gl-mr-3{ href: template.preview, rel: 'noopener noreferrer', target: '_blank', data: { track_label: "template_preview", track_property: template.name, track_event: "click_button", track_value: "" } } = _("Preview") %label.btn.btn-success.template-button.choose-template.gl-mb-0{ for: template.name } %input{ type: "radio", autocomplete: "off", name: "project[template_name]", id: template.name, value: template.name, data: { track_label: "template_use", track_property: template.name, track_event: "click_button", track_value: "" } } diff --git a/app/views/projects/project_templates/_project_fields_form.html.haml b/app/views/projects/project_templates/_project_fields_form.html.haml index c96010550d8..201e2d5b5fb 100644 --- a/app/views/projects/project_templates/_project_fields_form.html.haml +++ b/app/views/projects/project_templates/_project_fields_form.html.haml @@ -5,7 +5,7 @@ .input-group.template-input-group .input-group-prepend .input-group-text - .selected-icon.append-right-10 + .selected-icon.gl-mr-3 .selected-template .input-group-append %button.btn.btn-default.change-template{ type: "button" } diff --git a/app/views/sent_notifications/unsubscribe.html.haml b/app/views/sent_notifications/unsubscribe.html.haml index 1eecbe3bc0e..7aeecf26c39 100644 --- a/app/views/sent_notifications/unsubscribe.html.haml +++ b/app/views/sent_notifications/unsubscribe.html.haml @@ -15,5 +15,5 @@ %p = link_to _('Unsubscribe'), unsubscribe_sent_notification_path(@sent_notification, force: true), - class: 'btn btn-primary append-right-10' - = link_to _('Cancel'), new_user_session_path, class: 'btn append-right-10' + class: 'btn btn-primary gl-mr-3' + = link_to _('Cancel'), new_user_session_path, class: 'btn gl-mr-3' diff --git a/app/views/shared/groups/_dropdown.html.haml b/app/views/shared/groups/_dropdown.html.haml index f4915440cb2..9d2d3ce20c7 100644 --- a/app/views/shared/groups/_dropdown.html.haml +++ b/app/views/shared/groups/_dropdown.html.haml @@ -8,7 +8,7 @@ - else - default_sort_by = sort_value_recently_created -.dropdown.inline.js-group-filter-dropdown-wrap.append-right-10 +.dropdown.inline.js-group-filter-dropdown-wrap.gl-mr-3 %button.dropdown-menu-toggle{ type: 'button', 'data-toggle' => 'dropdown' } %span.dropdown-label = options_hash[default_sort_by] diff --git a/app/views/shared/issuable/_form.html.haml b/app/views/shared/issuable/_form.html.haml index cc5bd4d67c9..f54457b8b33 100644 --- a/app/views/shared/issuable/_form.html.haml +++ b/app/views/shared/issuable/_form.html.haml @@ -69,7 +69,7 @@ = link_to 'Delete', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable], params: { destroy_confirm: true }), data: { confirm: "#{issuable.human_class_name} will be removed! Are you sure?" }, method: :delete, class: 'btn btn-danger btn-grouped' = link_to 'Cancel', polymorphic_path([@project.namespace.becomes(Namespace), @project, issuable]), class: 'btn btn-grouped btn-cancel' - %span.append-right-10 + %span.gl-mr-3 - if issuable.new_record? = form.submit "Submit #{issuable.class.model_name.human.downcase}", class: 'btn btn-success qa-issuable-create-button' - else diff --git a/app/views/shared/milestones/_deprecation_message.html.haml b/app/views/shared/milestones/_deprecation_message.html.haml index ba5eb54f017..31b8b383fe1 100644 --- a/app/views/shared/milestones/_deprecation_message.html.haml +++ b/app/views/shared/milestones/_deprecation_message.html.haml @@ -1,6 +1,6 @@ .banner-callout.compact.milestone-deprecation-message.js-milestone-deprecation-message.prepend-top-20 .banner-graphic= image_tag 'illustrations/milestone_removing-page.svg' - .banner-body.prepend-left-10.append-right-10 + .banner-body.prepend-left-10.gl-mr-3 %h5.banner-title.gl-mt-0= _('This page will be removed in a future release.') %p.milestone-banner-text= _('Use group milestones to manage issues from multiple projects in the same milestone.') = button_tag _('Promote these project milestones into a group milestone.'), class: 'btn btn-link js-popover-link text-align-left milestone-banner-link' diff --git a/app/views/shared/notes/_comment_button.html.haml b/app/views/shared/notes/_comment_button.html.haml index 748bb1e6534..e151e55d0d2 100644 --- a/app/views/shared/notes/_comment_button.html.haml +++ b/app/views/shared/notes/_comment_button.html.haml @@ -1,6 +1,6 @@ - noteable_name = @note.noteable.human_class_name -.float-left.btn-group.append-right-10.droplab-dropdown.comment-type-dropdown.js-comment-type-dropdown +.float-left.btn-group.gl-mr-3.droplab-dropdown.comment-type-dropdown.js-comment-type-dropdown %input.btn.btn-nr.btn-success.js-comment-button.js-comment-submit-button{ type: 'submit', value: _('Comment'), data: { qa_selector: 'comment_button' } } - if @note.can_be_discussion_note? diff --git a/app/views/shared/projects/_project.html.haml b/app/views/shared/projects/_project.html.haml index ddf0bdeca4e..626e94e0202 100644 --- a/app/views/shared/projects/_project.html.haml +++ b/app/views/shared/projects/_project.html.haml @@ -39,11 +39,11 @@ %span.project-name< = project.name - %span.metadata-info.visibility-icon.append-right-10.gl-mt-3.text-secondary.has-tooltip{ data: { container: 'body', placement: 'top' }, title: visibility_icon_description(project) } + %span.metadata-info.visibility-icon.gl-mr-3.gl-mt-3.text-secondary.has-tooltip{ data: { container: 'body', placement: 'top' }, title: visibility_icon_description(project) } = visibility_level_icon(project.visibility_level, fw: true) - if explore_projects_tab? && project_license_name(project) - %span.metadata-info.d-inline-flex.align-items-center.append-right-10.gl-mt-3 + %span.metadata-info.d-inline-flex.align-items-center.gl-mr-3.gl-mt-3 = sprite_icon('scale', size: 14, css_class: 'gl-mr-2') = project_license_name(project) diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 0224b0db3dc..b079a114c71 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -691,6 +691,14 @@ :weight: 2 :idempotent: true :tags: [] +- :name: incident_management:incident_management_pager_duty_process_incident + :feature_category: :incident_management + :has_external_dependencies: + :urgency: :low + :resource_boundary: :unknown + :weight: 2 + :idempotent: + :tags: [] - :name: incident_management:incident_management_process_alert :feature_category: :incident_management :has_external_dependencies: @@ -869,7 +877,7 @@ :tags: [] - :name: pipeline_background:ci_pipeline_success_unlock_artifacts :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -877,7 +885,7 @@ :tags: [] - :name: pipeline_background:ci_ref_delete_unlock_artifacts :feature_category: :continuous_integration - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 @@ -1670,11 +1678,11 @@ :tags: [] - :name: service_desk_email_receiver :feature_category: :issue_tracking - :has_external_dependencies: + :has_external_dependencies: :urgency: :low :resource_boundary: :unknown :weight: 1 - :idempotent: + :idempotent: :tags: [] - :name: system_hook_push :feature_category: :source_code_management diff --git a/app/workers/incident_management/pager_duty/process_incident_worker.rb b/app/workers/incident_management/pager_duty/process_incident_worker.rb new file mode 100644 index 00000000000..3f378b012a1 --- /dev/null +++ b/app/workers/incident_management/pager_duty/process_incident_worker.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +module IncidentManagement + module PagerDuty + class ProcessIncidentWorker # rubocop:disable Scalability/IdempotentWorker + include ApplicationWorker + + queue_namespace :incident_management + feature_category :incident_management + + def perform(project_id, incident_payload) + return unless project_id + + project = find_project(project_id) + return unless project + + result = create_issue(project, incident_payload) + + log_error(result) if result.error? + end + + private + + def find_project(project_id) + Project.find_by_id(project_id) + end + + def create_issue(project, incident_payload) + ::IncidentManagement::PagerDuty::CreateIncidentIssueService + .new(project, incident_payload) + .execute + end + + def log_error(result) + Gitlab::AppLogger.warn( + message: 'Cannot create issue for PagerDuty incident', + issue_errors: result.message + ) + end + end + end +end |