dorfteich/apps/web/src/layout/SidebarViewSetting.tsx
Claude Fable 5 15184876bd
Some checks failed
CD / Deploy to Test (push) Blocked by required conditions
CD / Smoke tests against Test (push) Blocked by required conditions
CD / Promote to Int (push) Blocked by required conditions
CI / Auth e2e pack (push) Blocked by required conditions
CI / Import/export fidelity gate (push) Blocked by required conditions
CI / Build container images (push) Blocked by required conditions
CD / Build and push images (push) Has been cancelled
CI / Lint, typecheck, test (push) Has been cancelled
Sidebar folder view, label view, and the view toggle (#108)
The sidebar now presents pages as a collapsible tree built from parentId
(folder view) or grouped under the hierarchical label tree (label view,
read-only; multi-label pages appear under each label, untagged ones in
an 'unlabeled' group). The pond owner sets the default via a new
sidebarView pond setting (PATCH-merged like the other keys); every user
can override it locally (ui.sidebar.view.<pondId>), and the toggle sits
above the page list. Collapse state persists per pond.

New pages created while a page is open become its children — the inline
form says so and sends parentId. Reordering (buttons and drag-between)
now operates within one sibling group; the label filter stays a
folder-view feature and falls back to the flat list while active, so
the filtered order is never mistaken for a partial tree.

SidebarContent is keyed by pond id so the per-pond localStorage hooks
mount with the right key. e2e hooks (.sidebar__pages, .sidebar__page,
reorder buttons) kept; reorder/labels/content packs green locally, plus
a live smoke of nesting, collapse persistence, and both views.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 10:17:36 +02:00

62 lines
1.9 KiB
TypeScript

import type { SidebarViewMode } from '@dorfteich/shared';
import { SIDEBAR_VIEW_MODES } from '@dorfteich/shared';
import { useQueryClient } from '@tanstack/react-query';
import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FormError, FormSuccess } from '../components/forms';
import { apiPatch } from '../lib/api';
/**
* The pond's default sidebar view (issue #108): folders (page tree) or
* labels. Owner-set; every member can still override it locally via the
* sidebar toggle. Rides the generic pond PATCH like CommentPolicySetting.
*/
export function SidebarViewSetting({
pondId,
pondSlug,
value,
}: {
pondId: string;
pondSlug: string;
value: SidebarViewMode;
}): React.JSX.Element {
const { t } = useTranslation();
const queryClient = useQueryClient();
const [error, setError] = useState<unknown>(null);
const [saved, setSaved] = useState(false);
const save = async (view: SidebarViewMode): Promise<void> => {
setError(null);
setSaved(false);
try {
await apiPatch(`/ponds/${pondId}`, { sidebarView: view });
await queryClient.invalidateQueries({ queryKey: ['pond', pondSlug] });
setSaved(true);
} catch (err) {
setError(err);
}
};
return (
<div className="sidebar-view-setting">
<FormError error={error} />
<p className="sidebar-view-setting__hint">{t('layout.sidebar.view.defaultHint')}</p>
<label>
{t('layout.sidebar.view.defaultLabel')}{' '}
<select
value={value}
onChange={(event) => void save(event.target.value as SidebarViewMode)}
>
{SIDEBAR_VIEW_MODES.map((mode) => (
<option key={mode} value={mode}>
{t(`layout.sidebar.view.${mode}`)}
</option>
))}
</select>
</label>
{saved && <FormSuccess message={t('layout.sidebar.view.saved')} />}
</div>
);
}