From da075ee54a5ed63bd59888671dad92d6c9fda348 Mon Sep 17 00:00:00 2001 From: ibolton336 Date: Mon, 29 Jan 2024 17:07:05 -0500 Subject: [PATCH 1/2] :sparkles: Add app name filter to archetypes page & drawer link Signed-off-by: ibolton336 --- client/public/locales/en/translation.json | 2 + .../application-detail-drawer.tsx | 33 ++++++++++-- .../app/pages/archetypes/archetypes-page.tsx | 51 ++++++++++++++++++- 3 files changed, 80 insertions(+), 6 deletions(-) diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json index 01fd411fc..cc2460a23 100644 --- a/client/public/locales/en/translation.json +++ b/client/public/locales/en/translation.json @@ -265,6 +265,8 @@ "applications": "Applications", "archetype": "Archetype", "archetypes": "Archetypes", + "archetypes_singular": "Archetype", + "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 d978ae10a..d531d7aaa 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 @@ -58,6 +58,8 @@ import { RiskLabel } from "@app/components/RiskLabel"; import { ApplicationDetailFields } from "./application-detail-fields"; import { useFetchArchetypes } from "@app/queries/archetypes"; import { AssessedArchetypes } from "./components/assessed-archetypes"; +import { serializeFilterUrlParams } from "@app/hooks/table-controls"; +import { Paths } from "@app/Paths"; export interface IApplicationDetailDrawerProps extends Pick { @@ -190,15 +192,25 @@ export const ApplicationDetailDrawer: React.FC< {t("terms.associatedArchetypes")} - {application?.archetypes?.length ?? 0 > 0 ? ( - + {application?.archetypes?.length ? ( + <> + + {application.archetypes.length}{" "} + {t("terms.archetypes", { + count: application.archetypes.length, + context: + application.archetypes.length > 1 + ? "plural" + : "singular", + }).toLocaleLowerCase()}{" "} + + ) : ( )} + {t("terms.archetypesAssessed")} @@ -441,3 +453,16 @@ const ArchetypeLabels: React.FC<{ archetypeRefs?: Ref[] }> = ({ const ArchetypeItem: React.FC<{ archetype: Archetype }> = ({ archetype }) => { return ; }; + +const getArchetypesUrl = (applicationName: string) => { + const filterValues = { + "application.name": [applicationName], + }; + + const serializedParams = serializeFilterUrlParams(filterValues); + + const queryString = serializedParams.filters + ? `filters=${serializedParams.filters}` + : ""; + return `${Paths.archetypes}?${queryString}`; +}; diff --git a/client/src/app/pages/archetypes/archetypes-page.tsx b/client/src/app/pages/archetypes/archetypes-page.tsx index b4c6941e5..0f44e8f1c 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)", }} > - + From b8f74f1444f0d2fe5d9b056e087cb31a4fb66932 Mon Sep 17 00:00:00 2001 From: Ian Bolton Date: Wed, 21 Feb 2024 16:48:17 -0500 Subject: [PATCH 2/2] Invert the expected case Signed-off-by: Ian Bolton --- client/public/locales/en/translation.json | 4 +- .../applications-table/applications-table.tsx | 5 ++- .../application-detail-drawer.tsx | 34 +++++------------ .../components/archetype-detail-drawer.tsx | 37 +++++++++++++++---- 4 files changed, 43 insertions(+), 37 deletions(-) diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json index cc2460a23..c7b1c840a 100644 --- a/client/public/locales/en/translation.json +++ b/client/public/locales/en/translation.json @@ -256,16 +256,16 @@ "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_singular": "Archetype", "archetypes_plural": "Archetypes", "artifact": "Artifact", "artifactAssociated": "Associated artifact", diff --git a/client/src/app/pages/applications/applications-table/applications-table.tsx b/client/src/app/pages/applications/applications-table/applications-table.tsx index c13ac32e5..c4306c9e5 100644 --- a/client/src/app/pages/applications/applications-table/applications-table.tsx +++ b/client/src/app/pages/applications/applications-table/applications-table.tsx @@ -360,8 +360,9 @@ export const ApplicationsTable: React.FC = () => { selectOptions: [ ...new Set( applications - .flatMap((application) => - application?.archetypes?.map((archetype) => archetype.name) + .flatMap( + (application) => + application?.archetypes?.map((archetype) => archetype.name) ) .filter(Boolean) ), 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 d531d7aaa..7a127d343 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 @@ -58,8 +58,6 @@ import { RiskLabel } from "@app/components/RiskLabel"; import { ApplicationDetailFields } from "./application-detail-fields"; import { useFetchArchetypes } from "@app/queries/archetypes"; import { AssessedArchetypes } from "./components/assessed-archetypes"; -import { serializeFilterUrlParams } from "@app/hooks/table-controls"; -import { Paths } from "@app/Paths"; export interface IApplicationDetailDrawerProps extends Pick { @@ -194,16 +192,15 @@ export const ApplicationDetailDrawer: React.FC< {application?.archetypes?.length ? ( <> - - {application.archetypes.length}{" "} - {t("terms.archetypes", { - count: application.archetypes.length, - context: - application.archetypes.length > 1 - ? "plural" - : "singular", - }).toLocaleLowerCase()}{" "} - + + {application.archetypes.length ?? 0 > 0 ? ( + + ) : ( + + )} + ) : ( @@ -453,16 +450,3 @@ const ArchetypeLabels: React.FC<{ archetypeRefs?: Ref[] }> = ({ const ArchetypeItem: React.FC<{ archetype: Archetype }> = ({ archetype }) => { return ; }; - -const getArchetypesUrl = (applicationName: string) => { - const filterValues = { - "application.name": [applicationName], - }; - - const serializedParams = serializeFilterUrlParams(filterValues); - - const queryString = serializedParams.filters - ? `filters=${serializedParams.filters}` - : ""; - return `${Paths.archetypes}?${queryString}`; -}; 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 648fdd01f..90b85d057 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}`; +};