feat(WP-67): merge behandelportal into this repo as a monorepo
Restructures into apps/ssp + apps/behandelportal (two Angular projects) plus libs/shared + libs/beheer (cross-app libraries), replacing WP-61's separate sibling repo. That split had already produced real drift: a hand-vendored copy of the backend's OpenAPI doc, a shared/ui+layout tree forked and silently diverging (7 files), and beheer + the styles.scss token bridge duplicated byte-for-byte across both repos. - git mv the SSP's src/app/* into apps/ssp/; fold shared/, beheer/, environments/, the Storybook docs/*.mdx, and styles.scss into libs/shared + libs/beheer (all confirmed identical between the two repos before merging). auth stays deliberately duplicated per ADR-0002 (actor-specific, expected to diverge) - amended there. - One generated API client (libs/shared), no more vendored swagger.json. - .dependency-cruiser split into a base factory + one config per app, and Storybook into .storybook-ssp/.storybook-behandelportal - both forced by the @auth/* alias resolving to different directories per app. - SiteHeaderComponent/ShellComponent gained HEADER_NAV_ITEMS/ HEADER_ADMIN_LINKS/DEBUG_PANEL injection tokens so each app supplies its own nav/admin-links/dev-panel instead of one being hardcoded. - CLAUDE.md, ARCHITECTURE.md, dependencies.md, and ADR-0002 updated; WP-67 backlog entry documents the full decision trail. npm run ci green (lint, dep:check x2, 360 tests across ssp/ behandelportal/shared/beheer, both localized builds, backend tests, snippet + api-client drift); both dev servers, both Storybook instances, and docker compose verified working. The old sibling repo (/home/eho/repos/behandelportal) is left untouched, not deleted. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
import { Component, computed, input, output } from '@angular/core';
|
||||
import { RichTextBlock } from '@shared/kernel/rich-text';
|
||||
import {
|
||||
RichTextEditorComponent,
|
||||
PlaceholderOption,
|
||||
} from '@shared/ui/rich-text-editor/rich-text-editor.component';
|
||||
import { ButtonComponent } from '@shared/ui/button/button.component';
|
||||
import { LetterBlock } from '@brief/domain/brief';
|
||||
|
||||
/** Molecule: one block in a section — its editor plus provenance + block controls.
|
||||
Presentational: emits content/remove/move events; the section maps them to messages. */
|
||||
@Component({
|
||||
selector: 'app-letter-block',
|
||||
imports: [RichTextEditorComponent, ButtonComponent],
|
||||
styles: [
|
||||
`
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
.block {
|
||||
border-inline-start: var(--rhc-border-width-lg) solid var(--rhc-color-border-subtle);
|
||||
padding-inline-start: var(--rhc-space-max-md);
|
||||
}
|
||||
.meta {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: var(--rhc-space-max-md);
|
||||
margin-block-end: var(--rhc-space-max-sm);
|
||||
}
|
||||
.controls {
|
||||
display: flex;
|
||||
gap: var(--rhc-space-max-sm);
|
||||
}
|
||||
`,
|
||||
],
|
||||
template: `
|
||||
<div class="block">
|
||||
<div class="meta">
|
||||
<span class="app-text-subtle">{{ provenance() }}</span>
|
||||
@if (editable()) {
|
||||
<span class="controls">
|
||||
<app-button variant="subtle" (click)="moved.emit(-1)" i18n="@@brief.block.moveUp"
|
||||
>Omhoog</app-button
|
||||
>
|
||||
<app-button variant="subtle" (click)="moved.emit(1)" i18n="@@brief.block.moveDown"
|
||||
>Omlaag</app-button
|
||||
>
|
||||
<app-button variant="subtle" (click)="removed.emit()" i18n="@@brief.block.remove"
|
||||
>Verwijderen</app-button
|
||||
>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
<app-rich-text-editor
|
||||
[content]="block().content"
|
||||
[placeholders]="placeholders()"
|
||||
[editable]="editable()"
|
||||
(contentChanged)="contentChanged.emit($event)"
|
||||
/>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
export class LetterBlockComponent {
|
||||
block = input.required<LetterBlock>();
|
||||
placeholders = input<readonly PlaceholderOption[]>([]);
|
||||
editable = input(false);
|
||||
contentChanged = output<RichTextBlock>();
|
||||
removed = output<void>();
|
||||
moved = output<-1 | 1>();
|
||||
|
||||
protected provenance = computed(() => {
|
||||
const b = this.block();
|
||||
if (b.type === 'freeText') return $localize`:@@brief.provenance.free:Vrije tekst`;
|
||||
return b.edited
|
||||
? $localize`:@@brief.provenance.edited:Aangepaste standaardtekst`
|
||||
: $localize`:@@brief.provenance.standard:Standaardtekst`;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import type { Meta, StoryObj } from '@storybook/angular';
|
||||
import { LetterBlock } from '@brief/domain/brief';
|
||||
import { LetterBlockComponent } from './letter-block.component';
|
||||
|
||||
const passageBlock: LetterBlock = {
|
||||
type: 'passage',
|
||||
blockId: 'local-1',
|
||||
sourcePassageId: 'p1',
|
||||
sourceVersion: 1,
|
||||
edited: false,
|
||||
content: { paragraphs: [{ nodes: [{ type: 'text', text: 'Geachte heer/mevrouw,' }] }] },
|
||||
};
|
||||
|
||||
const freeTextBlock: LetterBlock = {
|
||||
type: 'freeText',
|
||||
blockId: 'local-2',
|
||||
content: {
|
||||
paragraphs: [
|
||||
{
|
||||
nodes: [
|
||||
{ type: 'text', text: 'Wij hebben besloten om reden ' },
|
||||
{ type: 'placeholder', key: 'reden_besluit' },
|
||||
{ type: 'text', text: '.' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
const placeholders = [{ key: 'reden_besluit', label: 'Reden besluit' }];
|
||||
|
||||
const meta: Meta<LetterBlockComponent> = {
|
||||
title: 'Domein/Brief/Letter Block',
|
||||
component: LetterBlockComponent,
|
||||
args: {
|
||||
block: passageBlock,
|
||||
placeholders,
|
||||
contentChanged: () => {},
|
||||
removed: () => {},
|
||||
moved: () => {},
|
||||
},
|
||||
};
|
||||
export default meta;
|
||||
type Story = StoryObj<LetterBlockComponent>;
|
||||
|
||||
export const ReadOnlyPassage: Story = { args: { editable: false } };
|
||||
export const EditableFreeText: Story = { args: { block: freeTextBlock, editable: true } };
|
||||
Reference in New Issue
Block a user