FE: Followup gitops YAML code nits (#29383)
This commit is contained in:
+10
-4
@@ -5,7 +5,11 @@ import paths from "router/paths";
|
||||
import classnames from "classnames";
|
||||
|
||||
import { ILabelSummary } from "interfaces/label";
|
||||
import { IAppStoreApp, ISoftwarePackage } from "interfaces/software";
|
||||
import {
|
||||
IAppStoreApp,
|
||||
ISoftwarePackage,
|
||||
isSoftwarePackage,
|
||||
} from "interfaces/software";
|
||||
import mdmAppleAPI from "services/entities/mdm_apple";
|
||||
|
||||
import { NotificationContext } from "context/notification";
|
||||
@@ -187,14 +191,16 @@ const EditSoftwareModal = ({
|
||||
},
|
||||
});
|
||||
|
||||
if ("title_id" in software && software.title_id && gitOpsModeEnabled) {
|
||||
if (
|
||||
isSoftwarePackage(software) &&
|
||||
software.title_id &&
|
||||
gitOpsModeEnabled
|
||||
) {
|
||||
// No longer refetch as we open YAML modal if editing with gitOpsModeEnabled
|
||||
const newQueryParams: QueryParams = {
|
||||
team_id: teamId,
|
||||
gitops_yaml: "true",
|
||||
};
|
||||
// Should have title_id so can return to the same page
|
||||
// TODO: Make it so YAML reopens! It's pushing to the same URL so it might need a refresh.
|
||||
router.push(
|
||||
getPathWithQueryParams(
|
||||
paths.SOFTWARE_TITLE_DETAILS(software.title_id.toString()),
|
||||
|
||||
+55
-42
@@ -15,11 +15,8 @@ import CustomLink from "components/CustomLink";
|
||||
import InputField from "components/forms/fields/InputField";
|
||||
import Editor from "components/Editor";
|
||||
|
||||
import {
|
||||
createPackageYaml,
|
||||
hyphenatedSoftwareTitle,
|
||||
renderYamlHelperText,
|
||||
} from "./helpers";
|
||||
import { hyphenateString } from "utilities/strings/stringUtils";
|
||||
import { createPackageYaml, renderYamlHelperText } from "./helpers";
|
||||
|
||||
const baseClass = "view-yaml-modal";
|
||||
|
||||
@@ -29,6 +26,14 @@ interface IViewYamlModalProps {
|
||||
onExit: () => void;
|
||||
}
|
||||
|
||||
interface HandleDownloadParams {
|
||||
evt: React.MouseEvent;
|
||||
content?: string;
|
||||
filename: string;
|
||||
filetype: string;
|
||||
errorMsg: string;
|
||||
}
|
||||
|
||||
const ViewYamlModal = ({
|
||||
softwareTitleName,
|
||||
softwarePackage,
|
||||
@@ -61,13 +66,13 @@ const ViewYamlModal = ({
|
||||
});
|
||||
|
||||
// Generic download handler
|
||||
const handleDownload = (
|
||||
evt: React.MouseEvent,
|
||||
content: string | undefined,
|
||||
filename: string,
|
||||
filetype: string,
|
||||
errorMsg: string
|
||||
) => {
|
||||
const handleDownload = ({
|
||||
evt,
|
||||
content,
|
||||
filename,
|
||||
filetype,
|
||||
errorMsg,
|
||||
}: HandleDownloadParams) => {
|
||||
evt.preventDefault();
|
||||
|
||||
if (content) {
|
||||
@@ -79,43 +84,51 @@ const ViewYamlModal = ({
|
||||
return false;
|
||||
};
|
||||
|
||||
const hyphenatedTitle = hyphenatedSoftwareTitle(softwareTitleName);
|
||||
const hyphenatedSoftwareTitle = hyphenateString(softwareTitleName);
|
||||
|
||||
const onDownloadPreInstallQuery = (evt: React.MouseEvent) =>
|
||||
handleDownload(
|
||||
const onDownloadPreInstallQuery = (evt: React.MouseEvent) => {
|
||||
handleDownload({
|
||||
evt,
|
||||
preInstallQuery,
|
||||
`pre-install-query-${hyphenatedTitle}.sh`,
|
||||
"text/yml",
|
||||
"Your pre-install query could not be downloaded. Please create YAML file (.yml) manually."
|
||||
);
|
||||
content: preInstallQuery,
|
||||
filename: `pre-install-query-${hyphenatedSoftwareTitle}.sh`,
|
||||
filetype: "text/yml",
|
||||
errorMsg:
|
||||
"Your pre-install query could not be downloaded. Please create YAML file (.yml) manually.",
|
||||
});
|
||||
};
|
||||
|
||||
const onDownloadPostInstallScript = (evt: React.MouseEvent) =>
|
||||
handleDownload(
|
||||
const onDownloadPostInstallScript = (evt: React.MouseEvent) => {
|
||||
handleDownload({
|
||||
evt,
|
||||
postInstallScript,
|
||||
`post-install-script-${hyphenatedTitle}.sh`,
|
||||
"text/sh",
|
||||
"Your post-install script could not be downloaded. Please create script file (.sh) manually."
|
||||
);
|
||||
content: postInstallScript,
|
||||
filename: `post-install-script-${hyphenatedSoftwareTitle}.sh`,
|
||||
filetype: "text/sh",
|
||||
errorMsg:
|
||||
"Your post-install script could not be downloaded. Please create script file (.sh) manually.",
|
||||
});
|
||||
};
|
||||
|
||||
const onDownloadInstallScript = (evt: React.MouseEvent) =>
|
||||
handleDownload(
|
||||
const onDownloadInstallScript = (evt: React.MouseEvent) => {
|
||||
handleDownload({
|
||||
evt,
|
||||
installScript,
|
||||
`install-script-${hyphenatedTitle}.sh`,
|
||||
"text/sh",
|
||||
"Your install script could not be downloaded. Please create script file (.sh) manually."
|
||||
);
|
||||
content: installScript,
|
||||
filename: `install-script-${hyphenatedSoftwareTitle}.sh`,
|
||||
filetype: "text/sh",
|
||||
errorMsg:
|
||||
"Your install script could not be downloaded. Please create script file (.sh) manually.",
|
||||
});
|
||||
};
|
||||
|
||||
const onDownloadUninstallScript = (evt: React.MouseEvent) =>
|
||||
handleDownload(
|
||||
const onDownloadUninstallScript = (evt: React.MouseEvent) => {
|
||||
handleDownload({
|
||||
evt,
|
||||
uninstallScript,
|
||||
`uninstall-script-${hyphenatedTitle}.sh`,
|
||||
"text/sh",
|
||||
"Your uninstall script could not be downloaded. Please create script file (.sh) manually."
|
||||
);
|
||||
content: uninstallScript,
|
||||
filename: `uninstall-script-${hyphenatedSoftwareTitle}.sh`,
|
||||
filetype: "text/sh",
|
||||
errorMsg:
|
||||
"Your uninstall script could not be downloaded. Please create script file (.sh) manually.",
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<Modal className={baseClass} title="YAML" onExit={onExit}>
|
||||
@@ -147,7 +160,7 @@ const ViewYamlModal = ({
|
||||
inputWrapperClass
|
||||
name="filename"
|
||||
label="Filename"
|
||||
value={`${hyphenatedSoftwareTitle(softwareTitleName)}.yml`}
|
||||
value={`${hyphenatedSoftwareTitle}.yml`}
|
||||
/>
|
||||
<Editor
|
||||
label="Contents"
|
||||
|
||||
+1
-47
@@ -2,53 +2,7 @@ import { render, screen } from "@testing-library/react";
|
||||
import { createMockSoftwarePackage } from "__mocks__/softwareMock";
|
||||
import { noop } from "lodash";
|
||||
|
||||
import {
|
||||
hyphenatedSoftwareTitle,
|
||||
createPackageYaml,
|
||||
renderYamlHelperText,
|
||||
} from "./helpers";
|
||||
|
||||
describe("hyphenatedSoftwareTitle", () => {
|
||||
it("converts spaces to hyphens and lowercases", () => {
|
||||
expect(hyphenatedSoftwareTitle("My Cool App")).toBe("my-cool-app");
|
||||
});
|
||||
|
||||
it("trims leading and trailing spaces", () => {
|
||||
expect(hyphenatedSoftwareTitle(" Leading and trailing ")).toBe(
|
||||
"leading-and-trailing"
|
||||
);
|
||||
});
|
||||
|
||||
it("collapses multiple spaces into one hyphen", () => {
|
||||
expect(hyphenatedSoftwareTitle("Multiple spaces here")).toBe(
|
||||
"multiple-spaces-here"
|
||||
);
|
||||
});
|
||||
|
||||
it("returns empty string for empty input", () => {
|
||||
expect(hyphenatedSoftwareTitle("")).toBe("");
|
||||
});
|
||||
|
||||
it("handles already hyphenated and lowercase input", () => {
|
||||
expect(hyphenatedSoftwareTitle("already-hyphenated-title")).toBe(
|
||||
"already-hyphenated-title"
|
||||
);
|
||||
});
|
||||
|
||||
it("handles single word", () => {
|
||||
expect(hyphenatedSoftwareTitle("Word")).toBe("word");
|
||||
});
|
||||
|
||||
it("handles all uppercase", () => {
|
||||
expect(hyphenatedSoftwareTitle("ALL UPPERCASE")).toBe("all-uppercase");
|
||||
});
|
||||
|
||||
it("handles mixed case and spaces", () => {
|
||||
expect(hyphenatedSoftwareTitle(" MixED CaSe App ")).toBe(
|
||||
"mixed-case-app"
|
||||
);
|
||||
});
|
||||
});
|
||||
import { createPackageYaml, renderYamlHelperText } from "./helpers";
|
||||
|
||||
describe("createPackageYaml", () => {
|
||||
const {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import React, { MouseEvent } from "react";
|
||||
|
||||
import Button from "components/buttons/Button";
|
||||
import { hyphenateString } from "utilities/strings/stringUtils";
|
||||
|
||||
interface RenderYamlHelperText {
|
||||
installScript?: string;
|
||||
@@ -13,6 +14,27 @@ interface RenderYamlHelperText {
|
||||
onClickUninstallScript?: (evt: MouseEvent) => void;
|
||||
}
|
||||
|
||||
// Helper to join items with commas and Oxford comma before "and"
|
||||
const joinWithCommasAnd = (
|
||||
elements: { key: string; element: JSX.Element }[]
|
||||
) => {
|
||||
return elements.map((item, idx) => {
|
||||
if (idx === 0) return item.element;
|
||||
if (idx === elements.length - 1) {
|
||||
return (
|
||||
<React.Fragment key={`and-${item.key}`}>
|
||||
{elements.length > 2 ? "," : ""} and {item.element}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<React.Fragment key={`comma-${item.key}`}>
|
||||
, {item.element}
|
||||
</React.Fragment>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export const renderYamlHelperText = ({
|
||||
preInstallQuery,
|
||||
installScript,
|
||||
@@ -80,27 +102,6 @@ export const renderYamlHelperText = ({
|
||||
|
||||
if (items.length === 0) return <></>;
|
||||
|
||||
// Helper to join items with commas and Oxford comma before "and"
|
||||
const joinWithCommasAnd = (
|
||||
elements: { key: string; element: JSX.Element }[]
|
||||
) => {
|
||||
return elements.map((item, idx) => {
|
||||
if (idx === 0) return item.element;
|
||||
if (idx === elements.length - 1) {
|
||||
return (
|
||||
<React.Fragment key={`and-${item.key}`}>
|
||||
{elements.length > 2 ? "," : ""} and {item.element}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<React.Fragment key={`comma-${item.key}`}>
|
||||
, {item.element}
|
||||
</React.Fragment>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
Next, download your {joinWithCommasAnd(items)} and add{" "}
|
||||
@@ -110,11 +111,6 @@ export const renderYamlHelperText = ({
|
||||
);
|
||||
};
|
||||
|
||||
/** Hyphenate the name for file paths */
|
||||
export const hyphenatedSoftwareTitle = (softwareTitle: string): string => {
|
||||
return softwareTitle.trim().toLowerCase().replace(/\s+/g, "-");
|
||||
};
|
||||
|
||||
interface CreatePackageYamlParams {
|
||||
softwareTitle: string;
|
||||
packageName: string;
|
||||
@@ -151,7 +147,7 @@ export const createPackageYaml = ({
|
||||
`;
|
||||
}
|
||||
|
||||
const hyphenatedSWTitle = hyphenatedSoftwareTitle(softwareTitle);
|
||||
const hyphenatedSWTitle = hyphenateString(softwareTitle);
|
||||
|
||||
if (preInstallQuery) {
|
||||
yaml += `pre_install_query:
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
strToBool,
|
||||
stripQuotes,
|
||||
isIncompleteQuoteQuery,
|
||||
hyphenateString,
|
||||
} from "./stringUtils";
|
||||
|
||||
describe("string utilities", () => {
|
||||
@@ -91,4 +92,54 @@ describe("string utilities", () => {
|
||||
expect(isIncompleteQuoteQuery("")).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("hyphenatedTitle", () => {
|
||||
it("converts spaces to hyphens and lowercases", () => {
|
||||
expect(hyphenateString("My Cool App")).toBe("my-cool-app");
|
||||
});
|
||||
|
||||
it("trims leading and trailing spaces", () => {
|
||||
expect(hyphenateString(" Leading and trailing ")).toBe(
|
||||
"leading-and-trailing"
|
||||
);
|
||||
});
|
||||
|
||||
it("collapses multiple spaces into one hyphen", () => {
|
||||
expect(hyphenateString("Multiple spaces here")).toBe(
|
||||
"multiple-spaces-here"
|
||||
);
|
||||
});
|
||||
|
||||
it("returns empty string for empty input", () => {
|
||||
expect(hyphenateString("")).toBe("");
|
||||
});
|
||||
|
||||
it("handles already hyphenated and lowercase input", () => {
|
||||
expect(hyphenateString("already-hyphenated-title")).toBe(
|
||||
"already-hyphenated-title"
|
||||
);
|
||||
});
|
||||
|
||||
it("handles single word", () => {
|
||||
expect(hyphenateString("Word")).toBe("word");
|
||||
});
|
||||
|
||||
it("handles all uppercase", () => {
|
||||
expect(hyphenateString("ALL UPPERCASE")).toBe("all-uppercase");
|
||||
});
|
||||
|
||||
it("handles mixed case and spaces", () => {
|
||||
expect(hyphenateString(" MixED CaSe App ")).toBe("mixed-case-app");
|
||||
});
|
||||
|
||||
it("handles numbers separated by spaces", () => {
|
||||
expect(hyphenateString("Numbered App 3")).toBe("numbered-app-3");
|
||||
});
|
||||
|
||||
it("handles numbers attached to words", () => {
|
||||
expect(hyphenateString("Attached Numbered App3")).toBe(
|
||||
"attached-numbered-app3"
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -94,6 +94,15 @@ export const isIncompleteQuoteQuery = (str: string) => {
|
||||
return pattern.test(str);
|
||||
};
|
||||
|
||||
/**
|
||||
* Hyphenates the words of the string passed in.
|
||||
* e.g. The name of an app to be used in a file name
|
||||
* @param str un-capitalized string
|
||||
*/
|
||||
export const hyphenateString = (str: string): string => {
|
||||
return str.trim().toLowerCase().replace(/\s+/g, "-");
|
||||
};
|
||||
|
||||
export default {
|
||||
capitalize,
|
||||
capitalizeRole,
|
||||
|
||||
Reference in New Issue
Block a user