diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json
index 4209d445de..95593f0e53 100644
--- a/client/public/locales/en/translation.json
+++ b/client/public/locales/en/translation.json
@@ -259,15 +259,17 @@
"analysis": "Analysis",
"answer": "Answer",
"application": "Application",
+ "application_plural": "Applications",
"applicationReview": "Application review",
"application(s)": "Application(s)",
+ "applications": "Applications",
"applicationImports": "Application imports",
"applicationName": "Application name",
"archetypeName": "Archetype name",
"applicationInformation": "Application information",
- "applications": "Applications",
"archetype": "Archetype",
"archetypes": "Archetypes",
+ "archetypes_plural": "Archetypes",
"artifact": "Artifact",
"artifactAssociated": "Associated artifact",
"artifactNotAssociated": "No associated artifact",
diff --git a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx
index e67153c3c1..b721a02478 100644
--- a/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx
+++ b/client/src/app/pages/applications/components/application-detail-drawer/application-detail-drawer.tsx
@@ -192,15 +192,24 @@ export const ApplicationDetailDrawer: React.FC<
{t("terms.associatedArchetypes")}
- {application?.archetypes?.length ?? 0 > 0 ? (
-
+ {application?.archetypes?.length ? (
+ <>
+
+ {application.archetypes.length ?? 0 > 0 ? (
+
+ ) : (
+
+ )}
+
+ >
) : (
)}
+
{t("terms.archetypesAssessed")}
diff --git a/client/src/app/pages/archetypes/archetypes-page.tsx b/client/src/app/pages/archetypes/archetypes-page.tsx
index b4c6941e54..0f44e8f1ca 100644
--- a/client/src/app/pages/archetypes/archetypes-page.tsx
+++ b/client/src/app/pages/archetypes/archetypes-page.tsx
@@ -38,7 +38,10 @@ import {
TableHeaderContentWithControls,
TableRowContentWithControls,
} from "@app/components/TableControls";
-import { useLocalTableControls } from "@app/hooks/table-controls";
+import {
+ deserializeFilterUrlParams,
+ useLocalTableControls,
+} from "@app/hooks/table-controls";
import {
useDeleteArchetypeMutation,
useFetchArchetypes,
@@ -171,6 +174,10 @@ const Archetypes: React.FC = () => {
});
}
};
+ const urlParams = new URLSearchParams(window.location.search);
+ const filters = urlParams.get("filters");
+
+ const deserializedFilterValues = deserializeFilterUrlParams({ filters });
const tableControls = useLocalTableControls({
persistTo: "urlParams",
@@ -206,15 +213,47 @@ const Archetypes: React.FC = () => {
return archetype?.name ?? "";
},
},
+ {
+ key: "application.name",
+ title: t("terms.applicationName"),
+ type: FilterType.multiselect,
+ logicOperator: "OR",
+ selectOptions: [
+ ...new Set(
+ archetypes.flatMap(
+ (archetype) =>
+ archetype?.applications
+ ?.map((app) => app.name)
+ .filter(Boolean) || []
+ )
+ ),
+ ].map((applicationName) => ({
+ key: applicationName,
+ value: applicationName,
+ })),
+ placeholderText:
+ t("actions.filterBy", {
+ what: t("terms.application").toLowerCase(),
+ }) + "...",
+ getItemValue: (archetype) => {
+ const appNames = archetype.applications
+ ?.map((app) => app.name)
+ .join("");
+ return appNames || "";
+ },
+ },
+
// TODO: Add filter for archetype tags
],
sortableColumns: ["name"],
+ initialFilterValues: deserializedFilterValues,
getSortValues: (archetype) => ({
name: archetype.name ?? "",
}),
initialSort: { columnKey: "name", direction: "asc" },
});
+
const {
currentPageItems,
numRenderedColumns,
@@ -285,6 +324,14 @@ const Archetypes: React.FC = () => {
assessmentWriteAccess = checkAccess(userScopes, assessmentWriteScopes),
reviewsWriteAccess = checkAccess(userScopes, reviewsWriteScopes);
+ const clearFilters = () => {
+ const currentPath = history.location.pathname;
+ const newSearch = new URLSearchParams(history.location.search);
+ newSearch.delete("filters");
+ history.push(`${currentPath}`);
+ filterToolbarProps.setFilterValues({});
+ };
+
return (
<>
@@ -302,7 +349,7 @@ const Archetypes: React.FC = () => {
backgroundColor: "var(--pf-v5-global--BackgroundColor--100)",
}}
>
-
+
diff --git a/client/src/app/pages/archetypes/components/archetype-detail-drawer.tsx b/client/src/app/pages/archetypes/components/archetype-detail-drawer.tsx
index 648fdd01f3..90b85d0574 100644
--- a/client/src/app/pages/archetypes/components/archetype-detail-drawer.tsx
+++ b/client/src/app/pages/archetypes/components/archetype-detail-drawer.tsx
@@ -27,6 +27,9 @@ import { LabelsFromItems } from "@app/components/labels/labels-from-items/labels
import { ReviewFields } from "@app/pages/applications/components/application-detail-drawer/review-fields";
import { RiskLabel } from "@app/components/RiskLabel";
import { LabelsFromTags } from "@app/components/labels/labels-from-tags/labels-from-tags";
+import { serializeFilterUrlParams } from "@app/hooks/table-controls";
+import { Paths } from "@app/Paths";
+import { Link } from "react-router-dom";
export interface IArchetypeDetailDrawerProps {
onCloseClick: () => void;
@@ -103,10 +106,19 @@ const ArchetypeDetailDrawer: React.FC = ({
{t("terms.applications")}
- {archetype?.applications?.length ?? 0 > 0 ? (
-
+ {archetype?.applications?.length ? (
+ <>
+
+ {archetype.applications.length}{" "}
+ {t("terms.application", {
+ count: archetype.applications.length,
+ context:
+ archetype.applications.length > 1
+ ? "plural"
+ : "singular",
+ }).toLocaleLowerCase()}{" "}
+
+ >
) : (
)}
@@ -223,10 +235,6 @@ const ArchetypeDetailDrawer: React.FC = ({
);
};
-const ApplicationLabels: React.FC<{ applicationRefs?: Ref[] }> = ({
- applicationRefs,
-}) => ;
-
const TagLabels: React.FC<{ tags?: Tag[] }> = ({ tags }) => (
);
@@ -240,3 +248,16 @@ const StakeholderGroupsLabels: React.FC<{ archetype: Archetype }> = ({
}) => ;
export default ArchetypeDetailDrawer;
+
+const getApplicationsUrl = (archetypeName: string) => {
+ const filterValues = {
+ archetypes: [archetypeName],
+ };
+
+ const serializedParams = serializeFilterUrlParams(filterValues);
+
+ const queryString = serializedParams.filters
+ ? `filters=${serializedParams.filters}`
+ : "";
+ return `${Paths.applications}?${queryString}`;
+};