You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Harmonia was bumped 2.3.1 -> 2.6.0 (dependabot #6311, pom only). Adapt the
generated Harmonia stack to the 2.4-2.6 breaking changes and adopt the new
pickers.
Slot Picker (2.5.0 breaking): the picker no longer renders its own toolbar,
so the `view: slots` page composed only a bare grid with no date navigation.
Compose the previous/calendar/next/title/today toolbar from the
x-h-slot-picker-* control directives; add the today/chooseDate i18n keys.
Month/Week pickers (new in 2.4.0): adopt as two new intent field types.
- parser: `month`/`week` accepted field types
- EdmIntentGenerator: both map to VARCHAR (len 7/8); the MONTH/WEEK widget
type is chosen from the LOGICAL type, not the JDBC dataType (both VARCHAR,
so invisible to widgetForType) - mirrors the documentTitle special-case
- Harmonia manage form-view + document-view: render x-h-month-picker /
x-h-week-picker instead of plain <input type="month|week">
- FormIntentGenerator + template-form-builder-harmonia: input-month /
input-week controls and picker blocks
- format.js: MONTH/WEEK are plain strings - toPayload passes them through
(not ISO-instant-ized), toDateInput slices; fmtDate maps input-week -> WEEK
The AngularJS stacks already handle both widget types (verified).
Range slider (2.6.0 breaking) and the removed `position-fit` (2.4.0) are not
used by any template, so nothing to change there.
Docs: remove the in-repo `reference/harmonia/` skill mirror (71 files) and
point CLAUDE.md / the migration note at the upstream skill + docs
(codbex.com/harmonia) to avoid drift; bump the "Harmonia 2.3.1" version
string to 2.6.0; document the two new field types.
Tests: EdmIntentGeneratorTest + IntentParserTest cover the month/week
mapping and acceptance; IntentEngineIT.month_and_week_fields_generate_the_harmonia_pickers
asserts the generated .model widget types and the rendered pickers end-to-end.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
A second runtime UI stack, parallel to the AngularJS/BlimpKit one: generated apps render as a self-contained **Alpine.js + Harmonia SPA** (client-routed by Pinecone in hash mode, no iframes/`postMessage` hubs), served at `/services/web/<project>/gen/<model>/index.html`, talking to the **reused** generated Java REST controllers over a `fetch` client. The AngularJS IDE is untouched; the two stacks coexist by URL. `template-application-ui-harmonia-java` (registered on `platform-templates` as "Application - UI (Harmonia) - Java") mirrors `template-application-ui-angular-java` and emits the view types (list, manage, setting, master-detail, reports) + built-in **Process Inbox** (`/inbox`) and **Documents** (`/documents`) shell sections + inline process-task surfacing; `template-form-builder-harmonia` ("Harmonia Generator from Form Model", extension `form`) is the runtime form generator. The whole stack — Alpine 3.15.11, Harmonia 2.3.1, Lucide 1.8.0 — is embedded as **webjars** via `components/resources/application-core` (report charts use Harmonia's own native `x-h-chart-*` SVG charts; the `chart.js` webjar remains only for the legacy AngularJS report/dashboard stacks) (incl. Pinecone Router — `org.webjars.npm:pinecone-router`, served version-less at `/webjars/pinecone-router/dist/router.min.js`; it was vendored until the 7.5.2 webjar existed). Developed on PR [#6078](https://github.com/eclipse-dirigible/dirigible/pull/6078).
194
+
A second runtime UI stack, parallel to the AngularJS/BlimpKit one: generated apps render as a self-contained **Alpine.js + Harmonia SPA** (client-routed by Pinecone in hash mode, no iframes/`postMessage` hubs), served at `/services/web/<project>/gen/<model>/index.html`, talking to the **reused** generated Java REST controllers over a `fetch` client. The AngularJS IDE is untouched; the two stacks coexist by URL. `template-application-ui-harmonia-java` (registered on `platform-templates` as "Application - UI (Harmonia) - Java") mirrors `template-application-ui-angular-java` and emits the view types (list, manage, setting, master-detail, reports) + built-in **Process Inbox** (`/inbox`) and **Documents** (`/documents`) shell sections + inline process-task surfacing; `template-form-builder-harmonia` ("Harmonia Generator from Form Model", extension `form`) is the runtime form generator. The whole stack — Alpine 3.15.11, Harmonia 2.6.0, Lucide 1.8.0 — is embedded as **webjars** via `components/resources/application-core` (report charts use Harmonia's own native `x-h-chart-*` SVG charts; the `chart.js` webjar remains only for the legacy AngularJS report/dashboard stacks) (incl. Pinecone Router — `org.webjars.npm:pinecone-router`, served version-less at `/webjars/pinecone-router/dist/router.min.js`; it was vendored until the 7.5.2 webjar existed). Developed on PR [#6078](https://github.com/eclipse-dirigible/dirigible/pull/6078).
195
195
196
-
**Component reference:**[`components/template/template-application-ui-harmonia-java/reference/harmonia/SKILL.md`](components/template/template-application-ui-harmonia-java/reference/harmonia/SKILL.md) is the full codbex-harmonia directive catalog (all `x-h-*` components incl. the `x-h-select` combobox contract, theming, layout), and [`.../reference/alpinejs/`](components/template/template-application-ui-harmonia-java/reference/alpinejs/) covers the Alpine patterns (routing, page components) — both mirrored from `codbex-athena-app`, the reference app this stack was adopted from. Read them before changing Harmonia markup.
196
+
**Component reference:** the full codbex-harmonia directive catalog (all `x-h-*` components incl. the `x-h-select` combobox contract, theming, layout) lives **upstream** — the docs site <https://codbex.com/harmonia/>and the agent-readable skill <https://github.com/codbex/harmonia/blob/main/skills/harmonia/SKILL.md> (formerly mirrored in-repo under `reference/harmonia/`; that copy was removed to avoid drift — always consult the upstream, version-matched to `harmonia.version` in the root `pom.xml`). [`.../reference/alpinejs/`](components/template/template-application-ui-harmonia-java/reference/alpinejs/)still covers the Alpine patterns (routing, page components), mirrored from `codbex-athena-app`, the reference app this stack was adopted from. Read them before changing Harmonia markup.
197
197
198
198
**Detailed guides:**[`components/template/template-application-ui-harmonia-java/README.md`](components/template/template-application-ui-harmonia-java/README.md) (the SPA shell, view-type parity checklist, the master-detail detail registry, process-tasks store) and [`components/template/template-form-builder-harmonia/README.md`](components/template/template-form-builder-harmonia/README.md) (the neutral `formController(ctx)` contract). The repo-root [`HARMONIA_RUNTIME_PLAN.md`](HARMONIA_RUNTIME_PLAN.md) is the design doc + implementation status. **Gotchas that already burned someone — read before changing the templates:**
199
199
@@ -207,7 +207,7 @@ A second runtime UI stack, parallel to the AngularJS/BlimpKit one: generated app
207
207
- **Process trigger writes ProcessId via a targeted single-column update (no event, no full row).** Starting a process on `onCreate` writes the instance id back; doing it through the normal `update()` republishes `<entity>-updated` and spuriously fires every onUpdate reaction (e.g. the member-email notification fired the instant a loan was created) — and even the silent `updateWithoutEvent()` was a **full-row merge of the trigger's stale snapshot**, which raced concurrent writes (line items recalculating the header totals milliseconds after create, a start-step status set) and silently reverted them. The trigger now uses `repository.updateProperty(id, "ProcessId", processId)` — an SDK `JavaRepository`/`JavaEntityStore` HQL mutation touching only the named column (same for a minted `businessKeyStrategy` field); no audit stamping, no events, nothing else to clobber. `updateProperty` is the sanctioned workflow/system write-back primitive — reserve it for system columns; user data keeps going through the generated repository's normal write path. The trigger guard is `ProcessId != null && !isBlank()` (an empty string from a form must not count as "already started").
208
208
-**Documents/CMS path contract (`/services/js/documents/api/documents.js`).** List the **root with NO `?path=`** (a `?path=/` 400s "null has no such function getName"); navigate by path. The CMS query layer does **not** decode an encoded slash, so build `?path=` with **literal slashes** — encode each segment, not the whole path (`p.split('/').map(encodeURIComponent).join('/')`); a blanket `encodeURIComponent` turns `/`→`%2F` and every subfolder/file 400s. Rename is `PUT {path,name}`; delete is `DELETE` with a JSON body of absolute paths; preview/download are `GET /preview|/download?path=`. Matches the dashboard `documents/js/documents.js`.
209
209
-**Edit forms: match the value to the input shape (dates + comboboxes).** The Java REST controller serializes `java.time` via Jackson as **arrays** (`LocalDate` → `[y,m,d]`, `LocalDateTime` → `[y,m,d,h,mi,s,ns]`) and `Instant` as a **numeric epoch** — NOT ISO strings — so the form's `toDateInput()` handles arrays/numbers/strings (a naive `String(v).slice()` yields garbage → empty date controls on edit). And a relationship FK comes back as a **number** while an option's `data-value` is a string (HTML attribute), so the value must be **stringified on load** (`form.X = String(record.X)`) or the `x-h-select` matches no option and renders empty on edit — the same `String(...)` the codbex-athena-app edit pages use.
210
-
-**Combobox = the Harmonia `x-h-select` contract; mirror codbex-athena-app's forms, not the SKILL's toy example.**`x-model` on `x-h-select-input` holds the VALUE (the option `data-value`); the input displays the matched option's label. Use `data-filter="contains"` + an in-dropdown `x-h-select-search` for searchable pickers, options via `x-for` with `:data-value="String(opt.value)"`. **Do NOT add `x-h-select-clear`** — athena's forms omit it (it appears only in the SKILL's standalone example) and it pushes the selected value ~half its height below the field frame. The component reference is `template-application-ui-harmonia-java/reference/harmonia/SKILL.md`.
210
+
-**Combobox = the Harmonia `x-h-select` contract; mirror codbex-athena-app's forms, not the SKILL's toy example.**`x-model` on `x-h-select-input` holds the VALUE (the option `data-value`); the input displays the matched option's label. Use `data-filter="contains"` + an in-dropdown `x-h-select-search` for searchable pickers, options via `x-for` with `:data-value="String(opt.value)"`. **Do NOT add `x-h-select-clear`** — athena's forms omit it (it appears only in the SKILL's standalone example) and it pushes the selected value ~half its height below the field frame. The component reference is the upstream Harmonia skill (<https://github.com/codbex/harmonia/blob/main/skills/harmonia/SKILL.md>).
211
211
- **Theme goes through Harmonia's own colour-scheme API — do not hand-toggle `.dark`.** `harmonia.min.js` manages the `.dark` class itself from `window.Harmonia.get/setColorScheme('light'|'dark'|'auto')`, persisted to localStorage key `codbex.harmonia.colorMode`; its default is `auto` (follow the OS). The shell's top-right switch (`appShell.js toggleTheme()`) calls `Harmonia.setColorScheme`, and a head bootstrap defaults the key to `light` on first run. Because **every** page loads harmonia.min.js and reads the same key, the shell and the standalone form/report iframes all theme consistently — this is why the task form no longer renders dark on a light shell (an earlier custom `dirigible.harmonia.theme` key + manual `.dark` toggle only fixed the shell, not the iframes). Settings is pinned to the **sidebar footer** (bottom-left, like codbex-athena-app); Reports is a single entry **discovered at runtime** (a `reports` store walks the project registry tree for `*/reports/*/index.html`, since intent reports are standalone pages in a separate gen folder the shell can't see at generation time). The intent recipe defaults (`IntentSettings.scaffold`) point model/form/report at the Harmonia templates; glue stays the neutral client-Java template.
212
212
213
213
- **Velocity vs Alpine `$` is the #1 trap in the Harmonia shell templates.** The shell's `index.html.template` and `dashboardPage.js.template` are **generated via Velocity** (they use `$models`/`$entity`/`$appIcon`), and Velocity parses `$`-references **everywhere — including inside HTML comments and JS string bodies**. An Alpine magic like `$store`/`$notifications`/`$nextTick` is fine as a *bare reference* (undefined → Velocity passes it through literally), but the moment it's followed by a **method call with args or trailing statements** Velocity tries to parse it and the generation 500s with `Encountered "..."`. Three real burns: `$store.processTasks.openTask(n.task); n.unread=false` in an `@click` (fixed by moving the logic to an `appShell.openNotification(n)` method and calling that), `$notifications.add({ template:'toast', data:{ message, variant } })` **in an HTML comment** (Velocity choked on `{ message,…}` — reworded the comment), and `$store...filter(r => r.dashboard !== false)` in a getter (escaped via `#set($dollar='$')` + `${dollar}store`, the same trick `report.js.template` uses for `$limit`/`$nextTick`). Rule: in a Velocity-generated file keep `$store.x` to bare refs / no-arg calls, escape with `${dollar}` for anything richer, or move it into a copied (non-Velocity) JS file / an appShell method.
Logical field types (`FieldIntent.type`) are: `string`, `text`, `integer`, `int`, `long`, `decimal`, `double`, `boolean`, `date`, `timestamp`, `uuid`. Generators map them to JDBC + EDM types. **Primary keys must be an integer type (`integer`/`int`/`long`)** - the Dirigible model convention is integer auto-increment identifiers, and a non-integer auto-increment column is invalid SQL (a `uuid`/`VARCHAR` PK produced `AUTO_INCREMENT` on a `VARCHAR(36)` column, which H2 rejects); the parser enforces this and the EDM generator only emits `dataAutoIncrement` for integer columns. `uuid` remains valid for non-PK fields (maps to `VARCHAR(36)`). Relation kinds: `oneToMany`, `manyToOne`, `oneToOne`, `manyToMany`. Step kinds: `userTask`, `serviceTask`, `decision`, `script`, `end`.
268
+
Logical field types (`FieldIntent.type`) are: `string`, `text`, `integer`, `int`, `long`, `decimal`, `double`, `boolean`, `date`, `timestamp`, `uuid`, `month`, `week`. Generators map them to JDBC + EDM types. `month` (`YYYY-MM`) and `week` (`YYYY-Www`) are stored as VARCHAR strings and get the `MONTH`/`WEEK` widget types (the Harmonia month/week pickers, `x-h-month-picker`/`x-h-week-picker`); their widget is chosen from the logical type, not the JDBC dataType, since both are VARCHAR. **Primary keys must be an integer type (`integer`/`int`/`long`)** - the Dirigible model convention is integer auto-increment identifiers, and a non-integer auto-increment column is invalid SQL (a `uuid`/`VARCHAR` PK produced `AUTO_INCREMENT` on a `VARCHAR(36)` column, which H2 rejects); the parser enforces this and the EDM generator only emits `dataAutoIncrement` for integer columns. `uuid` remains valid for non-PK fields (maps to `VARCHAR(36)`). Relation kinds: `oneToMany`, `manyToOne`, `oneToOne`, `manyToMany`. Step kinds: `userTask`, `serviceTask`, `decision`, `script`, `end`.
Copy file name to clipboardExpand all lines: components/engine/engine-intent/src/main/java/org/eclipse/dirigible/components/intent/generator/edm/EdmIntentGenerator.java
Copy file name to clipboardExpand all lines: components/engine/engine-intent/src/main/java/org/eclipse/dirigible/components/intent/generator/form/FormIntentGenerator.java
+4Lines changed: 4 additions & 0 deletions
Original file line number
Diff line number
Diff line change
@@ -545,6 +545,10 @@ private static Control pickControl(FieldIntent field) {
Copy file name to clipboardExpand all lines: components/engine/engine-intent/src/main/java/org/eclipse/dirigible/components/intent/model/FieldIntent.java
+4-2Lines changed: 4 additions & 2 deletions
Original file line number
Diff line number
Diff line change
@@ -11,8 +11,10 @@
11
11
12
12
/**
13
13
* Single attribute on an {@link EntityIntent}. {@link #type} carries a logical type string
Copy file name to clipboardExpand all lines: components/engine/engine-intent/src/main/java/org/eclipse/dirigible/components/intent/parser/IntentParser.java
0 commit comments