From c6992d4fd86169b3e4f916265da7b1a47b318464 Mon Sep 17 00:00:00 2001 From: delchev Date: Fri, 3 Jul 2026 18:18:52 +0300 Subject: [PATCH 1/2] feat(harmonia): read-only Preview route + master detail panels on the edit form Preview - /Entity/{id}/preview renders the same data as edit, fully read-only: - routes registered for MANAGE, SETTING, MASTER, DOCUMENT and DETAIL entities; the shared shell needs no change (it mirrors the embedded app's inner route generically, so #/app///{id}/preview just works) - form + document pages gain mode 'preview' (parsed from the live hash; loads like edit, save/dialog paths guarded); a display:contents
disables every control at once; selects also get :data-disabled so the dropdowns cannot open; footer swaps Cancel/Save for Close + Edit; BPM task buttons, item Add/Edit/Delete, allocation Add/Delete and FK Add-new/Refresh are hidden; the document Print button stays (printing is read-only) - Preview entry points: manage list details pane + row menu, master details toolbar + row menu, detail-panel row menu (detailPanel.previewRow) Detail panels on the edit form (bug fix): a master's detail collections (e.g. Member -> Loans in sample-intent-model) rendered ONLY on the browse view's details pane - the edit view showed just the scalar fields. The form view now renders the same generic detail panels below the form on edit/preview (App.detailsFor registry), outside the
so panel buttons cannot submit it, with add/edit returning to the same page (returnTo override) and read-only rendering in preview. Co-Authored-By: Claude Fable 5 --- .../shell/js/components/detailPanel.js | 5 + .../document/document-page.js.template | 22 ++-- .../document/document-view.html.template | 68 ++++++----- .../perspective/manage/form-page.js.template | 32 ++++-- .../manage/form-view.html.template | 107 +++++++++++++++--- .../perspective/manage/list-page.js.template | 1 + .../manage/list-view.html.template | 2 + .../master/master-page.js.template | 1 + .../master/master-view.html.template | 3 + .../ui/shell/index.html.template | 5 + 10 files changed, 191 insertions(+), 55 deletions(-) diff --git a/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/shell/js/components/detailPanel.js b/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/shell/js/components/detailPanel.js index af64ceac55..09bf4b3923 100644 --- a/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/shell/js/components/detailPanel.js +++ b/components/resources/application-core/src/main/resources/META-INF/dirigible/application-core/shell/js/components/detailPanel.js @@ -129,6 +129,11 @@ function detailPanel(def, masterId) { const q = '?returnTo=' + encodeURIComponent(this.def.returnTo); window.PineconeRouter.navigate('/' + this.def.entity + '/' + encodeURIComponent(row[this.def.primaryKey]) + '/edit' + q); }, + // Read-only view of the detail record (the routed form page in preview mode). + previewRow(row) { + const q = '?returnTo=' + encodeURIComponent(this.def.returnTo); + window.PineconeRouter.navigate('/' + this.def.entity + '/' + encodeURIComponent(row[this.def.primaryKey]) + '/preview' + q); + }, askDelete(row) { this.deleteTarget = row; this.deleteOpen = true; }, async confirmDelete() { diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/document/document-page.js.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/document/document-page.js.template index 05c09b87a1..a125d1b7f5 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/document/document-page.js.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/document/document-page.js.template @@ -6,9 +6,10 @@ */ /* - * Document (header-items) editor for ${name}. One component serves both routes: - * /${name}/create -> create mode (header only; items enable once the header is saved) + * Document (header-items) editor for ${name}. One component serves all three routes: + * /${name}/create -> create mode (header only; items enable once the header is saved) * /${name}/{id}/edit -> edit mode (loads the document, its items, and the totals) + * /${name}/{id}/preview -> preview mode (same data as edit, everything read-only; Print stays) * * Layout (see ${name}-document.html): the master's own fields as a header form (the `aggregate` * totals are excluded here and shown in the footer), an inline-editable line-items table for the @@ -157,9 +158,10 @@ document.addEventListener('alpine:init', () => { apiPath: '/${javaPerspectiveName}/${name}Controller', get isEdit() { return this.mode === 'edit'; }, + get isPreview() { return this.mode === 'preview'; }, get errorCount() { return Object.keys(this.errors).filter(k => this.errors[k]).length; }, // Items can only be added once the document (header) exists, so we have a master id to bind them to. - get itemsEnabled() { return this.isEdit && this.id != null; }, + get itemsEnabled() { return (this.isEdit || this.isPreview) && this.id != null; }, // Any OTHER composition child of this master (not the line-items entity) renders as a normal panel — // like the line items, only once the document (header) exists (nothing to allocate against on Create). get secondaryDetails() { return this.itemsEnabled ? App.detailsFor('${name}').filter(d => d.entity !== '${documentItemsEntity}') : []; }, @@ -232,7 +234,9 @@ document.addEventListener('alpine:init', () => { async init() { const params = (window.PineconeRouter.context && window.PineconeRouter.context.params) || {}; this.id = params.id ?? null; - this.mode = this.id != null ? 'edit' : 'create'; + // Read the live hash to tell /preview from /edit (Pinecone's context can lag the hash). + const routePath = (window.location.hash || '').split('?')[0]; + this.mode = this.id == null ? 'create' : (routePath.endsWith('/preview') ? 'preview' : 'edit'); // The line-items child registered itself as a detail of this master; pick it by name. this.itemsDef = App.detailsFor('${name}').find(d => d.entity === '${documentItemsEntity}') || null; @@ -250,7 +254,7 @@ document.addEventListener('alpine:init', () => { await this.loadOptions(); - if (this.isEdit) { + if (this.isEdit || this.isPreview) { this.state = 'loading'; try { await this.loadHeader(); @@ -383,6 +387,7 @@ document.addEventListener('alpine:init', () => { }, async save() { + if (this.isPreview) return; if (!this.validate()) { this.state = 'validation-error'; this.scrollToSummary(); @@ -601,7 +606,7 @@ document.addEventListener('alpine:init', () => { // ----- Add / edit line dialog ---------------------------------------------------------------- openRowDialog(row) { - if (!this.itemsEnabled) return; + if (!this.itemsEnabled || this.isPreview) return; this.draftError = null; this.draftMode = row ? 'edit' : 'create'; // Suppress the Depends-On watchers while the draft is (re)built - filling an existing row's @@ -681,7 +686,7 @@ document.addEventListener('alpine:init', () => { } }, - askDeleteRow(row) { this.deleteTarget = row; this.deleteOpen = true; }, + askDeleteRow(row) { if (this.isPreview) return; this.deleteTarget = row; this.deleteOpen = true; }, async confirmDeleteRow() { if (!this.deleteTarget) return; @@ -720,5 +725,8 @@ document.addEventListener('alpine:init', () => { }, backToList() { window.PineconeRouter.navigate('/${name}'); }, + + // Preview -> the editable document for the same record. + goEdit() { window.PineconeRouter.navigate('/${name}/' + encodeURIComponent(this.id) + '/edit'); }, })); }, { once: true }); diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/document/document-view.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/document/document-view.html.template index 89d7dce996..764da389c3 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/document/document-view.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/document/document-view.html.template @@ -1,10 +1,12 @@
## Document roles: the DOCUMENT_NUMBER field shows in the title (e.g. "SALES INVOICE 00001231"); the @@ -23,15 +25,15 @@ directive injects font-semibold, which the label must NOT have; only the number is bold. -->
- +
#else - + #end
#if($docStatusProp != "") - + #end
@@ -63,6 +65,9 @@ + +
#foreach($property in $properties) ## Read-only / system fields (ProcessId, audit, uuid, any field marked read-only) render in the @@ -89,7 +94,7 @@
-
+
@@ -98,11 +103,11 @@
- - + +
#else -
+
@@ -134,6 +139,7 @@ #end #end
+
@@ -142,7 +148,7 @@
${documentItemsLabel}
- +
@@ -150,7 +156,7 @@ - + @@ -159,7 +165,7 @@ - + @@ -172,7 +178,7 @@ - + @@ -200,10 +206,10 @@ correction is remove-the-wrong-row + add-the-right-one). Add/create returns to THIS document (returnTo override) rather than the detail's default list. Only once the document exists. ===== --> - - + + #else -
+
@@ -162,19 +168,25 @@ #end #end
+
#if($hasProcess) - + #end
- - + + + @@ -182,13 +194,13 @@
+ top-to-bottom (edit/preview only). --> #set($hasReadOnly = false) #foreach($property in $properties) #if($property.isReadOnlyProperty == "true" || ($property.auditType && $property.auditType != "NONE"))#set($hasReadOnly = true)#end #end #if($hasReadOnly) -
+

@@ -213,4 +225,73 @@ #end + +
+ +
+
diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/list-page.js.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/list-page.js.template index 124c8cca1e..f1da9b3aeb 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/list-page.js.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/list-page.js.template @@ -246,6 +246,7 @@ document.addEventListener('alpine:init', () => { newEntity() { window.PineconeRouter.navigate('/${name}/create'); }, editEntity(row) { window.PineconeRouter.navigate('/${name}/' + encodeURIComponent(row.${primaryKeysString}) + '/edit'); }, + previewEntity(row) { window.PineconeRouter.navigate('/${name}/' + encodeURIComponent(row.${primaryKeysString}) + '/preview'); }, askDelete(row) { this.deleteTarget = row; diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/list-view.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/list-view.html.template index 9dfe89e704..127572878c 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/list-view.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/list-view.html.template @@ -127,6 +127,7 @@
    +
  • @@ -161,6 +162,7 @@
    +
    diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/master/master-page.js.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/master/master-page.js.template index 9c9ed1bde8..5a07574cd4 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/master/master-page.js.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/master/master-page.js.template @@ -129,6 +129,7 @@ document.addEventListener('alpine:init', () => { newMaster() { window.PineconeRouter.navigate('/${name}/create'); }, editMaster(row) { window.PineconeRouter.navigate('/${name}/' + encodeURIComponent(row.${primaryKeysString}) + '/edit'); }, + previewMaster(row) { window.PineconeRouter.navigate('/${name}/' + encodeURIComponent(row.${primaryKeysString}) + '/preview'); }, askDelete(row) { this.deleteTarget = row; this.deleteOpen = true; }, async confirmDelete() { diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/master/master-view.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/master/master-view.html.template index c293d3ef1c..7aa9259fb3 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/master/master-view.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/master/master-view.html.template @@ -59,6 +59,7 @@
      +
    • @@ -85,6 +86,7 @@
      +
      @@ -165,6 +167,7 @@
        +
      • diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/shell/index.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/shell/index.html.template index 6775531db5..bff07eb19e 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/shell/index.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/shell/index.html.template @@ -306,6 +306,7 @@ + #end #end @@ -315,6 +316,7 @@ + #end #end @@ -324,6 +326,7 @@ + #end #end @@ -333,6 +336,7 @@ + #end #end @@ -341,6 +345,7 @@ #if(($entity.layoutType == "MANAGE_DETAILS" || $entity.layoutType == "LIST_DETAILS") && $entity.type == "DEPENDENT") + #end #end From 9766f291009f61d990b1b7cf63c719cc60b69bc7 Mon Sep 17 00:00:00 2001 From: delchev Date: Fri, 3 Jul 2026 18:19:08 +0300 Subject: [PATCH 2/2] feat(harmonia): Print on the generated report pages - report-file page (.report artefacts, the intent reports: surface): Print button next to Export - fetches the FULL filtered result set (POST /export, same as the CSV export, honoring the active per-column filters) and renders it into a minimal print document in a new window (title, row count + filtered marker + timestamp, bordered table, numeric columns right-aligned and pattern-formatted) - model report table page: same Print, with column labels/alignment/format emitted from the report model (printColumns) - model report chart page: Print snapshots the chart canvas as a PNG into the print document (printing the live canvas would clip it to the viewport) Co-Authored-By: Claude Fable 5 --- .../report-file/index.html.template | 1 + .../report-file/report.js.template | 32 +++++++++++++++ .../perspective/report/chart-page.js.template | 16 ++++++++ .../report/chart-view.html.template | 1 + .../perspective/report/table-page.js.template | 39 +++++++++++++++++++ .../report/table-view.html.template | 1 + .../ui/translations.json.template | 2 + 7 files changed, 92 insertions(+) diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/report-file/index.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/report-file/index.html.template index 3e57af8735..0a97b426b4 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/report-file/index.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/report-file/index.html.template @@ -33,6 +33,7 @@ +