Skip to content

feat(manifest): quick-filter tabs + "link" widget + built-in date formatters + readOnly + pages[].permission (closes #224)#226

Merged
rubenvdlinde merged 1 commit into
betafrom
feat/manifest-index-followups
May 13, 2026
Merged

feat(manifest): quick-filter tabs + "link" widget + built-in date formatters + readOnly + pages[].permission (closes #224)#226
rubenvdlinde merged 1 commit into
betafrom
feat/manifest-index-followups

Conversation

@rubenvdlinde
Copy link
Copy Markdown
Contributor

What

§1–7 of the manifest-index-page-followups opsx change — closes #224. A tight bundle of small additions surfaced by the fleet conversion wave (pipelinq #351, procest #436, scholiq #71, zaakafhandelapp #203, softwarecatalog #231, decidesk #197).

1. Quick-filter tabs (config.quickFilters) — REQ-MIPFU-1

type:"index" pages gain config.quickFilters: [{label, filter, default?, icon?}]. CnIndexPage renders the new CnQuickFilterBar above the table; the active tab's filter is merged into the useListView fetch after config.filter (so the tab wins on a colliding key) and before the user's activeFilters (which still narrow within the active tab). @route.<name> resolution parity with config.filter. Closes procest's filter-tabs gap (Voorstellen's Concept/InBehandeling/Afgerond tabs were dropped in the conversion — config.filter is fixed, not switchable; this is the missing piece).

2. Built-in widget:"link" — REQ-MIPFU-2

CnCellRenderer resolves widget:"link" to:

  • <router-link> when widgetProps.route is set (a manifest page id; default {id: row[rowKey]} param map; override via widgetProps.params: {routeParam: "rowField"})
  • <a target="_blank" rel="noopener"> when widgetProps.href is set (with {key} placeholder substitution from the row)
  • plain-text fallback + once-per-session console.warn (silence with widgetProps.fallback:"silent")

Consumer-registered link still wins. Resolves decidesk's Decisions.title widget:"link" no-op.

3. Built-in "date" / "datetime" / "relative-time" formatters — REQ-MIPFU-3

CnAppRoot provides cnFormatters as {...BUILT_IN_FORMATTERS, ...props.formatters} so consumer overrides win. All three are safe against null / empty / non-parseable inputs (Intl.DateTimeFormat / Intl.RelativeTimeFormat; return '' or the original value, no throw). Resolves decidesk's Decisions.decisionDate formatter:"date" no-op.

4. config.readOnly:true shorthand — REQ-MIPFU-4

CnPageRenderer expands config.readOnly:true on a type:"index" page to selectable:false, showAdd:false, showFormDialog:false, showEditAction:false, showCopyAction:false, showDeleteAction:false, showMassImport:false, showMassCopy:false, showMassDelete:false — merged under explicit config.* props so an explicit config.showAdd:true still wins. Replaces the 9-line CRUD-off boilerplate scholiq #71 had to spell out for its read-only AssessmentResults / LearningPlanEvaluations / Signatures pages.

5. pages[].permission — REQ-MIPFU-5

$defs.page (additionalProperties:false) now allows an optional permission: <string>. Schema-only — no runtime gating (consumers filter the manifest themselves if they want enforcement). Resolves procest's WmsLayers* / LhsMatrices* validation errors.

6. handler:"emit" — REQ-MIPFU-6

Verified the existing CnIndexPage.mergedActions already strips the handler key for "emit" (and unknown / non-resolvable handlers) → CnRowActions doesn't see a function → page emits @action only. No code change needed; spec scenario updated to match the existing {action: <label>, row: <item>} payload shape.

Verification

  • npm test91 suites / 1294 tests green (no regression; +27 new — formatters 12, CnPageRenderer readOnly 3, CnCellRenderer link 5, CnIndexPage quickFilters 7)
  • npm run lint0 errors (was 2 from the new <a> attribute wrap; fixed). 306 warnings are all pre-existing.
  • npm run build — ✓ (dist/nextcloud-vue.esm.js + dist/nextcloud-vue.cjs.js created)
  • npm run check:docs89/89 component docs cover their props and slots (added CnQuickFilterBar; rowKey + quickFilters props documented)
  • openspec validate manifest-index-page-followups — valid

opsx

openspec/changes/manifest-index-page-followups/ — proposal, design, specs (REQ-MIPFU-1…6), tasks all included.

Closes #224.

🤖 Generated with Claude Code

…matters + readOnly shorthand + pages[].permission

§1–7 of the `manifest-index-page-followups` opsx change — a tight
bundle of small additions surfaced by the fleet conversion wave
(pipelinq #351, procest #436, scholiq #71, zaakafhandelapp #203,
softwarecatalog #231, decidesk #197).

- **Quick-filter tabs** (REQ-MIPFU-1): `type:"index"` pages gain
  `config.quickFilters: [{label, filter, default?, icon?}]`. CnIndexPage
  renders the new `CnQuickFilterBar` above the table; the active tab's
  `filter` is merged into the useListView fetch AFTER `config.filter`
  (so the tab wins) and BEFORE the user's `activeFilters` (which still
  narrow within the active tab). `@route.<name>` resolution parity with
  `config.filter`. Closes procest's filter-tabs gap (Voorstellen tabs
  were dropped in the conversion — `config.filter` is fixed, not
  switchable).
- **Built-in `widget:"link"`** (REQ-MIPFU-2): `CnCellRenderer` resolves
  `widget:"link"` to a `<router-link>` (when `widgetProps.route` is a
  manifest page id; default `id` param from the new `rowKey` prop;
  override via `widgetProps.params: {routeParam: "rowField"}`) /
  external `<a target="_blank">` (when `widgetProps.href` is set, with
  `{key}` placeholder substitution from the row) / plain-text fallback
  + once-per-session `console.warn` (silence with
  `widgetProps.fallback:"silent"`). Consumer-registered `link` still
  wins. Resolves decidesk's `Decisions.title widget:"link"` no-op.
- **Built-in `"date"` / `"datetime"` / `"relative-time"` formatters**
  (REQ-MIPFU-3): `CnAppRoot` provides `cnFormatters` as
  `{...BUILT_IN_FORMATTERS, ...props.formatters}` so consumer
  overrides win. All three are safe against null/empty/non-parseable
  inputs (`Intl.DateTimeFormat` / `Intl.RelativeTimeFormat`; return ''
  or original value, no throw). Resolves decidesk's
  `Decisions.decisionDate formatter:"date"` no-op.
- **`config.readOnly:true` shorthand** (REQ-MIPFU-4): `CnPageRenderer`
  expands `config.readOnly:true` on a `type:"index"` page to
  `selectable:false, showAdd:false, showFormDialog:false,
  showEditAction:false, showCopyAction:false, showDeleteAction:false,
  showMassImport:false, showMassCopy:false, showMassDelete:false` —
  merged UNDER explicit `config.*` props so an explicit
  `config.showAdd:true` still wins. Replaces the 9-line CRUD-off
  boilerplate scholiq#71 had to spell out for its read-only pages.
- **`pages[].permission`** (REQ-MIPFU-5): the page schema's $defs.page
  (additionalProperties:false) now allows an optional
  `permission: <string>`. Schema-only — no runtime gating (consumers
  filter the manifest themselves if they want enforcement). Resolves
  procest's WmsLayers* / LhsMatrices* validation errors.
- **`handler:"emit"`** (REQ-MIPFU-6): verified the existing
  `CnIndexPage.mergedActions` already strips the `handler` key for
  `"emit"` so the page emits `@action` only. No code change —
  spec scenario updated to match the existing payload shape
  (`{action: <label>, row: <item>}`).

Verification: 91 suites / 1294 tests green (27 new); npm run lint —
0 errors (was 2; fixed); npm run build ✓; npm run check:docs —
89/89 components; openspec validate passes.
@rubenvdlinde rubenvdlinde merged commit 4471e80 into beta May 13, 2026
1 of 3 checks passed
@rubenvdlinde rubenvdlinde deleted the feat/manifest-index-followups branch May 13, 2026 05:51
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.0.0-beta.42 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant