diff --git a/frontend/components/queries/queryResults/QueryResultsHeading/QueryResultsHeading.tsx b/frontend/components/queries/queryResults/QueryResultsHeading/QueryResultsHeading.tsx index d8668dc6eb..8e5567e7a5 100644 --- a/frontend/components/queries/queryResults/QueryResultsHeading/QueryResultsHeading.tsx +++ b/frontend/components/queries/queryResults/QueryResultsHeading/QueryResultsHeading.tsx @@ -1,11 +1,13 @@ import React from "react"; +import strUtils from "utilities/strings"; + import Spinner from "components/Spinner"; import Button from "components/buttons/Button"; import TooltipWrapper from "components/TooltipWrapper"; const pluralizeHost = (count: number) => { - return count > 1 ? "hosts" : "host"; + return strUtils.pluralize(count, "host"); }; const baseClass = "query-results-heading"; diff --git a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx index 8fe3ce1323..15b7676701 100644 --- a/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx +++ b/frontend/pages/ManageControlsPage/OSSettings/cards/CustomSettings/components/ProfileListItem/ProfileListItem.tsx @@ -10,7 +10,7 @@ import Button from "components/buttons/Button"; import Graphic from "components/Graphic"; import Icon from "components/Icon"; -import { pluralize } from "utilities/helpers"; +import strUtils from "utilities/strings"; const baseClass = "profile-list-item"; @@ -22,7 +22,7 @@ const LabelCount = ({ count: number; }) => (
- {`${count} ${pluralize(count, "label", "s", "")}`} + {`${count} ${strUtils.pluralize(count, "label")}`}
); diff --git a/frontend/pages/hosts/components/DeleteHostModal/DeleteHostModal.tsx b/frontend/pages/hosts/components/DeleteHostModal/DeleteHostModal.tsx index 8524dee200..4b27ff3302 100644 --- a/frontend/pages/hosts/components/DeleteHostModal/DeleteHostModal.tsx +++ b/frontend/pages/hosts/components/DeleteHostModal/DeleteHostModal.tsx @@ -1,5 +1,7 @@ import React from "react"; +import strUtils from "utilities/strings"; + import Modal from "components/Modal"; import Button from "components/buttons/Button"; import CustomLink from "components/CustomLink"; @@ -29,11 +31,18 @@ const DeleteHostModal = ({ hostName, isUpdating, }: IDeleteHostModalProps): JSX.Element => { + const pluralizeHost = () => { + if (!selectedHostIds) { + return "host"; + } + return strUtils.pluralize(selectedHostIds.length, "host"); + }; + const hostText = () => { if (selectedHostIds) { return `${selectedHostIds.length}${ isAllMatchingHostsSelected ? "+" : "" - } ${selectedHostIds.length === 1 ? "host" : "hosts"}`; + } ${pluralizeHost()}`; } return hostName; }; @@ -58,17 +67,18 @@ const DeleteHostModal = ({ > <>

- This action will delete {hostText()} from your Fleet instance. - {largeVolumeText()} + This will remove the record of {hostText()}.{largeVolumeText()} +

+

+ The {pluralizeHost()} will re-appear unless fleet's agent is + uninstalled.

-

If the hosts come back online, they will automatically re-enroll.

- To prevent re-enrollment,{" "}

diff --git a/frontend/utilities/helpers.tsx b/frontend/utilities/helpers.tsx index f433cc97e6..6d446468d2 100644 --- a/frontend/utilities/helpers.tsx +++ b/frontend/utilities/helpers.tsx @@ -53,31 +53,6 @@ import { IScheduledQueryStats } from "interfaces/scheduled_query_stats"; const ORG_INFO_ATTRS = ["org_name", "org_logo_url"]; const ADMIN_ATTRS = ["email", "name", "password", "password_confirmation"]; -/** - * - * @param count The number of items. - * @param root The root of the word, omitting any suffixs. - * @param pluralSuffix The suffix to add to the root if the count is not 1. - * @param singularSuffix The suffix to add to the root if the count is 1. - * @returns A string with the root and the appropriate suffix. - * - * @example - * pluralize(1, "hero", "es", "") // "hero" - * pluralize(0, "hero", "es", "") // "heroes" - * pluralize(1, "fair", "ies", "y") // "fairy" - * pluralize(2, "fair", "ies", "y") // "fairies" - * pluralize(1, "dragon") // "dragon" - * pluralize(2, "dragon") // "dragons" - */ -export const pluralize = ( - count: number, - root: string, - pluralSuffix: string, - singularSuffix: string -) => { - return `${root}${count !== 1 ? pluralSuffix : singularSuffix}`; -}; - export const addGravatarUrlToResource = (resource: any): any => { const { email } = resource; const gravatarAvailable = @@ -887,7 +862,6 @@ export const getUniqueColumnNamesFromRows = (rows: any[]) => ); export default { - pluralize, addGravatarUrlToResource, formatConfigDataForServer, formatLabelResponse, diff --git a/frontend/utilities/strings/stringUtils.tests.ts b/frontend/utilities/strings/stringUtils.tests.ts index 9757456d84..25755873ff 100644 --- a/frontend/utilities/strings/stringUtils.tests.ts +++ b/frontend/utilities/strings/stringUtils.tests.ts @@ -1,23 +1,47 @@ -import { enforceFleetSentenceCasing } from "./stringUtils"; +import { enforceFleetSentenceCasing, pluralize } from "./stringUtils"; -describe("enforceFleetSentenceCasing utility", () => { - it("fixes a Title Cased String with no ignore words", () => { - expect(enforceFleetSentenceCasing("All Hosts")).toEqual("All hosts"); - expect(enforceFleetSentenceCasing("all Hosts")).toEqual("All hosts"); - expect(enforceFleetSentenceCasing("all hosts")).toEqual("All hosts"); - expect(enforceFleetSentenceCasing("All HosTs ")).toEqual("All hosts"); - }); +describe("string utilities", () => { + describe("enforceFleetSentenceCasing utility", () => { + it("fixes a Title Cased String with no ignore words", () => { + expect(enforceFleetSentenceCasing("All Hosts")).toEqual("All hosts"); + expect(enforceFleetSentenceCasing("all Hosts")).toEqual("All hosts"); + expect(enforceFleetSentenceCasing("all hosts")).toEqual("All hosts"); + expect(enforceFleetSentenceCasing("All HosTs ")).toEqual("All hosts"); + }); - it("fixes a title cased string while ignoring special words in various places ", () => { - expect(enforceFleetSentenceCasing("macOS")).toEqual("macOS"); - expect(enforceFleetSentenceCasing("macOS Settings")).toEqual( - "macOS settings" + it("fixes a title cased string while ignoring special words in various places ", () => { + expect(enforceFleetSentenceCasing("macOS")).toEqual("macOS"); + expect(enforceFleetSentenceCasing("macOS Settings")).toEqual( + "macOS settings" + ); + expect( + enforceFleetSentenceCasing("osquery shouldn't be Capitalized") + ).toEqual("osquery shouldn't be capitalized"); + }); + expect(enforceFleetSentenceCasing("fleet uses MySQL")).toEqual( + "Fleet uses MySQL" ); - expect( - enforceFleetSentenceCasing("osquery shouldn't be Capitalized") - ).toEqual("osquery shouldn't be capitalized"); }); - expect(enforceFleetSentenceCasing("fleet uses MySQL")).toEqual( - "Fleet uses MySQL" - ); + + describe("pluralize utility", () => { + it("returns the singular form of a word when count is 1", () => { + expect(pluralize(1, "hero", "es", "")).toEqual("hero"); + }); + + it("returns the plural form of a word when count is not 1", () => { + expect(pluralize(0, "hero", "es", "")).toEqual("heroes"); + expect(pluralize(2, "hero", "es", "")).toEqual("heroes"); + expect(pluralize(100, "hero", "es", "")).toEqual("heroes"); + }); + + it("returns the singular form of a word when count is 1 and a no custom suffix are provided", () => { + expect(pluralize(1, "hero")).toEqual("hero"); + }); + + it("returns the pluralized form of a word with 's' suffix when count is not 1 and no custom suffix are provided", () => { + expect(pluralize(0, "hero")).toEqual("heros"); + expect(pluralize(2, "hero")).toEqual("heros"); + expect(pluralize(100, "hero")).toEqual("heros"); + }); + }); }); diff --git a/frontend/utilities/strings/stringUtils.ts b/frontend/utilities/strings/stringUtils.ts index edc0aea69a..e7e205d98e 100644 --- a/frontend/utilities/strings/stringUtils.ts +++ b/frontend/utilities/strings/stringUtils.ts @@ -45,7 +45,36 @@ export const enforceFleetSentenceCasing = (s: string) => { return resArr.join(" ").trim(); }; + +/** + * Pluralizes a word based on the entitiy count and the desired suffixes. If no + * suffixes are provided, the default suffix "s" is used. + * + * @param count The number of items. + * @param root The root of the word, omitting any suffixs. + * @param pluralSuffix The suffix to add to the root if the count is not 1. + * @param singularSuffix The suffix to add to the root if the count is 1. + * @returns A string with the root and the appropriate suffix. + * + * @example + * pluralize(1, "hero", "es", "") // "hero" + * pluralize(0, "hero", "es", "") // "heroes" + * pluralize(1, "fair", "ies", "y") // "fairy" + * pluralize(2, "fair", "ies", "y") // "fairies" + * pluralize(1, "dragon") // "dragon" + * pluralize(2, "dragon") // "dragons" + */ +export const pluralize = ( + count: number, + root: string, + pluralSuffix = "s", + singularSuffix = "" +) => { + return `${root}${count !== 1 ? pluralSuffix : singularSuffix}`; +}; + export default { capitalize, capitalizeRole, + pluralize, };