Merge branch 'main' into avm99963-monorail

Merged commit 4137ed7879acadbf891e8c471108acb874dae886.

GitOrigin-RevId: b6100ffc5b1da355a35f37b13fcaaf746ee8b307
diff --git a/static_src/react/issue-wizard/IssueWizardUtils.tsx b/static_src/react/issue-wizard/IssueWizardUtils.tsx
new file mode 100644
index 0000000..e709115
--- /dev/null
+++ b/static_src/react/issue-wizard/IssueWizardUtils.tsx
@@ -0,0 +1,162 @@
+// Copyright 2022 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+import {CustomQuestion, IssueCategory, SelectMenuOption, IssueWizardPersona} from "./IssueWizardTypes";
+
+
+const CHROME_VERSION_REX = /chrome\/(\d|\.)+/i;
+// this function is used to get the issue list belong to different persona
+// when a user group is selected a list of related issue categories will show up
+export function GetCategoriesByPersona (categories: IssueCategory[]): Map<IssueWizardPersona, SelectMenuOption[]> {
+  const categoriesByPersona = new Map<IssueWizardPersona, SelectMenuOption[]>();
+
+  categories.forEach((category) => {
+    if (category.enabled) {
+      const currentIssuePersona = category.persona;
+      const currentCategories = categoriesByPersona.get(currentIssuePersona) ?? [];
+      currentCategories.push({
+        name: category.name,
+        description: category.description,
+      });
+      categoriesByPersona.set(currentIssuePersona, currentCategories);
+    }
+  });
+
+  return categoriesByPersona;
+}
+
+// this function is used to get the customer questions belong to different issue category
+// the customer question page will render base on these data
+export function GetQuestionsByCategory(categories: IssueCategory[]): Map<string, CustomQuestion[] | null> {
+  const questionsByCategory = new Map<string, CustomQuestion[] | null>();
+  categories.forEach((category) => {
+    questionsByCategory.set(category.name, category.customQuestions ?? null);
+  })
+  return questionsByCategory;
+}
+
+// this function is used to convert the options list fit for render use SelectMenu
+export function GetSelectMenuOptions(optionsList: string[]): SelectMenuOption[] {
+  const selectMenuOptionList = new Array<SelectMenuOption>();
+  optionsList.forEach((option) => {
+    selectMenuOptionList.push({name: option});
+  });
+  return selectMenuOptionList;
+}
+
+/**
+ * Detects the user's operating system.
+ */
+ export function getOs() {
+  const userAgent = window.navigator.userAgent,
+    platform = window.navigator.platform,
+    macosPlatforms = ['Macintosh', 'MacIntel', 'MacPPC', 'Mac68K'],
+    windowsPlatforms = ['Win32', 'Win64', 'Windows', 'WinCE'],
+    iosPlatforms = ['iPhone', 'iPad', 'iPod'];
+
+    if (macosPlatforms.indexOf(platform) !== -1) {
+      return'Mac OS';
+    } else if (iosPlatforms.indexOf(platform) !== -1) {
+      return 'iOS';
+    } else if (windowsPlatforms.indexOf(platform) !== -1) {
+      return 'Windows';
+    } else if (/Android/.test(userAgent)) {
+      return 'Android';
+    } else if (/Linux/.test(platform)) {
+      return 'Linux';
+    } else if (/\bCrOS\b/.test(userAgent)) {
+      return 'Chrome OS';
+    }
+
+    return 'Unknown / Other';
+
+}
+
+// this function is used to get the tip belong to different issue category
+// used for render detail page
+export function getTipByCategory(categories: IssueCategory[]): Map<string, string> {
+  const tipByCategory = new Map<string, string>();
+  categories.forEach((category) => {
+    if (category.tip) {
+      tipByCategory.set(category.name, category.tip);
+    }
+  })
+  return tipByCategory;
+}
+
+// this function is used to get the component value for each issue category used for make issue
+export function getCompValByCategory(categories: IssueCategory[]): Map<string, string> {
+  const compValByCategory = new Map<string, string>();
+  categories.forEach((category) => {
+    if (category.component) {
+      compValByCategory.set(category.name, category.component);
+    }
+  })
+  return compValByCategory;
+}
+
+export function getLabelsByCategory(categories: IssueCategory[]): Map<string, Array<string>> {
+  const labelsByCategory = new Map<string, Array<string>>();
+  categories.forEach((category) => {
+    if (category.labels) {
+      labelsByCategory.set(category.name, category.labels);
+    }
+  })
+  return labelsByCategory;
+}
+
+
+export function buildIssueDescription(
+  reproduceStep: string,
+  description: string,
+  comments: string,
+  os: string,
+  chromeVersion: string,
+  channel: string,
+  ): string {
+  const issueDescription =
+    "<b>Steps to reproduce the problem:</b>\n" + reproduceStep.trim() + "\n\n"
+    + "<b>Problem Description:</b>\n" + description.trim() + "\n\n"
+    + "<b>Additional Comments:</b>\n" + comments.trim() + "\n\n"
+    + "<b>Chrome version: </b>" + chromeVersion.trim() + " <b>Channel: </b>" + channel + "\n\n"
+    + "<b>OS:</b>" + os.trim();
+  return issueDescription;
+}
+
+export function buildIssueLabels(category: string, osName: string, chromeVersion: string, configLabels: Array<string> | null | undefined): Array<any> {
+  const labels = [
+    {label:'via-wizard-'+category},
+    {label:'Pri-2'},
+  ];
+
+  const os = osName.split(' ')[0];
+  if (os !== 'Unknown/Other') {
+    labels.push({
+      label: 'OS-'+os
+    })
+  }
+  const mainChromeVersion = chromeVersion.split('.').length > 0 ? chromeVersion.split('.')[0] : null;
+  if (mainChromeVersion !== null) {
+    labels.push({
+      label:'Needs-Triage-M'+mainChromeVersion
+    });
+  }
+
+  if (configLabels) {
+    configLabels.forEach((v) => {
+      labels.push({label: v});
+    })
+  }
+  return labels;
+}
+
+
+export function getChromeVersion() {
+  const userAgent = window.navigator.userAgent;
+  var browser= userAgent.match(CHROME_VERSION_REX) || [];
+  if (browser.length > 0) {
+    return browser[0].split('/')[1];
+  }
+  return "<Copy from:'about:version'>";
+}