mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-28 20:21:50 +01:00
Persist collapsed inbox groups
This commit is contained in:
1 parent
ab8682d2aa
commit
27c5cde7ad
3 files changed
+58
-2
No files matched your search
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in new issue
Block a user