Commit e518bbc8 authored by Tom Quirk's avatar Tom Quirk Committed by Natalia Tepluhina

Apply fullscreen-layout to Design View

Fixes bug where Issue content could be scrolled
when Design View (the overlay) was opened.
parent e6314c28
...@@ -12,3 +12,5 @@ export const ACTIVE_DISCUSSION_SOURCE_TYPES = { ...@@ -12,3 +12,5 @@ export const ACTIVE_DISCUSSION_SOURCE_TYPES = {
pin: 'pin', pin: 'pin',
discussion: 'discussion', discussion: 'discussion',
}; };
export const DESIGN_DETAIL_LAYOUT_CLASSLIST = ['design-detail-layout', 'overflow-hidden', 'm-0'];
...@@ -2,6 +2,9 @@ import $ from 'jquery'; ...@@ -2,6 +2,9 @@ import $ from 'jquery';
import Vue from 'vue'; import Vue from 'vue';
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
import routes from './routes'; import routes from './routes';
import { DESIGN_ROUTE_NAME } from './constants';
import { getPageLayoutElement } from '~/design_management/utils/design_management_utils';
import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '../constants';
Vue.use(VueRouter); Vue.use(VueRouter);
...@@ -11,10 +14,20 @@ export default function createRouter(base) { ...@@ -11,10 +14,20 @@ export default function createRouter(base) {
mode: 'history', mode: 'history',
routes, routes,
}); });
const pageEl = getPageLayoutElement();
router.beforeEach(({ meta: { el } }, from, next) => { router.beforeEach(({ meta: { el }, name }, _, next) => {
$(`#${el}`).tab('show'); $(`#${el}`).tab('show');
// apply a fullscreen layout style in Design View (a.k.a design detail)
if (pageEl) {
if (name === DESIGN_ROUTE_NAME) {
pageEl.classList.add(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
} else {
pageEl.classList.remove(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
}
}
next(); next();
}); });
......
...@@ -123,3 +123,5 @@ const normalizeAuthor = author => ({ ...@@ -123,3 +123,5 @@ const normalizeAuthor = author => ({
}); });
export const extractParticipants = users => users.edges.map(({ node }) => normalizeAuthor(node)); export const extractParticipants = users => users.edges.map(({ node }) => normalizeAuthor(node));
export const getPageLayoutElement = () => document.querySelector('.layout-page');
.layout-page.design-detail-layout {
max-height: 100vh;
}
.design-detail { .design-detail {
background-color: rgba($black, 0.9); background-color: rgba($black, 0.9);
......
---
title: Remove ability to scroll Issue while in Design View
merge_request: 29881
author:
type: fixed
import { shallowMount } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueRouter from 'vue-router';
import { GlAlert } from '@gitlab/ui'; import { GlAlert } from '@gitlab/ui';
import { ApolloMutation } from 'vue-apollo'; import { ApolloMutation } from 'vue-apollo';
import createFlash from '~/flash'; import createFlash from '~/flash';
...@@ -17,6 +18,9 @@ import { ...@@ -17,6 +18,9 @@ import {
DESIGN_VERSION_NOT_EXIST_ERROR, DESIGN_VERSION_NOT_EXIST_ERROR,
} from '~/design_management/utils/error_messages'; } from '~/design_management/utils/error_messages';
import { DESIGNS_ROUTE_NAME } from '~/design_management/router/constants'; import { DESIGNS_ROUTE_NAME } from '~/design_management/router/constants';
import createRouter from '~/design_management/router';
import * as utils from '~/design_management/utils/design_management_utils';
import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management/constants';
jest.mock('~/flash'); jest.mock('~/flash');
jest.mock('mousetrap', () => ({ jest.mock('mousetrap', () => ({
...@@ -24,8 +28,13 @@ jest.mock('mousetrap', () => ({ ...@@ -24,8 +28,13 @@ jest.mock('mousetrap', () => ({
unbind: jest.fn(), unbind: jest.fn(),
})); }));
const localVue = createLocalVue();
localVue.use(VueRouter);
describe('Design management design index page', () => { describe('Design management design index page', () => {
let wrapper; let wrapper;
let router;
const newComment = 'new comment'; const newComment = 'new comment';
const annotationCoordinates = { const annotationCoordinates = {
x: 10, x: 10,
...@@ -62,14 +71,13 @@ describe('Design management design index page', () => { ...@@ -62,14 +71,13 @@ describe('Design management design index page', () => {
}; };
const mutate = jest.fn().mockResolvedValue(); const mutate = jest.fn().mockResolvedValue();
const routerPush = jest.fn();
const findDiscussions = () => wrapper.findAll(DesignDiscussion); const findDiscussions = () => wrapper.findAll(DesignDiscussion);
const findDiscussionForm = () => wrapper.find(DesignReplyForm); const findDiscussionForm = () => wrapper.find(DesignReplyForm);
const findParticipants = () => wrapper.find(Participants); const findParticipants = () => wrapper.find(Participants);
const findDiscussionsWrapper = () => wrapper.find('.image-notes'); const findDiscussionsWrapper = () => wrapper.find('.image-notes');
function createComponent(loading = false, data = {}, { routeQuery = {} } = {}) { function createComponent(loading = false, data = {}) {
const $apollo = { const $apollo = {
queries: { queries: {
design: { design: {
...@@ -79,17 +87,11 @@ describe('Design management design index page', () => { ...@@ -79,17 +87,11 @@ describe('Design management design index page', () => {
mutate, mutate,
}; };
const $router = { router = createRouter();
push: routerPush,
};
const $route = {
query: routeQuery,
};
wrapper = shallowMount(DesignIndex, { wrapper = shallowMount(DesignIndex, {
propsData: { id: '1' }, propsData: { id: '1' },
mocks: { $apollo, $router, $route }, mocks: { $apollo },
stubs: { stubs: {
ApolloMutation, ApolloMutation,
DesignDiscussion, DesignDiscussion,
...@@ -104,6 +106,8 @@ describe('Design management design index page', () => { ...@@ -104,6 +106,8 @@ describe('Design management design index page', () => {
...data, ...data,
}; };
}, },
localVue,
router,
}); });
} }
...@@ -111,6 +115,23 @@ describe('Design management design index page', () => { ...@@ -111,6 +115,23 @@ describe('Design management design index page', () => {
wrapper.destroy(); wrapper.destroy();
}); });
describe('when navigating', () => {
it('applies fullscreen layout', () => {
const mockEl = {
classList: {
add: jest.fn(),
remove: jest.fn(),
},
};
jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockEl);
createComponent(true);
wrapper.vm.$router.push('/designs/test');
expect(mockEl.classList.add).toHaveBeenCalledTimes(1);
expect(mockEl.classList.add).toHaveBeenCalledWith(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
});
});
it('sets loading state', () => { it('sets loading state', () => {
createComponent(true); createComponent(true);
...@@ -269,31 +290,35 @@ describe('Design management design index page', () => { ...@@ -269,31 +290,35 @@ describe('Design management design index page', () => {
describe('with no designs', () => { describe('with no designs', () => {
it('redirects to /designs', () => { it('redirects to /designs', () => {
createComponent(true); createComponent(true);
router.push = jest.fn();
wrapper.vm.onDesignQueryResult({ data: mockResponseNoDesigns, loading: false }); wrapper.vm.onDesignQueryResult({ data: mockResponseNoDesigns, loading: false });
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(createFlash).toHaveBeenCalledTimes(1); expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(DESIGN_NOT_FOUND_ERROR); expect(createFlash).toHaveBeenCalledWith(DESIGN_NOT_FOUND_ERROR);
expect(routerPush).toHaveBeenCalledTimes(1); expect(router.push).toHaveBeenCalledTimes(1);
expect(routerPush).toHaveBeenCalledWith({ name: DESIGNS_ROUTE_NAME }); expect(router.push).toHaveBeenCalledWith({ name: DESIGNS_ROUTE_NAME });
}); });
}); });
}); });
describe('when no design exists for given version', () => { describe('when no design exists for given version', () => {
it('redirects to /designs', () => { it('redirects to /designs', () => {
// attempt to query for a version of the design that doesn't exist createComponent(true);
createComponent(true, {}, { routeQuery: { version: '999' } });
wrapper.setData({ wrapper.setData({
allVersions: mockAllVersions, allVersions: mockAllVersions,
}); });
// attempt to query for a version of the design that doesn't exist
router.push({ query: { version: '999' } });
router.push = jest.fn();
wrapper.vm.onDesignQueryResult({ data: mockResponseWithDesigns, loading: false }); wrapper.vm.onDesignQueryResult({ data: mockResponseWithDesigns, loading: false });
return wrapper.vm.$nextTick().then(() => { return wrapper.vm.$nextTick().then(() => {
expect(createFlash).toHaveBeenCalledTimes(1); expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(DESIGN_VERSION_NOT_EXIST_ERROR); expect(createFlash).toHaveBeenCalledWith(DESIGN_VERSION_NOT_EXIST_ERROR);
expect(routerPush).toHaveBeenCalledTimes(1); expect(router.push).toHaveBeenCalledTimes(1);
expect(routerPush).toHaveBeenCalledWith({ name: DESIGNS_ROUTE_NAME }); expect(router.push).toHaveBeenCalledWith({ name: DESIGNS_ROUTE_NAME });
}); });
}); });
}); });
......
...@@ -2,7 +2,6 @@ import { createLocalVue, shallowMount } from '@vue/test-utils'; ...@@ -2,7 +2,6 @@ import { createLocalVue, shallowMount } from '@vue/test-utils';
import { ApolloMutation } from 'vue-apollo'; import { ApolloMutation } from 'vue-apollo';
import VueRouter from 'vue-router'; import VueRouter from 'vue-router';
import { GlEmptyState } from '@gitlab/ui'; import { GlEmptyState } from '@gitlab/ui';
import Index from '~/design_management/pages/index.vue'; import Index from '~/design_management/pages/index.vue';
import uploadDesignQuery from '~/design_management/graphql/mutations/uploadDesign.mutation.graphql'; import uploadDesignQuery from '~/design_management/graphql/mutations/uploadDesign.mutation.graphql';
import DesignDestroyer from '~/design_management/components/design_destroyer.vue'; import DesignDestroyer from '~/design_management/components/design_destroyer.vue';
...@@ -14,20 +13,21 @@ import { ...@@ -14,20 +13,21 @@ import {
EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE, EXISTING_DESIGN_DROP_INVALID_FILENAME_MESSAGE,
} from '~/design_management/utils/error_messages'; } from '~/design_management/utils/error_messages';
import createFlash from '~/flash'; import createFlash from '~/flash';
import createRouter from '~/design_management/router';
import * as utils from '~/design_management/utils/design_management_utils';
import { DESIGN_DETAIL_LAYOUT_CLASSLIST } from '~/design_management/constants';
jest.mock('~/flash.js');
const mockPageEl = {
classList: {
remove: jest.fn(),
},
};
jest.spyOn(utils, 'getPageLayoutElement').mockReturnValue(mockPageEl);
const localVue = createLocalVue(); const localVue = createLocalVue();
const router = createRouter();
localVue.use(VueRouter); localVue.use(VueRouter);
const router = new VueRouter({
routes: [
{
name: DESIGNS_ROUTE_NAME,
path: '/designs',
component: Index,
},
],
});
jest.mock('~/flash.js');
const mockDesigns = [ const mockDesigns = [
{ {
...@@ -530,4 +530,14 @@ describe('Design management index page', () => { ...@@ -530,4 +530,14 @@ describe('Design management index page', () => {
expect(wrapper.vm.onUploadDesign).not.toHaveBeenCalled(); expect(wrapper.vm.onUploadDesign).not.toHaveBeenCalled();
}); });
}); });
describe('when navigating', () => {
it('ensures fullscreen layout is not applied', () => {
createComponent(true);
wrapper.vm.$router.push('/designs');
expect(mockPageEl.classList.remove).toHaveBeenCalledTimes(1);
expect(mockPageEl.classList.remove).toHaveBeenCalledWith(...DESIGN_DETAIL_LAYOUT_CLASSLIST);
});
});
}); });
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