Commit 0a782fcf authored by David O'Regan's avatar David O'Regan Committed by Natalia Tepluhina

Leverage Apollo Cache

Swap base side bar toggle data property for
apllo cache driven resolver.
parent 5f64156e
...@@ -12,13 +12,15 @@ import { ...@@ -12,13 +12,15 @@ import {
GlTable, GlTable,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import query from '../graphql/queries/details.query.graphql'; import alertQuery from '../graphql/queries/details.query.graphql';
import sidebarStatusQuery from '../graphql/queries/sidebar_status.query.graphql';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue';
import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user'; import highlightCurrentUser from '~/behaviors/markdown/highlight_current_user';
import initUserPopovers from '~/user_popovers'; import initUserPopovers from '~/user_popovers';
import { ALERTS_SEVERITY_LABELS, trackAlertsDetailsViewsOptions } from '../constants'; import { ALERTS_SEVERITY_LABELS, trackAlertsDetailsViewsOptions } from '../constants';
import createIssueQuery from '../graphql/mutations/create_issue_from_alert.graphql'; import createIssueMutation from '../graphql/mutations/create_issue_from_alert.graphql';
import toggleSidebarStatusMutation from '../graphql/mutations/toggle_sidebar_status.mutation.graphql';
import { visitUrl, joinPaths } from '~/lib/utils/url_utility'; import { visitUrl, joinPaths } from '~/lib/utils/url_utility';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { toggleContainerClasses } from '~/lib/utils/dom_utils'; import { toggleContainerClasses } from '~/lib/utils/dom_utils';
...@@ -52,28 +54,27 @@ export default { ...@@ -52,28 +54,27 @@ export default {
AlertSidebar, AlertSidebar,
SystemNote, SystemNote,
}, },
props: { inject: {
projectPath: {
default: '',
},
alertId: { alertId: {
type: String, type: String,
required: true, default: '',
}, },
projectId: { projectId: {
type: String, type: String,
required: true, default: '',
},
projectPath: {
type: String,
required: true,
}, },
projectIssuesPath: { projectIssuesPath: {
type: String, type: String,
required: true, default: '',
}, },
}, },
apollo: { apollo: {
alert: { alert: {
fetchPolicy: fetchPolicies.CACHE_AND_NETWORK, fetchPolicy: fetchPolicies.CACHE_AND_NETWORK,
query, query: alertQuery,
variables() { variables() {
return { return {
fullPath: this.projectPath, fullPath: this.projectPath,
...@@ -88,15 +89,18 @@ export default { ...@@ -88,15 +89,18 @@ export default {
Sentry.captureException(error); Sentry.captureException(error);
}, },
}, },
sidebarStatus: {
query: sidebarStatusQuery,
},
}, },
data() { data() {
return { return {
alert: null, alert: null,
errored: false, errored: false,
sidebarStatus: false,
isErrorDismissed: false, isErrorDismissed: false,
createIssueError: '', createIssueError: '',
issueCreationInProgress: false, issueCreationInProgress: false,
sidebarCollapsed: false,
sidebarErrorMessage: '', sidebarErrorMessage: '',
}; };
}, },
...@@ -132,10 +136,10 @@ export default { ...@@ -132,10 +136,10 @@ export default {
this.sidebarErrorMessage = ''; this.sidebarErrorMessage = '';
}, },
toggleSidebar() { toggleSidebar() {
this.sidebarCollapsed = !this.sidebarCollapsed; this.$apollo.mutate({ mutation: toggleSidebarStatusMutation });
toggleContainerClasses(containerEl, { toggleContainerClasses(containerEl, {
'right-sidebar-collapsed': this.sidebarCollapsed, 'right-sidebar-collapsed': !this.sidebarStatus,
'right-sidebar-expanded': !this.sidebarCollapsed, 'right-sidebar-expanded': this.sidebarStatus,
}); });
}, },
handleAlertSidebarError(errorMessage) { handleAlertSidebarError(errorMessage) {
...@@ -147,7 +151,7 @@ export default { ...@@ -147,7 +151,7 @@ export default {
this.$apollo this.$apollo
.mutate({ .mutate({
mutation: createIssueQuery, mutation: createIssueMutation,
variables: { variables: {
iid: this.alert.iid, iid: this.alert.iid,
projectPath: this.projectPath, projectPath: this.projectPath,
...@@ -197,7 +201,7 @@ export default { ...@@ -197,7 +201,7 @@ export default {
<div <div
v-if="alert" v-if="alert"
class="alert-management-details gl-relative" class="alert-management-details gl-relative"
:class="{ 'pr-sm-8': sidebarCollapsed }" :class="{ 'pr-sm-8': sidebarStatus }"
> >
<div <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" 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"
...@@ -330,10 +334,7 @@ export default { ...@@ -330,10 +334,7 @@ export default {
</gl-tab> </gl-tab>
</gl-tabs> </gl-tabs>
<alert-sidebar <alert-sidebar
:project-path="projectPath"
:project-id="projectId"
:alert="alert" :alert="alert"
:sidebar-collapsed="sidebarCollapsed"
@alert-refresh="alertRefresh" @alert-refresh="alertRefresh"
@toggle-sidebar="toggleSidebar" @toggle-sidebar="toggleSidebar"
@alert-error="handleAlertSidebarError" @alert-error="handleAlertSidebarError"
......
...@@ -4,6 +4,8 @@ import SidebarTodo from './sidebar/sidebar_todo.vue'; ...@@ -4,6 +4,8 @@ import SidebarTodo from './sidebar/sidebar_todo.vue';
import SidebarStatus from './sidebar/sidebar_status.vue'; import SidebarStatus from './sidebar/sidebar_status.vue';
import SidebarAssignees from './sidebar/sidebar_assignees.vue'; import SidebarAssignees from './sidebar/sidebar_assignees.vue';
import sidebarStatusQuery from '../graphql/queries/sidebar_status.query.graphql';
export default { export default {
components: { components: {
SidebarAssignees, SidebarAssignees,
...@@ -11,27 +13,34 @@ export default { ...@@ -11,27 +13,34 @@ export default {
SidebarTodo, SidebarTodo,
SidebarStatus, SidebarStatus,
}, },
props: { inject: {
sidebarCollapsed: { projectPath: {
type: Boolean, default: '',
required: true,
}, },
projectId: { projectId: {
type: String, type: String,
required: true, default: '',
},
projectPath: {
type: String,
required: true,
}, },
},
props: {
alert: { alert: {
type: Object, type: Object,
required: true, required: true,
}, },
}, },
apollo: {
sidebarStatus: {
query: sidebarStatusQuery,
},
},
data() {
return {
sidebarStatus: false,
};
},
computed: { computed: {
sidebarCollapsedClass() { sidebarCollapsedClass() {
return this.sidebarCollapsed ? 'right-sidebar-collapsed' : 'right-sidebar-expanded'; return this.sidebarStatus ? 'right-sidebar-collapsed' : 'right-sidebar-expanded';
}, },
}, },
}; };
...@@ -41,10 +50,10 @@ export default { ...@@ -41,10 +50,10 @@ export default {
<aside :class="sidebarCollapsedClass" class="right-sidebar alert-sidebar"> <aside :class="sidebarCollapsedClass" class="right-sidebar alert-sidebar">
<div class="issuable-sidebar js-issuable-update"> <div class="issuable-sidebar js-issuable-update">
<sidebar-header <sidebar-header
:sidebar-collapsed="sidebarCollapsed" :sidebar-collapsed="sidebarStatus"
@toggle-sidebar="$emit('toggle-sidebar')" @toggle-sidebar="$emit('toggle-sidebar')"
/> />
<sidebar-todo v-if="sidebarCollapsed" :sidebar-collapsed="sidebarCollapsed" /> <sidebar-todo v-if="sidebarStatus" :sidebar-collapsed="sidebarStatus" />
<sidebar-status <sidebar-status
:project-path="projectPath" :project-path="projectPath"
:alert="alert" :alert="alert"
...@@ -55,7 +64,7 @@ export default { ...@@ -55,7 +64,7 @@ export default {
:project-path="projectPath" :project-path="projectPath"
:project-id="projectId" :project-id="projectId"
:alert="alert" :alert="alert"
:sidebar-collapsed="sidebarCollapsed" :sidebar-collapsed="sidebarStatus"
@alert-refresh="$emit('alert-refresh')" @alert-refresh="$emit('alert-refresh')"
@toggle-sidebar="$emit('toggle-sidebar')" @toggle-sidebar="$emit('toggle-sidebar')"
@alert-error="$emit('alert-error', $event)" @alert-error="$emit('alert-error', $event)"
......
...@@ -3,6 +3,7 @@ import VueApollo from 'vue-apollo'; ...@@ -3,6 +3,7 @@ import VueApollo from 'vue-apollo';
import createDefaultClient from '~/lib/graphql'; import createDefaultClient from '~/lib/graphql';
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';
Vue.use(VueApollo); Vue.use(VueApollo);
...@@ -10,39 +11,51 @@ export default selector => { ...@@ -10,39 +11,51 @@ 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 resolvers = {
Mutation: {
toggleSidebarStatus: (_, __, { cache }) => {
const data = cache.readQuery({ query: sidebarStatusQuery });
data.sidebarStatus = !data.sidebarStatus;
cache.writeQuery({ query: sidebarStatusQuery, data });
},
},
};
const apolloProvider = new VueApollo({ const apolloProvider = new VueApollo({
defaultClient: createDefaultClient( defaultClient: createDefaultClient(resolvers, {
{}, cacheConfig: {
{ dataIdFromObject: object => {
cacheConfig: { // eslint-disable-next-line no-underscore-dangle
dataIdFromObject: object => { if (object.__typename === 'AlertManagementAlert') {
// eslint-disable-next-line no-underscore-dangle return object.iid;
if (object.__typename === 'AlertManagementAlert') { }
return object.iid; return defaultDataIdFromObject(object);
}
return defaultDataIdFromObject(object);
},
}, },
}, },
), }),
});
apolloProvider.clients.defaultClient.cache.writeData({
data: {
sidebarStatus: false,
},
}); });
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new Vue({ new Vue({
el: selector, el: selector,
provide: {
projectPath,
alertId,
projectIssuesPath,
projectId,
},
apolloProvider, apolloProvider,
components: { components: {
AlertDetails, AlertDetails,
}, },
render(createElement) { render(createElement) {
return createElement('alert-details', { return createElement('alert-details', {});
props: {
alertId,
projectPath,
projectId,
projectIssuesPath,
},
});
}, },
}); });
}; };
mutation($projectPath: ID!, $assigneeUsernames: [String!]!, $iid: String!) { mutation alertSetAssignees($projectPath: ID!, $assigneeUsernames: [String!]!, $iid: String!) {
alertSetAssignees( alertSetAssignees(
input: { iid: $iid, assigneeUsernames: $assigneeUsernames, projectPath: $projectPath } input: { iid: $iid, assigneeUsernames: $assigneeUsernames, projectPath: $projectPath }
) { ) {
......
mutation ($projectPath: ID!, $iid: String!) { mutation createAlertIssue($projectPath: ID!, $iid: String!) {
createAlertIssue(input: { iid: $iid, projectPath: $projectPath }) { createAlertIssue(input: { iid: $iid, projectPath: $projectPath }) {
errors errors
issue { issue {
......
mutation ($projectPath: ID!, $status: AlertManagementStatus!, $iid: String!) { mutation updateAlertStatus($projectPath: ID!, $status: AlertManagementStatus!, $iid: String!) {
updateAlertStatus(input: { iid: $iid, status: $status, projectPath: $projectPath }) { updateAlertStatus(input: { iid: $iid, status: $status, projectPath: $projectPath }) {
errors errors
alert { alert {
......
...@@ -3,7 +3,7 @@ import { GlAlert, GlLoadingIcon, GlTable } from '@gitlab/ui'; ...@@ -3,7 +3,7 @@ import { GlAlert, GlLoadingIcon, GlTable } from '@gitlab/ui';
import axios from 'axios'; import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import AlertDetails from '~/alert_management/components/alert_details.vue'; import AlertDetails from '~/alert_management/components/alert_details.vue';
import createIssueQuery from '~/alert_management/graphql/mutations/create_issue_from_alert.graphql'; import createIssueMutation from '~/alert_management/graphql/mutations/create_issue_from_alert.graphql';
import { joinPaths } from '~/lib/utils/url_utility'; import { joinPaths } from '~/lib/utils/url_utility';
import { import {
trackAlertsDetailsViewsOptions, trackAlertsDetailsViewsOptions,
...@@ -25,14 +25,14 @@ describe('AlertDetails', () => { ...@@ -25,14 +25,14 @@ describe('AlertDetails', () => {
function mountComponent({ data, loading = false, mountMethod = shallowMount, stubs = {} } = {}) { function mountComponent({ data, loading = false, mountMethod = shallowMount, stubs = {} } = {}) {
wrapper = mountMethod(AlertDetails, { wrapper = mountMethod(AlertDetails, {
propsData: { provide: {
alertId: 'alertId', alertId: 'alertId',
projectPath, projectPath,
projectIssuesPath, projectIssuesPath,
projectId, projectId,
}, },
data() { data() {
return { alert: { ...mockAlert }, ...data }; return { alert: { ...mockAlert }, sidebarStatus: false, ...data };
}, },
mocks: { mocks: {
$apollo: { $apollo: {
...@@ -41,6 +41,7 @@ describe('AlertDetails', () => { ...@@ -41,6 +41,7 @@ describe('AlertDetails', () => {
alert: { alert: {
loading, loading,
}, },
sidebarStatus: {},
}, },
}, },
}, },
...@@ -135,7 +136,7 @@ describe('AlertDetails', () => { ...@@ -135,7 +136,7 @@ describe('AlertDetails', () => {
it('should display "View issue" button that links the issue page when issue exists', () => { it('should display "View issue" button that links the issue page when issue exists', () => {
const issueIid = '3'; const issueIid = '3';
mountComponent({ mountComponent({
data: { alert: { ...mockAlert, issueIid } }, data: { alert: { ...mockAlert, issueIid }, sidebarStatus: false },
}); });
expect(findViewIssueBtn().exists()).toBe(true); expect(findViewIssueBtn().exists()).toBe(true);
expect(findViewIssueBtn().attributes('href')).toBe(joinPaths(projectIssuesPath, issueIid)); expect(findViewIssueBtn().attributes('href')).toBe(joinPaths(projectIssuesPath, issueIid));
...@@ -148,8 +149,11 @@ describe('AlertDetails', () => { ...@@ -148,8 +149,11 @@ describe('AlertDetails', () => {
mountMethod: mount, mountMethod: mount,
data: { alert: { ...mockAlert, issueIid } }, data: { alert: { ...mockAlert, issueIid } },
}); });
expect(findViewIssueBtn().exists()).toBe(false);
expect(findCreateIssueBtn().exists()).toBe(true); return wrapper.vm.$nextTick().then(() => {
expect(findViewIssueBtn().exists()).toBe(false);
expect(findCreateIssueBtn().exists()).toBe(true);
});
}); });
it('calls `$apollo.mutate` with `createIssueQuery`', () => { it('calls `$apollo.mutate` with `createIssueQuery`', () => {
...@@ -160,7 +164,7 @@ describe('AlertDetails', () => { ...@@ -160,7 +164,7 @@ describe('AlertDetails', () => {
findCreateIssueBtn().trigger('click'); findCreateIssueBtn().trigger('click');
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
mutation: createIssueQuery, mutation: createIssueMutation,
variables: { variables: {
iid: mockAlert.iid, iid: mockAlert.iid,
projectPath, projectPath,
......
...@@ -11,20 +11,28 @@ describe('Alert Details Sidebar', () => { ...@@ -11,20 +11,28 @@ describe('Alert Details Sidebar', () => {
let wrapper; let wrapper;
let mock; let mock;
function mountComponent({ function mountComponent({ mountMethod = shallowMount, stubs = {}, alert = {} } = {}) {
sidebarCollapsed = true,
mountMethod = shallowMount,
stubs = {},
alert = {},
} = {}) {
wrapper = mountMethod(AlertSidebar, { wrapper = mountMethod(AlertSidebar, {
data() {
return {
sidebarStatus: false,
};
},
propsData: { propsData: {
alert, alert,
sidebarCollapsed, },
provide: {
projectPath: 'projectPath', projectPath: 'projectPath',
projectId: '1', projectId: '1',
}, },
stubs, stubs,
mocks: {
$apollo: {
queries: {
sidebarStatus: {},
},
},
},
}); });
} }
...@@ -42,7 +50,7 @@ describe('Alert Details Sidebar', () => { ...@@ -42,7 +50,7 @@ describe('Alert Details Sidebar', () => {
}); });
it('open as default', () => { it('open as default', () => {
expect(wrapper.props('sidebarCollapsed')).toBe(true); expect(wrapper.classes('right-sidebar-expanded')).toBe(true);
}); });
it('should render side bar assignee dropdown', () => { it('should render side bar assignee dropdown', () => {
......
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