Author SHA1 Message Date
james.maes 7f89186ee7 Merge pull request 'ci: use shared ci-workflows Maven workflow' (#16) from ci/ci-workflows-develop into develop
QRun-IO/ci-policy: ci / fork-guard (push) Skipped
QRun-IO/ci-policy: native / fork-deny (push) Skipped
QRun-IO/ci-policy: native / dotnet-0 (push) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow 539bec410f7926fec3ef7fabe51934a91e0248be] (push) Successful in 9s
QRun-IO/ci-policy: ci / head-profile (push) Skipped
QRun-IO/ci-policy: ci / repository-policy (push) Skipped
QRun-IO/ci-policy: ci / application-template-0 (push) Skipped
QRun-IO/ci-policy: native / native-result (push) Successful in 9s
QRun-IO/ci-policy: ci / gradle-1 (push) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (push) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (push) Skipped
QRun-IO/ci-policy: ci / node-8 (push) Skipped
QRun-IO/ci-policy: ci / node-9 (push) Skipped
QRun-IO/ci-policy: ci / node-10 (push) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (push) Skipped
QRun-IO/ci-policy: ci / source-config-13 (push) Skipped
QRun-IO/ci-policy: ci / source-config-14 (push) Skipped
QRun-IO/ci-policy: ci / android-0 (push) Skipped
QRun-IO/ci-policy: ci / original-business (push) Skipped
QRun-IO/ci-policy: ci / original-mcp (push) Skipped
QRun-IO/ci-policy: ci / original-voyage (push) Skipped
QRun-IO/ci-policy: ci / original-cli (push) Skipped
QRun-IO/ci-policy: ci / not-enrolled (push) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (push) Skipped
QRun-IO/ci-policy: ci / ci-result (push) Successful in 7s
maven / build (push) Successful in 2m14s
build / maven (push) Successful in 2m14s
2026-11-06 17:20:35 +00:00
james.maesandClaude Opus 5.5 2b36e347a8 ci: use shared ci-workflows Maven workflow
QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / Scoped workflow [workflow 1e25bb5a243dfdcd95d4b9a4f780200ff8c8778a] (pull_request) Successful in 12s
QRun-IO/ci-policy: native / native-result (pull_request) Successful in 9s
QRun-IO/ci-policy: ci / head-profile (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (pull_request) Skipped
QRun-IO/ci-policy: ci / node-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-10 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-13 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-14 (pull_request) Skipped
QRun-IO/ci-policy: ci / android-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / original-business (pull_request) Skipped
QRun-IO/ci-policy: ci / original-mcp (pull_request) Skipped
QRun-IO/ci-policy: ci / original-voyage (pull_request) Skipped
QRun-IO/ci-policy: ci / original-cli (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: ci / shared-pipeline (pull_request) Skipped
QRun-IO/ci-policy: Shared Java Maven CI / secrets (pull_request) Successful in 23s
maven / build (push) Successful in 1m56s
build / maven (push) Successful in 1m56s
QRun-IO/ci-policy: Shared Java Maven CI / verify (pull_request) Successful in 1m11s
QRun-IO/ci-policy: Shared Java Maven CI / gate (pull_request) Successful in 15s
QRun-IO/ci-policy: ci / java-maven-6 (pull_request) Successful in 1h13m35s
QRun-IO/ci-policy: ci / ci-result (pull_request) Successful in 5s
Replace the platform-ci release callers with one caller of
KofTwentyTwo/ci-workflows maven.yaml (qqq-orb port).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 15:57:34 +00:00
forge-recovery deab23c782 ci: enroll shared Gitea lifecycle
QRun-IO/ci-policy: ci / fork-guard (push) Skipped
QRun-IO/ci-policy: ci / head-profile (push) Skipped
QRun-IO/ci-policy: ci / application-template-0 (push) Skipped
QRun-IO/ci-policy: ci / gradle-1 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (push) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (push) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (push) Skipped
QRun-IO/ci-policy: ci / node-8 (push) Skipped
QRun-IO/ci-policy: ci / node-9 (push) Skipped
QRun-IO/ci-policy: ci / node-10 (push) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (push) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (push) Skipped
QRun-IO/ci-policy: ci / source-config-13 (push) Skipped
QRun-IO/ci-policy: ci / source-config-14 (push) Skipped
QRun-IO/ci-policy: ci / android-0 (push) Skipped
QRun-IO/ci-policy: ci / not-enrolled (push) Skipped
QRun-IO/ci-policy: native / fork-deny (push) Skipped
QRun-IO/ci-policy: native / dotnet-0 (push) Skipped
Shared Java Maven CI / secrets (push) Successful in 21s
QRun-IO/ci-policy: Shared Java Maven CI / secrets (push) Successful in 22s
QRun-IO/ci-policy: ci / repository-policy (push) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (push) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (push) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (push) Skipped
QRun-IO/ci-policy: native / native-result (push) Successful in 8s
Shared Java Maven CI / verify (push) Successful in 56s
Shared Java Maven CI / gate (push) Successful in 9s
qrun-release / release (push) Successful in 1h46m44s
qrun-release / postpublish (push) Skipped
QRun-IO/ci-policy: Shared Java Maven CI / verify (push) Successful in 53s
QRun-IO/ci-policy: Shared Java Maven CI / gate (push) Successful in 13s
QRun-IO/ci-policy: ci / java-maven-6 (push) Successful in 1h46m57s
QRun-IO/ci-policy: ci / ci-result (push) Successful in 5s
2026-11-02 19:16:28 +00:00
65daa822bb ci: add the isolated postpublish job to the QRun release caller
QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
QRun-IO/ci-policy: ci / head-profile (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-4 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-10 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-11 (pull_request) Skipped
QRun-IO/ci-policy: ci / repository-policy-12 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-13 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-14 (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
Shared Java Maven CI / secrets (push) Successful in 14s
QRun-IO/ci-policy: Shared Java Maven CI / secrets (pull_request) Successful in 14s
QRun-IO/ci-policy: ci / repository-policy (pull_request) Skipped
QRun-IO/ci-policy: ci / java-core-2-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-3-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-6-head (pull_request) Skipped
QRun-IO/ci-policy: ci / java-maven-7-head (pull_request) Skipped
QRun-IO/ci-policy: native / native-result (pull_request) Successful in 4s
Shared Java Maven CI / gate (push) Canceled after 0s
Shared Java Maven CI / verify (push) Canceled after 0s
qrun-release / release (push) Canceled after 2h26m10s
qrun-release / postpublish (push) Canceled after 0s
QRun-IO/ci-policy: Shared Java Maven CI / verify (pull_request) Successful in 45s
QRun-IO/ci-policy: Shared Java Maven CI / gate (pull_request) Successful in 10s
QRun-IO/ci-policy: ci / java-maven-6 (pull_request) Successful in 3h4m48s
QRun-IO/ci-policy: ci / ci-result (pull_request) Successful in 5s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 15:54:15 +00:00
56a75b2a4f ci: move the QRun release caller to the thin v2 contract
QRun-IO/ci-policy: Shared Java Maven CI / gate (pull_request) Canceled after 0s
QRun-IO/ci-policy: ci / java-maven-4 (pull_request) Canceled after 14m7s
Shared Java Maven CI / gate (push) Canceled after 0s
Shared Java Maven CI / verify (push) Canceled after 0s
qrun-release / release (push) Canceled after 14m14s
QRun-IO/ci-policy: Shared Java Maven CI / verify (pull_request) Failing after 1m2s
QRun-IO/ci-policy: native / native-result (pull_request) Successful in 4s
QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-2 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-3 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-6 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-8 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-9 (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: native / fork-deny (pull_request) Skipped
QRun-IO/ci-policy: native / dotnet-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / ci-result (pull_request) Failing after 3s
Shared Java Maven CI / secrets (push) Successful in 17s
QRun-IO/ci-policy: Shared Java Maven CI / secrets (pull_request) Successful in 15s
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 06:21:24 +00:00
forge-recoveryandCodex 023683e00e ci: add the identical QRun release caller
QRun-IO/ci-policy: ci / ci-result (pull_request) Failing after 1s
QRun-IO/ci-policy: ci / fork-guard (pull_request) Skipped
QRun-IO/ci-policy: ci / application-template-0 (pull_request) Skipped
QRun-IO/ci-policy: ci / gradle-1 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-docker-2 (pull_request) Skipped
QRun-IO/ci-policy: ci / java-frontend-browser-3 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-6 (pull_request) Skipped
QRun-IO/ci-policy: ci / not-enrolled (pull_request) Skipped
QRun-IO/ci-policy: ci / node-5 (pull_request) Skipped
QRun-IO/ci-policy: ci / node-playwright-7 (pull_request) Skipped
QRun-IO/ci-policy: ci / source-config-8 (pull_request) Skipped
QRun-IO/ci-policy: Shared Java Maven CI / verify (pull_request) Failing after 1s
QRun-IO/ci-policy: Shared Java Maven CI / secrets (pull_request) Successful in 21s
QRun-IO/ci-policy: Shared Java Maven CI / gate (pull_request) Failing after 1s
QRun-IO/ci-policy: ci / java-maven-4 (pull_request) Failing after 1m34s
Co-Authored-By: Codex <noreply@openai.com>
2026-11-02 04:15:58 +00:00
james.maesandCodex 40bcf97456 ci: use shared advanced CodeQL scanning
Approved scanner-only rollout. Preserve branch language coverage and add workflow scanning.

Co-Authored-By: Codex (GPT-6) <noreply@openai.com>
2026-10-29 16:25:23 -05:00
james.maes f003cf7c76 Merge pull request #10 from QRun-IO/ci/develop-central-orb
fix: align develop with current template and central CI
2026-10-21 18:39:11 -05:00
james.maesandCodex ce0e1b1718 fix: align develop with current QQQ template baseline
Co-Authored-By: Codex <noreply@openai.com>
2026-10-21 18:36:21 -05:00
james.maesandCodex 46f003eaa7 ci: use central orb pipeline on develop
Co-Authored-By: Codex <noreply@openai.com>
2026-10-21 18:31:15 -05:00
james.maesandCodex 5d0abf3c39 ci: adopt managed orb 0.8 patch track (#9)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 16:34:41 -05:00
james.maesandCodex 11a4fc0eda ci: adopt central orb 0.7.12 and stable gates (#8)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 08:55:39 -05:00
james.maesandCodex f47012d25b ci: adopt shared orb 0.7.11 (#7)
Co-authored-by: Codex <noreply@openai.com>
2026-10-21 00:54:34 -05:00
james.maes 68162390a1 Merge pull request #6 from QRun-IO/feature/central-ci
ci: adopt central QQQ orb 0.7.4
2026-10-20 19:31:18 -05:00
james.maesandCodex 6a660223c7 ci: adopt central QQQ orb 0.7.4
Co-Authored-By: Codex <noreply@openai.com>
2026-10-20 19:25:06 -05:00
james.maes 7dc948dc10 chore: bump qqq to 0.40.0-SNAPSHOT 2026-01-10 21:05:32 -06:00
12 changed files with 93 additions and 252 deletions

No files matched your search

+11 -18
View File
@@ -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.8
workflows:
build:
jobs:
- qqq-orb/mvn_test_only:
pre-steps:
- configure-package-install
setup:
jobs:
- qqq-orb/generate_pipeline:
orb_version: '0.8'
filters:
branches:
ignore: automation/qbit-rc-pending
tags:
ignore: /.*/
+10
View File
@@ -0,0 +1,10 @@
name: build
on:
push:
jobs:
maven:
uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/maven.yaml@v1
secrets: inherit
with:
publish: false
browsers: true
+23
View File
@@ -0,0 +1,23 @@
name: CodeQL
'on':
push:
branches:
- main
- develop
- release/**
- hotfix/**
pull_request: {}
schedule:
- cron: 41 16 * * 0
workflow_dispatch: {}
permissions:
contents: read
actions: read
security-events: write
packages: read
concurrency:
group: codeql-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
analyze:
uses: QRun-IO/qqq-orb/.github/workflows/qbit-codeql.yml@c288a8864fe9054f68410e1d78f5863aea4c4d22
+16
View File
@@ -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
+1 -9
View File
@@ -7,7 +7,7 @@ Application QBits typically have multiple interconnected tables representing a b
Use `@QMetaDataProducingEntity` for automatic metadata generation:
```java
@QMetaDataProducingEntity(produceTableMetaData = true, producePossibleValueSource = true)
@QMetaDataProducingEntity(producePossibleValueSource = true)
public class Order extends QRecordEntity
{
public static final String TABLE_NAME = "order";
@@ -23,12 +23,6 @@ public class Order extends QRecordEntity
}
```
Provide JavaBean getters and setters for every persisted field, as in
[`ExampleEntity`](../src/main/java/com/kingsrook/qbits/example/model/ExampleEntity.java).
`producePossibleValueSource` alone does not create a table. Register the
referenced `customer` table and possible-value source before using this
relationship, or replace it with a registered name.
## Relationships
Define foreign keys using `possibleValueSourceName`:
@@ -54,5 +48,3 @@ new MyAppQBitProducer()
```
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.
The scaffold's child-module switch omits the child table, its possible-value
source, and its navigation entry when disabled.
+2 -12
View File
@@ -2,16 +2,6 @@
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.
In QQQ 4.0 and 4.1, import `MetaDataProducerInterface` from
`com.kingsrook.qqq.backend.core.model.metadata`. Define backend-step inputs
with `withInputData(new QFunctionInputMetaData().withField(...))`. The scaffold
uses `BackendStep.run(RunBackendStepInput, RunBackendStepOutput)` and adds each
updated record to the output. Keep that contract when renaming the step.
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.
To make the process discoverable, register its metadata first, then pass the
registered process and tables as children to
`QAppMetaData.withSectionOfChildren(section, children)` before calling
`qInstance.addApp(...)`. This populates both the section references and the
app's child metadata required by validation. Use the actual registered names
if you introduce a prefix. Add tests for record changes and failure cases
when replacing the example business logic.
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.
+4 -12
View File
@@ -6,26 +6,18 @@ The application producer registers a `QAppMetaData` containing a `QAppSection`.
QAppSection section = new QAppSection()
.withName("exampleSection")
.withLabel("Example Application")
.withIcon(new QIcon().withName("dashboard"));
.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")
.withSectionOfChildren(section, List.of(
qInstance.getTable(ExampleEntity.TABLE_NAME),
qInstance.getTable(ExampleChildEntity.TABLE_NAME),
qInstance.getProcess(ExampleProcessMetaDataProducer.NAME))));
.withSection(section));
```
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.
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.
Widgets are registered on `QInstance` separately. `QAppSection` has no
`withWidgets` method in QQQ 4.0 or 4.1, so a widget cannot be added as a
section navigation child. `QAppMetaData.withWidgets(List.of(widgetName))`
associates a registered widget with the app, but rendering and widget
navigation depend on the host UI; the scaffold does not provide a widget
navigation route.
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`.
@@ -17,7 +17,6 @@ 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.QAppChildMetaData;
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;
@@ -25,9 +24,8 @@ import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.qbits.QBitProducer;
import com.kingsrook.qqq.backend.core.model.metadata.qbits.SourceQBitAware;
import com.kingsrook.qqq.backend.core.model.metadata.tables.QTableMetaData;
import com.kingsrook.qbits.example.model.ExampleChildEntity;
import com.kingsrook.qbits.example.model.ExampleEntity;
import com.kingsrook.qbits.example.processes.ExampleProcessMetaDataProducer;
import com.kingsrook.qbits.example.model.ExampleChildEntity;
public class ExampleAppQBitProducer implements QBitProducer
@@ -109,7 +107,7 @@ public class ExampleAppQBitProducer implements QBitProducer
/////////////////////////////////////////////////////////////////////////
// Register QAppMetaData for UI navigation (REQUIRED for app QBits) //
/////////////////////////////////////////////////////////////////////////
qInstance.addApp(produceApp(qInstance, config));
qInstance.addApp(produceApp(config, qBitMetaData.getName()));
}
@@ -120,27 +118,27 @@ public class ExampleAppQBitProducer implements QBitProducer
** This is REQUIRED for Application QBits - it defines how users navigate
** to the tables, processes, and widgets in the UI.
*******************************************************************************/
private QAppMetaData produceApp(QInstance qInstance, ExampleAppQBitConfig config)
private QAppMetaData produceApp(ExampleAppQBitConfig config, String qbitName)
{
List<QAppChildMetaData> children = new ArrayList<>();
children.add(qInstance.getTable(config.applyPrefix(ExampleEntity.TABLE_NAME)));
List<String> tables = new ArrayList<>();
tables.add(config.applyPrefix(ExampleEntity.TABLE_NAME));
if(Boolean.TRUE.equals(config.getEnableChildModule()))
{
children.add(qInstance.getTable(config.applyPrefix(ExampleChildEntity.TABLE_NAME)));
tables.add(config.applyPrefix(ExampleChildEntity.TABLE_NAME));
}
children.add(qInstance.getProcess(ExampleProcessMetaDataProducer.NAME));
QAppSection section = new QAppSection()
.withName(config.applyPrefix("exampleSection"))
.withLabel("Example Application")
.withIcon(new QIcon().withName("dashboard"));
.withIcon(new QIcon().withName("dashboard"))
.withTables(tables);
return new QAppMetaData()
.withName(config.applyPrefix("exampleApp"))
.withLabel("Example Application")
.withIcon(new QIcon().withName("dashboard"))
.withSectionOfChildren(section, children);
.withSection(section);
}
@@ -155,7 +153,7 @@ public class ExampleAppQBitProducer implements QBitProducer
/////////////////////////////////////////////////////////////////////////
if(!Boolean.TRUE.equals(config.getEnableChildModule()))
{
if(ExampleChildEntity.class.equals(producer.getSourceClass()))
if(producer.getClass().getSimpleName().contains("ExampleChildEntity"))
{
return false;
}
@@ -14,7 +14,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity;
@QMetaDataProducingEntity(produceTableMetaData = true, producePossibleValueSource = true)
@QMetaDataProducingEntity(producePossibleValueSource = true)
public class ExampleChildEntity extends QRecordEntity
{
public static final String TABLE_NAME = "exampleChildEntity";
@@ -156,44 +156,4 @@ public class ExampleChildEntity extends QRecordEntity
{
return modifyDate;
}
public void setId(Integer id)
{
this.id = id;
}
public void setExampleEntityId(Integer exampleEntityId)
{
this.exampleEntityId = exampleEntityId;
}
public void setName(String name)
{
this.name = name;
}
public void setDescription(String description)
{
this.description = description;
}
public void setSortOrder(Integer sortOrder)
{
this.sortOrder = sortOrder;
}
public void setIsActive(Boolean isActive)
{
this.isActive = isActive;
}
public void setCreateDate(Instant createDate)
{
this.createDate = createDate;
}
public void setModifyDate(Instant modifyDate)
{
this.modifyDate = modifyDate;
}
}
@@ -16,7 +16,7 @@ import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.metadata.producers.annotations.QMetaDataProducingEntity;
@QMetaDataProducingEntity(produceTableMetaData = true, producePossibleValueSource = true)
@QMetaDataProducingEntity(producePossibleValueSource = true)
public class ExampleEntity extends QRecordEntity
{
public static final String TABLE_NAME = "exampleEntity";
@@ -142,39 +142,4 @@ public class ExampleEntity extends QRecordEntity
{
return modifyDate;
}
public void setId(Integer id)
{
this.id = id;
}
public void setName(String name)
{
this.name = name;
}
public void setDescription(String description)
{
this.description = description;
}
public void setStatus(String status)
{
this.status = status;
}
public void setIsActive(Boolean isActive)
{
this.isActive = isActive;
}
public void setCreateDate(Instant createDate)
{
this.createDate = createDate;
}
public void setModifyDate(Instant modifyDate)
{
this.modifyDate = modifyDate;
}
}
@@ -9,17 +9,19 @@
package com.kingsrook.qbits.example.processes;
import java.util.ArrayList;
import java.util.List;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
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;
public class ExampleProcessStep implements BackendStep
public class ExampleProcessStep extends AbstractTransformStep
{
private static final QLogger LOG = QLogger.getLogger(ExampleProcessStep.class);
@@ -29,7 +31,7 @@ public class ExampleProcessStep implements BackendStep
** Run the process step.
*******************************************************************************/
@Override
public void run(RunBackendStepInput input, RunBackendStepOutput output) throws QException
public void runOnePage(RunBackendStepInput input, RunBackendStepOutput output) throws QException
{
List<QRecord> records = input.getRecords();
LOG.info("Processing records", logPair("count", records.size()));
@@ -53,4 +55,13 @@ public class ExampleProcessStep implements BackendStep
/*******************************************************************************
** Return the process summary. Override this method in subclasses to provide
** meaningful summary lines for the result screen.
*******************************************************************************/
@Override
public ArrayList<ProcessSummaryLineInterface> getProcessSummary(RunBackendStepOutput runBackendStepOutput, boolean isForResultScreen)
{
return (new ArrayList<>());
}
}
@@ -1,109 +0,0 @@
/*
* QQQ - Low-code Application Framework for Engineers.
* Copyright (C) 2021-2022. Kingsrook, LLC
* 651 N Broad St Ste 205 # 6917 | Middletown DE 19709 | United States
* contact@kingsrook.com
* https://github.com/Kingsrook/
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.kingsrook.qbits.example;
import com.kingsrook.qqq.backend.core.actions.processes.BackendStep;
import com.kingsrook.qqq.backend.core.model.data.QRecordEntity;
import com.kingsrook.qqq.backend.core.model.data.QRecord;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepInput;
import com.kingsrook.qqq.backend.core.model.actions.processes.RunBackendStepOutput;
import java.util.List;
import com.kingsrook.qqq.backend.core.model.metadata.QBackendMetaData;
import com.kingsrook.qqq.backend.core.model.metadata.QInstance;
import com.kingsrook.qbits.example.model.ExampleChildEntity;
import com.kingsrook.qbits.example.model.ExampleEntity;
import com.kingsrook.qbits.example.processes.ExampleProcessStep;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
class ExampleAppQBitProducerTest
{
@Test
void producesBothTablesAndTheirPossibleValueSources() throws Exception
{
QInstance instance = produce();
assertNotNull(instance.getTable(ExampleEntity.TABLE_NAME));
assertNotNull(instance.getTable(ExampleChildEntity.TABLE_NAME));
assertNotNull(instance.getPossibleValueSource(ExampleEntity.TABLE_NAME));
assertNotNull(instance.getPossibleValueSource(ExampleChildEntity.TABLE_NAME));
assertEquals(7, QRecordEntity.getFieldList(ExampleEntity.class).size());
assertEquals(8, QRecordEntity.getFieldList(ExampleChildEntity.class).size());
}
@Test
void exampleProcessStepMatchesRegisteredBackendStepContract()
{
assertTrue(BackendStep.class.isAssignableFrom(ExampleProcessStep.class));
}
@Test
void exampleProcessTransformsPendingRecord() throws Exception
{
QRecord record = new QRecord().withValue("status", "PENDING");
RunBackendStepOutput output = new RunBackendStepOutput();
new ExampleProcessStep().run(new RunBackendStepInput().withRecords(List.of(record)), output);
assertEquals("PROCESSED", output.getRecords().getFirst().getValueString("status"));
}
@Test
void producedAppOwnsNavigableTablesAndProcess() throws Exception
{
QInstance instance = produce();
var app = instance.getApp("exampleApp");
assertNotNull(app);
assertNotNull(app.getChildren());
assertTrue(app.getChildren().contains(instance.getTable(ExampleEntity.TABLE_NAME)));
assertTrue(app.getChildren().contains(instance.getTable(ExampleChildEntity.TABLE_NAME)));
assertTrue(app.getChildren().contains(instance.getProcess("exampleProcess")));
assertTrue(app.getSections().stream().anyMatch(section ->
section.getTables().contains(ExampleEntity.TABLE_NAME)
&& section.getProcesses().contains("exampleProcess")));
}
@Test
void disabledChildModuleOmitsChildTableSourceAndNavigation() throws Exception
{
QInstance instance = new QInstance();
instance.addBackend(new QBackendMetaData().withName("rdbms"));
new ExampleAppQBitProducer()
.withConfig(new ExampleAppQBitConfig().withBackendName("rdbms").withEnableChildModule(false))
.produce(instance, "no-child");
assertNotNull(instance.getTable(ExampleEntity.TABLE_NAME));
assertNull(instance.getTable(ExampleChildEntity.TABLE_NAME));
assertNull(instance.getPossibleValueSource(ExampleChildEntity.TABLE_NAME));
assertTrue(instance.getApp("exampleApp").getSections().stream()
.noneMatch(section -> section.getTables().contains(ExampleChildEntity.TABLE_NAME)));
}
private QInstance produce() throws Exception
{
QInstance instance = new QInstance();
instance.addBackend(new QBackendMetaData().withName("rdbms"));
new ExampleAppQBitProducer()
.withConfig(new ExampleAppQBitConfig().withBackendName("rdbms"))
.produce(instance, "regression");
return instance;
}
}