diff --git a/client/public/locales/en/translation.json b/client/public/locales/en/translation.json index 89bfe0f895..2cb06e54d5 100644 --- a/client/public/locales/en/translation.json +++ b/client/public/locales/en/translation.json @@ -270,6 +270,8 @@ "jobFunction": "Job function", "jobFunctionDeleted": "Job function deleted", "jobFunctions": "Job functions", + "language": "Language", + "label": "Label", "loading": "Loading", "lowRisk": "Low risk", "mavenConfig": "Maven configuration", diff --git a/client/src/app/pages/dependencies/dependencies.tsx b/client/src/app/pages/dependencies/dependencies.tsx index dfcb04e65d..bc280d8681 100644 --- a/client/src/app/pages/dependencies/dependencies.tsx +++ b/client/src/app/pages/dependencies/dependencies.tsx @@ -35,26 +35,67 @@ import { import { useFetchDependencies } from "@app/queries/dependencies"; import { useSelectionState } from "@migtools/lib-ui"; import { getHubRequestParams } from "@app/shared/hooks/table-controls"; -import { PageDrawerContent } from "@app/shared/page-drawer-context"; import { DependencyAppsDetailDrawer } from "./dependency-apps-detail-drawer"; +import { useSharedAffectedApplicationFilterCategories } from "../issues/helpers"; export const Dependencies: React.FC = () => { const { t } = useTranslation(); + const allAffectedApplicationsFilterCategories = + useSharedAffectedApplicationFilterCategories(); + const tableControlState = useTableControlUrlParams({ columnNames: { name: "Dependency name", foundIn: "Found in", - language: "Language", + provider: "Language", labels: "Labels", + sha: "SHA", + version: "Version", }, sortableColumns: ["name", "labels"], initialSort: { columnKey: "name", direction: "asc" }, filterCategories: [ + ...allAffectedApplicationsFilterCategories, { key: "name", title: t("terms.name"), type: FilterType.search, + filterGroup: "Dependency", + placeholderText: + t("actions.filterBy", { + what: t("terms.name").toLowerCase(), + }) + "...", + getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), + }, + //TODO: Not implemented on hub + // { + // key: "provider", + // title: t("terms.language"), + // type: FilterType.search, + // filterGroup: "Dependency", + // placeholderText: + // t("actions.filterBy", { + // what: t("terms.language").toLowerCase(), + // }) + "...", + // getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), + // }, + { + key: "version", + title: t("terms.label"), + type: FilterType.search, + filterGroup: "Dependency", + placeholderText: + t("actions.filterBy", { + what: t("terms.label").toLowerCase(), + }) + "...", + getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), + }, + { + key: "sha", + title: "SHA", + type: FilterType.search, + filterGroup: "Dependency", placeholderText: t("actions.filterBy", { what: t("terms.name").toLowerCase(), @@ -75,8 +116,6 @@ export const Dependencies: React.FC = () => { ...tableControlState, // Includes filterState, sortState and paginationState hubSortFieldKeys: { name: "name", - // version: "version", - // sha: "sha", labels: "labels", }, }) @@ -140,8 +179,10 @@ export const Dependencies: React.FC = () => { - + + + @@ -185,15 +226,21 @@ export const Dependencies: React.FC = () => { {dependency.provider} + + {dependency.labels} + - {dependency.labels} + {dependency.version} + + + {dependency.sha} diff --git a/client/src/app/pages/issues/affected-applications/affected-applications.tsx b/client/src/app/pages/issues/affected-applications/affected-applications.tsx index 50ef249fc4..41e7c8df60 100644 --- a/client/src/app/pages/issues/affected-applications/affected-applications.tsx +++ b/client/src/app/pages/issues/affected-applications/affected-applications.tsx @@ -37,7 +37,7 @@ import { FilterToolbar } from "@app/shared/components/FilterToolbar"; import { useSelectionState } from "@migtools/lib-ui"; import { getBackToAllIssuesUrl, - useSharedFilterCategoriesForIssuesAndAffectedApps, + useSharedAffectedApplicationFilterCategories, } from "../helpers"; import { IssueDetailDrawer } from "../issue-detail-drawer"; import { TableURLParamKeyPrefix } from "@app/Constants"; @@ -66,7 +66,7 @@ export const AffectedApplications: React.FC = () => { }, sortableColumns: ["name", "businessService", "effort", "incidents"], initialSort: { columnKey: "name", direction: "asc" }, - filterCategories: useSharedFilterCategoriesForIssuesAndAffectedApps(), + filterCategories: useSharedAffectedApplicationFilterCategories(), initialItemsPerPage: 10, hasClickableRows: true, }); diff --git a/client/src/app/pages/issues/helpers.ts b/client/src/app/pages/issues/helpers.ts index 12e52de9a1..26f7ae7768 100644 --- a/client/src/app/pages/issues/helpers.ts +++ b/client/src/app/pages/issues/helpers.ts @@ -31,62 +31,64 @@ export type IssuesFilterValuesToCarry = Partial< Record >; -export const useSharedFilterCategoriesForIssuesAndAffectedApps = - (): FilterCategory[] => { - const { t } = useTranslation(); - const { tags } = useFetchTags(); - const { businessServices } = useFetchBusinessServices(); +export const useSharedAffectedApplicationFilterCategories = (): FilterCategory< + unknown, + IssuesFilterKeyToCarry +>[] => { + const { t } = useTranslation(); + const { tags } = useFetchTags(); + const { businessServices } = useFetchBusinessServices(); - return [ - { - key: "application.name", - title: t("terms.applicationName"), - filterGroup: IssueFilterGroups.ApplicationInventory, - type: FilterType.search, - placeholderText: - t("actions.filterBy", { - what: t("terms.applicationName").toLowerCase(), - }) + "...", - getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), - }, - { - key: "businessService.name", - title: t("terms.businessService"), - filterGroup: IssueFilterGroups.ApplicationInventory, - placeholderText: - t("actions.filterBy", { - what: t("terms.businessService").toLowerCase(), - }) + "...", - type: FilterType.select, - selectOptions: businessServices - .map((businessService) => businessService.name) - .map((name) => ({ key: name, value: name })), - }, - { - key: "tag.id", - title: t("terms.tags"), - filterGroup: IssueFilterGroups.ApplicationInventory, - type: FilterType.multiselect, - placeholderText: - t("actions.filterBy", { - what: t("terms.tagName").toLowerCase(), - }) + "...", - selectOptions: [...new Set(tags.map((tag) => tag.name))].map( - (tagName) => ({ key: tagName, value: tagName }) + return [ + { + key: "application.name", + title: t("terms.applicationName"), + filterGroup: IssueFilterGroups.ApplicationInventory, + type: FilterType.search, + placeholderText: + t("actions.filterBy", { + what: t("terms.applicationName").toLowerCase(), + }) + "...", + getServerFilterValue: (value) => (value ? [`*${value[0]}*`] : []), + }, + { + key: "businessService.name", + title: t("terms.businessService"), + filterGroup: IssueFilterGroups.ApplicationInventory, + placeholderText: + t("actions.filterBy", { + what: t("terms.businessService").toLowerCase(), + }) + "...", + type: FilterType.select, + selectOptions: businessServices + .map((businessService) => businessService.name) + .map((name) => ({ key: name, value: name })), + }, + { + key: "tag.id", + title: t("terms.tags"), + filterGroup: IssueFilterGroups.ApplicationInventory, + type: FilterType.multiselect, + placeholderText: + t("actions.filterBy", { + what: t("terms.tagName").toLowerCase(), + }) + "...", + selectOptions: [...new Set(tags.map((tag) => tag.name))].map( + (tagName) => ({ key: tagName, value: tagName }) + ), + // NOTE: The same tag name can appear in multiple tag categories. + // To replicate the behavior of the app inventory page, selecting a tag name + // will perform an OR filter matching all tags with that name across tag categories. + // In the future we may instead want to present the tag select options to the user in category sections. + getServerFilterValue: (tagNames) => + tagNames?.flatMap((tagName) => + tags + .filter((tag) => tag.name === tagName) + .map((tag) => String(tag.id)) ), - // NOTE: The same tag name can appear in multiple tag categories. - // To replicate the behavior of the app inventory page, selecting a tag name - // will perform an OR filter matching all tags with that name across tag categories. - // In the future we may instead want to present the tag select options to the user in category sections. - getServerFilterValue: (tagNames) => - tagNames?.flatMap((tagName) => - tags - .filter((tag) => tag.name === tagName) - .map((tag) => String(tag.id)) - ), - }, - ]; - }; + }, + ]; +}; const FROM_ISSUES_PARAMS_KEY = "~fromIssuesParams"; // ~ prefix sorts it at the end of the URL for readability diff --git a/client/src/app/pages/issues/issues-table.tsx b/client/src/app/pages/issues/issues-table.tsx index 7849b81d51..7f4392f7bc 100644 --- a/client/src/app/pages/issues/issues-table.tsx +++ b/client/src/app/pages/issues/issues-table.tsx @@ -56,9 +56,9 @@ import { } from "@app/shared/hooks/table-controls"; import { - useSharedFilterCategoriesForIssuesAndAffectedApps, parseReportLabels, getIssuesSingleAppSelectedLocation, + useSharedAffectedApplicationFilterCategories, } from "./helpers"; import { IssueFilterGroups } from "./issues"; import { @@ -94,7 +94,7 @@ export const IssuesTable: React.FC = ({ mode }) => { }; const allIssuesSpecificFilterCategories = - useSharedFilterCategoriesForIssuesAndAffectedApps(); + useSharedAffectedApplicationFilterCategories(); const tableControlState = useTableControlUrlParams({ urlParamKeyPrefix: TableURLParamKeyPrefix.issues,