feat(geschichte): wire StoryDocumentPanel into the story editor sidebar (#795)
GeschichteSidebar gains optional geschichteId/items props and renders the panel only when geschichteId is set. GeschichteEditor derives both from its existing GeschichteView prop — null on /geschichten/new, so the panel stays hidden there (create-then-edit, same as journeys). JourneyEditor's sidebar call site is untouched, so journeys never show the panel. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -234,7 +234,12 @@ function exec(action: () => void) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Sidebar -->
|
<!-- Sidebar -->
|
||||||
<GeschichteSidebar status={status} bind:selectedPersons={selectedPersons} />
|
<GeschichteSidebar
|
||||||
|
status={status}
|
||||||
|
bind:selectedPersons={selectedPersons}
|
||||||
|
geschichteId={geschichte?.id}
|
||||||
|
items={geschichte?.items ?? []}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Save bar -->
|
<!-- Save bar -->
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { afterEach, describe, expect, it, vi } from 'vitest';
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||||
import { cleanup, render } from 'vitest-browser-svelte';
|
import { cleanup, render } from 'vitest-browser-svelte';
|
||||||
import { page, userEvent } from 'vitest/browser';
|
import { page, userEvent } from 'vitest/browser';
|
||||||
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
import GeschichteEditor from './GeschichteEditor.svelte';
|
import GeschichteEditor from './GeschichteEditor.svelte';
|
||||||
|
|
||||||
const personFactory = (id: string, displayName: string) => ({
|
const personFactory = (id: string, displayName: string) => ({
|
||||||
@@ -171,3 +172,36 @@ describe('GeschichteEditor — onSubmit payload', () => {
|
|||||||
expect(payload.personIds).toEqual(['p1']);
|
expect(payload.personIds).toEqual(['p1']);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('GeschichteEditor — story document panel (#795)', () => {
|
||||||
|
it('shows the document panel with the story items when editing an existing story', async () => {
|
||||||
|
render(GeschichteEditor, {
|
||||||
|
geschichte: draftFactory({
|
||||||
|
items: [
|
||||||
|
{
|
||||||
|
id: 'i1',
|
||||||
|
position: 10,
|
||||||
|
document: {
|
||||||
|
id: 'd1',
|
||||||
|
title: 'Brief von Eugenie',
|
||||||
|
datePrecision: 'DAY' as const,
|
||||||
|
receiverCount: 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
onSubmit: vi.fn().mockResolvedValue(undefined)
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect
|
||||||
|
.element(page.getByRole('heading', { name: m.geschichte_documents_heading() }))
|
||||||
|
.toBeInTheDocument();
|
||||||
|
await expect.element(page.getByText('Brief von Eugenie')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('hides the document panel when no geschichte is set (creation flow)', async () => {
|
||||||
|
render(GeschichteEditor, { onSubmit: vi.fn() });
|
||||||
|
|
||||||
|
expect(document.body.textContent).not.toContain(m.geschichte_documents_heading());
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -1,14 +1,26 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import type { components } from '$lib/generated/api';
|
||||||
import { m } from '$lib/paraglide/messages.js';
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
import PersonMultiSelect from '$lib/person/PersonMultiSelect.svelte';
|
import PersonMultiSelect from '$lib/person/PersonMultiSelect.svelte';
|
||||||
import type { PersonOption } from '$lib/person/personOption';
|
import type { PersonOption } from '$lib/person/personOption';
|
||||||
|
import StoryDocumentPanel from './StoryDocumentPanel.svelte';
|
||||||
|
|
||||||
|
type JourneyItemView = components['schemas']['JourneyItemView'];
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
status: 'DRAFT' | 'PUBLISHED';
|
status: 'DRAFT' | 'PUBLISHED';
|
||||||
selectedPersons: PersonOption[];
|
selectedPersons: PersonOption[];
|
||||||
|
/** When set, the story document panel is rendered (STORY edit only). */
|
||||||
|
geschichteId?: string;
|
||||||
|
items?: JourneyItemView[];
|
||||||
}
|
}
|
||||||
|
|
||||||
let { status, selectedPersons = $bindable() }: Props = $props();
|
let {
|
||||||
|
status,
|
||||||
|
selectedPersons = $bindable(),
|
||||||
|
geschichteId = undefined,
|
||||||
|
items = []
|
||||||
|
}: Props = $props();
|
||||||
|
|
||||||
const isDraft = $derived(status === 'DRAFT');
|
const isDraft = $derived(status === 'DRAFT');
|
||||||
</script>
|
</script>
|
||||||
@@ -62,4 +74,9 @@ const isDraft = $derived(status === 'DRAFT');
|
|||||||
<PersonMultiSelect bind:selectedPersons={selectedPersons} />
|
<PersonMultiSelect bind:selectedPersons={selectedPersons} />
|
||||||
</section>
|
</section>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<!-- Documents section — STORY edit only; journeys manage items in the editor column -->
|
||||||
|
{#if geschichteId}
|
||||||
|
<StoryDocumentPanel geschichteId={geschichteId} items={items} />
|
||||||
|
{/if}
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
40
frontend/src/lib/geschichte/GeschichteSidebar.svelte.spec.ts
Normal file
40
frontend/src/lib/geschichte/GeschichteSidebar.svelte.spec.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
import { afterEach, describe, expect, it } from 'vitest';
|
||||||
|
import { cleanup, render } from 'vitest-browser-svelte';
|
||||||
|
import { page } from 'vitest/browser';
|
||||||
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
|
import GeschichteSidebar from './GeschichteSidebar.svelte';
|
||||||
|
|
||||||
|
const item = {
|
||||||
|
id: 'i1',
|
||||||
|
position: 10,
|
||||||
|
document: {
|
||||||
|
id: 'd1',
|
||||||
|
title: 'Brief von Eugenie',
|
||||||
|
datePrecision: 'DAY' as const,
|
||||||
|
receiverCount: 0
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => cleanup());
|
||||||
|
|
||||||
|
describe('GeschichteSidebar — document panel contract (#795)', () => {
|
||||||
|
it('renders the document panel when geschichteId and items are provided', async () => {
|
||||||
|
render(GeschichteSidebar, {
|
||||||
|
status: 'DRAFT',
|
||||||
|
selectedPersons: [],
|
||||||
|
geschichteId: 'g1',
|
||||||
|
items: [item]
|
||||||
|
});
|
||||||
|
|
||||||
|
await expect
|
||||||
|
.element(page.getByRole('heading', { name: m.geschichte_documents_heading() }))
|
||||||
|
.toBeInTheDocument();
|
||||||
|
await expect.element(page.getByText('Brief von Eugenie')).toBeInTheDocument();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('does not render the document panel without geschichteId', async () => {
|
||||||
|
render(GeschichteSidebar, { status: 'DRAFT', selectedPersons: [] });
|
||||||
|
|
||||||
|
expect(document.body.textContent).not.toContain(m.geschichte_documents_heading());
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
||||||
|
import { cleanup, render } from 'vitest-browser-svelte';
|
||||||
|
import { m } from '$lib/paraglide/messages.js';
|
||||||
|
|
||||||
|
vi.mock('$app/navigation', () => ({ beforeNavigate: vi.fn(), goto: vi.fn() }));
|
||||||
|
import StoryCreate from './StoryCreate.svelte';
|
||||||
|
|
||||||
|
afterEach(() => cleanup());
|
||||||
|
|
||||||
|
describe('StoryCreate — document panel guard (#795)', () => {
|
||||||
|
it('renders without the document panel — documents attach after the first save', async () => {
|
||||||
|
render(StoryCreate, { initialPersons: [] });
|
||||||
|
|
||||||
|
expect(document.body.textContent).not.toContain(m.geschichte_documents_heading());
|
||||||
|
});
|
||||||
|
});
|
||||||
Reference in New Issue
Block a user