diff --git a/designer/client/cypress/e2e/__image_snapshots__/electron/Linux/Processes list should filter by processing mode #0.png b/designer/client/cypress/e2e/__image_snapshots__/electron/Linux/Processes list should filter by processing mode #0.png index 422514c79d5..ed672acd5b9 100644 Binary files a/designer/client/cypress/e2e/__image_snapshots__/electron/Linux/Processes list should filter by processing mode #0.png and b/designer/client/cypress/e2e/__image_snapshots__/electron/Linux/Processes list should filter by processing mode #0.png differ diff --git a/designer/client/src/components/toolbars/scenarioDetails/ScenarioLabels.tsx b/designer/client/src/components/toolbars/scenarioDetails/ScenarioLabels.tsx index 9d0ea087736..34235357cc6 100644 --- a/designer/client/src/components/toolbars/scenarioDetails/ScenarioLabels.tsx +++ b/designer/client/src/components/toolbars/scenarioDetails/ScenarioLabels.tsx @@ -60,6 +60,11 @@ const StyledAutocomplete = styled(Autocomplete)<{ isEdited: boolean }>(({ isEdit }, })); +const StyledLabelChip = styled(Chip)({ + borderRadius: "16px", + margin: "2px", +}); + const filter = createFilterOptions(); type LabelOption = { @@ -332,7 +337,7 @@ export const ScenarioLabels = ({ readOnly }: Props) => { const props = isEdited ? { ...tagProps } : {}; const labelError = labelOptionsErrors.find((error) => error.label === toLabelValue(option)); return ( - void; } -export function CategoryChip({ value, filterValue, setFilter }: Props): JSX.Element { - const isSelected = useMemo(() => filterValue.includes(value), [filterValue, value]); +export function CategoryChip({ category, filterValues, setFilter }: Props): JSX.Element { + const isSelected = useMemo(() => filterValues.includes(category), [filterValues, category]); const onClick = useCallback( (e) => { - setFilter(isSelected ? filterValue.filter((v) => v !== value) : [...filterValue, value]); + setFilter(isSelected ? filterValues.filter((v) => v !== category) : [...filterValues, category]); e.preventDefault(); e.stopPropagation(); }, - [setFilter, isSelected, filterValue, value], + [setFilter, isSelected, filterValues, category], ); - return ; + return ; +} + +export function CategoryButton({ category, filterValues, setFilter }: Props): JSX.Element { + const isSelected = useMemo(() => filterValues.includes(category), [filterValues, category]); + + const onClick = useCallback( + (e) => { + setFilter(isSelected ? filterValues.filter((v) => v !== category) : [...filterValues, category]); + e.preventDefault(); + e.stopPropagation(); + }, + [setFilter, isSelected, filterValues, category], + ); + + return ( + + {category} + + ); } diff --git a/designer/submodules/packages/components/src/common/index.ts b/designer/submodules/packages/components/src/common/index.ts index d875dced827..dade033c50b 100644 --- a/designer/submodules/packages/components/src/common/index.ts +++ b/designer/submodules/packages/components/src/common/index.ts @@ -3,7 +3,7 @@ export { useDefaultTheme } from "./defaultTheme"; export { HistoryProvider, useHistory, useBackHref } from "./historyContext"; export { NuIcon } from "./nuIcon"; export { TextFieldWithClear, InputWithClear } from "./forms"; -export { CategoryChip } from "./categoryChip"; +export { CategoryButton, CategoryChip } from "./categoryChip"; export { useFilterContext, FiltersContextProvider, createFilterRules } from "./filters"; export { ExternalLink, NavigationProvider } from "./parentNavigationProvider"; export { nodeHref, fragmentNodeHref, scenarioHref, metricsHref } from "./scenarioHref"; diff --git a/designer/submodules/packages/components/src/common/labelChip.tsx b/designer/submodules/packages/components/src/common/labelChip.tsx index 1a581481312..5af600503bf 100644 --- a/designer/submodules/packages/components/src/common/labelChip.tsx +++ b/designer/submodules/packages/components/src/common/labelChip.tsx @@ -1,14 +1,18 @@ import React, { useCallback, useMemo } from "react"; -import { Chip } from "@mui/material"; +import { Chip, styled } from "@mui/material"; interface Props { - key: string; + id: string; value: string; filterValue: string[]; setFilter: (value: string[]) => void; } -export function LabelChip({ key, value, filterValue, setFilter }: Props): JSX.Element { +const StyledLabelChip = styled(Chip)({ + borderRadius: "16px", +}); + +export function LabelChip({ id, value, filterValue, setFilter }: Props): JSX.Element { const isSelected = useMemo(() => filterValue.includes(value), [filterValue, value]); const onClick = useCallback( @@ -21,13 +25,13 @@ export function LabelChip({ key, value, filterValue, setFilter }: Props): JSX.El ); return ( - ); diff --git a/designer/submodules/packages/components/src/components/cellRenderers/categoriesCell.tsx b/designer/submodules/packages/components/src/components/cellRenderers/categoriesCell.tsx index df95ec798a5..ec0b9ee7f72 100644 --- a/designer/submodules/packages/components/src/components/cellRenderers/categoriesCell.tsx +++ b/designer/submodules/packages/components/src/components/cellRenderers/categoriesCell.tsx @@ -12,7 +12,7 @@ export function CategoriesCell(props: CellRendererParams): JSX.Element { return ( {value.map((name) => ( - + ))} ); diff --git a/designer/submodules/packages/components/src/components/usages/filtersPart.tsx b/designer/submodules/packages/components/src/components/usages/filtersPart.tsx index e62927cb3e3..2ebda948806 100644 --- a/designer/submodules/packages/components/src/components/usages/filtersPart.tsx +++ b/designer/submodules/packages/components/src/components/usages/filtersPart.tsx @@ -3,14 +3,14 @@ import { useFilterContext } from "../../common"; import { QuickFilter } from "../../scenarios/filters/quickFilter"; import { FilterMenu } from "../../scenarios/filters/filterMenu"; import { SimpleOptionsStack } from "../../scenarios/filters/simpleOptionsStack"; -import { StatusOptionsStack } from "../../scenarios/filters/otherOptionsStack"; +import { StatusOptionsStack } from "../../scenarios/filters/typeOptionsStack"; import { OptionsStack } from "../../scenarios/filters/optionsStack"; import { FilterListItem } from "../../scenarios/filters/filterListItem"; import React from "react"; import { useTranslation } from "react-i18next"; import { Divider, Stack } from "@mui/material"; import { xor } from "lodash"; -import { EventTrackingType, EventTrackingSelector, getEventTrackingProps } from "nussknackerUi/eventTracking"; +import { EventTrackingSelector, getEventTrackingProps } from "nussknackerUi/eventTracking"; interface FiltersPartProps { isLoading: boolean; diff --git a/designer/submodules/packages/components/src/components/usages/usagesFiltersModel.ts b/designer/submodules/packages/components/src/components/usages/usagesFiltersModel.ts index 0d95a9315f7..cd709f10271 100644 --- a/designer/submodules/packages/components/src/components/usages/usagesFiltersModel.ts +++ b/designer/submodules/packages/components/src/components/usages/usagesFiltersModel.ts @@ -1,4 +1,4 @@ -import { StatusFilterOption } from "../../scenarios/filters/otherOptionsStack"; +import { StatusFilterOption } from "../../scenarios/filters/typeOptionsStack"; import { ProcessingMode } from "../../scenarios/list/processingMode"; export interface UsagesFiltersModel { diff --git a/designer/submodules/packages/components/src/scenarios/filters/filtersPart.tsx b/designer/submodules/packages/components/src/scenarios/filters/filtersPart.tsx index 6ddd0670b32..c8aa2c2f6fd 100644 --- a/designer/submodules/packages/components/src/scenarios/filters/filtersPart.tsx +++ b/designer/submodules/packages/components/src/scenarios/filters/filtersPart.tsx @@ -6,7 +6,7 @@ import { useScenarioLabelsQuery, useStatusDefinitions, useUserQuery } from "../u import { QuickFilter } from "./quickFilter"; import { FilterMenu } from "./filterMenu"; import { SimpleOptionsStack } from "./simpleOptionsStack"; -import { OtherOptionsStack, StatusOptionsStack } from "./otherOptionsStack"; +import { TypeOptionsStack, StatusOptionsStack } from "./typeOptionsStack"; import { SortOptionsStack } from "./sortOptionsStack"; import { ActiveFilters } from "./activeFilters"; import { RowType } from "../list/listPart"; @@ -135,8 +135,8 @@ export function FiltersPart({ withSort, isLoading, data = [] }: { data: RowType[ })} /> - - + + {withSort ? ( diff --git a/designer/submodules/packages/components/src/scenarios/filters/otherOptionsStack.tsx b/designer/submodules/packages/components/src/scenarios/filters/typeOptionsStack.tsx similarity index 97% rename from designer/submodules/packages/components/src/scenarios/filters/otherOptionsStack.tsx rename to designer/submodules/packages/components/src/scenarios/filters/typeOptionsStack.tsx index fdede824e87..f7c150b21c8 100644 --- a/designer/submodules/packages/components/src/scenarios/filters/otherOptionsStack.tsx +++ b/designer/submodules/packages/components/src/scenarios/filters/typeOptionsStack.tsx @@ -11,7 +11,7 @@ import ScanarioIcon from "../../assets/icons/scenario.svg"; import FragmentIcon from "../../assets/icons/fragment.svg"; import { EventTrackingSelector, getEventTrackingProps } from "nussknackerUi/eventTracking"; -export function OtherOptionsStack(): JSX.Element { +export function TypeOptionsStack(): JSX.Element { const { t } = useTranslation(); const { getFilter, setFilter } = useFilterContext(); const otherFilters: Array = ["TYPE"]; @@ -19,7 +19,7 @@ export function OtherOptionsStack(): JSX.Element { return ( ({ name }))} value={otherFilters .flatMap((k) => getFilter(k)) diff --git a/designer/submodules/packages/components/src/scenarios/list/item.tsx b/designer/submodules/packages/components/src/scenarios/list/item.tsx index 989bcbb939d..1e6267bf0b8 100644 --- a/designer/submodules/packages/components/src/scenarios/list/item.tsx +++ b/designer/submodules/packages/components/src/scenarios/list/item.tsx @@ -1,8 +1,8 @@ import { History } from "@mui/icons-material"; -import { Divider, Stack, Typography } from "@mui/material"; +import { Divider, Stack, styled, Typography } from "@mui/material"; import React, { useMemo } from "react"; import { useTranslation } from "react-i18next"; -import { CategoryChip, Highlight, useFilterContext } from "../../common"; +import { CategoryButton, Highlight, useFilterContext, TruncateWrapper } from "../../common"; import { Author } from "./author"; import { ScenariosFiltersModel } from "../filters/scenariosFiltersModel"; import { RowType } from "./listPart"; @@ -13,19 +13,24 @@ import { ScenarioStatus } from "./scenarioStatus"; import { ProcessingModeItem } from "./processingMode"; import { formatDateTime } from "nussknackerUi/DateUtils"; import { LabelChip } from "../../common/labelChip"; -import { TruncateWrapper } from "../../common/utils"; -function Category({ value, filtersContext }: { value: string; filtersContext: FiltersContextType }): JSX.Element { +function Category({ + category, + filtersContext, +}: { + category: string; + filtersContext: FiltersContextType; +}): JSX.Element { const { setFilter, getFilter } = filtersContext; const filterValue = useMemo(() => getFilter("CATEGORY", true), [getFilter]); - return ; + return ; } function Labels({ values, filtersContext }: { values: string[]; filtersContext: FiltersContextType }): JSX.Element { const { setFilter, getFilter } = filtersContext; const filterValue = useMemo(() => getFilter("LABEL", true), [getFilter]); - const elements = values.map((v) => ); + const elements = values.map((v) => ); return {elements}; } @@ -47,14 +52,23 @@ export function LastAction({ lastAction }: { lastAction: ProcessActionType }): J ) : null; } +const HighlightedName = styled(Highlight)({ + fontWeight: "bold", + fontSize: "1rem", +}); + export function FirstLine({ row }: { row: RowType }): JSX.Element { const { t } = useTranslation(); const filtersContext = useFilterContext(); return ( - - - +
+ + / + + + +
); } @@ -84,8 +98,7 @@ export function SecondLine({ row }: { row: RowType }): JSX.Element { {!row.isFragment && !row.isArchived && } - - + {row.labels.length && } ); } diff --git a/designer/submodules/packages/components/src/scenarios/list/tablePart.tsx b/designer/submodules/packages/components/src/scenarios/list/tablePart.tsx index cfefa903d46..e5d27fad18b 100644 --- a/designer/submodules/packages/components/src/scenarios/list/tablePart.tsx +++ b/designer/submodules/packages/components/src/scenarios/list/tablePart.tsx @@ -49,7 +49,7 @@ export function TablePart(props: ListPartProps): JSX.Element { { field: "createdAt", headerName: t("table.scenarios.title.CREATION_DATE", "Creation date"), - type: "dateTime", + type: "string", flex: 2, renderCell: (props) => , hide: true, @@ -72,7 +72,7 @@ export function TablePart(props: ListPartProps): JSX.Element { { field: "modificationDate", headerName: t("table.scenarios.title.MODIFICATION_DATE", "Modification date"), - type: "dateTime", + type: "string", flex: 2, renderCell: (props) => , sortingOrder: ["desc", "asc", null], @@ -124,12 +124,14 @@ export function TablePart(props: ListPartProps): JSX.Element { const text = filter?.toString(); if (!text?.length) return true; const segments = text.trim().split(/\s/); - return segments.every((segment) => - ["id"] - .map((field) => row[field]?.toString().toLowerCase()) + return segments.every((segment) => { + return columns + .filter((value) => visibleColumns[value.field]) + .filter((value) => ["id", "createdAt", "modificationDate"].includes(value.field)) + .map(({ field }) => row[field]?.toString().toLowerCase()) .filter(Boolean) - .some((value) => value.includes(segment.toLowerCase())), - ); + .some((value) => value.includes(segment.toLowerCase())); + }); }, ARCHIVED: (row, filter) => (filter ? row.isArchived : !row.isArchived), TYPE: (row, value) => diff --git a/designer/submodules/packages/components/src/scenarios/useScenariosQuery.tsx b/designer/submodules/packages/components/src/scenarios/useScenariosQuery.tsx index 822d5939dfd..ac58e5f0773 100644 --- a/designer/submodules/packages/components/src/scenarios/useScenariosQuery.tsx +++ b/designer/submodules/packages/components/src/scenarios/useScenariosQuery.tsx @@ -102,6 +102,7 @@ export function useScenariosWithStatus(): UseQueryResult { data: data.map((scenario) => ({ ...scenario, state: statuses?.data?.[scenario.name] || scenario.state, + id: scenario.name, // required by DataGrid when table=true })), } as UseQueryResult; }, [scenarios, statuses]);