diff --git a/src/components/DashboardPage/DashboardPage.tsx b/src/components/DashboardPage/DashboardPage.tsx index 6465e7ffd..5bff16147 100644 --- a/src/components/DashboardPage/DashboardPage.tsx +++ b/src/components/DashboardPage/DashboardPage.tsx @@ -122,6 +122,7 @@ export const DashboardPage = ({ user, ssrTime, defaultPresetFallback }: External filterPreset={preset} loading={isLoading} enableLayoutToggle + enableHideProjectToggle /> } > diff --git a/src/components/FiltersPanel/FiltersPanel.i18n/en.json b/src/components/FiltersPanel/FiltersPanel.i18n/en.json index 21f62fb13..e5659f513 100644 --- a/src/components/FiltersPanel/FiltersPanel.i18n/en.json +++ b/src/components/FiltersPanel/FiltersPanel.i18n/en.json @@ -14,5 +14,6 @@ "Reset": "Reset", "Grouping": "Grouping", "Visibility": "Visibility", - "Criteria": "Criteria" + "Criteria": "Criteria", + "Empty Projects": "Empty Projects" } diff --git a/src/components/FiltersPanel/FiltersPanel.i18n/ru.json b/src/components/FiltersPanel/FiltersPanel.i18n/ru.json index a5bf235ef..c38778dd0 100644 --- a/src/components/FiltersPanel/FiltersPanel.i18n/ru.json +++ b/src/components/FiltersPanel/FiltersPanel.i18n/ru.json @@ -14,5 +14,6 @@ "Reset": "Сбросить", "Grouping": "Группировка", "Visibility": "Видимость", - "Criteria": "Критерии" + "Criteria": "Критерии", + "Empty Projects": "Пустые Проекты" } diff --git a/src/components/FiltersPanel/FiltersPanel.tsx b/src/components/FiltersPanel/FiltersPanel.tsx index 29efce9ba..8bf959f2f 100644 --- a/src/components/FiltersPanel/FiltersPanel.tsx +++ b/src/components/FiltersPanel/FiltersPanel.tsx @@ -52,307 +52,336 @@ export const FiltersPanel: FC<{ filterPreset?: FilterById; enableViewToggle?: boolean; enableLayoutToggle?: boolean; + enableHideProjectToggle?: boolean; children?: ReactNode; -}> = memo(({ children, title, total = 0, counter = 0, enableViewToggle, enableLayoutToggle, filterPreset }) => { - const { toggleFilterStar } = useFilterResource(); - const { user } = usePageContext(); +}> = memo( + ({ + children, + title, + total = 0, + counter = 0, + enableViewToggle, + enableLayoutToggle, + enableHideProjectToggle, + filterPreset, + }) => { + const { toggleFilterStar } = useFilterResource(); + const { user } = usePageContext(); - const { - currentPreset, - queryString, - queryState, - resetQueryState, - batchQueryState, - setSortFilter, - queryFilterState, - groupBy, - view, - setGroupBy, - hideCriteria, - setHideCriteria, - setView, - } = useUrlFilterParams({ - preset: filterPreset, - }); - - const [filterQuery, setFilterQuery] = useState | undefined>(queryFilterState); - const filterQueryRef = useLatest(filterQuery); + const { + currentPreset, + queryString, + queryState, + resetQueryState, + batchQueryState, + setSortFilter, + queryFilterState, + groupBy, + view, + setGroupBy, + hideCriteria, + setHideCriteria, + hideEmptyProjects, + setHideEmptyProjects, + setView, + } = useUrlFilterParams({ + preset: filterPreset, + }); - useEffect(() => { - setFilterQuery(queryState); - }, [queryState]); + const [filterQuery, setFilterQuery] = useState | undefined>(queryFilterState); + const filterQueryRef = useLatest(filterQuery); - const setPartialQueryByKey = useCallback((key: K) => { - return (value?: QueryState[K]) => { - setFilterQuery((prev) => { - return { - ...prev, - [key]: value, - }; - }); - }; - }, []); + useEffect(() => { + setFilterQuery(queryState); + }, [queryState]); - const filterStarHandler = useCallback(async () => { - if (!currentPreset) { - dispatchModalEvent(ModalEvent.FilterCreateModal)(); - return; - } + const setPartialQueryByKey = useCallback((key: K) => { + return (value?: QueryState[K]) => { + setFilterQuery((prev) => { + return { + ...prev, + [key]: value, + }; + }); + }; + }, []); - if (currentPreset._isOwner) { - dispatchModalEvent(ModalEvent.FilterDeleteModal)(); - return; - } + const filterStarHandler = useCallback(async () => { + if (!currentPreset) { + dispatchModalEvent(ModalEvent.FilterCreateModal)(); + return; + } - await toggleFilterStar({ - id: currentPreset.id, - direction: !currentPreset._isStarred, - }); - }, [currentPreset, toggleFilterStar]); + if (currentPreset._isOwner) { + dispatchModalEvent(ModalEvent.FilterDeleteModal)(); + return; + } - const onApplyClick = useCallback( - (key?: keyof Omit) => { - if (!filterQueryRef.current) return; + await toggleFilterStar({ + id: currentPreset.id, + direction: !currentPreset._isStarred, + }); + }, [currentPreset, toggleFilterStar]); - if (key) { - filterQueryRef.current[key] = []; - } + const onApplyClick = useCallback( + (key?: keyof Omit) => { + if (!filterQueryRef.current) return; - if (key === 'state') { - filterQueryRef.current.stateType = []; - } + if (key) { + filterQueryRef.current[key] = []; + } - batchQueryState?.({ ...filterQueryRef.current }); - }, - [filterQueryRef, batchQueryState], - ); + if (key === 'state') { + filterQueryRef.current.stateType = []; + } - const onResetClick = useCallback(() => { - setFilterQuery(undefined); - resetQueryState(); - }, [resetQueryState]); + batchQueryState?.({ ...filterQueryRef.current }); + }, + [filterQueryRef, batchQueryState], + ); - const handleChange = useCallback( - (key: keyof FilterQueryState) => (values?: { id: string }[]) => { - if (key === 'state') { - setPartialQueryByKey('stateType')(); - } + const onResetClick = useCallback(() => { + setFilterQuery(undefined); + resetQueryState(); + }, [resetQueryState]); - setPartialQueryByKey(key)(values?.map(({ id }) => id)); - }, - [setPartialQueryByKey], - ); + const handleChange = useCallback( + (key: keyof FilterQueryState) => (values?: { id: string }[]) => { + if (key === 'state') { + setPartialQueryByKey('stateType')(); + } - const onClearFilter = useCallback( - (key: keyof Omit) => () => { - setPartialQueryByKey(key)(); - onApplyClick(key); - }, - [onApplyClick, setPartialQueryByKey], - ); + setPartialQueryByKey(key)(values?.map(({ id }) => id)); + }, + [setPartialQueryByKey], + ); - const isFiltersEmpty = useMemo(() => Object.values(filterQuery || {}).filter(Boolean).length === 0, [filterQuery]); - const groupedByProject = groupBy === 'project'; + const onClearFilter = useCallback( + (key: keyof Omit) => () => { + setPartialQueryByKey(key)(); + onApplyClick(key); + }, + [onApplyClick, setPartialQueryByKey], + ); - const filterItems: { id: keyof FilterQueryState; title: string }[] = useMemo(() => { - return [ - { id: 'state', title: tr('State') }, - { id: 'priority', title: tr('Priority') }, - { id: 'estimate', title: tr('Estimate') }, - { id: 'project', title: tr('Project') }, - { id: 'tag', title: tr('Tag') }, - { id: 'issuer', title: tr('Issuer') }, - { id: 'owner', title: tr('Owner') }, - { id: 'participant', title: tr('Participant') }, - ]; - }, []); + const isFiltersEmpty = useMemo( + () => Object.values(filterQuery || {}).filter(Boolean).length === 0, + [filterQuery], + ); + const groupedByProject = groupBy === 'project'; - const restFilterItems = useMemo(() => { - if (filterQuery && filterQuery.stateType) { - filterQuery.state = []; - } - return filterItems.filter(({ id }) => !filterQuery?.[id]); - }, [filterQuery, filterItems]); + const filterItems: { id: keyof FilterQueryState; title: string }[] = useMemo(() => { + return [ + { id: 'state', title: tr('State') }, + { id: 'priority', title: tr('Priority') }, + { id: 'estimate', title: tr('Estimate') }, + { id: 'project', title: tr('Project') }, + { id: 'tag', title: tr('Tag') }, + { id: 'issuer', title: tr('Issuer') }, + { id: 'owner', title: tr('Owner') }, + { id: 'participant', title: tr('Participant') }, + ]; + }, []); - return ( - <> - - - {title} - - - {children} - - - {nullable( - isFiltersEmpty, - () => ( - setPartialQueryByKey(id)([])} - /> - ), -