Skip to content

Commit b90cdd4

Browse files
authored
Merge pull request #398 from ConductionNL/wip/suite-wizard
feat: suite-wizard — guided registration of application suites (#372)
2 parents bb98e6e + 8e88d71 commit b90cdd4

24 files changed

Lines changed: 1671 additions & 42 deletions

File tree

docs/features/suite-wizard.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
<!--
2+
- SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>
3+
- SPDX-License-Identifier: EUPL-1.2
4+
-->
5+
6+
# Suite wizard
7+
8+
Lets a catalogue editor register an application **suite** — a bundled
9+
product made up of one or more existing applications, e.g. "Centric
10+
Leefomgeving" — and attach its member applications in one guided pass. This
11+
replaces the retired incumbent "product" concept per
12+
[VNG Softwarecatalogus issue #242](https://github.com/VNG-Realisatie/Softwarecatalogus/issues/242)
13+
and softwarecatalog#372.
14+
15+
Specification: [`openspec/specs/suite-wizard/spec.md`](../../openspec/specs/suite-wizard/spec.md).
16+
17+
## Registering a suite
18+
19+
Open **Suites** from the navigation menu, then click **New suite**. The
20+
guided wizard has three steps:
21+
22+
1. **Details** — name, short description (required), long description, and
23+
website of the suite.
24+
2. **Applications** — attach one or more applications that are *already* in
25+
the catalogue. Creating a brand-new application from the wizard is not
26+
supported — attach existing ones only. At least one application must be
27+
attached before you can continue.
28+
3. **Confirm** — review the suite's details and the list of attached
29+
applications, then click **Create suite**.
30+
31+
On success, the wizard closes and takes you to the new suite's detail page.
32+
33+
## Suite index and detail
34+
35+
The **Suites** page lists every suite in the catalogue. Opening a suite
36+
shows its own data (name, descriptions, website, logo, contact person)
37+
alongside its attached applications, with a link through to each
38+
application's own detail page.
39+
40+
## Suite membership on an application
41+
42+
An application's own detail page shows which suite(s), if any, include it.
43+
This uses OpenRegister's generic, bidirectional relation index (the same
44+
mechanism every other "which objects reference me" panel in this app relies
45+
on) rather than a bespoke lookup — so a suite's `applicaties` list and a
46+
module's "which suite am I in" view are always the same underlying data,
47+
read from two directions.
48+
49+
## Data model
50+
51+
`suite` is an OpenRegister schema in the `voorzieningen` register:
52+
53+
| Field | Type | Notes |
54+
|-------|------|-------|
55+
| `naam` | string | required |
56+
| `beschrijvingKort` | string | required |
57+
| `beschrijvingLang` | markdown | optional |
58+
| `logo` | file (base64) | optional |
59+
| `website` | url | optional |
60+
| `contactpersoon` | related object → `contactpersoon` | optional, not set by the wizard |
61+
| `applicaties` | array of related objects → `module` | the suite's member applications |
62+
63+
Out of scope for this feature: creating new modules from the wizard,
64+
suite-level contracts/licensing, and migrating the legacy "product" concept.

l10n/en.json

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -423,16 +423,12 @@
423423
"Save view": "Save view",
424424
"Approval": "Approval",
425425
"{source} will be marked as merged (not deleted) and will disappear from the organisations list.": "{source} will be marked as merged (not deleted) and will disappear from the organisations list.",
426-
"Approval": "Approval",
427-
"{source} will be marked as merged (not deleted) and will disappear from the organisations list.": "{source} will be marked as merged (not deleted) and will disappear from the organisations list.",
428426
"Annualised cost": "Annualised cost",
429427
"Applications": "Applications",
430428
"Applications in use": "Applications in use",
431429
"Approaching": "Approaching",
432-
"Approval": "Approval",
433430
"Cloud-transition share": "Cloud-transition share",
434431
"All applications": "All applications",
435-
"Approval": "Approval",
436432
"BBN level": "BBN level",
437433
"BIO measures": "BIO measures",
438434
"Compliance matrix scope": "Compliance matrix scope",
@@ -489,81 +485,89 @@
489485
"This will permanently fold {source} into {target}.": "This will permanently fold {source} into {target}.",
490486
"Usage records": "Usage records",
491487
"When disabled, the matcher never reads or writes anything — the same as the feed being unavailable.": "When disabled, the matcher never reads or writes anything — the same as the feed being unavailable.",
492-
"Could not load target organisations.": "Could not load target organisations.",
493-
"Could not merge the organisations.": "Could not merge the organisations.",
494-
"Could not preview the merge.": "Could not preview the merge.",
495488
"Count": "Count",
496489
"Eliminate": "Eliminate",
497490
"EOL exposed": "EOL exposed",
498491
"EOL status": "EOL status",
499492
"Export CSV": "Export CSV",
500493
"Failed to load the portfolio report.": "Failed to load the portfolio report.",
501-
"Fold this organisation into another one (gemeentelijke herindeling or leveranciersovername). Every contract, usage record, contact person, offering and compliance record is re-pointed to the target; this organisation is then marked as merged, never deleted.": "Fold this organisation into another one (gemeentelijke herindeling or leveranciersovername). Every contract, usage record, contact person, offering and compliance record is re-pointed to the target; this organisation is then marked as merged, never deleted.",
502-
"Go to the organisation it was merged into": "Go to the organisation it was merged into",
503-
"Group members": "Group members",
504494
"Hosting model": "Hosting model",
505495
"Invest": "Invest",
506496
"Lifecycle phase": "Lifecycle phase",
507-
"Loading merge status": "Loading merge status",
508-
"Merge organisation": "Merge organisation",
509-
"Merge organisations": "Merge organisations",
510497
"Migrate": "Migrate",
511498
"No applications in this quadrant": "No applications in this quadrant",
512-
"Offerings": "Offerings",
513499
"OK": "OK",
514500
"One-off cost": "One-off cost",
515-
"Organisation successfully merged.": "Organisation successfully merged.",
516501
"Passed": "Passed",
517502
"Pick an organisation above to render its portfolio rationalization report.": "Pick an organisation above to render its portfolio rationalization report.",
518503
"Portfolio rationalization": "Portfolio rationalization",
519-
"Preview merge": "Preview merge",
520504
"Quadrant": "Quadrant",
521505
"Quadrant summary": "Quadrant summary",
522506
"Rationale": "Rationale",
523-
"Records that will be re-pointed to {target}:": "Records that will be re-pointed to {target}:",
524507
"Refresh report": "Refresh report",
525508
"Review date": "Review date",
526-
"Select the organisation to merge into": "Select the organisation to merge into",
527509
"Showing the first {shown} of {total} applications in use for this organisation — the report is bounded to protect performance.": "Showing the first {shown} of {total} applications in use for this organisation — the report is bounded to protect performance.",
528-
"Target organisation": "Target organisation",
529-
"This organisation has been merged and is no longer active.": "This organisation has been merged and is no longer active.",
530-
"This will permanently fold {source} into {target}.": "This will permanently fold {source} into {target}.",
531510
"TIME classification (Tolerate / Invest / Migrate / Eliminate) of an organisation's applications in use, combined with end-of-support exposure, cloud-transition share, and annualised contract cost.": "TIME classification (Tolerate / Invest / Migrate / Eliminate) of an organisation's applications in use, combined with end-of-support exposure, cloud-transition share, and annualised contract cost.",
532511
"TIME quadrant counts": "TIME quadrant counts",
533512
"Tolerate": "Tolerate",
534513
"Unclassified": "Unclassified",
535-
"Usage records": "Usage records",
536514
"DPIA status": "DPIA status",
537515
"Executed": "Executed",
538-
"Fold this organisation into another one (gemeentelijke herindeling or leveranciersovername). Every contract, usage record, contact person, offering and compliance record is re-pointed to the target; this organisation is then marked as merged, never deleted.": "Fold this organisation into another one (gemeentelijke herindeling or leveranciersovername). Every contract, usage record, contact person, offering and compliance record is re-pointed to the target; this organisation is then marked as merged, never deleted.",
539-
"Go to the organisation it was merged into": "Go to the organisation it was merged into",
540-
"Group members": "Group members",
541-
"Loading merge status": "Loading merge status",
542-
"Merge organisation": "Merge organisation",
543-
"Merge organisations": "Merge organisations",
544516
"No BIO measures seeded": "No BIO measures seeded",
545517
"Not required": "Not required",
546518
"Not set": "Not set",
547-
"Offerings": "Offerings",
548519
"Organisation (scope to in-use applications)": "Organisation (scope to in-use applications)",
549-
"Organisation successfully merged.": "Organisation successfully merged.",
550520
"Pick one or more columns above to render the compliance matrix.": "Pick one or more columns above to render the compliance matrix.",
551-
"Preview merge": "Preview merge",
552-
"Records that will be re-pointed to {target}:": "Records that will be re-pointed to {target}:",
553521
"Required": "Required",
554522
"Select BIO measures to compare": "Select BIO measures to compare",
555523
"Select one or more BIO measures": "Select one or more BIO measures",
556-
"Select the organisation to merge into": "Select the organisation to merge into",
557524
"Some compliancy records reference both a standard and a BIO measure — a data-quality issue. They are excluded from both matrices until corrected.": "Some compliancy records reference both a standard and a BIO measure — a data-quality issue. They are excluded from both matrices until corrected.",
558-
"Target organisation": "Target organisation",
559525
"The BIO measures catalog is seeded on install/upgrade. Refresh, or check the BIO measures catalog.": "The BIO measures catalog is seeded on install/upgrade. Refresh, or check the BIO measures catalog.",
560-
"This organisation has been merged and is no longer active.": "This organisation has been merged and is no longer active.",
561-
"This will permanently fold {source} into {target}.": "This will permanently fold {source} into {target}.",
562-
"Usage records": "Usage records",
563526
"Which applications support which BIO 2.0 measures, plus each application's BBN level and DPIA status. A verified cell traces to evidence; a claimed cell is a supplier statement without evidence.": "Which applications support which BIO 2.0 measures, plus each application's BBN level and DPIA status. A verified cell traces to evidence; a claimed cell is a supplier statement without evidence.",
564527
"BBN1": "BBN1",
565528
"BBN2": "BBN2",
566529
"BBN3": "BBN3",
567-
"Without DPIA (BBN2+)": "Without DPIA (BBN2+)"
530+
"Without DPIA (BBN2+)": "Without DPIA (BBN2+)",
531+
"A brief summary of the suite": "A brief summary of the suite",
532+
"A detailed description of the suite and what it covers": "A detailed description of the suite and what it covers",
533+
"Application suites — bundled products made up of one or more existing applications.": "Application suites — bundled products made up of one or more existing applications.",
534+
"Applications ({count})": "Applications ({count})",
535+
"Attach the applications that make up this suite. Only applications already in the catalogue can be attached — creating a new application is not part of this wizard.": "Attach the applications that make up this suite. Only applications already in the catalogue can be attached — creating a new application is not part of this wizard.",
536+
"Back": "Back",
537+
"Choose an SBOM JSON file": "Choose an SBOM JSON file",
538+
"Components": "Components",
539+
"Confirm": "Confirm",
540+
"Confirmed match": "Confirmed match",
541+
"Could not load applications. Please try again.": "Could not load applications. Please try again.",
542+
"Create suite": "Create suite",
543+
"CycloneDX (JSON)": "CycloneDX (JSON)",
544+
"Details": "Details",
545+
"Distinct licenses": "Distinct licenses",
546+
"e.g. Centric Leefomgeving": "e.g. Centric Leefomgeving",
547+
"Enter a name and a short description.": "Enter a name and a short description.",
548+
"Existing applications": "Existing applications",
549+
"Failed to create the suite.": "Failed to create the suite.",
550+
"https://example.com/suite": "https://example.com/suite",
551+
"Import a CycloneDX or SPDX SBOM to see this version's components, licenses and any matching known vulnerabilities.": "Import a CycloneDX or SPDX SBOM to see this version's components, licenses and any matching known vulnerabilities.",
552+
"Import SBOM": "Import SBOM",
553+
"Imported {count} components.": "Imported {count} components.",
554+
"Last imported {date} from {file} ({format})": "Last imported {date} from {file} ({format})",
555+
"Licenses": "Licenses",
556+
"Loading components": "Loading components",
557+
"Long description": "Long description",
558+
"Matched vulnerabilities": "Matched vulnerabilities",
559+
"New suite": "New suite",
560+
"No applications attached yet.": "No applications attached yet.",
561+
"No components imported yet": "No components imported yet",
562+
"Package URL": "Package URL",
563+
"Possible match": "Possible match",
564+
"SBOM format": "SBOM format",
565+
"SBOM import failed": "SBOM import failed",
566+
"Select one or more applications": "Select one or more applications",
567+
"SPDX (JSON)": "SPDX (JSON)",
568+
"Suite created.": "Suite created.",
569+
"Suites": "Suites",
570+
"Version": "Version",
571+
"Vulnerability match": "Vulnerability match"
568572
}
569573
}

l10n/en_US.js

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,28 @@ OC.L10N.register(
348348
"BBN2" : "BBN2",
349349
"BBN3" : "BBN3",
350350
"Without DPIA (BBN2+)" : "Without DPIA (BBN2+)",
351-
"The most recent register import did not fully reach OpenRegister — some schemas or object types could not be verified. Re-run the import or check the server log for details." : "The most recent register import did not fully reach OpenRegister — some schemas or object types could not be verified. Re-run the import or check the server log for details."
351+
"The most recent register import did not fully reach OpenRegister — some schemas or object types could not be verified. Re-run the import or check the server log for details." : "The most recent register import did not fully reach OpenRegister — some schemas or object types could not be verified. Re-run the import or check the server log for details.",
352+
"Suites" : "Suites",
353+
"New suite" : "New suite",
354+
"Create suite" : "Create suite",
355+
"Suite created." : "Suite created.",
356+
"Failed to create the suite." : "Failed to create the suite.",
357+
"Application suites — bundled products made up of one or more existing applications." : "Application suites — bundled products made up of one or more existing applications.",
358+
"Details" : "Details",
359+
"Confirm" : "Confirm",
360+
"Back" : "Back",
361+
"A brief summary of the suite" : "A brief summary of the suite",
362+
"A detailed description of the suite and what it covers" : "A detailed description of the suite and what it covers",
363+
"Long description" : "Long description",
364+
"e.g. Centric Leefomgeving" : "e.g. Centric Leefomgeving",
365+
"https://example.com/suite" : "https://example.com/suite",
366+
"Enter a name and a short description." : "Enter a name and a short description.",
367+
"Existing applications" : "Existing applications",
368+
"Select one or more applications" : "Select one or more applications",
369+
"Attach the applications that make up this suite. Only applications already in the catalogue can be attached — creating a new application is not part of this wizard." : "Attach the applications that make up this suite. Only applications already in the catalogue can be attached — creating a new application is not part of this wizard.",
370+
"Could not load applications. Please try again." : "Could not load applications. Please try again.",
371+
"Applications ({count})" : "Applications ({count})",
372+
"No applications attached yet." : "No applications attached yet."
352373
},
353374
"nplurals=2; plural=(n != 1);"
354375
);

l10n/en_US.json

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,27 @@
407407
"BBN2": "BBN2",
408408
"BBN3": "BBN3",
409409
"Without DPIA (BBN2+)": "Without DPIA (BBN2+)",
410-
"The most recent register import did not fully reach OpenRegister — some schemas or object types could not be verified. Re-run the import or check the server log for details.": "The most recent register import did not fully reach OpenRegister — some schemas or object types could not be verified. Re-run the import or check the server log for details."
410+
"The most recent register import did not fully reach OpenRegister — some schemas or object types could not be verified. Re-run the import or check the server log for details.": "The most recent register import did not fully reach OpenRegister — some schemas or object types could not be verified. Re-run the import or check the server log for details.",
411+
"Suites": "Suites",
412+
"New suite": "New suite",
413+
"Create suite": "Create suite",
414+
"Suite created.": "Suite created.",
415+
"Failed to create the suite.": "Failed to create the suite.",
416+
"Application suites — bundled products made up of one or more existing applications.": "Application suites — bundled products made up of one or more existing applications.",
417+
"Details": "Details",
418+
"Confirm": "Confirm",
419+
"Back": "Back",
420+
"A brief summary of the suite": "A brief summary of the suite",
421+
"A detailed description of the suite and what it covers": "A detailed description of the suite and what it covers",
422+
"Long description": "Long description",
423+
"e.g. Centric Leefomgeving": "e.g. Centric Leefomgeving",
424+
"https://example.com/suite": "https://example.com/suite",
425+
"Enter a name and a short description.": "Enter a name and a short description.",
426+
"Existing applications": "Existing applications",
427+
"Select one or more applications": "Select one or more applications",
428+
"Attach the applications that make up this suite. Only applications already in the catalogue can be attached — creating a new application is not part of this wizard.": "Attach the applications that make up this suite. Only applications already in the catalogue can be attached — creating a new application is not part of this wizard.",
429+
"Could not load applications. Please try again.": "Could not load applications. Please try again.",
430+
"Applications ({count})": "Applications ({count})",
431+
"No applications attached yet.": "No applications attached yet."
411432
}
412433
}

0 commit comments

Comments
 (0)