fix(flags): surface a failed admin toggle instead of swallowing it
FeatureFlagStore.set() was try/finally with no catch. A rejected
PUT /admin/flags/{key} escaped into the `void this.store.set(...)` call site
as an unhandled promise rejection; the finally-block reload then snapped the
control back to its old value. The admin saw a toggle that silently refused
to move, with no error rendered anywhere and nothing in the state.
set() now folds through the existing runSubmit helper and returns
Result<string, void>, reloading either way so the state still reflects the
server. The page awaits it and renders the failure in an app-alert.
Found by the CQRS-light pass (CQ-002/CQ-004) as one of three mutations that
reach the raw ApiClient without producing a Result — the baseline's BL-007
inventory had missed all three.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { Component, computed, inject } from '@angular/core';
|
||||
import { Component, computed, inject, signal } 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';
|
||||
@@ -45,6 +45,9 @@ import { FeatureFlagStore } from '@shared/application/feature-flags.store';
|
||||
} @else if (!canManage()) {
|
||||
<app-alert type="error">{{ deniedText }}</app-alert>
|
||||
} @else {
|
||||
@if (setError(); as e) {
|
||||
<app-alert type="error">{{ e }}</app-alert>
|
||||
}
|
||||
<app-async [data]="store.flags()">
|
||||
<ng-template appAsyncError>
|
||||
<app-alert type="error">{{ failedText }}</app-alert>
|
||||
@@ -89,8 +92,13 @@ export class FeatureFlagsPage {
|
||||
protected enableText = $localize`:@@flags.enable:Aanzetten`;
|
||||
protected disableText = $localize`:@@flags.disable:Uitzetten`;
|
||||
|
||||
protected toggle(key: string, enabled: boolean) {
|
||||
void this.store.set(key, enabled);
|
||||
/** The last failed toggle, so a rejected PUT is visible instead of silently snapping back. */
|
||||
protected setError = signal<string | null>(null);
|
||||
|
||||
protected async toggle(key: string, enabled: boolean) {
|
||||
this.setError.set(null);
|
||||
const r = await this.store.set(key, enabled);
|
||||
if (!r.ok) this.setError.set(r.error);
|
||||
}
|
||||
protected reload() {
|
||||
void this.store.load();
|
||||
|
||||
Reference in New Issue
Block a user