blob: ecb666463ba5cb8e107e988b1add291fb9635dbe [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001// Copyright 2019 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5import {ReactElement} from 'react';
6import * as React from 'react'
7import ReactDOM from 'react-dom';
8import styles from './IssueWizard.css';
Copybara854996b2021-09-07 19:36:02 +00009import LandingStep from './issue-wizard/LandingStep.tsx';
10import DetailsStep from './issue-wizard/DetailsStep.tsx'
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020011import {IssueWizardPersona} from './issue-wizard/IssueWizardTypes.tsx';
12import CustomQuestionsStep from './issue-wizard/CustomQuestionsStep.tsx';
13import {getOs, getChromeVersion, buildIssueDescription} from './issue-wizard/IssueWizardUtils.tsx'
14import Header from './issue-wizard/Header.tsx'
15
16import {GetQuestionsByCategory, buildIssueLabels, getCompValByCategory, getLabelsByCategory} from './issue-wizard/IssueWizardUtils.tsx';
17import {ISSUE_WIZARD_QUESTIONS, ISSUE_REPRODUCE_PLACEHOLDER, OS_CHANNEL_LIST} from './issue-wizard/IssueWizardConfig.ts';
18import {prpcClient} from 'prpc-client-instance.js';
19import {expandDescriptions} from './issue-wizard/IssueWizardDescriptionsUtils.tsx';
20import SubmitSuccessStep from './issue-wizard/SubmitSuccessStep.tsx';
21import {IssueWizardFeedback} from './issue-wizard/IssueWizardFeedback.tsx';
Copybara854996b2021-09-07 19:36:02 +000022
23/**
24 * Base component for the issue filing wizard, wrapper for other components.
25 * @return Issue wizard JSX.
26 */
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020027 type Props = {
28 loginUrl: string,
29 userDisplayName: string,
30}
31export function IssueWizard(props: Props): ReactElement {
32 const {loginUrl, userDisplayName} = props;
33 React.useEffect(() => {
34 if(!userDisplayName) {
35 window.location.href = loginUrl;
36 }
37 },[loginUrl, userDisplayName]);
38
39 const [userPersona, setUserPersona] = React.useState(IssueWizardPersona.EndUser);
Copybara854996b2021-09-07 19:36:02 +000040 const [activeStep, setActiveStep] = React.useState(0);
41 const [category, setCategory] = React.useState('');
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020042 const [newIssueID, setnewIssueID] = React.useState('');
43 const [isRegression, setIsRegression] = React.useState(false);
Copybara854996b2021-09-07 19:36:02 +000044 const [textValues, setTextValues] = React.useState(
45 {
46 oneLineSummary: '',
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020047 stepsToReproduce: ISSUE_REPRODUCE_PLACEHOLDER,
Copybara854996b2021-09-07 19:36:02 +000048 describeProblem: '',
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020049 chromeVersion: getChromeVersion(),
50 osName: getOs(),
51 channel: OS_CHANNEL_LIST[0].name,
Copybara854996b2021-09-07 19:36:02 +000052 });
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020053 const [enableFeedback, setEnableFeedback] = React.useState(false);
54 const questionByCategory = GetQuestionsByCategory(ISSUE_WIZARD_QUESTIONS);
Copybara854996b2021-09-07 19:36:02 +000055
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020056 const moveStep = (step: number) => {
57 window.scrollTo(0, 0);
58 setActiveStep(step);
59 }
60
61 const reset = () => {
62 setTextValues({
63 oneLineSummary: '',
64 stepsToReproduce: ISSUE_REPRODUCE_PLACEHOLDER,
65 describeProblem: '',
66 chromeVersion: getChromeVersion(),
67 osName: getOs(),
68 channel: OS_CHANNEL_LIST[0].name,
69 });
70 setIsRegression(false);
71 }
72
73 const updateCategory = (category: string) => {
74 setCategory(category);
75 reset();
76 }
77
Copybara854996b2021-09-07 19:36:02 +000078 let page;
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020079 if (activeStep === 0) {
Copybara854996b2021-09-07 19:36:02 +000080 page = <LandingStep
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020081 userPersona={userPersona}
82 setUserPersona={setUserPersona}
Copybara854996b2021-09-07 19:36:02 +000083 category={category}
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020084 setCategory={updateCategory}
85 setActiveStep={moveStep}
Copybara854996b2021-09-07 19:36:02 +000086 />;
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +020087 } else if (activeStep === 1) {
88 page = <DetailsStep
89 textValues={textValues}
90 setTextValues={setTextValues}
91 category={category}
92 setActiveStep={moveStep}
93 setIsRegression={setIsRegression}
94 />;
95 } else if (activeStep === 2) {
96 const compValByCategory = getCompValByCategory(ISSUE_WIZARD_QUESTIONS);
97 const labelsByCategory = getLabelsByCategory(ISSUE_WIZARD_QUESTIONS);
98
99 const onSubmitIssue = (comments: string, customQuestionsAnswers: Array<string>, attachments: Array<any>,onSuccess: Function, onFailure: Function) => {
100 const summary = textValues.oneLineSummary;
101 const component = compValByCategory.get(category);
102 const description = buildIssueDescription(
103 textValues.stepsToReproduce,
104 textValues.describeProblem,
105 comments, textValues.osName,
106 textValues.chromeVersion,
107 textValues.channel);
108 const labels = buildIssueLabels(category, textValues.osName, textValues.chromeVersion, labelsByCategory.get(category));
109
110 const {expandDescription, expandLabels, compVal} =
111 expandDescriptions(category, customQuestionsAnswers, isRegression, description, labels, component);
112
113 const componentsArray = [];
114 if (compVal.length > 0) {
115 componentsArray.push({
116 component: 'projects/chromium/componentDefs/' + compVal
117 })
118 }
119
120 const response = prpcClient.call('monorail.v3.Issues', 'MakeIssue', {
121 parent: 'projects/chromium',
122 issue: {
123 summary,
124 status: {
125 status: 'Untriaged',
126 },
127 components: componentsArray,
128 labels: expandLabels,
129 },
130 description: expandDescription,
131 uploads: attachments,
132 });
133 response.then(onSuccess, onFailure);
134 }
135 page =
136 <CustomQuestionsStep
137 setActiveStep={moveStep}
138 questions={questionByCategory.get(category)}
139 onSubmit={onSubmitIssue}
140 setnewIssueID={setnewIssueID}
141 />;
142 } else if (activeStep === 3) {
143 page = <SubmitSuccessStep issueID={newIssueID}/>;
Copybara854996b2021-09-07 19:36:02 +0000144 }
145
146 return (
147 <>
148 <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Poppins"></link>
149 <div className={styles.container}>
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +0200150 <Header />
Copybara854996b2021-09-07 19:36:02 +0000151 {page}
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +0200152 <div className={styles.feedback} onClick={()=>{setEnableFeedback(true);}}>Report a problem with this wizard</div>
Copybara854996b2021-09-07 19:36:02 +0000153 </div>
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +0200154 <IssueWizardFeedback enable={enableFeedback} setEnable={setEnableFeedback}/>
Copybara854996b2021-09-07 19:36:02 +0000155 </>
156 );
157}
158
159/**
160 * Renders the issue filing wizard page.
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +0200161 * @param mount HTMLElement that the React component should be added to.
162 * @param loginUrl redirect to login page
163 * @param userDisplayName login user
Copybara854996b2021-09-07 19:36:02 +0000164 */
Adrià Vilanova Martínezac4a6442022-05-15 19:05:13 +0200165export function renderWizard(mount: HTMLElement, loginUrl: string, userDisplayName: string): void {
166 ReactDOM.render(<IssueWizard loginUrl={loginUrl} userDisplayName={userDisplayName}/>, mount);
Copybara854996b2021-09-07 19:36:02 +0000167}