-
Notifications
You must be signed in to change notification settings - Fork 2.7k
[WIKI-608] Change the header of the pages to be more generic #7787
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: preview
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import { useCallback, ReactNode } from "react"; | ||
import { observer } from "mobx-react"; | ||
import { ListFilter } from "lucide-react"; | ||
// plane imports | ||
import { useTranslation } from "@plane/i18n"; | ||
import { type TPageFilterProps } from "@plane/types"; | ||
import { Header, EHeaderVariant } from "@plane/ui"; | ||
import { calculateTotalFilters } from "@plane/utils"; | ||
// components | ||
import { FiltersDropdown } from "@/components/issues/issue-layouts/filters"; | ||
// hooks | ||
import { useMember } from "@/hooks/store/use-member"; | ||
// plane web hooks | ||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store"; | ||
// local imports | ||
import { PageAppliedFiltersList } from "../list/applied-filters"; | ||
import { PageFiltersSelection } from "../list/filters"; | ||
import { PageOrderByDropdown } from "../list/order-by"; | ||
import { PageSearchInput } from "../list/search-input"; | ||
|
||
type BasePagesListHeaderRootProps = { | ||
storeType: EPageStoreType; | ||
tabNavigationComponent: ReactNode; | ||
}; | ||
|
||
export const BasePagesListHeaderRoot: React.FC<BasePagesListHeaderRootProps> = observer((props) => { | ||
const { storeType, tabNavigationComponent } = props; | ||
const { t } = useTranslation(); | ||
// store hooks | ||
const { filters, updateFilters, clearAllFilters } = usePageStore(storeType); | ||
const { | ||
workspace: { workspaceMemberIds }, | ||
} = useMember(); | ||
|
||
const handleRemoveFilter = useCallback( | ||
(key: keyof TPageFilterProps, value: string | null) => { | ||
let newValues = filters.filters?.[key]; | ||
|
||
if (key === "favorites") newValues = !!value; | ||
if (Array.isArray(newValues)) { | ||
if (!value) newValues = []; | ||
else newValues = newValues.filter((val) => val !== value); | ||
} | ||
|
||
updateFilters("filters", { [key]: newValues }); | ||
}, | ||
[filters.filters, updateFilters] | ||
); | ||
|
||
const isFiltersApplied = calculateTotalFilters(filters?.filters ?? {}) !== 0; | ||
|
||
return ( | ||
<> | ||
<Header variant={EHeaderVariant.SECONDARY}> | ||
<Header.LeftItem>{tabNavigationComponent}</Header.LeftItem> | ||
<Header.RightItem className="items-center"> | ||
<PageSearchInput | ||
searchQuery={filters.searchQuery} | ||
updateSearchQuery={(val) => updateFilters("searchQuery", val)} | ||
/> | ||
<PageOrderByDropdown | ||
sortBy={filters.sortBy} | ||
sortKey={filters.sortKey} | ||
onChange={(val) => { | ||
if (val.key) updateFilters("sortKey", val.key); | ||
if (val.order) updateFilters("sortBy", val.order); | ||
}} | ||
/> | ||
<FiltersDropdown | ||
icon={<ListFilter className="h-3 w-3" />} | ||
title={t("common.filters")} | ||
placement="bottom-end" | ||
isFiltersApplied={isFiltersApplied} | ||
> | ||
<PageFiltersSelection | ||
filters={filters} | ||
handleFiltersUpdate={updateFilters} | ||
memberIds={workspaceMemberIds ?? undefined} | ||
/> | ||
</FiltersDropdown> | ||
</Header.RightItem> | ||
</Header> | ||
{calculateTotalFilters(filters?.filters ?? {}) !== 0 && ( | ||
<Header variant={EHeaderVariant.TERNARY}> | ||
<PageAppliedFiltersList | ||
appliedFilters={filters.filters ?? {}} | ||
handleClearAllFilters={clearAllFilters} | ||
handleRemoveFilter={handleRemoveFilter} | ||
alwaysAllowEditing | ||
/> | ||
</Header> | ||
)} | ||
</> | ||
); | ||
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,100 +1,27 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { useCallback } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { observer } from "mobx-react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { ListFilter } from "lucide-react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
// plane imports | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { useTranslation } from "@plane/i18n"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { TPageFilterProps, TPageNavigationTabs } from "@plane/types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { Header, EHeaderVariant } from "@plane/ui"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { calculateTotalFilters } from "@plane/utils"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
// components | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { FiltersDropdown } from "@/components/issues/issue-layouts/filters"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
// hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { useMember } from "@/hooks/store/use-member"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { TPageNavigationTabs } from "@plane/types"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
// plane web hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { EPageStoreType, usePageStore } from "@/plane-web/hooks/store"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { EPageStoreType } from "@/plane-web/hooks/store"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
// local imports | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { PageAppliedFiltersList } from "../list/applied-filters"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { PageFiltersSelection } from "../list/filters"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { PageOrderByDropdown } from "../list/order-by"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { PageSearchInput } from "../list/search-input"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { PageTabNavigation } from "../list/tab-navigation"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
import { BasePagesListHeaderRoot } from "./base"; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
type Props = { | ||||||||||||||||||||||||||||||||||||||||||||||||||
pageType: TPageNavigationTabs; | ||||||||||||||||||||||||||||||||||||||||||||||||||
projectId: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||
storeType: EPageStoreType; | ||||||||||||||||||||||||||||||||||||||||||||||||||
workspaceSlug: string; | ||||||||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
export const PagesListHeaderRoot: React.FC<Props> = observer((props) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
const { pageType, projectId, storeType, workspaceSlug } = props; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const { t } = useTranslation(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
// store hooks | ||||||||||||||||||||||||||||||||||||||||||||||||||
const { filters, updateFilters, clearAllFilters } = usePageStore(storeType); | ||||||||||||||||||||||||||||||||||||||||||||||||||
const { | ||||||||||||||||||||||||||||||||||||||||||||||||||
workspace: { workspaceMemberIds }, | ||||||||||||||||||||||||||||||||||||||||||||||||||
} = useMember(); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const handleRemoveFilter = useCallback( | ||||||||||||||||||||||||||||||||||||||||||||||||||
(key: keyof TPageFilterProps, value: string | null) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
let newValues = filters.filters?.[key]; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
if (key === "favorites") newValues = !!value; | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (Array.isArray(newValues)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (!value) newValues = []; | ||||||||||||||||||||||||||||||||||||||||||||||||||
else newValues = newValues.filter((val) => val !== value); | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
updateFilters("filters", { [key]: newValues }); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}, | ||||||||||||||||||||||||||||||||||||||||||||||||||
[filters.filters, updateFilters] | ||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
const isFiltersApplied = calculateTotalFilters(filters?.filters ?? {}) !== 0; | ||||||||||||||||||||||||||||||||||||||||||||||||||
const { pageType, projectId, workspaceSlug } = props; | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
<> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<Header variant={EHeaderVariant.SECONDARY}> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<Header.LeftItem> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<PageTabNavigation workspaceSlug={workspaceSlug} projectId={projectId} pageType={pageType} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</Header.LeftItem> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<Header.RightItem className="items-center"> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<PageSearchInput | ||||||||||||||||||||||||||||||||||||||||||||||||||
searchQuery={filters.searchQuery} | ||||||||||||||||||||||||||||||||||||||||||||||||||
updateSearchQuery={(val) => updateFilters("searchQuery", val)} | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<PageOrderByDropdown | ||||||||||||||||||||||||||||||||||||||||||||||||||
sortBy={filters.sortBy} | ||||||||||||||||||||||||||||||||||||||||||||||||||
sortKey={filters.sortKey} | ||||||||||||||||||||||||||||||||||||||||||||||||||
onChange={(val) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (val.key) updateFilters("sortKey", val.key); | ||||||||||||||||||||||||||||||||||||||||||||||||||
if (val.order) updateFilters("sortBy", val.order); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<FiltersDropdown | ||||||||||||||||||||||||||||||||||||||||||||||||||
icon={<ListFilter className="h-3 w-3" />} | ||||||||||||||||||||||||||||||||||||||||||||||||||
title={t("common.filters")} | ||||||||||||||||||||||||||||||||||||||||||||||||||
placement="bottom-end" | ||||||||||||||||||||||||||||||||||||||||||||||||||
isFiltersApplied={isFiltersApplied} | ||||||||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<PageFiltersSelection | ||||||||||||||||||||||||||||||||||||||||||||||||||
filters={filters} | ||||||||||||||||||||||||||||||||||||||||||||||||||
handleFiltersUpdate={updateFilters} | ||||||||||||||||||||||||||||||||||||||||||||||||||
memberIds={workspaceMemberIds ?? undefined} | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</FiltersDropdown> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</Header.RightItem> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</Header> | ||||||||||||||||||||||||||||||||||||||||||||||||||
{calculateTotalFilters(filters?.filters ?? {}) !== 0 && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
<Header variant={EHeaderVariant.TERNARY}> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<PageAppliedFiltersList | ||||||||||||||||||||||||||||||||||||||||||||||||||
appliedFilters={filters.filters ?? {}} | ||||||||||||||||||||||||||||||||||||||||||||||||||
handleClearAllFilters={clearAllFilters} | ||||||||||||||||||||||||||||||||||||||||||||||||||
handleRemoveFilter={handleRemoveFilter} | ||||||||||||||||||||||||||||||||||||||||||||||||||
alwaysAllowEditing | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
</Header> | ||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||
</> | ||||||||||||||||||||||||||||||||||||||||||||||||||
<BasePagesListHeaderRoot | ||||||||||||||||||||||||||||||||||||||||||||||||||
storeType={EPageStoreType.PROJECT} | ||||||||||||||||||||||||||||||||||||||||||||||||||
tabNavigationComponent={ | ||||||||||||||||||||||||||||||||||||||||||||||||||
<PageTabNavigation workspaceSlug={workspaceSlug} projectId={projectId} pageType={pageType} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+21
to
+25
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainDon’t hard-code PROJECT; thread storeType through to Base Hard-coding ties the “generic” header to project scope and can desync from views using other stores. Accept an optional type Props = {
pageType: TPageNavigationTabs;
projectId: string;
workspaceSlug: string;
+ storeType?: EPageStoreType;
};
export const PagesListHeaderRoot: React.FC<Props> = observer((props) => {
- const { pageType, projectId, workspaceSlug } = props;
+ const { pageType, projectId, workspaceSlug, storeType = EPageStoreType.PROJECT } = props;
return (
<BasePagesListHeaderRoot
- storeType={EPageStoreType.PROJECT}
+ storeType={storeType}
tabNavigationComponent={
<PageTabNavigation workspaceSlug={workspaceSlug} projectId={projectId} pageType={pageType} />
}
/>
);
}); After this change, pass 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "=== repo root ==="
pwd
echo
echo "=== show file if exists: apps/web/core/components/pages/header/root.tsx ==="
if [ -f "apps/web/core/components/pages/header/root.tsx" ]; then
sed -n '1,240p' apps/web/core/components/pages/header/root.tsx
else
echo "MISSING: apps/web/core/components/pages/header/root.tsx"
fi
echo
echo "=== search for related symbols ==="
rg -n --hidden -S 'PagesListHeaderRoot' -g '!*node_modules/*' -C3 || true
rg -n --hidden -S 'BasePagesListHeaderRoot' -g '!*node_modules/*' -C3 || true
rg -n --hidden -S 'EPageStoreType' -g '!*node_modules/*' -C3 || true
rg -n --hidden -S 'PagesListView' -g '!*node_modules/*' -C3 || true
rg -n --hidden -S 'PageTabNavigation' -g '!*node_modules/*' -C3 || true Length of output: 1674 Don't hard-code PROJECT — thread storeType through to Base Hard-coding ties the generic header to project scope and can desync from views using other stores. Accept an optional File: apps/web/core/components/pages/header/root.tsx (around lines 21–25) type Props = {
pageType: TPageNavigationTabs;
projectId: string;
workspaceSlug: string;
+ storeType?: EPageStoreType;
};
export const PagesListHeaderRoot: React.FC<Props> = observer((props) => {
- const { pageType, projectId, workspaceSlug } = props;
+ const { pageType, projectId, workspaceSlug, storeType = EPageStoreType.PROJECT } = props;
return (
<BasePagesListHeaderRoot
- storeType={EPageStoreType.PROJECT}
+ storeType={storeType}
tabNavigationComponent={
<PageTabNavigation workspaceSlug={workspaceSlug} projectId={projectId} pageType={pageType} />
}
/>
);
}); After this change, pass 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||||||||
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -30,12 +30,7 @@ export const PagesListView: React.FC<TPageView> = observer((props) => { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<div className="relative w-full h-full overflow-hidden flex flex-col"> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{/* tab header */} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{isAnyPageAvailable && ( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<PagesListHeaderRoot | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
pageType={pageType} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
projectId={projectId} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
storeType={storeType} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
workspaceSlug={workspaceSlug} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
/> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<PagesListHeaderRoot pageType={pageType} projectId={projectId} workspaceSlug={workspaceSlug} /> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 Verification agent 🧩 Analysis chainHeader store now diverges from view store (PROJECT vs storeType) Header is hard-coded to the PROJECT store via the wrapper, while this view gates and fetches via Apply: - <PagesListHeaderRoot pageType={pageType} projectId={projectId} workspaceSlug={workspaceSlug} />
+ <PagesListHeaderRoot
+ pageType={pageType}
+ projectId={projectId}
+ workspaceSlug={workspaceSlug}
+ storeType={storeType}
+ /> To verify current usages and whether non-PROJECT store types exist: 🏁 Script executed: #!/bin/bash
# Find PagesListView call sites and inspect storeType usage.
rg -nP --type tsx -C3 '<PagesListView\b' | sed -n '1,200p'
rg -nP --type tsx -C3 'storeType\s*=' | sed -n '1,200p' Length of output: 55 🏁 Script executed: #!/bin/bash
set -o pipefail
echo "=== search for PagesListView / PagesListHeaderRoot usages ==="
rg -n --hidden -S '<PagesListView\b' || true
rg -n --hidden -S '<PagesListHeaderRoot\b' || true
echo
echo "=== search for filenames / symbols ==="
rg -n --hidden -S 'pages-list-view|pages-list-header-root|PagesListHeaderRoot|PagesListView' || true
echo
echo "=== show specific file if it exists ==="
if [ -f "apps/web/core/components/pages/pages-list-view.tsx" ]; then
echo "---- apps/web/core/components/pages/pages-list-view.tsx ----"
sed -n '1,240p' apps/web/core/components/pages/pages-list-view.tsx || true
else
echo "file apps/web/core/components/pages/pages-list-view.tsx not found"
fi
echo
echo "=== find files that define PagesListHeaderRoot and print head ==="
files=$(rg -l --hidden -S 'PagesListHeaderRoot' || true)
if [ -n "$files" ]; then
for f in $files; do
echo "---- $f ----"
sed -n '1,240p' "$f" || true
echo
done
else
echo "No files named PagesListHeaderRoot found by rg"
fi
echo
echo "=== search for storeType / StoreType.PROJECT mentions ==="
rg -n --hidden -S 'storeType|StoreType\.PROJECT' || true
echo
echo "=== list files in apps/web/core/components/pages if present ==="
if [ -d "apps/web/core/components/pages" ]; then
ls -la apps/web/core/components/pages || true
else
echo "dir apps/web/core/components/pages not found"
fi Length of output: 40506 Pass storeType through to the header and make the header respect it Header is hard-coded to EPageStoreType.PROJECT while PagesListView fetches/renders by the incoming storeType — this can desync filters/search/sort or hide the header when storeType !== PROJECT. Change both files so header receives and uses the same storeType.
- <PagesListHeaderRoot pageType={pageType} projectId={projectId} workspaceSlug={workspaceSlug} />
+ <PagesListHeaderRoot
+ pageType={pageType}
+ projectId={projectId}
+ workspaceSlug={workspaceSlug}
+ storeType={storeType}
+ />
-type Props = {
- pageType: TPageNavigationTabs;
- projectId: string;
- workspaceSlug: string;
-};
+type Props = {
+ pageType: TPageNavigationTabs;
+ projectId: string;
+ workspaceSlug: string;
+ storeType?: EPageStoreType;
+};
export const PagesListHeaderRoot: React.FC<Props> = observer((props) => {
- const { pageType, projectId, workspaceSlug } = props;
+ const { pageType, projectId, workspaceSlug, storeType = EPageStoreType.PROJECT } = props;
return (
<BasePagesListHeaderRoot
- storeType={EPageStoreType.PROJECT}
+ storeType={storeType}
tabNavigationComponent={
<PageTabNavigation workspaceSlug={workspaceSlug} projectId={projectId} pageType={pageType} />
}
/>
);
}); 📝 Committable suggestion
Suggested change
Suggested change
🤖 Prompt for AI Agents
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
<PagesListMainContent pageType={pageType} storeType={storeType}> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
{children} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Fix favorites removal and improve type safety in handleRemoveFilter
Setting favorites to
false
on removal may leave a redundant key and relies on downstream logic to ignore it. Prefer clearing the key (undefined) and narrow types per-key to avoid boolean/array confusion.📝 Committable suggestion
🤖 Prompt for AI Agents