diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 14:34:42 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-05-20 14:34:42 +0000 |
commit | 9f46488805e86b1bc341ea1620b866016c2ce5ed (patch) | |
tree | f9748c7e287041e37d6da49e0a29c9511dc34768 /app/assets/javascripts/alert_management | |
parent | dfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff) | |
download | gitlab-ce-9f46488805e86b1bc341ea1620b866016c2ce5ed.tar.gz |
Add latest changes from gitlab-org/gitlab@13-0-stable-ee
Diffstat (limited to 'app/assets/javascripts/alert_management')
11 files changed, 745 insertions, 0 deletions
diff --git a/app/assets/javascripts/alert_management/components/alert_details.vue b/app/assets/javascripts/alert_management/components/alert_details.vue new file mode 100644 index 00000000000..89db7db77d5 --- /dev/null +++ b/app/assets/javascripts/alert_management/components/alert_details.vue @@ -0,0 +1,236 @@ +<script> +import * as Sentry from '@sentry/browser'; +import { + GlAlert, + GlIcon, + GlLoadingIcon, + GlDropdown, + GlDropdownItem, + GlSprintf, + GlTabs, + GlTab, + GlButton, + GlTable, +} from '@gitlab/ui'; +import createFlash from '~/flash'; +import { s__ } from '~/locale'; +import query from '../graphql/queries/details.query.graphql'; +import { fetchPolicies } from '~/lib/graphql'; +import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import { ALERTS_SEVERITY_LABELS } from '../constants'; +import updateAlertStatus from '../graphql/mutations/update_alert_status.graphql'; + +export default { + statuses: { + TRIGGERED: s__('AlertManagement|Triggered'), + ACKNOWLEDGED: s__('AlertManagement|Acknowledged'), + RESOLVED: s__('AlertManagement|Resolved'), + }, + i18n: { + errorMsg: s__( + 'AlertManagement|There was an error displaying the alert. Please refresh the page to try again.', + ), + fullAlertDetailsTitle: s__('AlertManagement|Alert details'), + overviewTitle: s__('AlertManagement|Overview'), + reportedAt: s__('AlertManagement|Reported %{when}'), + reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'), + }, + severityLabels: ALERTS_SEVERITY_LABELS, + components: { + GlAlert, + GlIcon, + GlLoadingIcon, + GlSprintf, + GlDropdown, + GlDropdownItem, + GlTab, + GlTabs, + GlButton, + GlTable, + TimeAgoTooltip, + }, + mixins: [glFeatureFlagsMixin()], + props: { + alertId: { + type: String, + required: true, + }, + projectPath: { + type: String, + required: true, + }, + newIssuePath: { + type: String, + required: true, + }, + }, + apollo: { + alert: { + fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, + query, + variables() { + return { + fullPath: this.projectPath, + alertId: this.alertId, + }; + }, + update(data) { + return data?.project?.alertManagementAlerts?.nodes?.[0] ?? null; + }, + error(error) { + this.errored = true; + Sentry.captureException(error); + }, + }, + }, + data() { + return { alert: null, errored: false, isErrorDismissed: false }; + }, + computed: { + loading() { + return this.$apollo.queries.alert.loading; + }, + reportedAtMessage() { + return this.alert?.monitoringTool + ? this.$options.i18n.reportedAtWithTool + : this.$options.i18n.reportedAt; + }, + showErrorMsg() { + return this.errored && !this.isErrorDismissed; + }, + }, + methods: { + dismissError() { + this.isErrorDismissed = true; + }, + updateAlertStatus(status) { + this.$apollo + .mutate({ + mutation: updateAlertStatus, + variables: { + iid: this.alertId, + status: status.toUpperCase(), + projectPath: this.projectPath, + }, + }) + .catch(() => { + createFlash( + s__( + 'AlertManagement|There was an error while updating the status of the alert. Please try again.', + ), + ); + }); + }, + }, +}; +</script> +<template> + <div> + <gl-alert v-if="showErrorMsg" variant="danger" @dismiss="dismissError"> + {{ $options.i18n.errorMsg }} + </gl-alert> + <div v-if="loading"><gl-loading-icon size="lg" class="gl-mt-5" /></div> + <div v-if="alert" class="alert-management-details gl-relative"> + <div + class="gl-display-flex gl-justify-content-space-between gl-align-items-baseline gl-px-1 py-3 py-md-4 gl-border-b-1 gl-border-b-gray-200 gl-border-b-solid flex-column flex-sm-row" + > + <div + data-testid="alert-header" + class="gl-display-flex gl-align-items-center gl-justify-content-center" + > + <div + class="gl-display-inline-flex gl-align-items-center gl-justify-content-space-between" + > + <gl-icon + class="gl-mr-3 align-middle" + :size="12" + :name="`severity-${alert.severity.toLowerCase()}`" + :class="`icon-${alert.severity.toLowerCase()}`" + /> + <strong>{{ $options.severityLabels[alert.severity] }}</strong> + </div> + <span class="mx-2">•</span> + <gl-sprintf :message="reportedAtMessage"> + <template #when> + <time-ago-tooltip :time="alert.createdAt" class="gl-ml-3" /> + </template> + <template #tool>{{ alert.monitoringTool }}</template> + </gl-sprintf> + </div> + <gl-button + v-if="glFeatures.createIssueFromAlertEnabled" + class="gl-mt-3 mt-sm-0 align-self-center align-self-sm-baseline alert-details-create-issue-button" + data-testid="createIssueBtn" + :href="newIssuePath" + category="primary" + variant="success" + > + {{ s__('AlertManagement|Create issue') }} + </gl-button> + </div> + <div + v-if="alert" + class="gl-display-flex gl-justify-content-space-between gl-align-items-center" + > + <h2 data-testid="title">{{ alert.title }}</h2> + </div> + <gl-dropdown :text="$options.statuses[alert.status]" class="gl-absolute gl-right-0" right> + <gl-dropdown-item + v-for="(label, field) in $options.statuses" + :key="field" + data-testid="statusDropdownItem" + class="gl-vertical-align-middle" + @click="updateAlertStatus(label)" + > + <span class="d-flex"> + <gl-icon + class="flex-shrink-0 append-right-4" + :class="{ invisible: label.toUpperCase() !== alert.status }" + name="mobile-issue-close" + /> + {{ label }} + </span> + </gl-dropdown-item> + </gl-dropdown> + <gl-tabs v-if="alert" data-testid="alertDetailsTabs"> + <gl-tab data-testid="overviewTab" :title="$options.i18n.overviewTitle"> + <ul class="pl-4 mb-n1"> + <li v-if="alert.startedAt" class="my-2"> + <strong class="bold">{{ s__('AlertManagement|Start time') }}:</strong> + <time-ago-tooltip data-testid="startTimeItem" :time="alert.startedAt" /> + </li> + <li v-if="alert.eventCount" class="my-2"> + <strong class="bold">{{ s__('AlertManagement|Events') }}:</strong> + <span data-testid="eventCount">{{ alert.eventCount }}</span> + </li> + <li v-if="alert.monitoringTool" class="my-2"> + <strong class="bold">{{ s__('AlertManagement|Tool') }}:</strong> + <span data-testid="monitoringTool">{{ alert.monitoringTool }}</span> + </li> + <li v-if="alert.service" class="my-2"> + <strong class="bold">{{ s__('AlertManagement|Service') }}:</strong> + <span data-testid="service">{{ alert.service }}</span> + </li> + </ul> + </gl-tab> + <gl-tab data-testid="fullDetailsTab" :title="$options.i18n.fullAlertDetailsTitle"> + <gl-table + class="alert-management-details-table" + :items="[{ key: 'Value', ...alert }]" + :show-empty="true" + :busy="loading" + stacked + > + <template #empty> + {{ s__('AlertManagement|No alert data to display.') }} + </template> + <template #table-busy> + <gl-loading-icon size="lg" color="dark" class="mt-3" /> + </template> + </gl-table> + </gl-tab> + </gl-tabs> + </div> + </div> +</template> diff --git a/app/assets/javascripts/alert_management/components/alert_management_list.vue b/app/assets/javascripts/alert_management/components/alert_management_list.vue new file mode 100644 index 00000000000..74fc19ff3d4 --- /dev/null +++ b/app/assets/javascripts/alert_management/components/alert_management_list.vue @@ -0,0 +1,303 @@ +<script> +import { + GlEmptyState, + GlDeprecatedButton, + GlLoadingIcon, + GlTable, + GlAlert, + GlIcon, + GlDropdown, + GlDropdownItem, + GlTabs, + GlTab, +} from '@gitlab/ui'; +import createFlash from '~/flash'; +import { s__ } from '~/locale'; +import { joinPaths, visitUrl } from '~/lib/utils/url_utility'; +import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; +import getAlerts from '../graphql/queries/getAlerts.query.graphql'; +import { ALERTS_STATUS, ALERTS_STATUS_TABS, ALERTS_SEVERITY_LABELS } from '../constants'; +import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; +import updateAlertStatus from '../graphql/mutations/update_alert_status.graphql'; +import { capitalizeFirstCharacter } from '~/lib/utils/text_utility'; + +const tdClass = 'table-col d-flex d-md-table-cell align-items-center'; +const bodyTrClass = + 'gl-border-1 gl-border-t-solid gl-border-gray-100 hover-bg-blue-50 hover-gl-cursor-pointer hover-gl-border-b-solid hover-gl-border-blue-200'; + +export default { + bodyTrClass, + i18n: { + noAlertsMsg: s__( + "AlertManagement|No alerts available to display. If you think you're seeing this message in error, refresh the page.", + ), + errorMsg: s__( + "AlertManagement|There was an error displaying the alerts. Confirm your endpoint's configuration details to ensure alerts appear.", + ), + }, + fields: [ + { + key: 'severity', + label: s__('AlertManagement|Severity'), + tdClass: `${tdClass} rounded-top text-capitalize`, + }, + { + key: 'startedAt', + label: s__('AlertManagement|Start time'), + tdClass, + }, + { + key: 'endedAt', + label: s__('AlertManagement|End time'), + tdClass, + }, + { + key: 'title', + label: s__('AlertManagement|Alert'), + thClass: 'w-30p', + tdClass, + }, + { + key: 'eventCount', + label: s__('AlertManagement|Events'), + thClass: 'text-right event-count', + tdClass: `${tdClass} text-md-right event-count`, + }, + { + key: 'status', + thClass: 'w-15p', + label: s__('AlertManagement|Status'), + tdClass: `${tdClass} rounded-bottom`, + }, + ], + statuses: { + [ALERTS_STATUS.TRIGGERED]: s__('AlertManagement|Triggered'), + [ALERTS_STATUS.ACKNOWLEDGED]: s__('AlertManagement|Acknowledged'), + [ALERTS_STATUS.RESOLVED]: s__('AlertManagement|Resolved'), + }, + severityLabels: ALERTS_SEVERITY_LABELS, + statusTabs: ALERTS_STATUS_TABS, + components: { + GlEmptyState, + GlLoadingIcon, + GlTable, + GlAlert, + GlDeprecatedButton, + TimeAgo, + GlDropdown, + GlDropdownItem, + GlIcon, + GlTabs, + GlTab, + }, + mixins: [glFeatureFlagsMixin()], + props: { + projectPath: { + type: String, + required: true, + }, + alertManagementEnabled: { + type: Boolean, + required: true, + }, + enableAlertManagementPath: { + type: String, + required: true, + }, + userCanEnableAlertManagement: { + type: Boolean, + required: true, + }, + emptyAlertSvgPath: { + type: String, + required: true, + }, + }, + apollo: { + alerts: { + query: getAlerts, + variables() { + return { + projectPath: this.projectPath, + statuses: this.statusFilter, + }; + }, + update(data) { + return data.project.alertManagementAlerts.nodes; + }, + error() { + this.errored = true; + }, + }, + }, + data() { + return { + alerts: null, + errored: false, + isAlertDismissed: false, + isErrorAlertDismissed: false, + statusFilter: this.$options.statusTabs[4].filters, + }; + }, + computed: { + showNoAlertsMsg() { + return !this.errored && !this.loading && !this.alerts?.length && !this.isAlertDismissed; + }, + showErrorMsg() { + return this.errored && !this.isErrorAlertDismissed; + }, + loading() { + return this.$apollo.queries.alerts.loading; + }, + }, + methods: { + filterAlertsByStatus(tabIndex) { + this.statusFilter = this.$options.statusTabs[tabIndex].filters; + }, + capitalizeFirstCharacter, + updateAlertStatus(status, iid) { + this.$apollo + .mutate({ + mutation: updateAlertStatus, + variables: { + iid, + status: status.toUpperCase(), + projectPath: this.projectPath, + }, + }) + .then(() => { + this.$apollo.queries.alerts.refetch(); + }) + .catch(() => { + createFlash( + s__( + 'AlertManagement|There was an error while updating the status of the alert. Please try again.', + ), + ); + }); + }, + navigateToAlertDetails({ iid }) { + return visitUrl(joinPaths(window.location.pathname, iid, 'details')); + }, + }, +}; +</script> +<template> + <div> + <div v-if="alertManagementEnabled" class="alert-management-list"> + <gl-alert v-if="showNoAlertsMsg" @dismiss="isAlertDismissed = true"> + {{ $options.i18n.noAlertsMsg }} + </gl-alert> + <gl-alert v-if="showErrorMsg" variant="danger" @dismiss="isErrorAlertDismissed = true"> + {{ $options.i18n.errorMsg }} + </gl-alert> + + <gl-tabs v-if="glFeatures.alertListStatusFilteringEnabled" @input="filterAlertsByStatus"> + <gl-tab v-for="tab in $options.statusTabs" :key="tab.status"> + <template slot="title"> + <span>{{ tab.title }}</span> + </template> + </gl-tab> + </gl-tabs> + + <h4 class="d-block d-md-none my-3"> + {{ s__('AlertManagement|Alerts') }} + </h4> + <gl-table + class="alert-management-table mt-3" + :items="alerts" + :fields="$options.fields" + :show-empty="true" + :busy="loading" + stacked="md" + :tbody-tr-class="$options.bodyTrClass" + @row-clicked="navigateToAlertDetails" + > + <template #cell(severity)="{ item }"> + <div + class="d-inline-flex align-items-center justify-content-between" + data-testid="severityField" + > + <gl-icon + class="mr-2" + :size="12" + :name="`severity-${item.severity.toLowerCase()}`" + :class="`icon-${item.severity.toLowerCase()}`" + /> + {{ $options.severityLabels[item.severity] }} + </div> + </template> + + <template #cell(startedAt)="{ item }"> + <time-ago v-if="item.startedAt" :time="item.startedAt" /> + </template> + + <template #cell(endedAt)="{ item }"> + <time-ago v-if="item.endedAt" :time="item.endedAt" /> + </template> + + <template #cell(title)="{ item }"> + <div class="gl-max-w-full text-truncate">{{ item.title }}</div> + </template> + + <template #cell(status)="{ item }"> + <gl-dropdown + :text="capitalizeFirstCharacter(item.status.toLowerCase())" + class="w-100" + right + > + <gl-dropdown-item + v-for="(label, field) in $options.statuses" + :key="field" + @click="updateAlertStatus(label, item.iid)" + > + <span class="d-flex"> + <gl-icon + class="flex-shrink-0 append-right-4" + :class="{ invisible: label.toUpperCase() !== item.status }" + name="mobile-issue-close" + /> + {{ label }} + </span> + </gl-dropdown-item> + </gl-dropdown> + </template> + + <template #empty> + {{ s__('AlertManagement|No alerts to display.') }} + </template> + + <template #table-busy> + <gl-loading-icon size="lg" color="dark" class="mt-3" /> + </template> + </gl-table> + </div> + <gl-empty-state + v-else + :title="s__('AlertManagement|Surface alerts in GitLab')" + :svg-path="emptyAlertSvgPath" + > + <template #description> + <div class="d-block"> + <span>{{ + s__( + 'AlertManagement|Display alerts from all your monitoring tools directly within GitLab. Streamline the investigation of your alerts and the escalation of alerts to incidents.', + ) + }}</span> + <a href="/help/user/project/operations/alert_management.html" target="_blank"> + {{ s__('AlertManagement|More information') }} + </a> + </div> + <div v-if="userCanEnableAlertManagement" class="d-block center pt-4"> + <gl-deprecated-button + category="primary" + variant="success" + :href="enableAlertManagementPath" + > + {{ s__('AlertManagement|Authorize external service') }} + </gl-deprecated-button> + </div> + </template> + </gl-empty-state> + </div> +</template> diff --git a/app/assets/javascripts/alert_management/constants.js b/app/assets/javascripts/alert_management/constants.js new file mode 100644 index 00000000000..9df01d9d0b5 --- /dev/null +++ b/app/assets/javascripts/alert_management/constants.js @@ -0,0 +1,46 @@ +import { s__ } from '~/locale'; + +export const ALERTS_SEVERITY_LABELS = { + CRITICAL: s__('AlertManagement|Critical'), + HIGH: s__('AlertManagement|High'), + MEDIUM: s__('AlertManagement|Medium'), + LOW: s__('AlertManagement|Low'), + INFO: s__('AlertManagement|Info'), + UNKNOWN: s__('AlertManagement|Unknown'), +}; + +export const ALERTS_STATUS = { + OPEN: 'OPEN', + TRIGGERED: 'TRIGGERED', + ACKNOWLEDGED: 'ACKNOWLEDGED', + RESOLVED: 'RESOLVED', + ALL: 'ALL', +}; + +export const ALERTS_STATUS_TABS = [ + { + title: s__('AlertManagement|Open'), + status: ALERTS_STATUS.OPEN, + filters: [ALERTS_STATUS.TRIGGERED, ALERTS_STATUS.ACKNOWLEDGED], + }, + { + title: s__('AlertManagement|Triggered'), + status: ALERTS_STATUS.TRIGGERED, + filters: [ALERTS_STATUS.TRIGGERED], + }, + { + title: s__('AlertManagement|Acknowledged'), + status: ALERTS_STATUS.ACKNOWLEDGED, + filters: [ALERTS_STATUS.ACKNOWLEDGED], + }, + { + title: s__('AlertManagement|Resolved'), + status: ALERTS_STATUS.RESOLVED, + filters: [ALERTS_STATUS.RESOLVED], + }, + { + title: s__('AlertManagement|All alerts'), + status: ALERTS_STATUS.ALL, + filters: [ALERTS_STATUS.TRIGGERED, ALERTS_STATUS.ACKNOWLEDGED, ALERTS_STATUS.RESOLVED], + }, +]; diff --git a/app/assets/javascripts/alert_management/details.js b/app/assets/javascripts/alert_management/details.js new file mode 100644 index 00000000000..d3523e0a29d --- /dev/null +++ b/app/assets/javascripts/alert_management/details.js @@ -0,0 +1,47 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import { defaultDataIdFromObject } from 'apollo-cache-inmemory'; +import AlertDetails from './components/alert_details.vue'; + +Vue.use(VueApollo); + +export default selector => { + const domEl = document.querySelector(selector); + const { alertId, projectPath, newIssuePath } = domEl.dataset; + + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient( + {}, + { + cacheConfig: { + dataIdFromObject: object => { + // eslint-disable-next-line no-underscore-dangle + if (object.__typename === 'AlertManagementAlert') { + return object.iid; + } + return defaultDataIdFromObject(object); + }, + }, + }, + ), + }); + + // eslint-disable-next-line no-new + new Vue({ + el: selector, + apolloProvider, + components: { + AlertDetails, + }, + render(createElement) { + return createElement('alert-details', { + props: { + alertId, + projectPath, + newIssuePath, + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/alert_management/graphql/fragments/detailItem.fragment.graphql b/app/assets/javascripts/alert_management/graphql/fragments/detailItem.fragment.graphql new file mode 100644 index 00000000000..df802616e97 --- /dev/null +++ b/app/assets/javascripts/alert_management/graphql/fragments/detailItem.fragment.graphql @@ -0,0 +1,11 @@ +#import "./listItem.fragment.graphql" + +fragment AlertDetailItem on AlertManagementAlert { + ...AlertListItem + createdAt + monitoringTool + service + description + updatedAt + details +} diff --git a/app/assets/javascripts/alert_management/graphql/fragments/listItem.fragment.graphql b/app/assets/javascripts/alert_management/graphql/fragments/listItem.fragment.graphql new file mode 100644 index 00000000000..fffe07b0cfd --- /dev/null +++ b/app/assets/javascripts/alert_management/graphql/fragments/listItem.fragment.graphql @@ -0,0 +1,9 @@ +fragment AlertListItem on AlertManagementAlert { + iid + title + severity + status + startedAt + endedAt + eventCount +} diff --git a/app/assets/javascripts/alert_management/graphql/mutations/update_alert_status.graphql b/app/assets/javascripts/alert_management/graphql/mutations/update_alert_status.graphql new file mode 100644 index 00000000000..009ae0b2930 --- /dev/null +++ b/app/assets/javascripts/alert_management/graphql/mutations/update_alert_status.graphql @@ -0,0 +1,9 @@ +mutation ($projectPath: ID!, $status: AlertManagementStatus!, $iid: String!) { + updateAlertStatus(input: { iid: $iid, status: $status, projectPath: $projectPath }) { + errors + alert { + iid, + status, + } + } +} diff --git a/app/assets/javascripts/alert_management/graphql/queries/details.query.graphql b/app/assets/javascripts/alert_management/graphql/queries/details.query.graphql new file mode 100644 index 00000000000..7c77715fad2 --- /dev/null +++ b/app/assets/javascripts/alert_management/graphql/queries/details.query.graphql @@ -0,0 +1,11 @@ +#import "../fragments/detailItem.fragment.graphql" + +query alertDetails($fullPath: ID!, $alertId: String) { + project(fullPath: $fullPath) { + alertManagementAlerts(iid: $alertId) { + nodes { + ...AlertDetailItem + } + } + } +} diff --git a/app/assets/javascripts/alert_management/graphql/queries/getAlerts.query.graphql b/app/assets/javascripts/alert_management/graphql/queries/getAlerts.query.graphql new file mode 100644 index 00000000000..54b66389d5b --- /dev/null +++ b/app/assets/javascripts/alert_management/graphql/queries/getAlerts.query.graphql @@ -0,0 +1,11 @@ +#import "../fragments/listItem.fragment.graphql" + +query getAlerts($projectPath: ID!, $statuses: [AlertManagementStatus!]) { + project(fullPath: $projectPath) { + alertManagementAlerts(statuses: $statuses) { + nodes { + ...AlertListItem + } + } + } +} diff --git a/app/assets/javascripts/alert_management/list.js b/app/assets/javascripts/alert_management/list.js new file mode 100644 index 00000000000..cae6a536b56 --- /dev/null +++ b/app/assets/javascripts/alert_management/list.js @@ -0,0 +1,55 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; +import createDefaultClient from '~/lib/graphql'; +import { defaultDataIdFromObject } from 'apollo-cache-inmemory'; +import { parseBoolean } from '~/lib/utils/common_utils'; +import AlertManagementList from './components/alert_management_list.vue'; + +Vue.use(VueApollo); + +export default () => { + const selector = '#js-alert_management'; + + const domEl = document.querySelector(selector); + const { projectPath, enableAlertManagementPath, emptyAlertSvgPath } = domEl.dataset; + let { alertManagementEnabled, userCanEnableAlertManagement } = domEl.dataset; + + alertManagementEnabled = parseBoolean(alertManagementEnabled); + userCanEnableAlertManagement = parseBoolean(userCanEnableAlertManagement); + + const apolloProvider = new VueApollo({ + defaultClient: createDefaultClient( + {}, + { + cacheConfig: { + dataIdFromObject: object => { + // eslint-disable-next-line no-underscore-dangle + if (object.__typename === 'AlertManagementAlert') { + return object.iid; + } + return defaultDataIdFromObject(object); + }, + }, + }, + ), + }); + + return new Vue({ + el: selector, + apolloProvider, + components: { + AlertManagementList, + }, + render(createElement) { + return createElement('alert-management-list', { + props: { + projectPath, + enableAlertManagementPath, + emptyAlertSvgPath, + alertManagementEnabled, + userCanEnableAlertManagement, + }, + }); + }, + }); +}; diff --git a/app/assets/javascripts/alert_management/services/index.js b/app/assets/javascripts/alert_management/services/index.js new file mode 100644 index 00000000000..787603d3e7a --- /dev/null +++ b/app/assets/javascripts/alert_management/services/index.js @@ -0,0 +1,7 @@ +import axios from '~/lib/utils/axios_utils'; + +export default { + getAlertManagementList({ endpoint }) { + return axios.get(endpoint); + }, +}; |