Files
atomic-design-poc/src/app/beheer/ui/stamdata.page.ts
T
ehoandClaude Opus 4.8 5761b13dd2 style: format the repo with prettier (green format:check)
`npm run format:check` (a CI gate) had drifted red across 44 files — pre-existing
files plus recently-added ones committed without formatting. Ran `prettier --write .`;
no logic changes. Also regenerates documentation.json (compodoc reflects the reformatted
component sources).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-21 17:20:42 +02:00

90 lines
3.8 KiB
TypeScript

import { Component, computed, effect, inject } from '@angular/core';
import { PageShellComponent } from '@shared/layout/page-shell/page-shell.component';
import { AlertComponent } from '@shared/ui/alert/alert.component';
import { ButtonComponent } from '@shared/ui/button/button.component';
import { ASYNC } from '@shared/ui/async/async.component';
import { AccessStore } from '@shared/application/access.store';
import { StamdataStore } from '@beheer/application/stamdata.store';
import { StamdataTableEditorComponent } from '@beheer/ui/stamdata-table-editor/stamdata-table-editor.component';
/**
* Page: thin container for the stamdata maintenance editor (ADR-0004). Deny-by-default
* capability gate (`stamdata:edit`) — a denial alert for non-admins, the generic grid for
* admins. Loads once the capability resolves; wires store commands to the organism.
*/
@Component({
selector: 'app-stamdata-page',
imports: [
PageShellComponent,
AlertComponent,
ButtonComponent,
...ASYNC,
StamdataTableEditorComponent,
],
template: `
<app-page-shell [heading]="heading" [intro]="intro" backLink="/dashboard">
@if (!access.ready()) {
<!-- wait for /me before deciding — avoids flashing the denial to an admin -->
} @else if (!canEdit()) {
<app-alert type="error">{{ deniedText }}</app-alert>
} @else {
<app-async [data]="store.remoteData()">
<ng-template appAsyncError>
<app-alert type="error">{{ failedText }}</app-alert>
<app-button variant="secondary" (click)="reload()">{{ retryText }}</app-button>
</ng-template>
<ng-template appAsyncLoaded>
@if (store.table(); as table) {
<app-stamdata-table-editor
[table]="table"
[rows]="store.rows()"
[errors]="store.errors()"
[counts]="store.counts()"
[previewDate]="store.previewDate()"
[canDownload]="store.canDownload()"
[tables]="store.tables()"
[selectedTableId]="store.selectedTableId()"
(selectTable)="store.selectTable($event)"
(cellEdited)="store.editCell($event.row, $event.column, $event.value)"
(rowAdded)="store.addRow()"
(rowRemoved)="store.removeRow($event)"
(previewDateChanged)="store.setPreviewDate($event)"
(download)="store.download()"
/>
}
</ng-template>
</app-async>
}
</app-page-shell>
`,
})
export class StamdataPage {
protected store = inject(StamdataStore);
protected access = inject(AccessStore);
protected canEdit = computed(() => this.access.can('stamdata:edit'));
protected heading = $localize`:@@beheer.page.heading:Stamdata onderhouden`;
protected intro = $localize`:@@beheer.page.intro:Beheer de business-tabellen die de registratie stuurt. Wijzigingen worden als JSON gedownload en via een pull request toegepast; de build blijft de bewaker.`;
protected deniedText = $localize`:@@beheer.page.denied:U hebt geen rechten om stamdata te onderhouden.`;
protected failedText = $localize`:@@beheer.page.failed:De stamdata kon niet worden geladen.`;
protected retryText = $localize`:@@beheer.page.retry:Opnieuw proberen`;
private loadRequested = false;
constructor() {
// Load once the capability resolves to `allowed` (a 403 GET would be wasted otherwise).
// Depends only on canEdit() + a plain flag — never on the store model, so dispatching
// `Loading` inside load() can't retrigger this effect (the WP-26 runaway-loop lesson).
effect(() => {
if (this.canEdit() && !this.loadRequested) {
this.loadRequested = true;
void this.store.load();
}
});
}
protected reload() {
void this.store.load();
}
}