Persist collapsed inbox groups

This commit is contained in:
Dotta committed 2026-04-14 11:52:02 -05:00
1 parent ab8682d2aa
commit 27c5cde7ad
3 files changed
+58 -2

No files matched your search

+16
View File
@@ -31,6 +31,7 @@ import {
loadInboxFilterPreferences,
loadInboxIssueColumns,
loadInboxWorkItemGroupBy,
loadCollapsedInboxGroupKeys,
loadLastInboxTab,
matchesInboxIssueSearch,
normalizeInboxIssueColumns,
@@ -40,6 +41,7 @@ import {
resolveIssueWorkspaceGroup,
resolveInboxSelectionIndex,
saveInboxFilterPreferences,
saveCollapsedInboxGroupKeys,
saveInboxIssueColumns,
saveInboxWorkItemGroupBy,
saveLastInboxTab,
@@ -1081,6 +1083,20 @@ describe("inbox helpers", () => {
expect(loadInboxWorkItemGroupBy()).toBe("workspace");
});
it("persists collapsed inbox groups per company", () => {
saveCollapsedInboxGroupKeys("company-1", new Set(["workspace:alpha", "workspace:beta"]));
saveCollapsedInboxGroupKeys("company-2", new Set(["type:approval"]));
expect(loadCollapsedInboxGroupKeys("company-1")).toEqual(new Set(["workspace:alpha", "workspace:beta"]));
expect(loadCollapsedInboxGroupKeys("company-2")).toEqual(new Set(["type:approval"]));
});
it("returns empty collapsed inbox groups for missing or invalid storage", () => {
expect(loadCollapsedInboxGroupKeys("company-1")).toEqual(new Set());
localStorage.setItem("paperclip:inbox:collapsed-groups:company-1", JSON.stringify({ nope: true }));
expect(loadCollapsedInboxGroupKeys("company-1")).toEqual(new Set());
});
it("does not reset workspace grouping before experimental settings have loaded", () => {
expect(shouldResetInboxWorkspaceGrouping("workspace", false, false)).toBe(false);
});
+36
View File
@@ -22,6 +22,7 @@ export const INBOX_ISSUE_COLUMNS_KEY = "paperclip:inbox:issue-columns";
export const INBOX_NESTING_KEY = "paperclip:inbox:nesting";
export const INBOX_GROUP_BY_KEY = "paperclip:inbox:group-by";
export const INBOX_FILTER_PREFERENCES_KEY_PREFIX = "paperclip:inbox:filters";
export const INBOX_COLLAPSED_GROUPS_KEY_PREFIX = "paperclip:inbox:collapsed-groups";
export type InboxTab = "mine" | "recent" | "unread" | "all";
export type InboxCategoryFilter =
| "everything"
@@ -164,6 +165,11 @@ function getInboxFilterPreferencesStorageKey(companyId: string | null | undefine
return `${INBOX_FILTER_PREFERENCES_KEY_PREFIX}:${companyId}`;
}
function getInboxCollapsedGroupsStorageKey(companyId: string | null | undefined): string | null {
if (!companyId) return null;
return `${INBOX_COLLAPSED_GROUPS_KEY_PREFIX}:${companyId}`;
}
export function loadInboxFilterPreferences(
companyId: string | null | undefined,
): InboxFilterPreferences {
@@ -218,6 +224,36 @@ export function saveInboxFilterPreferences(
}
}
export function loadCollapsedInboxGroupKeys(
companyId: string | null | undefined,
): Set<string> {
const storageKey = getInboxCollapsedGroupsStorageKey(companyId);
if (!storageKey) return new Set();
try {
const raw = localStorage.getItem(storageKey);
if (!raw) return new Set();
const parsed = JSON.parse(raw);
return new Set(normalizeStringArray(parsed));
} catch {
return new Set();
}
}
export function saveCollapsedInboxGroupKeys(
companyId: string | null | undefined,
groupKeys: ReadonlySet<string>,
) {
const storageKey = getInboxCollapsedGroupsStorageKey(companyId);
if (!storageKey) return;
try {
localStorage.setItem(storageKey, JSON.stringify([...groupKeys]));
} catch {
// Ignore localStorage failures.
}
}
export function loadDismissedInboxAlerts(): Set<string> {
try {
const raw = localStorage.getItem(DISMISSED_KEY);
+6 -2
View File
@@ -110,6 +110,7 @@ import {
groupInboxWorkItems,
isInboxEntityDismissed,
isMineInboxTab,
loadCollapsedInboxGroupKeys,
loadInboxFilterPreferences,
loadInboxIssueColumns,
loadInboxNesting,
@@ -120,6 +121,7 @@ import {
resolveIssueWorkspaceName,
resolveInboxSelectionIndex,
saveInboxFilterPreferences,
saveCollapsedInboxGroupKeys,
saveInboxIssueColumns,
saveInboxNesting,
saveInboxWorkItemGroupBy,
@@ -724,6 +726,7 @@ export function Inbox() {
if (previousSelectedCompanyIdRef.current !== selectedCompanyId) {
previousSelectedCompanyIdRef.current = selectedCompanyId;
setFilterPreferences(loadInboxFilterPreferences(selectedCompanyId));
setCollapsedGroupKeys(loadCollapsedInboxGroupKeys(selectedCompanyId));
}
}, [selectedCompanyId]);
@@ -1107,15 +1110,16 @@ export function Inbox() {
});
}, []);
const [collapsedInboxParents, setCollapsedInboxParents] = useState<Set<string>>(new Set());
const [collapsedGroupKeys, setCollapsedGroupKeys] = useState<Set<string>>(new Set());
const [collapsedGroupKeys, setCollapsedGroupKeys] = useState<Set<string>>(() => loadCollapsedInboxGroupKeys(selectedCompanyId));
const toggleGroupCollapse = useCallback((groupKey: string) => {
setCollapsedGroupKeys((prev) => {
const next = new Set(prev);
if (next.has(groupKey)) next.delete(groupKey);
else next.add(groupKey);
saveCollapsedInboxGroupKeys(selectedCompanyId, next);
return next;
});
}, []);
}, [selectedCompanyId]);
const groupedSections = useMemo<InboxGroupedSection[]>(() => [
...buildGroupedInboxSections(effectiveWorkItems, groupBy, nestingEnabled, inboxWorkspaceGrouping),
...buildGroupedInboxSections(