Commit 346f8bfc authored by Olena Horal-Koretska's avatar Olena Horal-Koretska Committed by Kushal Pandya

Preserve active tab on page reload

parent 41cc47c4
...@@ -35,13 +35,24 @@ export default { ...@@ -35,13 +35,24 @@ export default {
errorMsg: s__( errorMsg: s__(
'AlertManagement|There was an error displaying the alert. Please refresh the page to try again.', 'AlertManagement|There was an error displaying the alert. Please refresh the page to try again.',
), ),
fullAlertDetailsTitle: s__('AlertManagement|Alert details'),
overviewTitle: s__('AlertManagement|Overview'),
metricsTitle: s__('AlertManagement|Metrics'),
reportedAt: s__('AlertManagement|Reported %{when}'), reportedAt: s__('AlertManagement|Reported %{when}'),
reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'), reportedAtWithTool: s__('AlertManagement|Reported %{when} by %{tool}'),
}, },
severityLabels: ALERTS_SEVERITY_LABELS, severityLabels: ALERTS_SEVERITY_LABELS,
tabsConfig: [
{
id: 'overview',
title: s__('AlertManagement|Overview'),
},
{
id: 'fullDetails',
title: s__('AlertManagement|Alert details'),
},
{
id: 'metrics',
title: s__('AlertManagement|Metrics'),
},
],
components: { components: {
GlBadge, GlBadge,
GlAlert, GlAlert,
...@@ -119,6 +130,18 @@ export default { ...@@ -119,6 +130,18 @@ export default {
showErrorMsg() { showErrorMsg() {
return this.errored && !this.isErrorDismissed; return this.errored && !this.isErrorDismissed;
}, },
activeTab() {
return this.$route.params.tabId || this.$options.tabsConfig[0].id;
},
currentTabIndex: {
get() {
return this.$options.tabsConfig.findIndex(tab => tab.id === this.activeTab);
},
set(tabIdx) {
const tabId = this.$options.tabsConfig[tabIdx].id;
this.$router.replace({ name: 'tab', params: { tabId } });
},
},
}, },
mounted() { mounted() {
this.trackPageViews(); this.trackPageViews();
...@@ -257,8 +280,8 @@ export default { ...@@ -257,8 +280,8 @@ export default {
> >
<h2 data-testid="title">{{ alert.title }}</h2> <h2 data-testid="title">{{ alert.title }}</h2>
</div> </div>
<gl-tabs v-if="alert" data-testid="alertDetailsTabs"> <gl-tabs v-if="alert" v-model="currentTabIndex" data-testid="alertDetailsTabs">
<gl-tab data-testid="overviewTab" :title="$options.i18n.overviewTitle"> <gl-tab :data-testid="$options.tabsConfig[0].id" :title="$options.tabsConfig[0].title">
<div v-if="alert.severity" class="gl-mt-3 gl-mb-5 gl-display-flex"> <div v-if="alert.severity" class="gl-mt-3 gl-mb-5 gl-display-flex">
<div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3"> <div class="gl-font-weight-bold gl-w-13 gl-text-right gl-pr-3">
{{ s__('AlertManagement|Severity') }}: {{ s__('AlertManagement|Severity') }}:
...@@ -309,7 +332,7 @@ export default { ...@@ -309,7 +332,7 @@ export default {
</div> </div>
</template> </template>
</gl-tab> </gl-tab>
<gl-tab data-testid="fullDetailsTab" :title="$options.i18n.fullAlertDetailsTitle"> <gl-tab :data-testid="$options.tabsConfig[1].id" :title="$options.tabsConfig[1].title">
<gl-table <gl-table
class="alert-management-details-table" class="alert-management-details-table"
:items="[{ key: 'Value', ...alert }]" :items="[{ key: 'Value', ...alert }]"
...@@ -325,7 +348,7 @@ export default { ...@@ -325,7 +348,7 @@ export default {
</template> </template>
</gl-table> </gl-table>
</gl-tab> </gl-tab>
<gl-tab data-testId="metricsTab" :title="$options.i18n.metricsTitle"> <gl-tab :data-testid="$options.tabsConfig[2].id" :title="$options.tabsConfig[2].title">
<alert-metrics :dashboard-url="alert.metricsDashboardUrl" /> <alert-metrics :dashboard-url="alert.metricsDashboardUrl" />
</gl-tab> </gl-tab>
</gl-tabs> </gl-tabs>
......
import Vue from 'vue'; import Vue from 'vue';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
import createRouter from './router';
import { defaultDataIdFromObject } from 'apollo-cache-inmemory'; import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
import AlertDetails from './components/alert_details.vue'; import AlertDetails from './components/alert_details.vue';
import sidebarStatusQuery from './graphql/queries/sidebar_status.query.graphql'; import sidebarStatusQuery from './graphql/queries/sidebar_status.query.graphql';
...@@ -10,6 +11,7 @@ Vue.use(VueApollo); ...@@ -10,6 +11,7 @@ Vue.use(VueApollo);
export default selector => { export default selector => {
const domEl = document.querySelector(selector); const domEl = document.querySelector(selector);
const { alertId, projectPath, projectIssuesPath, projectId } = domEl.dataset; const { alertId, projectPath, projectIssuesPath, projectId } = domEl.dataset;
const router = createRouter();
const resolvers = { const resolvers = {
Mutation: { Mutation: {
...@@ -54,6 +56,7 @@ export default selector => { ...@@ -54,6 +56,7 @@ export default selector => {
components: { components: {
AlertDetails, AlertDetails,
}, },
router,
render(createElement) { render(createElement) {
return createElement('alert-details', {}); return createElement('alert-details', {});
}, },
......
import Vue from 'vue';
import VueRouter from 'vue-router';
import { joinPaths } from '~/lib/utils/url_utility';
Vue.use(VueRouter);
export default function createRouter(base) {
return new VueRouter({
mode: 'hash',
base: joinPaths(gon.relative_url_root || '', base),
routes: [{ path: '/:tabId', name: 'tab' }],
});
}
---
title: Preserve active tab on alert details page reload
merge_request: 39369
author:
type: added
...@@ -20,6 +20,7 @@ describe('AlertDetails', () => { ...@@ -20,6 +20,7 @@ describe('AlertDetails', () => {
const projectPath = 'root/alerts'; const projectPath = 'root/alerts';
const projectIssuesPath = 'root/alerts/-/issues'; const projectIssuesPath = 'root/alerts/-/issues';
const projectId = '1'; const projectId = '1';
const $router = { replace: jest.fn() };
const findDetailsTable = () => wrapper.find(GlTable); const findDetailsTable = () => wrapper.find(GlTable);
...@@ -44,6 +45,8 @@ describe('AlertDetails', () => { ...@@ -44,6 +45,8 @@ describe('AlertDetails', () => {
sidebarStatus: {}, sidebarStatus: {},
}, },
}, },
$router,
$route: { params: {} },
}, },
stubs, stubs,
}); });
...@@ -81,11 +84,11 @@ describe('AlertDetails', () => { ...@@ -81,11 +84,11 @@ describe('AlertDetails', () => {
}); });
it('renders a tab with overview information', () => { it('renders a tab with overview information', () => {
expect(wrapper.find('[data-testid="overviewTab"]').exists()).toBe(true); expect(wrapper.find('[data-testid="overview"]').exists()).toBe(true);
}); });
it('renders a tab with full alert information', () => { it('renders a tab with full alert information', () => {
expect(wrapper.find('[data-testid="fullDetailsTab"]').exists()).toBe(true); expect(wrapper.find('[data-testid="fullDetails"]').exists()).toBe(true);
}); });
it('renders severity', () => { it('renders severity', () => {
...@@ -191,7 +194,7 @@ describe('AlertDetails', () => { ...@@ -191,7 +194,7 @@ describe('AlertDetails', () => {
mountComponent({ data: { alert: mockAlert } }); mountComponent({ data: { alert: mockAlert } });
}); });
it('should display a table of raw alert details data', () => { it('should display a table of raw alert details data', () => {
wrapper.find('[data-testid="fullDetailsTab"]').trigger('click'); wrapper.find('[data-testid="fullDetails"]').trigger('click');
expect(findDetailsTable().exists()).toBe(true); expect(findDetailsTable().exists()).toBe(true);
}); });
}); });
...@@ -252,6 +255,22 @@ describe('AlertDetails', () => { ...@@ -252,6 +255,22 @@ describe('AlertDetails', () => {
); );
}); });
}); });
describe('tab navigation', () => {
beforeEach(() => {
mountComponent({ data: { alert: mockAlert } });
});
it.each`
index | tabId
${0} | ${'overview'}
${1} | ${'fullDetails'}
${2} | ${'metrics'}
`('will navigate to the correct tab via $tabId', ({ index, tabId }) => {
wrapper.setData({ currentTabIndex: index });
expect($router.replace).toHaveBeenCalledWith({ name: 'tab', params: { tabId } });
});
});
}); });
describe('Snowplow tracking', () => { describe('Snowplow tracking', () => {
......
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