From 263f463edeacc181ff84eed95699f200182f61a2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 26 Jan 2026 21:52:45 +0000 Subject: [PATCH 1/9] chore(deps-dev): bump org.assertj:assertj-core Bumps the maven group with 1 update in the / directory: [org.assertj:assertj-core](https://github.com/assertj/assertj). Updates `org.assertj:assertj-core` from 3.24.2 to 3.27.7 - [Release notes](https://github.com/assertj/assertj/releases) - [Commits](https://github.com/assertj/assertj/compare/assertj-build-3.24.2...assertj-build-3.27.7) --- updated-dependencies: - dependency-name: org.assertj:assertj-core dependency-version: 3.27.7 dependency-type: direct:development dependency-group: maven ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 07f81b5..62e4f54 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,7 @@ org.assertj assertj-core - 3.24.2 + 3.27.7 test -- 2.54.0 From fb9395ac0d0751b8427410f7afb1b0aac286f864 Mon Sep 17 00:00:00 2001 From: James Maes Date: Thu, 21 May 2026 17:14:30 -0500 Subject: [PATCH 2/9] chore: add CODEOWNERS pointing to sole maintainer Architecture audit pass 2026-05-21. Minimal CODEOWNERS file making the implicit ownership explicit. Co-Authored-By: Claude Opus 4.7 (1M context) --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) create mode 100644 .github/CODEOWNERS diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..e7d84f9 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +* @KofTwentyTwo -- 2.54.0 From 170be8739e0c323b1e3c686e1e540a03480f54fe Mon Sep 17 00:00:00 2001 From: James Maes Date: Sun, 12 Jul 2026 05:31:19 -0500 Subject: [PATCH 3/9] docs: add CLAUDE.md pointer to QQQ knowledge-base dossier + hub Co-Authored-By: Claude Opus 4.8 --- CLAUDE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..334f05d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,21 @@ +# qbit-template-application + +GitHub template repository for scaffolding Application QBits (complete mini-applications +with tables, processes, widgets, and UI navigation) on the QQQ platform. + +## Knowledge base + +Reviewed dossier and platform knowledge live in the second-brain vault: + +- Hub: `R:/Git.Local/KofTwentyTwo/second-brain/knowledge/qqq/qqq-hub.md` +- This repo's dossier: `R:/Git.Local/KofTwentyTwo/second-brain/knowledge/qqq/repos/qbit-template-application.md` +- QBit mechanics refresher: `R:/Git.Local/KofTwentyTwo/second-brain/knowledge/qqq/architecture/metadata-model.md` + +Reviewed at commit `fb9395ac0d07` (branch `main`, 2026-07-04). + +Key caveat from that review: the scaffold in `src/main` references six qqq APIs that do not +exist in any qqq version (wrong packages for `MetaDataProducerInterface` / +`AbstractWidgetRenderer` / `RenderWidgetInput`, plus nonexistent `QInstance.addAppSection`, +`QProcessMetaData.withInputFields`, `QAppSection.withSourceQBitName`) — it has never compiled, +and CI on `main` is red. Verify against the qqq checkout (`R:/Git.Local/QRunIO/qqq`) before +trusting any API usage shown here. -- 2.54.0 From ebc77b939c955119b6335778405ee00534e17a73 Mon Sep 17 00:00:00 2001 From: James Maes Date: Thu, 24 Sep 2026 13:32:06 -0500 Subject: [PATCH 4/9] feat(release): migrate application template to QQQ 4.0 (#4) * fix(template): complete QQQ 4.0 application migration * fix(ci): avoid interactive package restart prompts * docs: align guides and examples with QQQ 4.0 * docs(release): finalize QQQ 4.0 template instructions Refs QRun-IO/qqq#631. --- .circleci/config.yml | 14 +++- CLAUDE.md | 4 ++ README.md | 23 +++---- docs/00-getting-started.md | 57 ++++++---------- docs/01-tables-and-relationships.md | 3 +- docs/02-processes.md | 57 +--------------- docs/03-widgets-and-ui.md | 68 ++++--------------- pom.xml | 2 +- .../qbits/example/ExampleAppQBitProducer.java | 20 ++++-- .../ExampleProcessMetaDataProducer.java | 12 ++-- .../example/processes/ExampleProcessStep.java | 18 ++++- ...xampleDashboardWidgetMetaDataProducer.java | 5 +- .../ExampleDashboardWidgetRenderer.java | 20 +++--- 13 files changed, 112 insertions(+), 191 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8828026..010cd62 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -3,7 +3,19 @@ version: 2.1 orbs: qqq-orb: kingsrook/qqq-orb@0.5.0 +commands: + configure-package-install: + steps: + - run: + name: Keep package installation unattended + command: | + # These build machines are discarded after the job. + sudo install -d /etc/needrestart/conf.d + printf '%s\n' '$nrconf{restart} = "l";' | sudo tee /etc/needrestart/conf.d/99-qqq-ci.conf >/dev/null + workflows: build: jobs: - - qqq-orb/mvn_test + - qqq-orb/mvn_test_only: + pre-steps: + - configure-package-install diff --git a/CLAUDE.md b/CLAUDE.md index 334f05d..7e48329 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -3,6 +3,10 @@ GitHub template repository for scaffolding Application QBits (complete mini-applications with tables, processes, widgets, and UI navigation) on the QQQ platform. +## QQQ 4.0 baseline — 2026-09-24 + +The historical review below predates the 4.0 migration. This template targets Java 21 and the public QQQ 4.0.0 release from Maven Central. The corrected APIs, license references and actual template commands are in README.md and docs/00-getting-started.md. Preserve the documented multi-instance and scaffold limitations. + ## Knowledge base Reviewed dossier and platform knowledge live in the second-brain vault: diff --git a/README.md b/README.md index f36871f..f225c00 100644 --- a/README.md +++ b/README.md @@ -12,30 +12,23 @@ Use this template when building: ## Quick Start -1. Click "Use this template" on GitHub -2. Clone your new repository -3. Run the customization script: - ```bash - python scripts/customize_template.py --name my-app --package com.mycompany.qbits.myapp - ``` -4. Implement your tables, processes, and widgets -5. Add your QAppSection for UI navigation +Requires **Java 21**, **Maven 3.8+**, and QQQ **4.0.0**. Create a repository with **Use this template**, customize its Maven coordinates and Java package/classes, then run `mvn clean verify`. Follow the [Getting Started guide](docs/00-getting-started.md) for the full sequence. ## Structure ``` src/main/java/com/kingsrook/qbits/example/ -├── ExampleAppQBitConfig.java # Configuration options -├── ExampleAppQBitProducer.java # Entry point, registers QAppSection +├── ExampleAppQBitConfig.java +├── ExampleAppQBitProducer.java ├── model/ │ ├── ExampleEntity.java │ └── ExampleChildEntity.java ├── processes/ -│ └── ExampleProcess.java -├── widgets/ -│ └── ExampleDashboardWidget.java -└── api/ - └── ExampleApiHandler.java +│ ├── ExampleProcessStep.java +│ └── ExampleProcessMetaDataProducer.java +└── widgets/ + ├── ExampleDashboardWidgetRenderer.java + └── ExampleDashboardWidgetMetaDataProducer.java ``` ## Key Characteristics diff --git a/docs/00-getting-started.md b/docs/00-getting-started.md index d869daf..f235d60 100644 --- a/docs/00-getting-started.md +++ b/docs/00-getting-started.md @@ -1,47 +1,30 @@ # Getting Started -This template helps you create Application QBits - complete mini-applications with UI navigation. +Targets Java 21, Maven 3.8 or later, and QQQ 4.0.0. Maven resolves the framework dependencies from Maven Central. -## Quick Start +1. Choose **Use this template** on GitHub, then clone the repository you created. +2. In `pom.xml`, set your own `groupId`, `artifactId`, name, description, and version. +3. Use your IDE's package refactoring to rename `com.kingsrook.qbits.example` throughout `src/`. Rename the `Example*` classes and update their imports and references with the IDE's rename refactoring. +4. Update the QBit producer's `GROUP_ID`, `ARTIFACT_ID`, and `VERSION` constants to match your project. Give the metadata names their own stable names before combining the QBit with other examples. +5. Build the generated project: -1. **Create from template:** - ```bash - gh repo create my-company/qbit-my-app --template QRun-IO/qbit-template-application - ``` +```bash +mvn clean verify +``` -2. **Run customization script:** - ```bash - python scripts/customize_template.py --name my-app --package com.mycompany.qbits.myapp - ``` +The repository provides example Java sources; customization uses normal package/class refactoring. Keep example coordinates unpublished. After customizing, add tests for your QBit's behavior before setting up its publishing workflow. -3. **Build and test:** - ```bash - mvn clean test - ``` +## Register with a host application -## Key Differences from Other QBit Types - -| Feature | Extension | Data | Application | -|---------|-----------|------|-------------| -| QAppSection | No | Optional | **Required** | -| Tables | 0-few | Few (reference) | Many (business) | -| Processes | Customizers | Sync | Full business logic | -| Widgets | No | No | **Yes** | - -## What to Customize - -1. `ExampleAppQBitConfig.java` - Add your configuration options -2. `ExampleAppQBitProducer.java` - Update QAppSection with your tables -3. `model/` - Replace with your entities -4. `processes/` - Implement your business logic -5. `widgets/` - Create your dashboard components - -## Usage in Host Application +The following uses the original example names; substitute the names chosen above: ```java -new MyAppQBitProducer() - .withConfig(new MyAppQBitConfig() - .withBackendName("rdbms") - .withTableNamePrefix("myapp")) - .produce(qInstance, "my-app"); +new ExampleAppQBitProducer() + .withConfig(new ExampleAppQBitConfig() + .withBackendName("rdbms")) + .produce(qInstance, "my-application"); ``` + +Register the configured backend in the host first. If you add table prefixes or multiple QBit instances, update related table references, possible-value-source names, and process/widget names consistently. A table prefix alone does not namespace all metadata. + +[Tables and Relationships](01-tables-and-relationships.md) describes the model; the `processes/` and `widgets/` directories contain the remaining examples. diff --git a/docs/01-tables-and-relationships.md b/docs/01-tables-and-relationships.md index de78bee..c661ae3 100644 --- a/docs/01-tables-and-relationships.md +++ b/docs/01-tables-and-relationships.md @@ -42,8 +42,9 @@ Application QBits support optional table prefixing: new MyAppQBitProducer() .withConfig(new MyAppQBitConfig() + .withBackendName("rdbms") .withTableNamePrefix("sales")) .produce(qInstance, "sales-app"); ``` -The producer automatically applies the prefix to all table names. +The producer applies the prefix to table names. When extending this pattern, also update possible-value-source names, relationship targets, process tables, and navigation references; table renaming alone does not provide complete multi-instance support. diff --git a/docs/02-processes.md b/docs/02-processes.md index 0407eee..ba48fa7 100644 --- a/docs/02-processes.md +++ b/docs/02-processes.md @@ -1,58 +1,7 @@ # Processes -Application QBits include processes for business logic execution. +Start with [ExampleProcessMetaDataProducer](../src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessMetaDataProducer.java) and [ExampleProcessStep](../src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessStep.java). The producer defines the process, its table, inputs, and backend step; the step transforms `PENDING` records to `PROCESSED` and returns them in the output. -## Process Structure +In QQQ 4.0, import `MetaDataProducerInterface` from `com.kingsrook.qqq.backend.core.model.metadata`. Define process inputs through `withInputMetaData(new QFunctionInputMetaData().withField(...))`. An `AbstractTransformStep` must implement both `runOnePage(RunBackendStepInput, RunBackendStepOutput)` and `getProcessSummary(RunBackendStepOutput, boolean)`; keep the example's implementations when renaming it. -```java -public class MyProcessMetaDataProducer implements MetaDataProducerInterface -{ - public static final String NAME = "myProcess"; - - @Override - public QProcessMetaData produce(QInstance qInstance) - { - return new QProcessMetaData() - .withName(NAME) - .withLabel("My Process") - .withTableName(MyEntity.TABLE_NAME) - .withStepList(List.of( - new QBackendStepMetaData() - .withName("execute") - .withCode(new QCodeReference(MyProcessStep.class)) - )); - } -} -``` - -## Process Steps - -Implement `AbstractTransformStep` for record processing: - -```java -public class MyProcessStep extends AbstractTransformStep -{ - @Override - public void runOnePage(RunBackendStepInput input, RunBackendStepOutput output) - { - for(QRecord record : input.getRecords()) - { - // Business logic here - output.addRecord(record); - } - } -} -``` - -## Including in QAppSection - -Add processes to your app's navigation: - -```java -return new QAppSection() - .withName("myApp") - .withTables(List.of(...)) - .withProcesses(List.of( - config.applyPrefix(MyProcess.NAME) - )); -``` +To make the process discoverable in navigation, add its registered name to a `QAppSection` through `withProcesses(List.of(ExampleProcessMetaDataProducer.NAME))`, then include the section in a `QAppMetaData` registered with `qInstance.addApp(...)`. Use the actual registered name if you introduce a prefix. Add tests for record changes and failure cases when replacing the example business logic. diff --git a/docs/03-widgets-and-ui.md b/docs/03-widgets-and-ui.md index d16fff5..8dd11f8 100644 --- a/docs/03-widgets-and-ui.md +++ b/docs/03-widgets-and-ui.md @@ -1,61 +1,23 @@ # Widgets and UI -Application QBits include dashboard widgets and UI navigation via QAppSection. - -## QAppSection (Required) - -Every Application QBit must register a QAppSection: +The application producer registers a `QAppMetaData` containing a `QAppSection`. The section references metadata names already registered in the instance; it is not registered directly on `QInstance`. ```java -private QAppSection produceAppSection(MyAppConfig config, String qbitName) -{ - return new QAppSection() - .withName(config.applyPrefix("myApp")) - .withLabel("My Application") - .withIcon(new QIcon().withName("dashboard")) - .withTables(List.of( - config.applyPrefix(Order.TABLE_NAME), - config.applyPrefix(OrderLine.TABLE_NAME) - )) - .withProcesses(List.of( - config.applyPrefix(ProcessOrder.NAME) - )) - .withWidgets(List.of( - config.applyPrefix(OrderDashboard.NAME) - )) - .withSourceQBitName(qbitName); -} +QAppSection section = new QAppSection() + .withName("exampleSection") + .withLabel("Example Application") + .withTables(List.of(ExampleEntity.TABLE_NAME, ExampleChildEntity.TABLE_NAME)) + .withProcesses(List.of(ExampleProcessMetaDataProducer.NAME)) + .withWidgets(List.of(ExampleDashboardWidgetMetaDataProducer.NAME)); + +qInstance.addApp(new QAppMetaData() + .withName("exampleApp") + .withLabel("Example Application") + .withSection(section)); ``` -## Dashboard Widgets +Use [ExampleAppQBitProducer](../src/main/java/com/kingsrook/qbits/example/ExampleAppQBitProducer.java) as the starting point. Keep these references consistent when enabling/disabling tables or introducing prefixes. -Create widgets with metadata producer and renderer: +The widget has two parts: [its metadata producer](../src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetMetaDataProducer.java) declares a statistics widget and its renderer, and [its renderer](../src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetRenderer.java) returns a `RenderWidgetOutput` containing `StatisticsData`. Replace the example count with a query or calculation. Choose a widget type that matches the returned data model. -```java -// MetaData Producer -public class MyWidgetMetaDataProducer implements MetaDataProducerInterface -{ - @Override - public QWidgetMetaData produce(QInstance qInstance) - { - return new QWidgetMetaData() - .withName("myWidget") - .withLabel("My Dashboard") - .withType("chart") - .withCodeReference(new QCodeReference(MyWidgetRenderer.class)); - } -} - -// Renderer -public class MyWidgetRenderer extends AbstractWidgetRenderer -{ - @Override - public RenderWidgetOutput render(RenderWidgetInput input) - { - Map data = new HashMap<>(); - data.put("title", "Dashboard"); - // Add chart data, counts, etc. - return new RenderWidgetOutput(data); - } -} -``` +For QQQ 4.0, `AbstractWidgetRenderer` is in `com.kingsrook.qqq.backend.core.actions.dashboard.widgets`; `RenderWidgetInput` and `RenderWidgetOutput` are in `com.kingsrook.qqq.backend.core.model.actions.widgets`. diff --git a/pom.xml b/pom.xml index 07f81b5..0ce6b8e 100644 --- a/pom.xml +++ b/pom.xml @@ -16,7 +16,7 @@ 21 21 UTF-8 - 0.35.0 + 4.0.0 diff --git a/src/main/java/com/kingsrook/qbits/example/ExampleAppQBitProducer.java b/src/main/java/com/kingsrook/qbits/example/ExampleAppQBitProducer.java index 9dac58d..e5fb536 100644 --- a/src/main/java/com/kingsrook/qbits/example/ExampleAppQBitProducer.java +++ b/src/main/java/com/kingsrook/qbits/example/ExampleAppQBitProducer.java @@ -17,6 +17,7 @@ import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerHelper; import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerOutput; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppMetaData; import com.kingsrook.qqq.backend.core.model.metadata.layout.QAppSection; import com.kingsrook.qqq.backend.core.model.metadata.layout.QIcon; import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaData; @@ -104,20 +105,20 @@ public class ExampleAppQBitProducer implements QBitProducer } ///////////////////////////////////////////////////////////////////////// - // Register QAppSection for UI navigation (REQUIRED for app QBits) // + // Register QAppMetaData for UI navigation (REQUIRED for app QBits) // ///////////////////////////////////////////////////////////////////////// - qInstance.addAppSection(produceAppSection(config, qBitMetaData.getName())); + qInstance.addApp(produceApp(config, qBitMetaData.getName())); } /******************************************************************************* - ** Produce the QAppSection for UI navigation. + ** Produce the QAppMetaData for UI navigation. ** ** This is REQUIRED for Application QBits - it defines how users navigate ** to the tables, processes, and widgets in the UI. *******************************************************************************/ - private QAppSection produceAppSection(ExampleAppQBitConfig config, String qbitName) + private QAppMetaData produceApp(ExampleAppQBitConfig config, String qbitName) { List tables = new ArrayList<>(); tables.add(config.applyPrefix(ExampleEntity.TABLE_NAME)); @@ -127,12 +128,17 @@ public class ExampleAppQBitProducer implements QBitProducer tables.add(config.applyPrefix(ExampleChildEntity.TABLE_NAME)); } - return new QAppSection() + QAppSection section = new QAppSection() + .withName(config.applyPrefix("exampleSection")) + .withLabel("Example Application") + .withIcon(new QIcon().withName("dashboard")) + .withTables(tables); + + return new QAppMetaData() .withName(config.applyPrefix("exampleApp")) .withLabel("Example Application") .withIcon(new QIcon().withName("dashboard")) - .withTables(tables) - .withSourceQBitName(qbitName); + .withSection(section); } diff --git a/src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessMetaDataProducer.java b/src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessMetaDataProducer.java index ba49c74..93cfee1 100644 --- a/src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessMetaDataProducer.java +++ b/src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessMetaDataProducer.java @@ -7,12 +7,13 @@ package com.kingsrook.qbits.example.processes; import java.util.List; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldMetaData; import com.kingsrook.qqq.backend.core.model.metadata.fields.QFieldType; import com.kingsrook.qqq.backend.core.model.metadata.processes.QBackendStepMetaData; +import com.kingsrook.qqq.backend.core.model.metadata.processes.QFunctionInputMetaData; import com.kingsrook.qqq.backend.core.model.metadata.processes.QProcessMetaData; -import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface; import com.kingsrook.qbits.example.model.ExampleEntity; @@ -32,15 +33,14 @@ public class ExampleProcessMetaDataProducer implements MetaDataProducerInterface .withName(NAME) .withLabel("Example Process") .withTableName(ExampleEntity.TABLE_NAME) - .withInputFields(List.of( - new QFieldMetaData("confirmAction", QFieldType.BOOLEAN) - .withLabel("Confirm Action") - .withDefaultValue(false) - )) .withStepList(List.of( new QBackendStepMetaData() .withName("process") .withCode(new QCodeReference(ExampleProcessStep.class)) + .withInputData(new QFunctionInputMetaData() + .withField(new QFieldMetaData("confirmAction", QFieldType.BOOLEAN) + .withLabel("Confirm Action") + .withDefaultValue(false))) )); } } diff --git a/src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessStep.java b/src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessStep.java index 14fcac0..216d83d 100644 --- a/src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessStep.java +++ b/src/main/java/com/kingsrook/qbits/example/processes/ExampleProcessStep.java @@ -9,11 +9,13 @@ package com.kingsrook.qbits.example.processes; +import java.util.ArrayList; import java.util.List; -import com.kingsrook.qqq.backend.core.actions.processes.RunBackendStepInput; -import com.kingsrook.qqq.backend.core.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.exceptions.QException; import com.kingsrook.qqq.backend.core.logging.QLogger; +import com.kingsrook.qqq.backend.core.model.actions.processes.ProcessSummaryLineInterface; +import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput; +import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput; import com.kingsrook.qqq.backend.core.model.data.QRecord; import com.kingsrook.qqq.backend.core.processes.implementations.etl.streamedwithfrontend.AbstractTransformStep; import static com.kingsrook.qqq.backend.core.logging.LogUtils.logPair; @@ -50,4 +52,16 @@ public class ExampleProcessStep extends AbstractTransformStep LOG.info("Processing complete", logPair("processed", records.size())); } + + + + /******************************************************************************* + ** Return the process summary. Override this method in subclasses to provide + ** meaningful summary lines for the result screen. + *******************************************************************************/ + @Override + public ArrayList getProcessSummary(RunBackendStepOutput runBackendStepOutput, boolean isForResultScreen) + { + return (new ArrayList<>()); + } } diff --git a/src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetMetaDataProducer.java b/src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetMetaDataProducer.java index 6ce47f3..a2bec6c 100644 --- a/src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetMetaDataProducer.java +++ b/src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetMetaDataProducer.java @@ -7,10 +7,11 @@ package com.kingsrook.qbits.example.widgets; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.dashboard.widgets.WidgetType; import com.kingsrook.qqq.backend.core.model.metadata.QInstance; import com.kingsrook.qqq.backend.core.model.metadata.code.QCodeReference; import com.kingsrook.qqq.backend.core.model.metadata.dashboard.QWidgetMetaData; -import com.kingsrook.qqq.backend.core.model.MetaDataProducerInterface; +import com.kingsrook.qqq.backend.core.model.metadata.MetaDataProducerInterface; public class ExampleDashboardWidgetMetaDataProducer implements MetaDataProducerInterface @@ -28,7 +29,7 @@ public class ExampleDashboardWidgetMetaDataProducer implements MetaDataProducerI return new QWidgetMetaData() .withName(NAME) .withLabel("Example Dashboard") - .withType("chart") + .withType(WidgetType.STATISTICS.getType()) .withCodeReference(new QCodeReference(ExampleDashboardWidgetRenderer.class)); } } diff --git a/src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetRenderer.java b/src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetRenderer.java index 42e487e..6bec978 100644 --- a/src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetRenderer.java +++ b/src/main/java/com/kingsrook/qbits/example/widgets/ExampleDashboardWidgetRenderer.java @@ -6,12 +6,11 @@ package com.kingsrook.qbits.example.widgets; -import java.util.HashMap; -import java.util.Map; -import com.kingsrook.qqq.backend.core.actions.dashboard.AbstractWidgetRenderer; -import com.kingsrook.qqq.backend.core.actions.dashboard.RenderWidgetInput; -import com.kingsrook.qqq.backend.core.actions.dashboard.RenderWidgetOutput; +import com.kingsrook.qqq.backend.core.actions.dashboard.widgets.AbstractWidgetRenderer; import com.kingsrook.qqq.backend.core.exceptions.QException; +import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetInput; +import com.kingsrook.qqq.backend.core.model.actions.widgets.RenderWidgetOutput; +import com.kingsrook.qqq.backend.core.model.dashboard.widgets.StatisticsData; public class ExampleDashboardWidgetRenderer extends AbstractWidgetRenderer @@ -22,16 +21,13 @@ public class ExampleDashboardWidgetRenderer extends AbstractWidgetRenderer @Override public RenderWidgetOutput render(RenderWidgetInput input) throws QException { - Map data = new HashMap<>(); - data.put("title", "Example Dashboard"); - data.put("description", "This is an example widget for the Application QBit template."); - ///////////////////////////////////////////////////////////////////////// // Add chart data, counts, or other dashboard information here // ///////////////////////////////////////////////////////////////////////// - data.put("totalCount", 0); - data.put("activeCount", 0); + StatisticsData data = new StatisticsData() + .withCount(0) + .withCountContext("Total items"); - return new RenderWidgetOutput(data); + return (new RenderWidgetOutput(data)); } } -- 2.54.0 From 6a660223c74bba6b870852bc29547f382622c749 Mon Sep 17 00:00:00 2001 From: James Maes Date: Tue, 20 Oct 2026 07:21:56 -0500 Subject: [PATCH 5/9] ci: adopt central QQQ orb 0.7.4 Co-Authored-By: Codex --- .circleci/config.yml | 29 +++++++++++------------------ .qqq-ci.yml | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 18 deletions(-) create mode 100644 .qqq-ci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 010cd62..f8102d3 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,21 +1,14 @@ version: 2.1 - +setup: true orbs: - qqq-orb: kingsrook/qqq-orb@0.5.0 - -commands: - configure-package-install: - steps: - - run: - name: Keep package installation unattended - command: | - # These build machines are discarded after the job. - sudo install -d /etc/needrestart/conf.d - printf '%s\n' '$nrconf{restart} = "l";' | sudo tee /etc/needrestart/conf.d/99-qqq-ci.conf >/dev/null - + qqq-orb: kingsrook/qqq-orb@0.7.4 workflows: - build: - jobs: - - qqq-orb/mvn_test_only: - pre-steps: - - configure-package-install + setup: + jobs: + - qqq-orb/generate_pipeline: + orb_version: 0.7.4 + filters: + branches: + ignore: automation/qbit-rc-pending + tags: + ignore: /.*/ diff --git a/.qqq-ci.yml b/.qqq-ci.yml new file mode 100644 index 0000000..dc27824 --- /dev/null +++ b/.qqq-ci.yml @@ -0,0 +1,16 @@ +profile: qbit +orb_version: 0.7.4 +default_branch: main +java_version: '21' +browsers: true +api_checks: false +docs_only: false +release_on_main: false +release_tag_policy: none +test_branch_policy: all +publish: + snapshot: false + release_candidate: false + release: false + asciidoc: false +release_completion: false -- 2.54.0 From f47012d25bbeed9e69adc264470c28ca5a3562ad Mon Sep 17 00:00:00 2001 From: James Maes Date: Wed, 21 Oct 2026 00:54:34 -0500 Subject: [PATCH 6/9] ci: adopt shared orb 0.7.11 (#7) Co-authored-by: Codex --- .circleci/config.yml | 4 ++-- .qqq-ci.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f8102d3..ff93256 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,12 +1,12 @@ version: 2.1 setup: true orbs: - qqq-orb: kingsrook/qqq-orb@0.7.4 + qqq-orb: kingsrook/qqq-orb@0.7.11 workflows: setup: jobs: - qqq-orb/generate_pipeline: - orb_version: 0.7.4 + orb_version: 0.7.11 filters: branches: ignore: automation/qbit-rc-pending diff --git a/.qqq-ci.yml b/.qqq-ci.yml index dc27824..8e2829f 100644 --- a/.qqq-ci.yml +++ b/.qqq-ci.yml @@ -1,5 +1,5 @@ profile: qbit -orb_version: 0.7.4 +orb_version: 0.7.11 default_branch: main java_version: '21' browsers: true -- 2.54.0 From 11a4fc0eda4c14db8f8a99f0265666a2e2f3d7f1 Mon Sep 17 00:00:00 2001 From: James Maes Date: Wed, 21 Oct 2026 08:55:39 -0500 Subject: [PATCH 7/9] ci: adopt central orb 0.7.12 and stable gates (#8) Co-authored-by: Codex --- .circleci/config.yml | 4 ++-- .qqq-ci.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ff93256..8b8bfbd 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,12 +1,12 @@ version: 2.1 setup: true orbs: - qqq-orb: kingsrook/qqq-orb@0.7.11 + qqq-orb: kingsrook/qqq-orb@0.7.12 workflows: setup: jobs: - qqq-orb/generate_pipeline: - orb_version: 0.7.11 + orb_version: 0.7.12 filters: branches: ignore: automation/qbit-rc-pending diff --git a/.qqq-ci.yml b/.qqq-ci.yml index 8e2829f..7028d97 100644 --- a/.qqq-ci.yml +++ b/.qqq-ci.yml @@ -1,5 +1,5 @@ profile: qbit -orb_version: 0.7.11 +orb_version: 0.7.12 default_branch: main java_version: '21' browsers: true -- 2.54.0 From 5d0abf3c39c72b9cf702460036fccae2e86a1099 Mon Sep 17 00:00:00 2001 From: James Maes Date: Wed, 21 Oct 2026 16:34:41 -0500 Subject: [PATCH 8/9] ci: adopt managed orb 0.8 patch track (#9) Co-authored-by: Codex --- .circleci/config.yml | 4 ++-- .qqq-ci.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 8b8bfbd..32df77b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,12 +1,12 @@ version: 2.1 setup: true orbs: - qqq-orb: kingsrook/qqq-orb@0.7.12 + qqq-orb: kingsrook/qqq-orb@0.8 workflows: setup: jobs: - qqq-orb/generate_pipeline: - orb_version: 0.7.12 + orb_version: '0.8' filters: branches: ignore: automation/qbit-rc-pending diff --git a/.qqq-ci.yml b/.qqq-ci.yml index 7028d97..d65dd23 100644 --- a/.qqq-ci.yml +++ b/.qqq-ci.yml @@ -1,5 +1,5 @@ profile: qbit -orb_version: 0.7.12 +orb_version: '0.8' default_branch: main java_version: '21' browsers: true -- 2.54.0 From 46f003eaa76adf270d4be9f9ff54ef17ffe25bb2 Mon Sep 17 00:00:00 2001 From: James Maes Date: Wed, 21 Oct 2026 18:31:15 -0500 Subject: [PATCH 9/9] ci: use central orb pipeline on develop Co-Authored-By: Codex --- .circleci/config.yml | 17 +++++++++++------ .qqq-ci.yml | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 6 deletions(-) create mode 100644 .qqq-ci.yml diff --git a/.circleci/config.yml b/.circleci/config.yml index 8828026..32df77b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,9 +1,14 @@ version: 2.1 - +setup: true orbs: - qqq-orb: kingsrook/qqq-orb@0.5.0 - + qqq-orb: kingsrook/qqq-orb@0.8 workflows: - build: - jobs: - - qqq-orb/mvn_test + setup: + jobs: + - qqq-orb/generate_pipeline: + orb_version: '0.8' + filters: + branches: + ignore: automation/qbit-rc-pending + tags: + ignore: /.*/ diff --git a/.qqq-ci.yml b/.qqq-ci.yml new file mode 100644 index 0000000..d65dd23 --- /dev/null +++ b/.qqq-ci.yml @@ -0,0 +1,16 @@ +profile: qbit +orb_version: '0.8' +default_branch: main +java_version: '21' +browsers: true +api_checks: false +docs_only: false +release_on_main: false +release_tag_policy: none +test_branch_policy: all +publish: + snapshot: false + release_candidate: false + release: false + asciidoc: false +release_completion: false -- 2.54.0