Commit 9eb0b043 authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'alert-management-apollo-cache' into 'master'

Alert Management Sidebar Apollo Cache

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