diff options
Diffstat (limited to 'app')
46 files changed, 386 insertions, 340 deletions
diff --git a/app/assets/javascripts/alert_management/components/system_notes/system_note.vue b/app/assets/javascripts/alert_management/components/system_notes/system_note.vue index 9042d51aecf..39717ab609f 100644 --- a/app/assets/javascripts/alert_management/components/system_notes/system_note.vue +++ b/app/assets/javascripts/alert_management/components/system_notes/system_note.vue @@ -24,7 +24,7 @@ export default { return { ...author, id: id?.split('/').pop() }; }, iconHtml() { - return spriteIcon('user'); + return spriteIcon(this.note?.systemNoteIconName); }, }, }; diff --git a/app/assets/javascripts/alert_management/graphql/fragments/alert_note.fragment.graphql b/app/assets/javascripts/alert_management/graphql/fragments/alert_note.fragment.graphql index c72300e9757..74b425717a0 100644 --- a/app/assets/javascripts/alert_management/graphql/fragments/alert_note.fragment.graphql +++ b/app/assets/javascripts/alert_management/graphql/fragments/alert_note.fragment.graphql @@ -1,16 +1,17 @@ #import "~/graphql_shared/fragments/author.fragment.graphql" fragment AlertNote on Note { + id + author { id - author { - id - state - ...Author - } - body - bodyHtml - createdAt - discussion { - id - } + state + ...Author + } + body + bodyHtml + createdAt + discussion { + id + } + systemNoteIconName } diff --git a/app/assets/javascripts/diffs/constants.js b/app/assets/javascripts/diffs/constants.js index 9269dacd582..e3dd882f3dc 100644 --- a/app/assets/javascripts/diffs/constants.js +++ b/app/assets/javascripts/diffs/constants.js @@ -1,3 +1,7 @@ +// The backend actually uses "hide_whitespace" while the frontend +// uses "show whitspace" so these values are opposite what you might expect +export const NO_SHOW_WHITESPACE = '1'; +export const SHOW_WHITESPACE = '0'; export const INLINE_DIFF_VIEW_TYPE = 'inline'; export const PARALLEL_DIFF_VIEW_TYPE = 'parallel'; export const MATCH_LINE_TYPE = 'match'; @@ -20,6 +24,7 @@ export const LINE_SIDE_LEFT = 'left-side'; export const LINE_SIDE_RIGHT = 'right-side'; export const DIFF_VIEW_COOKIE_NAME = 'diff_view'; +export const DIFF_WHITESPACE_COOKIE_NAME = 'diff_whitespace'; export const LINE_HOVER_CLASS_NAME = 'is-over'; export const LINE_UNFOLD_CLASS_NAME = 'unfold js-unfold'; export const CONTEXT_LINE_CLASS_NAME = 'diff-expanded'; @@ -35,7 +40,6 @@ export const MR_TREE_SHOW_KEY = 'mr_tree_show'; export const TREE_TYPE = 'tree'; export const TREE_LIST_STORAGE_KEY = 'mr_diff_tree_list'; -export const WHITESPACE_STORAGE_KEY = 'mr_show_whitespace'; export const TREE_LIST_WIDTH_STORAGE_KEY = 'mr_tree_list_width'; export const INITIAL_TREE_WIDTH = 320; diff --git a/app/assets/javascripts/diffs/index.js b/app/assets/javascripts/diffs/index.js index ce48e36bfd7..028f04095a9 100644 --- a/app/assets/javascripts/diffs/index.js +++ b/app/assets/javascripts/diffs/index.js @@ -1,11 +1,11 @@ import Vue from 'vue'; import { mapActions, mapState, mapGetters } from 'vuex'; import { parseBoolean } from '~/lib/utils/common_utils'; -import { getParameterValues } from '~/lib/utils/url_utility'; import FindFile from '~/vue_shared/components/file_finder/index.vue'; import eventHub from '../notes/event_hub'; import diffsApp from './components/app.vue'; -import { TREE_LIST_STORAGE_KEY } from './constants'; +import { TREE_LIST_STORAGE_KEY, DIFF_WHITESPACE_COOKIE_NAME } from './constants'; +import Cookies from 'js-cookie'; export default function initDiffsApp(store) { const fileFinderEl = document.getElementById('js-diff-file-finder'); @@ -86,15 +86,16 @@ export default function initDiffsApp(store) { }), }, created() { - let hideWhitespace = getParameterValues('w')[0]; const treeListStored = localStorage.getItem(TREE_LIST_STORAGE_KEY); const renderTreeList = treeListStored !== null ? parseBoolean(treeListStored) : true; this.setRenderTreeList(renderTreeList); - if (!hideWhitespace) { - hideWhitespace = this.showWhitespaceDefault ? '0' : '1'; + + // Set whitespace default as per user preferences unless cookie is already set + if (!Cookies.get(DIFF_WHITESPACE_COOKIE_NAME)) { + const hideWhitespace = this.showWhitespaceDefault ? '0' : '1'; + this.setShowWhitespace({ showWhitespace: hideWhitespace !== '1' }); } - this.setShowWhitespace({ showWhitespace: hideWhitespace !== '1' }); }, methods: { ...mapActions('diffs', ['setRenderTreeList', 'setShowWhitespace']), @@ -114,7 +115,6 @@ export default function initDiffsApp(store) { isFluidLayout: this.isFluidLayout, dismissEndpoint: this.dismissEndpoint, showSuggestPopover: this.showSuggestPopover, - showWhitespaceDefault: this.showWhitespaceDefault, }, }); }, diff --git a/app/assets/javascripts/diffs/store/actions.js b/app/assets/javascripts/diffs/store/actions.js index a8d348e1836..6f903bd09f0 100644 --- a/app/assets/javascripts/diffs/store/actions.js +++ b/app/assets/javascripts/diffs/store/actions.js @@ -25,7 +25,6 @@ import { DIFF_VIEW_COOKIE_NAME, MR_TREE_SHOW_KEY, TREE_LIST_STORAGE_KEY, - WHITESPACE_STORAGE_KEY, TREE_LIST_WIDTH_STORAGE_KEY, OLD_LINE_KEY, NEW_LINE_KEY, @@ -38,6 +37,9 @@ import { INLINE_DIFF_LINES_KEY, PARALLEL_DIFF_LINES_KEY, DIFFS_PER_PAGE, + DIFF_WHITESPACE_COOKIE_NAME, + SHOW_WHITESPACE, + NO_SHOW_WHITESPACE, } from '../constants'; import { diffViewerModes } from '~/ide/constants'; @@ -484,11 +486,12 @@ export const setRenderTreeList = ({ commit }, renderTreeList) => { export const setShowWhitespace = ({ commit }, { showWhitespace, pushState = false }) => { commit(types.SET_SHOW_WHITESPACE, showWhitespace); + const w = showWhitespace ? SHOW_WHITESPACE : NO_SHOW_WHITESPACE; - localStorage.setItem(WHITESPACE_STORAGE_KEY, showWhitespace); + Cookies.set(DIFF_WHITESPACE_COOKIE_NAME, w); if (pushState) { - historyPushState(mergeUrlParams({ w: showWhitespace ? '0' : '1' }, window.location.href)); + historyPushState(mergeUrlParams({ w }, window.location.href)); } eventHub.$emit('refetchDiffData'); diff --git a/app/assets/javascripts/diffs/store/modules/diff_state.js b/app/assets/javascripts/diffs/store/modules/diff_state.js index 87938ababed..1f165dd4971 100644 --- a/app/assets/javascripts/diffs/store/modules/diff_state.js +++ b/app/assets/javascripts/diffs/store/modules/diff_state.js @@ -1,10 +1,17 @@ import Cookies from 'js-cookie'; import { getParameterValues } from '~/lib/utils/url_utility'; -import { INLINE_DIFF_VIEW_TYPE, DIFF_VIEW_COOKIE_NAME } from '../../constants'; +import { + INLINE_DIFF_VIEW_TYPE, + DIFF_VIEW_COOKIE_NAME, + DIFF_WHITESPACE_COOKIE_NAME, +} from '../../constants'; +import { getDefaultWhitespace } from '../utils'; const viewTypeFromQueryString = getParameterValues('view')[0]; const viewTypeFromCookie = Cookies.get(DIFF_VIEW_COOKIE_NAME); const defaultViewType = INLINE_DIFF_VIEW_TYPE; +const whiteSpaceFromQueryString = getParameterValues('w')[0]; +const whiteSpaceFromCookie = Cookies.get(DIFF_WHITESPACE_COOKIE_NAME); export default () => ({ isLoading: true, @@ -29,7 +36,7 @@ export default () => ({ commentForms: [], highlightedRow: null, renderTreeList: true, - showWhitespace: true, + showWhitespace: getDefaultWhitespace(whiteSpaceFromQueryString, whiteSpaceFromCookie), fileFinderVisible: false, dismissEndpoint: '', showSuggestPopover: true, diff --git a/app/assets/javascripts/diffs/store/utils.js b/app/assets/javascripts/diffs/store/utils.js index d261be1b550..bc85dd0a1d4 100644 --- a/app/assets/javascripts/diffs/store/utils.js +++ b/app/assets/javascripts/diffs/store/utils.js @@ -15,6 +15,8 @@ import { TREE_TYPE, INLINE_DIFF_VIEW_TYPE, PARALLEL_DIFF_VIEW_TYPE, + SHOW_WHITESPACE, + NO_SHOW_WHITESPACE, } from '../constants'; export function findDiffFile(files, match, matchKey = 'file_hash') { @@ -701,3 +703,10 @@ export const allDiscussionWrappersExpanded = diff => { return discussionsExpanded; }; + +export const getDefaultWhitespace = (queryString, cookie) => { + // Querystring should override stored cookie value + if (queryString) return queryString === SHOW_WHITESPACE; + if (cookie === NO_SHOW_WHITESPACE) return false; + return true; +}; diff --git a/app/assets/javascripts/monitoring/components/create_dashboard_modal.vue b/app/assets/javascripts/monitoring/components/create_dashboard_modal.vue new file mode 100644 index 00000000000..74799002b17 --- /dev/null +++ b/app/assets/javascripts/monitoring/components/create_dashboard_modal.vue @@ -0,0 +1,66 @@ +<script> +import { GlButton, GlModal, GlSprintf } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import { isSafeURL } from '~/lib/utils/url_utility'; + +export default { + components: { GlButton, GlModal, GlSprintf }, + props: { + modalId: { + type: String, + required: true, + }, + projectPath: { + type: String, + required: true, + validator: isSafeURL, + }, + addDashboardDocumentationPath: { + type: String, + required: true, + }, + }, + methods: { + cancelHandler() { + this.$refs.modal.hide(); + }, + }, + i18n: { + titleText: s__('Metrics|Create your dashboard configuration file'), + mainText: s__( + 'Metrics|To create a new dashboard, add a new YAML file to %{codeStart}.gitlab/dashboards%{codeEnd} at the root of this project.', + ), + }, +}; +</script> + +<template> + <gl-modal ref="modal" :modal-id="modalId" :title="$options.i18n.titleText"> + <p> + <gl-sprintf :message="$options.i18n.mainText"> + <template #code="{ content }"> + <code>{{ content }}</code> + </template> + </gl-sprintf> + </p> + <template #modal-footer> + <gl-button category="secondary" @click="cancelHandler">{{ s__('Metrics|Cancel') }}</gl-button> + <gl-button + category="secondary" + variant="info" + target="_blank" + :href="addDashboardDocumentationPath" + data-testid="create-dashboard-modal-docs-button" + > + {{ s__('Metrics|View documentation') }} + </gl-button> + <gl-button + variant="success" + data-testid="create-dashboard-modal-repo-button" + :href="projectPath" + > + {{ s__('Metrics|Open repository') }} + </gl-button> + </template> + </gl-modal> +</template> diff --git a/app/assets/javascripts/monitoring/components/dashboard.vue b/app/assets/javascripts/monitoring/components/dashboard.vue index 28c588de468..f685d67751c 100644 --- a/app/assets/javascripts/monitoring/components/dashboard.vue +++ b/app/assets/javascripts/monitoring/components/dashboard.vue @@ -72,6 +72,10 @@ export default { type: String, required: true, }, + addDashboardDocumentationPath: { + type: String, + required: true, + }, settingsPath: { type: String, required: true, @@ -395,6 +399,7 @@ export default { v-if="showHeader" ref="prometheusGraphsHeader" class="prometheus-graphs-header d-sm-flex flex-sm-wrap pt-2 pr-1 pb-0 pl-2 border-bottom bg-gray-light" + :add-dashboard-documentation-path="addDashboardDocumentationPath" :default-branch="defaultBranch" :rearrange-panels-available="rearrangePanelsAvailable" :custom-metrics-available="customMetricsAvailable" diff --git a/app/assets/javascripts/monitoring/components/dashboard_header.vue b/app/assets/javascripts/monitoring/components/dashboard_header.vue index b47adc9db11..4c973b6bb67 100644 --- a/app/assets/javascripts/monitoring/components/dashboard_header.vue +++ b/app/assets/javascripts/monitoring/components/dashboard_header.vue @@ -8,6 +8,9 @@ import { GlDropdownItem, GlDropdownHeader, GlDropdownDivider, + GlNewDropdown, + GlNewDropdownDivider, + GlNewDropdownItem, GlModal, GlLoadingIcon, GlSearchBoxByType, @@ -23,6 +26,8 @@ import DateTimePicker from '~/vue_shared/components/date_time_picker/date_time_p import DashboardsDropdown from './dashboards_dropdown.vue'; import RefreshButton from './refresh_button.vue'; +import CreateDashboardModal from './create_dashboard_modal.vue'; +import DuplicateDashboardModal from './duplicate_dashboard_modal.vue'; import TrackEventDirective from '~/vue_shared/directives/track_event'; import { getAddMetricTrackingOptions, timeRangeToUrl } from '../utils'; @@ -39,6 +44,9 @@ export default { GlDropdownItem, GlDropdownHeader, GlDropdownDivider, + GlNewDropdown, + GlNewDropdownDivider, + GlNewDropdownItem, GlSearchBoxByType, GlModal, CustomMetricsFormFields, @@ -46,6 +54,8 @@ export default { DateTimePicker, DashboardsDropdown, RefreshButton, + DuplicateDashboardModal, + CreateDashboardModal, }, directives: { GlModal: GlModalDirective, @@ -95,6 +105,10 @@ export default { type: Object, required: true, }, + addDashboardDocumentationPath: { + type: String, + required: true, + }, }, data() { return { @@ -108,8 +122,12 @@ export default { 'isUpdatingStarredValue', 'showEmptyState', 'dashboardTimezone', + 'projectPath', ]), ...mapGetters('monitoringDashboard', ['selectedDashboard', 'filteredEnvironments']), + isSystemDashboard() { + return this.selectedDashboard?.system_dashboard; + }, shouldShowEnvironmentsDropdownNoMatchedMsg() { return !this.environmentsLoading && this.filteredEnvironments.length === 0; }, @@ -129,6 +147,9 @@ export default { displayUtc() { return this.dashboardTimezone === timezones.UTC; }, + shouldShowActionsMenu() { + return Boolean(this.projectPath); + }, }, methods: { ...mapActions('monitoringDashboard', ['filterEnvironments', 'toggleStarredValue']), @@ -136,6 +157,7 @@ export default { const params = { dashboard: encodeURIComponent(dashboard.path), }; + redirectTo(mergeUrlParams(params, window.location.href)); }, debouncedEnvironmentsSearch: debounce(function environmentsSearchOnInput(searchTerm) { @@ -162,13 +184,15 @@ export default { this.$refs.customMetricsForm.submit(); }, }, - addMetric: { - title: s__('Metrics|Add metric'), - modalId: 'add-metric', + modalIds: { + addMetric: 'addMetric', + createDashboard: 'createDashboard', + duplicateDashboard: 'duplicateDashboard', }, i18n: { starDashboard: s__('Metrics|Star dashboard'), unstarDashboard: s__('Metrics|Unstar dashboard'), + addMetric: s__('Metrics|Add metric'), }, timeRanges, }; @@ -176,17 +200,20 @@ export default { <template> <div ref="prometheusGraphsHeader"> - <div class="mb-2 pr-2 d-flex d-sm-block"> + <div class="mb-2 mr-2 d-flex d-sm-block"> <dashboards-dropdown id="monitor-dashboards-dropdown" data-qa-selector="dashboards_filter_dropdown" class="flex-grow-1" toggle-class="dropdown-menu-toggle" :default-branch="defaultBranch" + :modal-id="$options.modalIds.duplicateDashboard" @selectDashboard="selectDashboard" /> </div> + <span aria-hidden="true" class="gl-pl-3 border-left gl-mb-3 d-none d-sm-block"></span> + <div class="mb-2 pr-2 d-flex d-sm-block"> <gl-dropdown id="monitor-environments-dropdown" @@ -290,17 +317,17 @@ export default { <div v-if="addingMetricsAvailable" class="mb-2 mr-2 d-flex d-sm-block"> <gl-deprecated-button ref="addMetricBtn" - v-gl-modal="$options.addMetric.modalId" + v-gl-modal="$options.modalIds.addMetric" variant="outline-success" data-qa-selector="add_metric_button" class="flex-grow-1" > - {{ $options.addMetric.title }} + {{ $options.i18n.addMetric }} </gl-deprecated-button> <gl-modal ref="addMetricModal" - :modal-id="$options.addMetric.modalId" - :title="$options.addMetric.title" + :modal-id="$options.modalIds.addMetric" + :title="$options.i18n.addMetric" > <form ref="customMetricsForm" :action="customMetricsPath" method="post"> <custom-metrics-form-fields @@ -353,6 +380,50 @@ export default { {{ __('View full dashboard') }} <icon name="external-link" /> </gl-deprecated-button> </div> + + <template v-if="shouldShowActionsMenu"> + <span aria-hidden="true" class="gl-pl-3 border-left gl-mb-3 d-none d-sm-block"></span> + + <div class="gl-mb-3 gl-mr-3 d-flex d-sm-block"> + <gl-new-dropdown + v-gl-tooltip + right + class="gl-flex-grow-1" + data-testid="actions-menu" + :title="s__('Metrics|Create dashboard')" + :icon="'plus-square'" + > + <gl-new-dropdown-item + v-gl-modal="$options.modalIds.createDashboard" + data-testid="action-create-dashboard" + >{{ s__('Metrics|Create new dashboard') }}</gl-new-dropdown-item + > + + <create-dashboard-modal + data-testid="create-dashboard-modal" + :add-dashboard-documentation-path="addDashboardDocumentationPath" + :modal-id="$options.modalIds.createDashboard" + :project-path="projectPath" + /> + + <template v-if="isSystemDashboard"> + <gl-new-dropdown-divider /> + <gl-new-dropdown-item + ref="duplicateDashboardItem" + v-gl-modal="$options.modalIds.duplicateDashboard" + data-testid="action-duplicate-dashboard" + > + {{ s__('Metrics|Duplicate current dashboard') }} + </gl-new-dropdown-item> + </template> + </gl-new-dropdown> + </div> + </template> </div> + <duplicate-dashboard-modal + :default-branch="defaultBranch" + :modal-id="$options.modalIds.duplicateDashboard" + @dashboardDuplicated="selectDashboard" + /> </div> </template> diff --git a/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue b/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue index 8b86890715f..0e96d57b8a1 100644 --- a/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue +++ b/app/assets/javascripts/monitoring/components/dashboards_dropdown.vue @@ -1,19 +1,14 @@ <script> import { mapState, mapActions, mapGetters } from 'vuex'; import { - GlAlert, GlIcon, GlDropdown, GlDropdownItem, GlDropdownHeader, GlDropdownDivider, GlSearchBoxByType, - GlModal, - GlLoadingIcon, GlModalDirective, } from '@gitlab/ui'; -import { s__ } from '~/locale'; -import DuplicateDashboardForm from './duplicate_dashboard_form.vue'; const events = { selectDashboard: 'selectDashboard', @@ -21,16 +16,12 @@ const events = { export default { components: { - GlAlert, GlIcon, GlDropdown, GlDropdownItem, GlDropdownHeader, GlDropdownDivider, GlSearchBoxByType, - GlModal, - GlLoadingIcon, - DuplicateDashboardForm, }, directives: { GlModal: GlModalDirective, @@ -40,12 +31,13 @@ export default { type: String, required: true, }, + modalId: { + type: String, + required: true, + }, }, data() { return { - alert: null, - loading: false, - form: {}, searchTerm: '', }; }, @@ -76,10 +68,6 @@ export default { nonStarredDashboards() { return this.filteredDashboards.filter(({ starred }) => !starred); }, - - okButtonText() { - return this.loading ? s__('Metrics|Duplicating...') : s__('Metrics|Duplicate'); - }, }, methods: { ...mapActions('monitoringDashboard', ['duplicateSystemDashboard']), @@ -89,37 +77,6 @@ export default { selectDashboard(dashboard) { this.$emit(events.selectDashboard, dashboard); }, - ok(bvModalEvt) { - // Prevent modal from hiding in case submit fails - bvModalEvt.preventDefault(); - - this.loading = true; - this.alert = null; - this.duplicateSystemDashboard(this.form) - .then(createdDashboard => { - this.loading = false; - this.alert = null; - - // Trigger hide modal as submit is successful - this.$refs.duplicateDashboardModal.hide(); - - // Dashboards in the default branch become available immediately. - // Not so in other branches, so we refresh the current dashboard - const dashboard = - this.form.branch === this.defaultBranch ? createdDashboard : this.selectedDashboard; - this.$emit(events.selectDashboard, dashboard); - }) - .catch(error => { - this.loading = false; - this.alert = error; - }); - }, - hide() { - this.alert = null; - }, - formChange(form) { - this.form = form; - }, }, }; </script> @@ -178,32 +135,14 @@ export default { {{ __('No matching results') }} </div> + <!-- + This Duplicate Dashboard item will be removed from the dashboards dropdown + in https://gitlab.com/gitlab-org/gitlab/-/issues/223223 + --> <template v-if="isSystemDashboard"> <gl-dropdown-divider /> - <gl-modal - ref="duplicateDashboardModal" - modal-id="duplicateDashboardModal" - :title="s__('Metrics|Duplicate dashboard')" - ok-variant="success" - @ok="ok" - @hide="hide" - > - <gl-alert v-if="alert" class="mb-3" variant="danger" @dismiss="alert = null"> - {{ alert }} - </gl-alert> - <duplicate-dashboard-form - :dashboard="selectedDashboard" - :default-branch="defaultBranch" - @change="formChange" - /> - <template #modal-ok> - <gl-loading-icon v-if="loading" inline color="light" /> - {{ okButtonText }} - </template> - </gl-modal> - - <gl-dropdown-item ref="duplicateDashboardItem" v-gl-modal="'duplicateDashboardModal'"> + <gl-dropdown-item v-gl-modal="modalId" data-testid="duplicateDashboardItem"> {{ s__('Metrics|Duplicate dashboard') }} </gl-dropdown-item> </template> diff --git a/app/assets/javascripts/monitoring/components/duplicate_dashboard_modal.vue b/app/assets/javascripts/monitoring/components/duplicate_dashboard_modal.vue new file mode 100644 index 00000000000..e64afc01fd9 --- /dev/null +++ b/app/assets/javascripts/monitoring/components/duplicate_dashboard_modal.vue @@ -0,0 +1,95 @@ +<script> +import { mapActions, mapGetters } from 'vuex'; +import { GlAlert, GlLoadingIcon, GlModal } from '@gitlab/ui'; +import { s__ } from '~/locale'; +import DuplicateDashboardForm from './duplicate_dashboard_form.vue'; + +const events = { + dashboardDuplicated: 'dashboardDuplicated', +}; + +export default { + components: { GlAlert, GlLoadingIcon, GlModal, DuplicateDashboardForm }, + props: { + defaultBranch: { + type: String, + required: true, + }, + modalId: { + type: String, + required: true, + }, + }, + data() { + return { + alert: null, + loading: false, + form: {}, + }; + }, + computed: { + ...mapGetters('monitoringDashboard', ['selectedDashboard']), + okButtonText() { + return this.loading ? s__('Metrics|Duplicating...') : s__('Metrics|Duplicate'); + }, + }, + methods: { + ...mapActions('monitoringDashboard', ['duplicateSystemDashboard']), + ok(bvModalEvt) { + // Prevent modal from hiding in case submit fails + bvModalEvt.preventDefault(); + + this.loading = true; + this.alert = null; + this.duplicateSystemDashboard(this.form) + .then(createdDashboard => { + this.loading = false; + this.alert = null; + + // Trigger hide modal as submit is successful + this.$refs.duplicateDashboardModal.hide(); + + // Dashboards in the default branch become available immediately. + // Not so in other branches, so we refresh the current dashboard + const dashboard = + this.form.branch === this.defaultBranch ? createdDashboard : this.selectedDashboard; + this.$emit(events.dashboardDuplicated, dashboard); + }) + .catch(error => { + this.loading = false; + this.alert = error; + }); + }, + hide() { + this.alert = null; + }, + formChange(form) { + this.form = form; + }, + }, +}; +</script> + +<template> + <gl-modal + ref="duplicateDashboardModal" + :modal-id="modalId" + :title="s__('Metrics|Duplicate dashboard')" + ok-variant="success" + @ok="ok" + @hide="hide" + > + <gl-alert v-if="alert" class="mb-3" variant="danger" @dismiss="alert = null"> + {{ alert }} + </gl-alert> + <duplicate-dashboard-form + :dashboard="selectedDashboard" + :default-branch="defaultBranch" + @change="formChange" + /> + <template #modal-ok> + <gl-loading-icon v-if="loading" inline color="light" /> + {{ okButtonText }} + </template> + </gl-modal> +</template> diff --git a/app/assets/javascripts/repository/components/breadcrumbs.vue b/app/assets/javascripts/repository/components/breadcrumbs.vue index 8a11c3dcafe..45c343c3f7f 100644 --- a/app/assets/javascripts/repository/components/breadcrumbs.vue +++ b/app/assets/javascripts/repository/components/breadcrumbs.vue @@ -4,9 +4,9 @@ import { joinPaths, escapeFileUrl } from '~/lib/utils/url_utility'; import { __ } from '../../locale'; import Icon from '../../vue_shared/components/icon.vue'; import getRefMixin from '../mixins/get_ref'; -import projectShortPathQuery from '../queries/project_short_path.query.graphql'; -import projetPathQuery from '../queries/project_path.query.graphql'; -import permissionsQuery from '../queries/permissions.query.graphql'; +import getProjectShortPath from '../queries/getProjectShortPath.query.graphql'; +import getProjectPath from '../queries/getProjectPath.query.graphql'; +import getPermissions from '../queries/getPermissions.query.graphql'; const ROW_TYPES = { header: 'header', @@ -23,13 +23,13 @@ export default { }, apollo: { projectShortPath: { - query: projectShortPathQuery, + query: getProjectShortPath, }, projectPath: { - query: projetPathQuery, + query: getProjectPath, }, userPermissions: { - query: permissionsQuery, + query: getPermissions, variables() { return { projectPath: this.projectPath, diff --git a/app/assets/javascripts/repository/components/last_commit.vue b/app/assets/javascripts/repository/components/last_commit.vue index 0206a61487c..c5c99d56e2a 100644 --- a/app/assets/javascripts/repository/components/last_commit.vue +++ b/app/assets/javascripts/repository/components/last_commit.vue @@ -8,8 +8,8 @@ import TimeagoTooltip from '../../vue_shared/components/time_ago_tooltip.vue'; import CiIcon from '../../vue_shared/components/ci_icon.vue'; import ClipboardButton from '../../vue_shared/components/clipboard_button.vue'; import getRefMixin from '../mixins/get_ref'; -import projectPathQuery from '../queries/project_path.query.graphql'; -import pathLastCommitQuery from '../queries/path_last_commit.query.graphql'; +import getProjectPath from '../queries/getProjectPath.query.graphql'; +import pathLastCommit from '../queries/pathLastCommit.query.graphql'; export default { components: { @@ -28,10 +28,10 @@ export default { mixins: [getRefMixin], apollo: { projectPath: { - query: projectPathQuery, + query: getProjectPath, }, commit: { - query: pathLastCommitQuery, + query: pathLastCommit, variables() { return { projectPath: this.projectPath, @@ -102,7 +102,7 @@ export default { <template v-else-if="commit"> <user-avatar-link v-if="commit.author" - :link-href="commit.author.webPath" + :link-href="commit.author.webUrl" :img-src="commit.author.avatarUrl" :img-size="40" class="avatar-cell" @@ -118,7 +118,7 @@ export default { <div class="commit-detail flex-list"> <div class="commit-content qa-commit-content"> <gl-link - :href="commit.webPath" + :href="commit.webUrl" :class="{ 'font-italic': !commit.message }" class="commit-row-message item-title" v-html="commit.titleHtml" @@ -135,7 +135,7 @@ export default { <div class="committer"> <gl-link v-if="commit.author" - :href="commit.author.webPath" + :href="commit.author.webUrl" class="commit-author-link js-user-link" > {{ commit.author.name }} diff --git a/app/assets/javascripts/repository/components/preview/index.vue b/app/assets/javascripts/repository/components/preview/index.vue index ecf98ebe7db..f96523bb497 100644 --- a/app/assets/javascripts/repository/components/preview/index.vue +++ b/app/assets/javascripts/repository/components/preview/index.vue @@ -3,15 +3,15 @@ import $ from 'jquery'; import '~/behaviors/markdown/render_gfm'; import { GlLink, GlLoadingIcon } from '@gitlab/ui'; import { handleLocationHash } from '~/lib/utils/common_utils'; -import readmeQery from '../../queries/readme.query.graphql'; +import getReadmeQuery from '../../queries/getReadme.query.graphql'; export default { apollo: { readme: { - query: readmeQery, + query: getReadmeQuery, variables() { return { - url: this.blob.webPath, + url: this.blob.webUrl, }; }, loadingKey: 'loading', @@ -51,7 +51,7 @@ export default { <div class="js-file-title file-title-flex-parent"> <div class="file-header-content"> <i aria-hidden="true" class="fa fa-file-text-o fa-fw"></i> - <gl-link :href="blob.webPath"> + <gl-link :href="blob.webUrl"> <strong>{{ blob.name }}</strong> </gl-link> </div> diff --git a/app/assets/javascripts/repository/components/table/index.vue b/app/assets/javascripts/repository/components/table/index.vue index 4077e3f8cdc..c1f350dccd6 100644 --- a/app/assets/javascripts/repository/components/table/index.vue +++ b/app/assets/javascripts/repository/components/table/index.vue @@ -2,7 +2,7 @@ import { GlSkeletonLoading } from '@gitlab/ui'; import { sprintf, __ } from '../../../locale'; import getRefMixin from '../../mixins/get_ref'; -import projectPathQuery from '../../queries/project_path.query.graphql'; +import getProjectPath from '../../queries/getProjectPath.query.graphql'; import TableHeader from './header.vue'; import TableRow from './row.vue'; import ParentRow from './parent_row.vue'; @@ -17,7 +17,7 @@ export default { mixins: [getRefMixin], apollo: { projectPath: { - query: projectPathQuery, + query: getProjectPath, }, }, props: { @@ -96,7 +96,7 @@ export default { :name="entry.name" :path="entry.flatPath" :type="entry.type" - :url="entry.webUrl || entry.webPath" + :url="entry.webUrl" :submodule-tree-url="entry.treeUrl" :lfs-oid="entry.lfsOid" :loading-path="loadingPath" diff --git a/app/assets/javascripts/repository/components/table/row.vue b/app/assets/javascripts/repository/components/table/row.vue index 95e34280665..d5363016335 100644 --- a/app/assets/javascripts/repository/components/table/row.vue +++ b/app/assets/javascripts/repository/components/table/row.vue @@ -12,7 +12,7 @@ import { escapeFileUrl } from '~/lib/utils/url_utility'; import TimeagoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import FileIcon from '~/vue_shared/components/file_icon.vue'; import getRefMixin from '../../mixins/get_ref'; -import commitQuery from '../../queries/commit.query.graphql'; +import getCommit from '../../queries/getCommit.query.graphql'; export default { components: { @@ -29,7 +29,7 @@ export default { }, apollo: { commit: { - query: commitQuery, + query: getCommit, variables() { return { fileName: this.name, diff --git a/app/assets/javascripts/repository/components/tree_content.vue b/app/assets/javascripts/repository/components/tree_content.vue index 721cc6787dc..59ba1caa8c9 100644 --- a/app/assets/javascripts/repository/components/tree_content.vue +++ b/app/assets/javascripts/repository/components/tree_content.vue @@ -3,8 +3,8 @@ import createFlash from '~/flash'; import { __ } from '../../locale'; import FileTable from './table/index.vue'; import getRefMixin from '../mixins/get_ref'; -import filesQuery from '../queries/files.query.graphql'; -import projectPathQuery from '../queries/project_path.query.graphql'; +import getFiles from '../queries/getFiles.query.graphql'; +import getProjectPath from '../queries/getProjectPath.query.graphql'; import FilePreview from './preview/index.vue'; import { readmeFile } from '../utils/readme'; @@ -18,7 +18,7 @@ export default { mixins: [getRefMixin], apollo: { projectPath: { - query: projectPathQuery, + query: getProjectPath, }, }, props: { @@ -70,7 +70,7 @@ export default { return this.$apollo .query({ - query: filesQuery, + query: getFiles, variables: { projectPath: this.projectPath, ref: this.ref, diff --git a/app/assets/javascripts/repository/log_tree.js b/app/assets/javascripts/repository/log_tree.js index 704dd88aabe..cef17bf7acb 100644 --- a/app/assets/javascripts/repository/log_tree.js +++ b/app/assets/javascripts/repository/log_tree.js @@ -1,8 +1,8 @@ import { normalizeData } from 'ee_else_ce/repository/utils/commit'; import axios from '~/lib/utils/axios_utils'; -import commitsQuery from './queries/commits.query.graphql'; -import projectPathQuery from './queries/project_path.query.graphql'; -import refQuery from './queries/ref.query.graphql'; +import getCommits from './queries/getCommits.query.graphql'; +import getProjectPath from './queries/getProjectPath.query.graphql'; +import getRef from './queries/getRef.query.graphql'; let fetchpromise; let resolvers = []; @@ -22,8 +22,8 @@ export function fetchLogsTree(client, path, offset, resolver = null) { if (fetchpromise) return fetchpromise; - const { projectPath } = client.readQuery({ query: projectPathQuery }); - const { escapedRef } = client.readQuery({ query: refQuery }); + const { projectPath } = client.readQuery({ query: getProjectPath }); + const { escapedRef } = client.readQuery({ query: getRef }); fetchpromise = axios .get( @@ -36,10 +36,10 @@ export function fetchLogsTree(client, path, offset, resolver = null) { ) .then(({ data, headers }) => { const headerLogsOffset = headers['more-logs-offset']; - const { commits } = client.readQuery({ query: commitsQuery }); + const { commits } = client.readQuery({ query: getCommits }); const newCommitData = [...commits, ...normalizeData(data, path)]; client.writeQuery({ - query: commitsQuery, + query: getCommits, data: { commits: newCommitData }, }); diff --git a/app/assets/javascripts/repository/mixins/get_ref.js b/app/assets/javascripts/repository/mixins/get_ref.js index 1f1880a48c7..99d19b77c35 100644 --- a/app/assets/javascripts/repository/mixins/get_ref.js +++ b/app/assets/javascripts/repository/mixins/get_ref.js @@ -1,9 +1,9 @@ -import refQuery from '../queries/ref.query.graphql'; +import getRef from '../queries/getRef.query.graphql'; export default { apollo: { ref: { - query: refQuery, + query: getRef, manual: true, result({ data, loading }) { if (!loading) { diff --git a/app/assets/javascripts/repository/mixins/preload.js b/app/assets/javascripts/repository/mixins/preload.js index cb1d7f3aac9..cb6c2294679 100644 --- a/app/assets/javascripts/repository/mixins/preload.js +++ b/app/assets/javascripts/repository/mixins/preload.js @@ -1,12 +1,12 @@ -import filesQuery from '../queries/files.query.graphql'; +import getFiles from '../queries/getFiles.query.graphql'; import getRefMixin from './get_ref'; -import projectPathQuery from '../queries/project_path.query.graphql'; +import getProjectPath from '../queries/getProjectPath.query.graphql'; export default { mixins: [getRefMixin], apollo: { projectPath: { - query: projectPathQuery, + query: getProjectPath, }, }, data() { @@ -21,7 +21,7 @@ export default { return this.$apollo .query({ - query: filesQuery, + query: getFiles, variables: { projectPath: this.projectPath, ref: this.ref, diff --git a/app/assets/javascripts/repository/queries/commit.query.graphql b/app/assets/javascripts/repository/queries/getCommit.query.graphql index d2c94733bb9..e4aeaaff8fe 100644 --- a/app/assets/javascripts/repository/queries/commit.query.graphql +++ b/app/assets/javascripts/repository/queries/getCommit.query.graphql @@ -1,6 +1,6 @@ #import "ee_else_ce/repository/queries/commit.fragment.graphql" -query Commit($fileName: String!, $type: String!, $path: String!) { +query getCommit($fileName: String!, $type: String!, $path: String!) { commit(path: $path, fileName: $fileName, type: $type) @client { ...TreeEntryCommit } diff --git a/app/assets/javascripts/repository/queries/commits.query.graphql b/app/assets/javascripts/repository/queries/getCommits.query.graphql index 8747649f56f..0976b8f32d7 100644 --- a/app/assets/javascripts/repository/queries/commits.query.graphql +++ b/app/assets/javascripts/repository/queries/getCommits.query.graphql @@ -1,6 +1,6 @@ #import "ee_else_ce/repository/queries/commit.fragment.graphql" -query Commits { +query getCommits { commits @client { ...TreeEntryCommit } diff --git a/app/assets/javascripts/repository/queries/files.query.graphql b/app/assets/javascripts/repository/queries/getFiles.query.graphql index 10843b0450f..2aaf5066b4a 100644 --- a/app/assets/javascripts/repository/queries/files.query.graphql +++ b/app/assets/javascripts/repository/queries/getFiles.query.graphql @@ -8,7 +8,7 @@ fragment TreeEntry on Entry { type } -query Files( +query getFiles( $projectPath: ID! $path: String $ref: String! @@ -22,7 +22,7 @@ query Files( edges { node { ...TreeEntry - webPath + webUrl } } pageInfo { @@ -45,7 +45,7 @@ query Files( edges { node { ...TreeEntry - webPath + webUrl lfsOid } } diff --git a/app/assets/javascripts/repository/queries/permissions.query.graphql b/app/assets/javascripts/repository/queries/getPermissions.query.graphql index 57976ca2689..092fa44e2d0 100644 --- a/app/assets/javascripts/repository/queries/permissions.query.graphql +++ b/app/assets/javascripts/repository/queries/getPermissions.query.graphql @@ -1,4 +1,4 @@ -query Permissions($projectPath: ID!) { +query getPermissions($projectPath: ID!) { project(fullPath: $projectPath) { userPermissions { pushCode diff --git a/app/assets/javascripts/repository/queries/getProjectPath.query.graphql b/app/assets/javascripts/repository/queries/getProjectPath.query.graphql new file mode 100644 index 00000000000..74e73e07577 --- /dev/null +++ b/app/assets/javascripts/repository/queries/getProjectPath.query.graphql @@ -0,0 +1,3 @@ +query getProjectPath { + projectPath +} diff --git a/app/assets/javascripts/repository/queries/project_short_path.query.graphql b/app/assets/javascripts/repository/queries/getProjectShortPath.query.graphql index e6abe9d78cd..34eb26598c2 100644 --- a/app/assets/javascripts/repository/queries/project_short_path.query.graphql +++ b/app/assets/javascripts/repository/queries/getProjectShortPath.query.graphql @@ -1,3 +1,3 @@ -query ProjectShortPath { +query getProjectShortPath { projectShortPath @client } diff --git a/app/assets/javascripts/repository/queries/readme.query.graphql b/app/assets/javascripts/repository/queries/getReadme.query.graphql index 38ecc2e1bb2..cf056330133 100644 --- a/app/assets/javascripts/repository/queries/readme.query.graphql +++ b/app/assets/javascripts/repository/queries/getReadme.query.graphql @@ -1,4 +1,4 @@ -query Readme($url: String!) { +query getReadme($url: String!) { readme(url: $url) @client { html } diff --git a/app/assets/javascripts/repository/queries/ref.query.graphql b/app/assets/javascripts/repository/queries/getRef.query.graphql index e3498acd688..91afb751626 100644 --- a/app/assets/javascripts/repository/queries/ref.query.graphql +++ b/app/assets/javascripts/repository/queries/getRef.query.graphql @@ -1,4 +1,4 @@ -query Ref { +query getRef { ref @client escapedRef @client } diff --git a/app/assets/javascripts/repository/queries/path_last_commit.query.graphql b/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql index 8dc00fd9c7b..f54f09fd647 100644 --- a/app/assets/javascripts/repository/queries/path_last_commit.query.graphql +++ b/app/assets/javascripts/repository/queries/pathLastCommit.query.graphql @@ -1,4 +1,4 @@ -query PathLastCommit($projectPath: ID!, $path: String, $ref: String!) { +query pathLastCommit($projectPath: ID!, $path: String, $ref: String!) { project(fullPath: $projectPath) { repository { tree(path: $path, ref: $ref) { @@ -8,14 +8,14 @@ query PathLastCommit($projectPath: ID!, $path: String, $ref: String!) { titleHtml description message - webPath + webUrl authoredDate authorName authorGravatar author { name avatarUrl - webPath + webUrl } signatureHtml pipelines(ref: $ref, first: 1) { diff --git a/app/assets/javascripts/repository/queries/project_path.query.graphql b/app/assets/javascripts/repository/queries/project_path.query.graphql deleted file mode 100644 index 462ae5382a1..00000000000 --- a/app/assets/javascripts/repository/queries/project_path.query.graphql +++ /dev/null @@ -1,3 +0,0 @@ -query ProjectPath { - projectPath -} diff --git a/app/graphql/types/commit_type.rb b/app/graphql/types/commit_type.rb index b4ec1d5cb6c..be5165da545 100644 --- a/app/graphql/types/commit_type.rb +++ b/app/graphql/types/commit_type.rb @@ -23,8 +23,6 @@ module Types description: 'Timestamp of when the commit was authored' field :web_url, type: GraphQL::STRING_TYPE, null: false, description: 'Web URL of the commit' - field :web_path, type: GraphQL::STRING_TYPE, null: false, - description: 'Web path of the commit' field :signature_html, type: GraphQL::STRING_TYPE, null: true, calls_gitaly: true, description: 'Rendered HTML of the commit signature' field :author_name, type: GraphQL::STRING_TYPE, null: true, diff --git a/app/graphql/types/notes/note_type.rb b/app/graphql/types/notes/note_type.rb index 8755b4ccad5..5d41f0032bd 100644 --- a/app/graphql/types/notes/note_type.rb +++ b/app/graphql/types/notes/note_type.rb @@ -27,6 +27,8 @@ module Types field :system, GraphQL::BOOLEAN_TYPE, null: false, description: 'Indicates whether this note was created by the system or by a user' + field :system_note_icon_name, GraphQL::STRING_TYPE, null: true, + description: 'Name of the icon corresponding to a system note' field :body, GraphQL::STRING_TYPE, null: false, @@ -46,6 +48,10 @@ module Types field :confidential, GraphQL::BOOLEAN_TYPE, null: true, description: 'Indicates if this note is confidential', method: :confidential? + + def system_note_icon_name + SystemNoteHelper.system_note_icon_name(object) if object.system? + end end end end diff --git a/app/graphql/types/tree/blob_type.rb b/app/graphql/types/tree/blob_type.rb index 4fdb4570b7d..22349203519 100644 --- a/app/graphql/types/tree/blob_type.rb +++ b/app/graphql/types/tree/blob_type.rb @@ -12,8 +12,6 @@ module Types field :web_url, GraphQL::STRING_TYPE, null: true, description: 'Web URL of the blob' - field :web_path, GraphQL::STRING_TYPE, null: true, - description: 'Web path of the blob' field :lfs_oid, GraphQL::STRING_TYPE, null: true, description: 'LFS ID of the blob', resolve: -> (blob, args, ctx) do diff --git a/app/graphql/types/tree/tree_entry_type.rb b/app/graphql/types/tree/tree_entry_type.rb index aff2e025761..81a7a7e66ae 100644 --- a/app/graphql/types/tree/tree_entry_type.rb +++ b/app/graphql/types/tree/tree_entry_type.rb @@ -13,8 +13,6 @@ module Types field :web_url, GraphQL::STRING_TYPE, null: true, description: 'Web URL for the tree entry (directory)' - field :web_path, GraphQL::STRING_TYPE, null: true, - description: 'Web path for the tree entry (directory)' end # rubocop: enable Graphql/AuthorizeTypes end diff --git a/app/graphql/types/user_type.rb b/app/graphql/types/user_type.rb index f636f1b02b2..ab3c84ea539 100644 --- a/app/graphql/types/user_type.rb +++ b/app/graphql/types/user_type.rb @@ -22,8 +22,6 @@ module Types description: "URL of the user's avatar" field :web_url, GraphQL::STRING_TYPE, null: false, description: 'Web URL of the user' - field :web_path, GraphQL::STRING_TYPE, null: false, - description: 'Web path of the user' field :todos, Types::TodoType.connection_type, null: false, resolver: Resolvers::TodoResolver, description: 'Todos of the user' diff --git a/app/helpers/ci/pipeline_schedules_helper.rb b/app/helpers/ci/pipeline_schedules_helper.rb new file mode 100644 index 00000000000..20e5c90a60e --- /dev/null +++ b/app/helpers/ci/pipeline_schedules_helper.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +module Ci + module PipelineSchedulesHelper + def timezone_data + ActiveSupport::TimeZone.all.map do |timezone| + { + name: timezone.name, + offset: timezone.now.utc_offset, + identifier: timezone.tzinfo.identifier + } + end + end + end +end diff --git a/app/helpers/environments_helper.rb b/app/helpers/environments_helper.rb index 41a255434af..4e5d12de8d3 100644 --- a/app/helpers/environments_helper.rb +++ b/app/helpers/environments_helper.rb @@ -92,6 +92,7 @@ module EnvironmentsHelper def static_metrics_data { 'documentation-path' => help_page_path('administration/monitoring/prometheus/index.md'), + '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'), diff --git a/app/helpers/pipeline_schedules_helper.rb b/app/helpers/pipeline_schedules_helper.rb deleted file mode 100644 index 0e166106b32..00000000000 --- a/app/helpers/pipeline_schedules_helper.rb +++ /dev/null @@ -1,13 +0,0 @@ -# frozen_string_literal: true - -module PipelineSchedulesHelper - def timezone_data - ActiveSupport::TimeZone.all.map do |timezone| - { - name: timezone.name, - offset: timezone.now.utc_offset, - identifier: timezone.tzinfo.identifier - } - end - end -end diff --git a/app/presenters/blob_presenter.rb b/app/presenters/blob_presenter.rb index cff935d51b5..e0077db8d5c 100644 --- a/app/presenters/blob_presenter.rb +++ b/app/presenters/blob_presenter.rb @@ -18,10 +18,6 @@ class BlobPresenter < Gitlab::View::Presenter::Delegated Gitlab::Routing.url_helpers.project_blob_url(blob.repository.project, File.join(blob.commit_id, blob.path)) end - def web_path - Gitlab::Routing.url_helpers.project_blob_path(blob.repository.project, File.join(blob.commit_id, blob.path)) - end - private def load_all_blob_data diff --git a/app/presenters/commit_presenter.rb b/app/presenters/commit_presenter.rb index 998e5160f8b..9ded00fcb7a 100644 --- a/app/presenters/commit_presenter.rb +++ b/app/presenters/commit_presenter.rb @@ -21,10 +21,6 @@ class CommitPresenter < Gitlab::View::Presenter::Delegated url_builder.build(commit) end - def web_path - url_builder.build(commit, only_path: true) - end - def signature_html return unless commit.has_signature? diff --git a/app/presenters/tree_entry_presenter.rb b/app/presenters/tree_entry_presenter.rb index 216b3b0d4c9..7bb10cd1455 100644 --- a/app/presenters/tree_entry_presenter.rb +++ b/app/presenters/tree_entry_presenter.rb @@ -6,8 +6,4 @@ class TreeEntryPresenter < Gitlab::View::Presenter::Delegated def web_url Gitlab::Routing.url_helpers.project_tree_url(tree.repository.project, File.join(tree.commit_id, tree.path)) end - - def web_path - Gitlab::Routing.url_helpers.project_tree_path(tree.repository.project, File.join(tree.commit_id, tree.path)) - end end diff --git a/app/presenters/user_presenter.rb b/app/presenters/user_presenter.rb index 2a4d6a070f8..14ef53e9ec8 100644 --- a/app/presenters/user_presenter.rb +++ b/app/presenters/user_presenter.rb @@ -6,8 +6,4 @@ class UserPresenter < Gitlab::View::Presenter::Delegated def web_url Gitlab::Routing.url_helpers.user_url(user) end - - def web_path - Gitlab::Routing.url_helpers.user_path(user) - end end diff --git a/app/services/projects/prometheus/alerts/create_events_service.rb b/app/services/projects/prometheus/alerts/create_events_service.rb deleted file mode 100644 index 4fcf841314b..00000000000 --- a/app/services/projects/prometheus/alerts/create_events_service.rb +++ /dev/null @@ -1,71 +0,0 @@ -# frozen_string_literal: true - -module Projects - module Prometheus - module Alerts - # Persists a series of Prometheus alert events as list of PrometheusAlertEvent. - class CreateEventsService < BaseService - def execute - create_events_from(alerts) - end - - private - - def create_events_from(alerts) - Array.wrap(alerts).map { |alert| create_event(alert) }.compact - end - - def create_event(payload) - parsed_alert = Gitlab::Alerting::Alert.new(project: project, payload: payload) - - return unless parsed_alert.valid? - - if parsed_alert.gitlab_managed? - create_managed_prometheus_alert_event(parsed_alert) - else - create_self_managed_prometheus_alert_event(parsed_alert) - end - end - - def alerts - params['alerts'] - end - - def find_alert(metric) - Projects::Prometheus::AlertsFinder - .new(project: project, metric: metric) - .execute - .first - end - - def create_managed_prometheus_alert_event(parsed_alert) - alert = find_alert(parsed_alert.metric_id) - event = PrometheusAlertEvent.find_or_initialize_by_payload_key(parsed_alert.project, alert, parsed_alert.gitlab_fingerprint) - - set_status(parsed_alert, event) - end - - def create_self_managed_prometheus_alert_event(parsed_alert) - event = SelfManagedPrometheusAlertEvent.find_or_initialize_by_payload_key(parsed_alert.project, parsed_alert.gitlab_fingerprint) do |event| - event.environment = parsed_alert.environment - event.title = parsed_alert.title - event.query_expression = parsed_alert.full_query - end - - set_status(parsed_alert, event) - end - - def set_status(parsed_alert, event) - persisted = case parsed_alert.status - when 'firing' - event.fire(parsed_alert.starts_at) - when 'resolved' - event.resolve(parsed_alert.ends_at) - end - - event if persisted - end - end - end - end -end diff --git a/app/services/projects/prometheus/alerts/notify_service.rb b/app/services/projects/prometheus/alerts/notify_service.rb index 877a4f99a94..4b3aed2d1d9 100644 --- a/app/services/projects/prometheus/alerts/notify_service.rb +++ b/app/services/projects/prometheus/alerts/notify_service.rb @@ -23,9 +23,7 @@ module Projects return unauthorized unless valid_alert_manager_token?(token) process_prometheus_alerts - persist_events send_alert_email if send_email? - process_incident_issues if process_issues? ServiceResponse.success end @@ -132,13 +130,6 @@ module Projects .prometheus_alerts_fired(project, firings) end - def process_incident_issues - alerts.each do |alert| - IncidentManagement::ProcessPrometheusAlertWorker - .perform_async(project.id, alert.to_h) - end - end - def process_prometheus_alerts alerts.each do |alert| AlertManagement::ProcessPrometheusAlertService @@ -147,10 +138,6 @@ module Projects end end - def persist_events - CreateEventsService.new(project, nil, params).execute - end - def bad_request ServiceResponse.error(message: 'Bad Request', http_status: :bad_request) end diff --git a/app/workers/incident_management/process_prometheus_alert_worker.rb b/app/workers/incident_management/process_prometheus_alert_worker.rb index e405bc2c2d2..4b778f6a621 100644 --- a/app/workers/incident_management/process_prometheus_alert_worker.rb +++ b/app/workers/incident_management/process_prometheus_alert_worker.rb @@ -9,68 +9,13 @@ module IncidentManagement worker_resource_boundary :cpu def perform(project_id, alert_hash) - project = find_project(project_id) - return unless project - - parsed_alert = Gitlab::Alerting::Alert.new(project: project, payload: alert_hash) - event = find_prometheus_alert_event(parsed_alert) - - if event&.resolved? - issue = event.related_issues.order_created_at_desc.detect(&:opened?) - - close_issue(project, issue) - else - issue = create_issue(project, alert_hash) - - relate_issue_to_event(event, issue) - end - end - - private - - def find_project(project_id) - Project.find_by_id(project_id) - end - - def find_prometheus_alert_event(alert) - if alert.gitlab_managed? - find_gitlab_managed_event(alert) - else - find_self_managed_event(alert) - end - end - - def find_gitlab_managed_event(alert) - PrometheusAlertEvent.find_by_payload_key(alert.gitlab_fingerprint) - end - - def find_self_managed_event(alert) - SelfManagedPrometheusAlertEvent.find_by_payload_key(alert.gitlab_fingerprint) - end - - def create_issue(project, alert) - IncidentManagement::CreateIssueService - .new(project, alert) - .execute - .dig(:issue) - end - - def close_issue(project, issue) - return if issue.blank? || issue.closed? - - processed_issue = Issues::CloseService - .new(project, User.alert_bot) - .execute(issue, system_note: false) - - SystemNoteService.auto_resolve_prometheus_alert(issue, project, User.alert_bot) if processed_issue.reset.closed? - end - - def relate_issue_to_event(event, issue) - return unless event && issue - - if event.related_issues.exclude?(issue) - event.related_issues << issue - end + # no-op + # + # This worker is not scheduled anymore since + # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/35943 + # and will be removed completely via + # https://gitlab.com/gitlab-org/gitlab/-/issues/227146 + # in 14.0. end end end |