Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-09-09 03:09:52 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-09 03:09:52 +0300
commitf9e1ee549e79c7c9ac119d125732d1d3a35fa060 (patch)
treecedf856715158a4fbbc974382acea5b74a49559f
parent6a315e2d9c09da0efffdabed91ee872e867a981c (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/issues/index.js35
-rw-r--r--app/assets/javascripts/issues/show/index.js143
-rw-r--r--app/assets/javascripts/pages/projects/incidents/show/index.js4
-rw-r--r--app/assets/javascripts/pages/projects/issues/show/index.js7
-rw-r--r--app/assets/javascripts/related_issues/index.js5
-rw-r--r--app/views/projects/issues/_related_issues.html.haml1
-rw-r--r--spec/frontend/issues/show/issue_spec.js43
7 files changed, 55 insertions, 183 deletions
diff --git a/app/assets/javascripts/issues/index.js b/app/assets/javascripts/issues/index.js
index 8552a5a93fc..3bd28c50800 100644
--- a/app/assets/javascripts/issues/index.js
+++ b/app/assets/javascripts/issues/index.js
@@ -4,20 +4,19 @@ import IssuableLabelSelector from '~/issuable/issuable_label_selector';
import ShortcutsIssuable from '~/behaviors/shortcuts/shortcuts_issuable';
import ShortcutsNavigation from '~/behaviors/shortcuts/shortcuts_navigation';
import { initIssuableSidebar } from '~/issuable';
-import { TYPE_INCIDENT } from '~/issues/constants';
import Issue from '~/issues/issue';
import { initTitleSuggestions, initTypePopover, initTypeSelect } from '~/issues/new';
import { initRelatedMergeRequests } from '~/issues/related_merge_requests';
import { initRelatedIssues } from '~/related_issues';
-import { initIncidentApp, initIssueApp, initSentryErrorStackTrace } from '~/issues/show';
-import { parseIssuableData } from '~/issues/show/utils/parse_data';
+import { initIssuableApp, initSentryErrorStackTrace } from '~/issues/show';
import LabelsSelect from '~/labels/labels_select';
import initNotesApp from '~/notes';
import { store } from '~/notes/stores';
import { mountMilestoneDropdown } from '~/sidebar/mount_sidebar';
+import initSidebarBundle from '~/sidebar/sidebar_bundle';
+import initWorkItemLinks from '~/work_items/components/work_item_links';
import ZenMode from '~/zen_mode';
import initAwardsApp from '~/emoji/awards_app';
-import initLinkedResources from '~/linked_resources';
import FilteredSearchServiceDesk from './filtered_search_service_desk';
export function initFilteredSearchServiceDesk() {
@@ -42,32 +41,20 @@ export function initForm() {
mountMilestoneDropdown();
}
-export function initShow({ notesParams } = {}) {
- const el = document.getElementById('js-issuable-app');
-
- if (!el) {
- return;
- }
-
- const issuableData = parseIssuableData(el);
-
- if (issuableData.issueType === TYPE_INCIDENT) {
- initIncidentApp(issuableData, store);
- initLinkedResources();
- initRelatedIssues(TYPE_INCIDENT);
- } else {
- initIssueApp(issuableData, store);
- }
-
+export function initShow() {
new Issue(); // eslint-disable-line no-new
new ShortcutsIssuable(); // eslint-disable-line no-new
new ZenMode(); // eslint-disable-line no-new
+
+ initAwardsApp(document.getElementById('js-vue-awards-block'));
+ initIssuableApp(store);
initIssuableSidebar();
- initNotesApp(notesParams);
+ initNotesApp();
+ initRelatedIssues();
initRelatedMergeRequests();
initSentryErrorStackTrace();
-
- initAwardsApp(document.getElementById('js-vue-awards-block'));
+ initSidebarBundle(store);
+ initWorkItemLinks();
import(/* webpackChunkName: 'design_management' */ '~/design_management')
.then((module) => module.default())
diff --git a/app/assets/javascripts/issues/show/index.js b/app/assets/javascripts/issues/show/index.js
index f7fe8ccf0e9..b94f88f690e 100644
--- a/app/assets/javascripts/issues/show/index.js
+++ b/app/assets/javascripts/issues/show/index.js
@@ -3,15 +3,18 @@ import Vue from 'vue';
import { mapGetters } from 'vuex';
import errorTrackingStore from '~/error_tracking/store';
import { apolloProvider } from '~/graphql_shared/issuable_client';
-import { TYPE_INCIDENT } from '~/issues/constants';
+import { TYPE_INCIDENT, TYPE_ISSUE } from '~/issues/constants';
import { convertObjectPropsToCamelCase, parseBoolean } from '~/lib/utils/common_utils';
import { scrollToTargetOnResize } from '~/lib/utils/resize_observer';
+import initLinkedResources from '~/linked_resources';
import IssueApp from './components/app.vue';
+import DescriptionComponent from './components/description.vue';
import IncidentTabs from './components/incidents/incident_tabs.vue';
import SentryErrorStackTrace from './components/sentry_error_stack_trace.vue';
import { issueState } from './constants';
import getIssueStateQuery from './queries/get_issue_state.query.graphql';
import createRouter from './components/incidents/router';
+import { parseIssuableData } from './utils/parse_data';
const bootstrapApollo = (state = {}) => {
return apolloProvider.clients.defaultClient.cache.writeQuery({
@@ -22,146 +25,79 @@ const bootstrapApollo = (state = {}) => {
});
};
-export function initIncidentApp(issueData = {}, store) {
+export function initIssuableApp(store) {
const el = document.getElementById('js-issuable-app');
if (!el) {
return undefined;
}
+ const issuableData = parseIssuableData(el);
+ const headerActionsData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.headerActionsData));
+
const {
authorId,
authorName,
authorUsername,
authorWebUrl,
canCreateIncident,
- hasIterationsFeature,
- canUpdate,
- canUpdateTimelineEvent,
+ fullPath,
iid,
issuableId,
issueType,
- fullPath,
+ hasIterationsFeature,
+ // for issue
+ registerPath,
+ signInPath,
+ // for incident
+ canUpdate,
+ canUpdateTimelineEvent,
currentPath,
currentTab,
- projectId,
hasLinkedAlerts,
+ projectId,
slaFeatureAvailable,
uploadMetricsFeatureAvailable,
- } = issueData;
+ } = issuableData;
- const headerActionsData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.headerActionsData));
+ const issueProvideData = { registerPath, signInPath };
+ const incidentProvideData = {
+ canUpdate,
+ canUpdateTimelineEvent,
+ hasLinkedAlerts: parseBoolean(hasLinkedAlerts),
+ projectId,
+ slaFeatureAvailable: parseBoolean(slaFeatureAvailable),
+ uploadMetricsFeatureAvailable: parseBoolean(uploadMetricsFeatureAvailable),
+ };
bootstrapApollo({ ...issueState, issueType });
- const router = createRouter(currentPath, currentTab);
-
- return new Vue({
- el,
- name: 'DescriptionRoot',
- apolloProvider,
- store,
- router,
- provide: {
- issueType,
- canCreateIncident,
- canUpdateTimelineEvent,
- canUpdate,
- fullPath,
- iid,
- issuableId,
- projectId,
- hasIterationsFeature,
- hasLinkedAlerts: parseBoolean(hasLinkedAlerts),
- slaFeatureAvailable: parseBoolean(slaFeatureAvailable),
- uploadMetricsFeatureAvailable: parseBoolean(uploadMetricsFeatureAvailable),
- contentEditorOnIssues: gon.features.contentEditorOnIssues,
- // for HeaderActions component
- canCreateIssue: parseBoolean(headerActionsData.canCreateIncident),
- canDestroyIssue: parseBoolean(headerActionsData.canDestroyIssue),
- canPromoteToEpic: parseBoolean(headerActionsData.canPromoteToEpic),
- canReopenIssue: parseBoolean(headerActionsData.canReopenIssue),
- canReportSpam: parseBoolean(headerActionsData.canReportSpam),
- canUpdateIssue: parseBoolean(headerActionsData.canUpdateIssue),
- isIssueAuthor: parseBoolean(headerActionsData.isIssueAuthor),
- issuePath: headerActionsData.issuePath,
- newIssuePath: headerActionsData.newIssuePath,
- projectPath: headerActionsData.projectPath,
- reportAbusePath: headerActionsData.reportAbusePath,
- reportedUserId: headerActionsData.reportedUserId,
- reportedFromUrl: headerActionsData.reportedFromUrl,
- submitAsSpamPath: headerActionsData.submitAsSpamPath,
- issuableEmailAddress: headerActionsData.issuableEmailAddress,
- },
- computed: {
- ...mapGetters(['getNoteableData']),
- },
- render(createElement) {
- return createElement(IssueApp, {
- props: {
- ...issueData,
- author: {
- id: authorId,
- name: authorName,
- username: authorUsername,
- webUrl: authorWebUrl,
- },
- issueId: Number(issuableId),
- issuableStatus: this.getNoteableData?.state,
- issuableType: TYPE_INCIDENT,
- descriptionComponent: IncidentTabs,
- showTitleBorder: false,
- isConfidential: this.getNoteableData?.confidential,
- },
- });
- },
- });
-}
-
-export function initIssueApp(issueData, store) {
- const el = document.getElementById('js-issuable-app');
+ scrollToTargetOnResize();
- if (!el) {
- return undefined;
+ if (issueType === TYPE_INCIDENT) {
+ initLinkedResources();
}
- const {
- authorId,
- authorName,
- authorUsername,
- authorWebUrl,
- canCreateIncident,
- hasIterationsFeature,
- iid,
- issuableId,
- issueType,
- fullPath,
- registerPath,
- signInPath,
- } = issueData;
-
- const headerActionsData = convertObjectPropsToCamelCase(JSON.parse(el.dataset.headerActionsData));
-
- bootstrapApollo({ ...issueState, issueType });
-
- scrollToTargetOnResize();
-
return new Vue({
el,
name: 'DescriptionRoot',
apolloProvider,
store,
+ router: issueType === TYPE_INCIDENT ? createRouter(currentPath, currentTab) : undefined,
provide: {
canCreateIncident,
fullPath,
iid,
issuableId,
issueType,
- registerPath,
- signInPath,
hasIterationsFeature,
+ ...(issueType === TYPE_ISSUE && issueProvideData),
+ ...(issueType === TYPE_INCIDENT && incidentProvideData),
// for HeaderActions component
- canCreateIssue: parseBoolean(headerActionsData.canCreateIssue),
+ canCreateIssue:
+ issueType === TYPE_INCIDENT
+ ? parseBoolean(headerActionsData.canCreateIncident)
+ : parseBoolean(headerActionsData.canCreateIssue),
canDestroyIssue: parseBoolean(headerActionsData.canDestroyIssue),
canPromoteToEpic: parseBoolean(headerActionsData.canPromoteToEpic),
canReopenIssue: parseBoolean(headerActionsData.canReopenIssue),
@@ -183,18 +119,21 @@ export function initIssueApp(issueData, store) {
render(createElement) {
return createElement(IssueApp, {
props: {
- ...issueData,
+ ...issuableData,
author: {
id: authorId,
name: authorName,
username: authorUsername,
webUrl: authorWebUrl,
},
+ descriptionComponent: issueType === TYPE_INCIDENT ? IncidentTabs : DescriptionComponent,
isConfidential: this.getNoteableData?.confidential,
isLocked: this.getNoteableData?.discussion_locked,
issuableStatus: this.getNoteableData?.state,
+ issuableType: issueType,
issueId: this.getNoteableData?.id,
issueIid: this.getNoteableData?.iid,
+ showTitleBorder: issueType !== TYPE_INCIDENT,
},
});
},
diff --git a/app/assets/javascripts/pages/projects/incidents/show/index.js b/app/assets/javascripts/pages/projects/incidents/show/index.js
index a83c4f1c0d2..a2ff45b454a 100644
--- a/app/assets/javascripts/pages/projects/incidents/show/index.js
+++ b/app/assets/javascripts/pages/projects/incidents/show/index.js
@@ -1,7 +1,3 @@
import { initShow } from '~/issues';
-import initSidebarBundle from '~/sidebar/sidebar_bundle';
-import initWorkItemLinks from '~/work_items/components/work_item_links';
initShow();
-initSidebarBundle();
-initWorkItemLinks();
diff --git a/app/assets/javascripts/pages/projects/issues/show/index.js b/app/assets/javascripts/pages/projects/issues/show/index.js
index c92958cd8c7..a2ff45b454a 100644
--- a/app/assets/javascripts/pages/projects/issues/show/index.js
+++ b/app/assets/javascripts/pages/projects/issues/show/index.js
@@ -1,10 +1,3 @@
import { initShow } from '~/issues';
-import { store } from '~/notes/stores';
-import { initRelatedIssues } from '~/related_issues';
-import initSidebarBundle from '~/sidebar/sidebar_bundle';
-import initWorkItemLinks from '~/work_items/components/work_item_links';
initShow();
-initSidebarBundle(store);
-initRelatedIssues();
-initWorkItemLinks();
diff --git a/app/assets/javascripts/related_issues/index.js b/app/assets/javascripts/related_issues/index.js
index 23620432feb..cc0dae355b6 100644
--- a/app/assets/javascripts/related_issues/index.js
+++ b/app/assets/javascripts/related_issues/index.js
@@ -1,10 +1,9 @@
import Vue from 'vue';
-import { TYPE_ISSUE } from '~/issues/constants';
import { apolloProvider } from '~/graphql_shared/issuable_client';
import { parseBoolean } from '~/lib/utils/common_utils';
import RelatedIssuesRoot from './components/related_issues_root.vue';
-export function initRelatedIssues(issueType = TYPE_ISSUE) {
+export function initRelatedIssues() {
const el = document.querySelector('.js-related-issues-root');
if (!el) {
@@ -28,7 +27,7 @@ export function initRelatedIssues(issueType = TYPE_ISSUE) {
canAdmin: parseBoolean(el.dataset.canAddRelatedIssues),
helpPath: el.dataset.helpPath,
showCategorizedIssues: parseBoolean(el.dataset.showCategorizedIssues),
- issuableType: issueType,
+ issuableType: el.dataset.issuableType,
autoCompleteEpics: false,
},
}),
diff --git a/app/views/projects/issues/_related_issues.html.haml b/app/views/projects/issues/_related_issues.html.haml
index 2409c61fbf2..73a88e63a4e 100644
--- a/app/views/projects/issues/_related_issues.html.haml
+++ b/app/views/projects/issues/_related_issues.html.haml
@@ -4,6 +4,7 @@
full_path: @project.full_path,
has_issue_weights_feature: @project.licensed_feature_available?(:issue_weights).to_s,
help_path: help_page_path('user/project/issues/related_issues'),
+ issuable_type: @issue.issue_type,
show_categorized_issues: @project.licensed_feature_available?(:blocked_issues).to_s,
has_iterations_feature: @project.licensed_feature_available?(:iterations).to_s,
report_abuse_path: add_category_abuse_reports_path } }
diff --git a/spec/frontend/issues/show/issue_spec.js b/spec/frontend/issues/show/issue_spec.js
deleted file mode 100644
index 561035242eb..00000000000
--- a/spec/frontend/issues/show/issue_spec.js
+++ /dev/null
@@ -1,43 +0,0 @@
-import MockAdapter from 'axios-mock-adapter';
-import waitForPromises from 'helpers/wait_for_promises';
-import { initIssueApp } from '~/issues/show';
-import * as parseData from '~/issues/show/utils/parse_data';
-import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
-import createStore from '~/notes/stores';
-import { appProps } from './mock_data/mock_data';
-
-const mock = new MockAdapter(axios);
-mock.onGet().reply(HTTP_STATUS_OK);
-
-jest.mock('~/lib/utils/poll');
-
-const setupHTML = (initialData) => {
- document.body.innerHTML = `<div id="js-issuable-app"></div>`;
- document.getElementById('js-issuable-app').dataset.initial = JSON.stringify(initialData);
-};
-
-describe('Issue show index', () => {
- describe('initIssueApp', () => {
- // quarantine: https://gitlab.com/gitlab-org/gitlab/-/issues/390368
- // eslint-disable-next-line jest/no-disabled-tests
- it.skip('should initialize app with no potential XSS attack', async () => {
- const alertSpy = jest.spyOn(window, 'alert').mockImplementation(() => {});
- const parseDataSpy = jest.spyOn(parseData, 'parseIssuableData');
-
- setupHTML({
- ...appProps,
- initialDescriptionHtml: '<svg onload=window.alert(1)>',
- });
-
- const initialDataEl = document.getElementById('js-issuable-app');
- const issuableData = parseData.parseIssuableData(initialDataEl);
- initIssueApp(issuableData, createStore());
-
- await waitForPromises();
-
- expect(parseDataSpy).toHaveBeenCalled();
- expect(alertSpy).not.toHaveBeenCalled();
- });
- });
-});