diff --git a/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx b/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx
index 358c09ffad..1a1fc02ad0 100644
--- a/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx
+++ b/frontend/pages/SoftwarePage/components/AppStoreVpp/AppStoreVpp.tsx
@@ -20,6 +20,7 @@ import { NotificationContext } from "context/notification";
import { getErrorReason } from "interfaces/errors";
import { buildQueryStringFromParams } from "utilities/url";
import SoftwareIcon from "../icons/SoftwareIcon";
+import { getErrorMessage } from "./helpers";
const baseClass = "app-store-vpp";
@@ -171,13 +172,7 @@ const AppStoreVpp = ({ teamId, router, onExit }: IAppStoreVppProps) => {
});
router.push(`${PATHS.SOFTWARE}?${queryParams}`);
} catch (e) {
- const reason = getErrorReason(e);
- // TODO: update with pre-defined error messages we want to pass through from the API
- if (reason.toLowerCase().includes("already")) {
- renderFlash("error", reason);
- } else {
- renderFlash("error", "Couldn’t add software. Please try again.");
- }
+ renderFlash("error", getErrorMessage(e));
}
onExit();
};
diff --git a/frontend/pages/SoftwarePage/components/AppStoreVpp/helpers.tsx b/frontend/pages/SoftwarePage/components/AppStoreVpp/helpers.tsx
new file mode 100644
index 0000000000..b32495cbb8
--- /dev/null
+++ b/frontend/pages/SoftwarePage/components/AppStoreVpp/helpers.tsx
@@ -0,0 +1,32 @@
+import React from "react";
+import { getErrorReason } from "interfaces/errors";
+
+const ADD_SOFTWARE_ERROR_PREFIX = "Couldn’t add software.";
+const DEFAULT_ERROR_MESSAGE = `${ADD_SOFTWARE_ERROR_PREFIX} Please try again.`;
+
+const generateAlreadyAvailableMessage = (msg: string) => {
+ const regex = new RegExp(
+ `${ADD_SOFTWARE_ERROR_PREFIX} (.+) already.+on the (.+) team.`
+ );
+
+ const match = msg.match(regex);
+ if (!match) return DEFAULT_ERROR_MESSAGE;
+
+ return (
+ <>
+ {ADD_SOFTWARE_ERROR_PREFIX} {match[1]} already has software
+ available for install on the {match[2]} team.{" "}
+ >
+ );
+};
+
+// eslint-disable-next-line import/prefer-default-export
+export const getErrorMessage = (e: unknown) => {
+ const reason = getErrorReason(e);
+
+ // software is already available for install
+ if (reason.toLowerCase().includes("already")) {
+ return generateAlreadyAvailableMessage(reason);
+ }
+ return DEFAULT_ERROR_MESSAGE;
+};
diff --git a/frontend/pages/hosts/details/cards/Software/HostSoftware.tsx b/frontend/pages/hosts/details/cards/Software/HostSoftware.tsx
index 6cf80111ac..f4a369cdb4 100644
--- a/frontend/pages/hosts/details/cards/Software/HostSoftware.tsx
+++ b/frontend/pages/hosts/details/cards/Software/HostSoftware.tsx
@@ -27,6 +27,7 @@ import CustomLink from "components/CustomLink";
import { generateSoftwareTableHeaders as generateHostSoftwareTableConfig } from "./HostSoftwareTableConfig";
import { generateSoftwareTableHeaders as generateDeviceSoftwareTableConfig } from "./DeviceSoftwareTableConfig";
import HostSoftwareTable from "./HostSoftwareTable";
+import { getErrorMessage } from "./helpers";
const baseClass = "software-card";
@@ -187,17 +188,7 @@ const HostSoftware = ({
"Software is installing or will install when the host comes online."
);
} catch (e) {
- const reason = upperFirst(trimEnd(getErrorReason(e), "."));
- if (reason.includes("fleetd installed")) {
- renderFlash("error", `Couldn't install. ${reason}.`);
- } else if (reason.includes("can be installed only on")) {
- renderFlash(
- "error",
- `Couldn't install. ${reason.replace("darwin", "macOS")}.`
- );
- } else {
- renderFlash("error", "Couldn't install. Please try again.");
- }
+ renderFlash("error", getErrorMessage(e));
}
setInstallingSoftwareId(null);
refetchSoftware();
diff --git a/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx b/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx
index 0d54533b37..5825f48146 100644
--- a/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx
+++ b/frontend/pages/hosts/details/cards/Software/HostSoftwareTableConfig.tsx
@@ -123,7 +123,7 @@ export const generateSoftwareTableHeaders = ({
accessor: "name",
disableSortBy: false,
Cell: (cellProps: ITableStringCellProps) => {
- const { id, name, source } = cellProps.row.original;
+ const { id, name, source, app_store_app } = cellProps.row.original;
const softwareTitleDetailsPath = PATHS.SOFTWARE_TITLE_DETAILS(
id.toString().concat(`?team_id=${teamId}`)
@@ -133,6 +133,7 @@ export const generateSoftwareTableHeaders = ({
diff --git a/frontend/pages/hosts/details/cards/Software/helpers.tsx b/frontend/pages/hosts/details/cards/Software/helpers.tsx
new file mode 100644
index 0000000000..e251728bdf
--- /dev/null
+++ b/frontend/pages/hosts/details/cards/Software/helpers.tsx
@@ -0,0 +1,36 @@
+import React from "react";
+import { getErrorReason } from "interfaces/errors";
+import { trimEnd, upperFirst } from "lodash";
+
+const INSTALL_SOFTWARE_ERROR_PREFIX = "Couldn't install.";
+const DEFAULT_ERROR_MESSAGE = `${INSTALL_SOFTWARE_ERROR_PREFIX} Please try again.`;
+
+const createOnlyInstallableOnMacOSMessage = (reason: string) =>
+ `Couldn't install. ${reason.replace("darwin", "macOS")}.`;
+
+const createVPPTokenExpiredMessage = () => (
+ <>
+ {INSTALL_SOFTWARE_ERROR_PREFIX} VPP token expired. Go to{" "}
+
+ Settings {">"} Integration {">"} Volume Purchasing Program
+ {" "}
+ and renew token.
+ >
+);
+
+// eslint-disable-next-line import/prefer-default-export
+export const getErrorMessage = (e: unknown) => {
+ const reason = upperFirst(trimEnd(getErrorReason(e), "."));
+
+ if (reason.includes("fleetd installed")) {
+ return `${INSTALL_SOFTWARE_ERROR_PREFIX}. ${reason}.`;
+ } else if (reason.includes("can be installed only on")) {
+ return createOnlyInstallableOnMacOSMessage(reason);
+ } else if (reason.includes("VPP token expired")) {
+ createVPPTokenExpiredMessage();
+ } else if (reason.includes("MDM is turned off")) {
+ return reason;
+ }
+
+ return DEFAULT_ERROR_MESSAGE;
+};