Commit 235ebffc authored by Denys Mishunov's avatar Denys Mishunov Committed by David O'Regan

Timely sanitization of initial Epic data

Epic, even though is using the issuable components,
doesn't follow the same pattern of sanitization of the
HTML data at the moment the data is read. This leads to
double-rendering of the Vue applications when description
content fetched with polling doesn't match the initial
one. Even though the difference is purely cosmetic
(stripped out line breaks in the initial description),
Vue still updates state and rerenders the view seeing
that the description is different.

This MR fixes this and unifies the way we sanitize output
for Issues and Epics
parent ae6f1b66
......@@ -3,7 +3,6 @@ import { GlIcon, GlIntersectionObserver } from '@gitlab/ui';
import Visibility from 'visibilityjs';
import { __, s__, sprintf } from '~/locale';
import { deprecatedCreateFlash as createFlash } from '~/flash';
import { sanitize } from '~/lib/dompurify';
import { visitUrl } from '~/lib/utils/url_utility';
import Poll from '~/lib/utils/poll';
import eventHub from '../event_hub';
......@@ -179,7 +178,7 @@ export default {
const store = new Store({
titleHtml: this.initialTitleHtml,
titleText: this.initialTitleText,
descriptionHtml: sanitize(this.initialDescriptionHtml),
descriptionHtml: this.initialDescriptionHtml,
descriptionText: this.initialDescriptionText,
updatedAt: this.updatedAt,
updatedByName: this.updatedByName,
......
......@@ -4,13 +4,11 @@ import { sanitize } from '~/lib/dompurify';
// We currently load + parse the data from the issue app and related merge request
let cachedParsedData;
export const parseIssuableData = () => {
export const parseIssuableData = el => {
try {
if (cachedParsedData) return cachedParsedData;
const initialDataEl = document.getElementById('js-issuable-app');
const parsedData = JSON.parse(initialDataEl.dataset.initial);
const parsedData = JSON.parse(el.dataset.initial);
parsedData.initialTitleHtml = sanitize(parsedData.initialTitleHtml);
parsedData.initialDescriptionHtml = sanitize(parsedData.initialDescriptionHtml);
......
......@@ -17,7 +17,8 @@ import initInviteMemberModal from '~/invite_member/init_invite_member_modal';
import { IssuableType } from '~/issuable_show/constants';
export default function() {
const { issueType, ...issuableData } = parseIssuableData();
const initialDataEl = document.getElementById('js-issuable-app');
const { issueType, ...issuableData } = parseIssuableData(initialDataEl);
switch (issueType) {
case IssuableType.Incident:
......
......@@ -5,6 +5,7 @@ import Cookies from 'js-cookie';
import { GlBreakpointInstance as bp } from '@gitlab/ui/dist/utils';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import labelsSelectModule from '~/vue_shared/components/sidebar/labels_select_vue/store';
import { parseIssuableData } from '~/issue_show/utils/parse_data';
import createStore from './store';
import EpicApp from './components/epic_app.vue';
......@@ -43,7 +44,7 @@ export default (epicCreate = false) => {
}
const epicMeta = convertObjectPropsToCamelCase(JSON.parse(el.dataset.meta), { deep: true });
const epicData = JSON.parse(el.dataset.initial);
const epicData = parseIssuableData(el);
// Collapse the sidebar on mobile screens by default
const bpBreakpoint = bp.getBreakpointSize();
......
......@@ -30,7 +30,8 @@ describe('Issue show index', () => {
initialDescriptionHtml: '<svg onload=window.alert(1)>',
});
const issuableData = parseData.parseIssuableData();
const initialDataEl = document.getElementById('js-issuable-app');
const issuableData = parseData.parseIssuableData(initialDataEl);
initIssuableApp(issuableData, createStore());
await waitForPromises();
......
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