Skip to content

feat(dashboard): give stackiq the KPI tiles it never had - #892

Merged
rubenvdlinde merged 1 commit into
developmentfrom
feat/stackiq-dashboard-kpis
Aug 31, 2026
Merged

feat(dashboard): give stackiq the KPI tiles it never had#892
rubenvdlinde merged 1 commit into
developmentfrom
feat/stackiq-dashboard-kpis

Conversation

@rubenvdlinde

Copy link
Copy Markdown
Contributor

Stackiq was the one fleet dashboard with no KPI cards at all. Not a rendering fault: the page was type:"custom" rendering a 675-line hand-written view whose entire widget list was an info box and two object-statistics tables. The app's five manifest KPI widgets all sit on detail pages, never on the dashboard.

What changed

The page is now type:"dashboard" with four declarative stat widgets — Organisaties, Modules, Diensten, Contracten — counted by OpenRegister through @resolve:voorzieningen_register, the same register/schema pairs every other page in this manifest already uses.

The non-KPI content is preserved exactly: the info box and both tables move to src/components/CatalogPanels.vue (template restructured, script untouched) and mount as the catalog-panels widget.

Two things worth carrying forward

1. A dashboard widget TYPE resolves against the LIBRARY's catalog (registerDashboardWidget / getWidgetTypeEntry) — not the app's registry prop, and not the page's slots map; both of those are for page components and slot overrides. An unregistered type renders "Widget not available" and logs nothing, so it looks exactly like a wiring mistake.

2. eslint-suppressions.json is keyed by FILE PATH. Renaming a suppressed file orphans its entries, and --prune-suppressions then deletes them, so every previously-suppressed error surfaces at once — that briefly took this repo from eslint exit 0 to 12 errors. The entry is moved to the new path deliberately, minus two suppressions the rename genuinely fixed: vue/multi-word-component-names (Dashboard → CatalogPanels) and an unused arg (route_route, docblock updated).

Verification

Built and checked against the published @conduction/nextcloud-vue (USE_LOCAL_LIB=false).

  • Four cards render in the canonical horizontal white card, 0 grey, no "Widget not available".
  • The info box and both statistics tables still render.
  • eslint src exits 0, matching the pre-change baseline (warnings 219 → 217); webpack compiles.

⚠️ The tiles read 0/0/0/0, and that is correct. The statistics tables beside them independently report Organization 0, Service 0, Contract 0 in this environment — so the tiles agree with the tables rather than reporting a confident zero on a failed fetch. Only BIO measure (5) and Usage (3) hold data here.

Stackiq's dashboard was the one fleet dashboard with no KPI cards at all.
Not a rendering fault: the page was type:"custom" rendering a 675-line
hand-written view whose entire widget list was an info box and two
object-statistics tables. The app's five manifest KPI widgets all sit on
detail pages, never on the dashboard.

The page is now type:"dashboard" with four declarative "stat" widgets --
Organisaties, Modules, Diensten, Contracten -- counted by OpenRegister
through @resolve:voorzieningen_register, the same register/schema pairs
every other page in this manifest already uses.

The non-KPI content is preserved exactly. The info box and both tables
move to src/components/CatalogPanels.vue (template restructured, script
untouched) and mount as the "catalog-panels" widget.

Worth knowing for the next app:

1. A dashboard widget TYPE resolves against the LIBRARY's widget catalog
   (registerDashboardWidget / getWidgetTypeEntry), not the app's registry
   prop and not the page's slots map -- both of those are for page
   components and slot overrides. An unregistered type renders "Widget
   not available" and logs nothing, so it looks exactly like a wiring
   mistake.

2. eslint-suppressions.json is keyed by FILE PATH. Renaming a suppressed
   file orphans its entries, and --prune-suppressions then deletes them,
   so every previously-suppressed error surfaces at once. The entry moved
   to the new path deliberately, minus two suppressions the rename
   genuinely fixed: vue/multi-word-component-names (Dashboard ->
   CatalogPanels) and an unused arg (route -> _route, docblock updated).

Verified in the browser against the published @conduction/nextcloud-vue
(USE_LOCAL_LIB=false): four cards render in the canonical horizontal
white card, zero grey, no "Widget not available", the info box and both
tables still render. The tiles read 0/0/0/0 and that is CORRECT -- the
statistics tables beside them independently report Organization 0,
Service 0, Contract 0 in this environment, so the tiles agree with the
tables rather than reporting a confident zero on a failed fetch.

eslint exits 0, matching the pre-change baseline; webpack compiles.
@rubenvdlinde
rubenvdlinde merged commit 26d1854 into development Aug 31, 2026
34 of 35 checks passed
@rubenvdlinde
rubenvdlinde deleted the feat/stackiq-dashboard-kpis branch August 31, 2026 21:06
@github-actions

Copy link
Copy Markdown
Contributor

Quality Report — ConductionNL/stackiq @ 9d2933f

Check PHP Vue Security License Tests
lint
phpcs
phpmd
psalm
phpstan
phpmetrics
eslint
stylelint
build
check-manifest
check-vue-demi
test-l10n
format
check-schema-l10n
check-l10n-js
composer ✅ 130/130
npm ✅ 711/711
app:check-code ⏭️
info.xml
REUSE
PHPUnit
Newman ⏭️
Playwright ⏭️ deferred — runs on the promotion into beta/main, not on a pull request into development
Hydra gates

Quality workflow — 2026-08-31 21:12 UTC

Download the full PDF report from the workflow artifacts.

rubenvdlinde pushed a commit that referenced this pull request Sep 1, 2026
The icon PR could not go green because stackiq development is red on its own
account. All three are pre-existing, not introduced here.

1. Frontend Check (format): prettier flagged src/components/CatalogPanels.vue,
   a file this PR never touched. It has been failing on development since
   #892. Reformatted with the repo own config; the whole tree now reports
   "All matched files use Prettier code style!".

2. gate-60 icon-vocabulary FAILED, not warned: FileDocument and Web are named
   by src/manifest.json but were absent from src/icons.js, so both rendered
   as NOTHING. Registered.

3. gate-102 manifest-l10n-coverage: three manifest strings had no nl.json
   key, so they rendered English to a Dutch user. Two of them were the
   opposite problem, hardcoded DUTCH in a manifest whose menu labels are all
   English (Dashboard, Organisations, Applications, Suites, Services), so an
   English user saw Dutch:

     "Diensten"            -> "Services"          nl.json already had Services: Diensten
     "Object statistieken" -> "Object statistics" + new key
     "Modules"                                    + new key, same word either way

   Only title and label were touched. The id, route and name values keep
   "Diensten" because they are identifiers, not copy.

⚠️ The keys were added to BOTH l10n/nl.json and l10n/nl.js. The browser reads
the .js; a key in the .json alone is invisible to the user and check:l10n
would still call the two in sync. Verified by loading nl.js and diffing the
key sets: 760 each, 0 in one and not the other.

Sentence case per the Conduction voice rules, not Title Case.
rubenvdlinde added a commit that referenced this pull request Sep 1, 2026
* chore(icons): adopt the Tier B vocabulary in full

gate-60 reported 8 Tier B warnings, four concepts duplicated across the real
and mock register. All adopted. 8 -> 0.

  Vulnerability  ShieldAlert       -> ShieldAlertOutline
  Contract       FileDocumentEdit  -> FileSign
  Connection     Link              -> TransitConnectionVariant
  View           Eye               -> EyeOutline

Contract is the substantive one: FileDocumentEdit is a document being
EDITED, which is the opposite of what a signed contract is. FileSign says
signed.

⚠️ TransitConnectionVariant and EyeOutline had to be REGISTERED in
src/icons.js in the same commit. Neither was there, and an icon a manifest
names but the registry does not hold renders as NOTHING, not a fallback.

* fix(quality): clear the three failures development was already carrying

The icon PR could not go green because stackiq development is red on its own
account. All three are pre-existing, not introduced here.

1. Frontend Check (format): prettier flagged src/components/CatalogPanels.vue,
   a file this PR never touched. It has been failing on development since
   #892. Reformatted with the repo own config; the whole tree now reports
   "All matched files use Prettier code style!".

2. gate-60 icon-vocabulary FAILED, not warned: FileDocument and Web are named
   by src/manifest.json but were absent from src/icons.js, so both rendered
   as NOTHING. Registered.

3. gate-102 manifest-l10n-coverage: three manifest strings had no nl.json
   key, so they rendered English to a Dutch user. Two of them were the
   opposite problem, hardcoded DUTCH in a manifest whose menu labels are all
   English (Dashboard, Organisations, Applications, Suites, Services), so an
   English user saw Dutch:

     "Diensten"            -> "Services"          nl.json already had Services: Diensten
     "Object statistieken" -> "Object statistics" + new key
     "Modules"                                    + new key, same word either way

   Only title and label were touched. The id, route and name values keep
   "Diensten" because they are identifiers, not copy.

⚠️ The keys were added to BOTH l10n/nl.json and l10n/nl.js. The browser reads
the .js; a key in the .json alone is invisible to the user and check:l10n
would still call the two in sync. Verified by loading nl.js and diffing the
key sets: 760 each, 0 in one and not the other.

Sentence case per the Conduction voice rules, not Title Case.

---------

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
rubenvdlinde added a commit that referenced this pull request Sep 1, 2026
…on a Dutch instance (#915)

development E2E has been red for a day with six failures in two clusters.
Both are the suite describing a world the app left behind. Neither was
introduced by the icon work merged earlier today; the same six fail on the
08-31 21:06 run, checked.

## dashboard.spec.ts, three tests

They assert an info box: the sentence "Overzicht van uw softwarecatalogus",
a heading "Beheer van Organisaties", a "Vernieuwen" button on the surface and
a "Ga naar Organisaties" quick-nav. None of that string set exists anywhere
in src/ or l10n/nl.json any more. The dashboard is now four stat tiles plus
the catalog-panels widget, since the KPI tiles landed in #892, and the spec
was never updated.

  - the overview test now asserts the four tiles and the object-statistics
    panel;
  - the refresh test now opens the PAGE ACTIONS menu, where CnDashboardPage
    puts Refresh (showRefresh defaults true), instead of looking for a button
    on the surface;
  - the "Ga naar Organisaties" test is REMOVED rather than retargeted. Its
    own comment already recorded that the button was a no-op in the shared
    shell and that the user real path is the Organisations nav entry, which
    is the very next test in the file. Rewriting it would have tested that
    path twice while pretending to cover a control that no longer exists.

⚠️ The tile labels are asserted in DUTCH, and they are not all the manifest
source. The manifest says "Services"; nl.json maps it to "Diensten". An
English assertion would pass only on an English instance.

## sbom-import.spec.ts, two tests

  await page.getByRole("tab", { name: "Components" }).click()

The manifest labels that tab "Components" and nl.json maps it to
"Componenten". The e2e instance runs Dutch, so the tab never matched and both
tests died on a 60s click timeout that reads like a missing feature rather
than a wrong string. The matcher now accepts either spelling, as does the
"Open sidebar" button above it.

🔑 The underlying debt is that this suite mixes locales: the dashboard tests
asserted Dutch, the sbom tests asserted English, against one Dutch instance.
Locale-tolerant matchers are the cheap fix; a decided convention is the real
one.

Co-authored-by: Conduction Release Bot <release-bot@conduction.nl>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant