fix(pleno-vue): pin Selvvask accept/reject/ignore button wiring (#287)
## Why The XL Vask Selvvask view (Superuser → Fakturaer → Periode → Selvvask) was silently broken: the orders table never received `allow-review-actions=true`, so Accept / Reject / Ignore / Link / Compare buttons never rendered. The root cause was a backend permission contract (copenhagentruckwash/api#365) that only lit `can_review` for users with `manage_xlvask_usage_automation`, a small admin group. ## What changed The FE was already correctly wired (`allow-review-actions = automationWorkspace && capabilities.can_review`). Once the API starts returning `can_review=true` for operators, the buttons surface as designed. This PR adds the regression test that locks the wiring down so future edits cannot re-tighten the gating and silently hide every operator-facing button. - `tests/unit/superuser-invoices-view.spec.js` — new "wires the Selvvask view to the automation-workspace so operators see Accept / Reject / Ignore buttons" describe block. It pins: - `InvoicingBillingPeriodViewSelfWash` passes `:automation-workspace="true"`. - `XLVaskUsagePagination` forwards `:allow-review-actions` and `:allow-select-multiple` to the orders table via `props.automationWorkspace && capabilities.can_review`. - `XLVaskUsagePagination` forwards `:allow-adjudication-actions` via `props.automationWorkspace && capabilities.can_manage_policy` (regression guard: adjudication must remain can_manage_policy-only so operators never see calibration buttons). - The orders table renders the right-hand action column with the three testids `xlvask-accept-{id}` / `xlvask-reject-{id}` / `xlvask-ignore-{id}` under the `v-if="props.allowReviewActions"` gate. - The AI adjudication row testid pattern is preserved. ## Verification - `npm run test:unit:fast` → 224 files, 1359 tests pass. - `npm run test:unit` (serial batch) → 28 spec files, all 6 batches pass. - `npm run lint` → 0 errors / 0 warnings. - `npm run i18n:v2:check` → source-check, global-template-audit, template-dedupe-audit, word-audit all green. - `npm run build` → built in 2.25s, PWA precache 726 entries. ## Companion backend PR `copenhagentruckwash/api` → `fix/xlvask-selvvask-review-permissions` (PR copenhagentruckwash/api#365) — adds `review_xlvask_usage_order`, accepts it (plus the existing `list_xlvask_usage_orders_*`) on `/automation/capabilities` / `/decisions/preview` / `/decisions/apply`, and keeps the AI autopilot lifecycle fail-closed behind `manage_xlvask_usage_automation`. Co-authored-by: Hermes Agent <agent@truckwash.io>
This commit is contained in:
@@ -619,6 +619,46 @@ describe("Periode tab contract", () => {
|
||||
expect(xlvaskUsageOrdersTableSource).toContain("const { loadList } = usePaginatedListInstance();");
|
||||
});
|
||||
|
||||
it("wires the Selvvask view to the automation-workspace so operators see Accept / Reject / Ignore buttons", () => {
|
||||
// The Selvvask view (Superuser → Fakturaer → Periode → Selvvask) must enable
|
||||
// the automation workspace so the review actions surface in the orders table.
|
||||
expect(periodViewSelfWashSource).toContain(':automation-workspace="true"');
|
||||
|
||||
// The pagination must forward `allow-review-actions` to the orders table using
|
||||
// the per-request capability flag, so operators with can_review=true get the
|
||||
// Accept / Reject / Ignore buttons. The AI-administrator-only flags
|
||||
// (can_dry_run / can_execute / can_manage_policy) must remain on automationWorkspace
|
||||
// directly so an operator without manage_xlvask_usage_automation cannot dry-run or
|
||||
// execute the autopilot pipeline.
|
||||
expect(xlvaskUsagePaginationSource).toContain(
|
||||
':allow-review-actions="props.automationWorkspace && capabilities.can_review"'
|
||||
);
|
||||
expect(xlvaskUsagePaginationSource).toContain(
|
||||
':allow-select-multiple="props.automationWorkspace && capabilities.can_review"'
|
||||
);
|
||||
expect(xlvaskUsagePaginationSource).toContain(
|
||||
':allow-adjudication-actions="props.automationWorkspace && capabilities.can_manage_policy"'
|
||||
);
|
||||
|
||||
// The orders table must render the operator-facing action buttons
|
||||
// (Accept / Reject / Ignore / Audit) inside the right-hand action column,
|
||||
// gated only on `allowReviewActions` (i.e. the API capability, not on
|
||||
// manage_xlvask_usage_automation). This is the contract that lets the
|
||||
// /superuser/invoicing/.../?periodView=self_wash view actually accept and
|
||||
// edit XL Vask washes.
|
||||
expect(xlvaskUsageOrdersTableSource).toContain(
|
||||
'<div v-if="props.allowReviewActions" class="column is-2 xlvask-usage-actions-column">'
|
||||
);
|
||||
expect(xlvaskUsageOrdersTableSource).toContain(":data-testid=\"'xlvask-accept-' + object.id\"");
|
||||
expect(xlvaskUsageOrdersTableSource).toContain(":data-testid=\"'xlvask-reject-' + object.id\"");
|
||||
expect(xlvaskUsageOrdersTableSource).toContain(":data-testid=\"'xlvask-ignore-' + object.id\"");
|
||||
|
||||
// Regression guard: the AI-adjudication row (adjudication) must remain gated
|
||||
// on allowAdjudicationActions (can_manage_policy) so a normal operator never
|
||||
// sees the calibration label buttons.
|
||||
expect(xlvaskUsageOrdersTableSource).toContain(':data-testid="`xlvask-adjudication-${outcome}-${object.id}`"');
|
||||
});
|
||||
|
||||
it("keeps Selvvask usage entries wrapped inside the period content area", () => {
|
||||
expect(xlvaskUsageOrdersTableSource).toContain("xlvask-usage-card-primary");
|
||||
expect(xlvaskUsageOrdersTableSource).toContain("xlvask-usage-card-status");
|
||||
|
||||
Reference in New Issue
Block a user