From 820a4efc76d05866b5fab27ca8b1a7697b63ce58 Mon Sep 17 00:00:00 2001 From: jeffvli Date: Sun, 16 Nov 2025 14:39:38 -0800 Subject: [PATCH] add modularity to the ListConfigMenu --- .../shared/components/grid-config.tsx | 34 +++++++++- .../shared/components/list-config-menu.tsx | 68 +++++++++++++++++-- .../shared/components/table-config.tsx | 40 +++++++++-- 3 files changed, 126 insertions(+), 16 deletions(-) diff --git a/src/renderer/features/shared/components/grid-config.tsx b/src/renderer/features/shared/components/grid-config.tsx index c668907a5..2463e9868 100644 --- a/src/renderer/features/shared/components/grid-config.tsx +++ b/src/renderer/features/shared/components/grid-config.tsx @@ -46,9 +46,20 @@ type GridConfigProps = { }[]; gridRowsData: { label: string; value: string }[]; listKey: ItemListKey; + optionsConfig?: { + [key: string]: { + disabled?: boolean; + hidden?: boolean; + }; + }; }; -export const GridConfig = ({ extraOptions, gridRowsData, listKey }: GridConfigProps) => { +export const GridConfig = ({ + extraOptions, + gridRowsData, + listKey, + optionsConfig, +}: GridConfigProps) => { const { t } = useTranslation(); const list = useSettingsStore((state) => state.lists[listKey]) as ItemListSettings; @@ -56,7 +67,7 @@ export const GridConfig = ({ extraOptions, gridRowsData, listKey }: GridConfigPr const { setList } = useSettingsStoreActions(); const options = useMemo(() => { - return [ + const allOptions = [ { component: ( { + const config = optionsConfig?.[option.id]; + if (config?.hidden) { + return null; + } + return { + ...option, + disabled: config?.disabled || false, + }; + }) + .filter( + (option): option is typeof allOptions[0] & { disabled?: boolean } => + option !== null, + ); + }, [list, t, grid, extraOptions, optionsConfig, setList, listKey]); return ( <> diff --git a/src/renderer/features/shared/components/list-config-menu.tsx b/src/renderer/features/shared/components/list-config-menu.tsx index cd3dd9b50..862a12820 100644 --- a/src/renderer/features/shared/components/list-config-menu.tsx +++ b/src/renderer/features/shared/components/list-config-menu.tsx @@ -1,4 +1,4 @@ -import { ReactNode } from 'react'; +import { ReactNode, useMemo } from 'react'; import { useTranslation } from 'react-i18next'; import i18n from '/@/i18n/i18n'; @@ -77,8 +77,30 @@ export const ListConfigBooleanControl = ({ ); }; +export interface ListConfigMenuDisplayTypeConfig { + disabled?: boolean; + hidden?: boolean; + value: ListDisplayType; +} + +export interface ListConfigMenuOptionConfig { + disabled?: boolean; + hidden?: boolean; +} + +export interface ListConfigMenuOptionsConfig { + grid?: { + [key: string]: ListConfigMenuOptionConfig; + }; + table?: { + [key: string]: ListConfigMenuOptionConfig; + }; +} + interface ListConfigMenuProps { + displayTypes?: ListConfigMenuDisplayTypeConfig[]; listKey: ItemListKey; + optionsConfig?: ListConfigMenuOptionsConfig; tableColumnsData: { label: string; value: string }[]; } @@ -90,6 +112,29 @@ export const ListConfigMenu = (props: ListConfigMenuProps) => { const { setList } = useSettingsStoreActions(); const [isOpen, handlers] = useDisclosure(false); + // Filter display types based on config + const availableDisplayTypes = useMemo(() => { + if (!props.displayTypes) { + return DISPLAY_TYPES; + } + + const filtered = DISPLAY_TYPES.map((type) => { + const config = props.displayTypes?.find((c) => c.value === type.value); + if (config?.hidden) { + return null; + } + const result: (typeof DISPLAY_TYPES)[0] & { disabled?: boolean } = { + ...type, + }; + if (config?.disabled) { + result.disabled = true; + } + return result; + }).filter((type): type is NonNullable => type !== null); + + return filtered; + }, [props.displayTypes]); + return ( <> @@ -101,9 +146,7 @@ export const ListConfigMenu = (props: ListConfigMenuProps) => { > ({ - ...type, - }))} + data={availableDisplayTypes} fullWidth onChange={(value) => { setList(props.listKey, { @@ -122,15 +165,28 @@ export const ListConfigMenu = (props: ListConfigMenuProps) => { const Config = ({ displayType, + optionsConfig, tableColumnsData, ...props }: ListConfigMenuProps & { displayType: ListDisplayType }) => { switch (displayType) { case ListDisplayType.GRID: - return ; + return ( + + ); case ListDisplayType.TABLE: - return ; + return ( + + ); default: return null; diff --git a/src/renderer/features/shared/components/table-config.tsx b/src/renderer/features/shared/components/table-config.tsx index 9216df03a..141707dfb 100644 --- a/src/renderer/features/shared/components/table-config.tsx +++ b/src/renderer/features/shared/components/table-config.tsx @@ -11,7 +11,7 @@ import { import { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview'; import { useDebouncedState } from '@mantine/hooks'; import clsx from 'clsx'; -import Fuse from 'fuse.js'; +import Fuse, { type FuseResultMatch } from 'fuse.js'; import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react'; import { useTranslation } from 'react-i18next'; @@ -45,17 +45,28 @@ interface TableConfigProps { label: string; }[]; listKey: ItemListKey; + optionsConfig?: { + [key: string]: { + disabled?: boolean; + hidden?: boolean; + }; + }; tableColumnsData: { label: string; value: string }[]; } -export const TableConfig = ({ extraOptions, listKey, tableColumnsData }: TableConfigProps) => { +export const TableConfig = ({ + extraOptions, + listKey, + optionsConfig, + tableColumnsData, +}: TableConfigProps) => { const { t } = useTranslation(); const list = useSettingsStore((state) => state.lists[listKey]) as ItemListSettings; const { setList } = useSettingsStoreActions(); const options = useMemo(() => { - return [ + const allOptions = [ { component: ( { + const config = optionsConfig?.[option.id]; + if (config?.hidden) { + return null; + } + return option; + }) + .filter((option): option is NonNullable => option !== null); + }, [extraOptions, listKey, optionsConfig, setList, t, list]); return ( <> @@ -497,14 +519,18 @@ const TableColumnConfig = ({ ); }; -const DragHandle = ({ dragHandleRef }: { dragHandleRef: React.RefObject }) => { +const DragHandle = ({ + dragHandleRef, +}: { + dragHandleRef: React.RefObject; +}) => { return ( } size="xs" style={{ cursor: 'grab' }} variant="default" @@ -542,7 +568,7 @@ const TableColumnItem = memo( handleRowWidth: (item: ItemTableListColumnConfig, number: number | string) => void; item: ItemTableListColumnConfig; label: string; - matches: null | readonly Fuse.FuseResultMatch[]; + matches: null | readonly FuseResultMatch[]; }) => { const { t } = useTranslation(); const ref = useRef(null);