Commit 32a27fdf authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'lm-update-status-details-page' into 'master'

Update status on alert management detail view

See merge request gitlab-org/gitlab!31680
parents 210527c6 f0e998ae
<script>
import * as Sentry from '@sentry/browser';
import { GlAlert, GlIcon, GlLoadingIcon, GlSprintf, GlTabs, GlTab, GlButton } from '@gitlab/ui';
import {
GlAlert,
GlIcon,
GlLoadingIcon,
GlDropdown,
GlDropdownItem,
GlSprintf,
GlTabs,
GlTab,
GlButton,
} from '@gitlab/ui';
import createFlash from '~/flash';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
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: {
......@@ -29,6 +42,8 @@ export default {
GlIcon,
GlLoadingIcon,
GlSprintf,
GlDropdown,
GlDropdownItem,
GlTab,
GlTabs,
GlButton,
......@@ -85,9 +100,28 @@ export default {
},
},
methods: {
capitalizeFirstCharacter,
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>
......@@ -97,7 +131,7 @@ export default {
{{ $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">
<div v-if="alert" class="alert-management-details gl-relative">
<div
class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-px-1 gl-py-6 gl-border-b-1 gl-border-b-gray-200 gl-border-b-solid"
>
......@@ -137,6 +171,28 @@ export default {
>
<h2 data-testid="title">{{ alert.title }}</h2>
</div>
<gl-dropdown
:text="capitalizeFirstCharacter(alert.status.toLowerCase())"
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">
......
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);
......@@ -10,7 +11,20 @@ export default selector => {
const { alertId, projectPath, newIssuePath } = domEl.dataset;
const apolloProvider = new VueApollo({
defaultClient: createDefaultClient(),
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
......
import { mount, shallowMount } from '@vue/test-utils';
import { GlAlert, GlLoadingIcon } from '@gitlab/ui';
import { GlAlert, GlLoadingIcon, GlDropdownItem } from '@gitlab/ui';
import AlertDetails from '~/alert_management/components/alert_details.vue';
import updateAlertStatus from '~/alert_management/graphql/mutations/update_alert_status.graphql';
import createFlash from '~/flash';
import mockAlerts from '../mocks/alerts.json';
const mockAlert = mockAlerts[0];
jest.mock('~/flash');
describe('AlertDetails', () => {
let wrapper;
const newIssuePath = 'root/alerts/-/issues/new';
const findStatusDropdownItem = () => wrapper.find(GlDropdownItem);
function mountComponent({
data,
......@@ -31,6 +35,7 @@ describe('AlertDetails', () => {
},
mocks: {
$apollo: {
mutate: jest.fn(),
queries: {
alert: {
loading,
......@@ -184,4 +189,50 @@ describe('AlertDetails', () => {
});
});
});
describe('updating the alert status', () => {
const mockUpdatedMutationResult = {
data: {
updateAlertStatus: {
errors: [],
alert: {
status: 'acknowledged',
},
},
},
};
beforeEach(() => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
data: { alert: mockAlert },
loading: false,
});
});
it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', () => {
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
findStatusDropdownItem().vm.$emit('click');
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
mutation: updateAlertStatus,
variables: {
iid: 'alertId',
status: 'TRIGGERED',
projectPath: 'projectPath',
},
});
});
it('calls `createFlash` when request fails', () => {
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
findStatusDropdownItem().vm.$emit('click');
setImmediate(() => {
expect(createFlash).toHaveBeenCalledWith(
'There was an error while updating the status of the alert. Please try again.',
);
});
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment