From fbe276ee0754cbfd3755901ddc41c4bd6b8df093 Mon Sep 17 00:00:00 2001 From: Nikol Georgieva Date: Wed, 16 Sep 2026 00:06:06 +0300 Subject: [PATCH 1/5] ui: a document's footer offers a clear Finish, and workflow tasks leave the editor footer for the Inbox (#7403) On a generated document (header-items) entity the editing footer confused a non-developer: line items persist the moment they are added (each row is its own POST/PUT), so the header form is clean and the Save guard `isEdit && !isDirty()` greys Save out - correct, but it reads as "stuck". The footer also mixed workflow (Approve/Issue user-tasks), utilities (Print/Duplicate/...) and the editing session, with two primary buttons (a BPM task and Save) competing for "which one finishes this?". Separate authoring the document from advancing its lifecycle: - Remove the BPM user-task buttons from the record-editor footers (power document and plain form). They are only an inline mirror of the Process Inbox - the same tasks come from /services/inbox/tasks and feed the notification bell - so the Inbox and the bell keep them; nothing is lost. The master-detail read view keeps its inline task surfacing (that is not an editor footer). - Document entities get one honest primary: Create (persist the header, then STAY so line items can be added) on create, and Finish (save any header change, then return to the list) once saved. Finish only navigates on a successful save - a failed validation keeps the user on the page with the error. Never a greyed Save. - Discard/Cancel is shown only while the header has unsaved edits; a clean saved document yields to Finish. Preview (immutable) footer unchanged. - Applied to the power, my and partner document views + pages, and the plain form footer; `finish` added to the shared defaults catalog. Deliberately reverses two earlier choices for these editors: #7359 (Save stayed on the document - Finish navigates away after saving, but the unsaved-changes guard still applies) and #6074 (inline task surfacing - workflow moves to the Inbox). Verified: ModelGenerationIT green (every template renders twice, descriptor + cross-project entity extension asserted); reactor quick-build SUCCESS; formatter:validate SUCCESS on the changed module. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ui/my/my-document-page.js.template | 11 +++++++ .../ui/my/my-document-view.html.template | 16 +++++++--- .../partner/partner-document-page.js.template | 11 +++++++ .../partner-document-view.html.template | 16 +++++++--- .../document/document-page.js.template | 14 ++++++++ .../document/document-view.html.template | 32 +++++++++++-------- .../manage/form-view.html.template | 15 +++------ .../ui/translations.json.template | 1 + 8 files changed, 84 insertions(+), 32 deletions(-) diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-page.js.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-page.js.template index cca3a69534c..b7b74281269 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-page.js.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-page.js.template @@ -638,6 +638,17 @@ document.addEventListener('alpine:init', () => { // A document with unsaved header edits asks before it is abandoned (issue #7359); a clean one // leaves silently, as before. goBack() { this.guardExit(() => this.navigate('/my/${name}')); }, + + // "Finish" on a saved document (issue #7403). Line items persist as they are added, so the only + // thing still unsaved is a header edit: save it, and only leave if the save succeeded (a failure + // sets this.error and keeps the user on the page). A clean header just returns to the list. + async finish() { + if (this.isDirty()) { + await this.save(); + if (this.error) return; + } + this.goBack(); + }, #set($docChildren = []) #if($myChildren) #foreach($child in $myChildren) diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-view.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-view.html.template index faddadd42b0..b2e796583fd 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-view.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-view.html.template @@ -366,12 +366,20 @@
- - - + + #end diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-page.js.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-page.js.template index cb80256292d..06b9ea07a98 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-page.js.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-page.js.template @@ -524,5 +524,16 @@ document.addEventListener('alpine:init', () => { // A document with unsaved header edits asks before it is abandoned (issue #7359); a clean one // leaves silently, as before. goBack() { this.guardExit(() => this.navigate('/partner/${name}')); }, + + // "Finish" on a saved document (issue #7403). Line items persist as they are added, so the only + // thing still unsaved is a header edit: save it, and only leave if the save succeeded (a failure + // sets this.error and keeps the user on the page). A clean header just returns to the list. + async finish() { + if (this.isDirty()) { + await this.save(); + if (this.error) return; + } + this.goBack(); + }, })); }); diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template index 09918455284..6a30b7f0d46 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template @@ -220,12 +220,20 @@
- - - + + 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 c9cc9395c6d..07ff7304233 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 @@ -1406,6 +1406,20 @@ document.addEventListener('alpine:init', () => { // being asked about (issue #7359). A clean one leaves silently, as before. backToList() { this.guardExit(() => window.PineconeRouter.navigate('/${name}')); }, + // "Finish" on a saved document (issue #7403). Line items persist as they are added, so the only + // thing that can still be unsaved is a header edit: save it first, and only leave if the save + // succeeded - a failed validation keeps the user on the page with the error, never navigating on + // failure. A clean header just returns to the list. Not offered on create (that is the Create + // button, which stays on the document so line items can be added). + async finish() { + if (this.isPreview) return; + if (this.isDirty()) { + await this.save(); + if (this.state !== 'ready') return; + } + window.PineconeRouter.navigate('/${name}'); + }, + // Preview -> the editable document for the same record. goEdit() { window.PineconeRouter.navigate('/${name}/' + encodeURIComponent(this.id) + '/edit'); }, })); 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 ce1123dd0fc..c2d79f90778 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 @@ -529,16 +529,13 @@ - +
-#if($hasProcess) - - -#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/form-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/form-view.html.template index a0d607447ee..dcfb558bb39 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/perspective/manage/form-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/form-view.html.template @@ -457,17 +457,12 @@ + document view. Cancel + Save/Create on the RIGHT; workflow user-tasks live in the Process + Inbox, not here (issue #7403). Save is type=button @click=save() because it lives outside the + header
. -->
-#if($hasProcess) - - -#end +
#if($hasPrint == "true") -
- - - - + + - - + + #end
diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-page.js.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-page.js.template index 06b9ea07a98..454a085d79c 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-page.js.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-page.js.template @@ -20,6 +20,10 @@ document.addEventListener('alpine:init', () => { ...basePage(), state: 'loading', mode: 'create', + // True when this session began as a NEW document (create route); stays true after the header is + // saved and `mode` flips to 'edit', so the create flow shows Finish and an existing document opened + // for editing shows Save (issue #7403). + createFlow: false, id: null, error: null, // The single header property a rejected save NAMED ("The 'Name' property is required"), else @@ -105,6 +109,7 @@ document.addEventListener('alpine:init', () => { const params = (window.PineconeRouter.context && window.PineconeRouter.context.params) || {}; this.id = params.id || null; this.mode = this.id ? 'edit' : 'create'; + this.createFlow = this.mode === 'create'; if (this.id) { try { const record = await App.services.api.get(this.apiPath + '/' + this.id); diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template index b98f820be87..51e2b0b9696 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template @@ -229,12 +229,19 @@ - - + + 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 07ff7304233..5efad5a8c1e 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 @@ -138,6 +138,10 @@ document.addEventListener('alpine:init', () => { state: 'ready', // empty-form | loading | ready | saving | validation-error | save-failure | load-failure mode: 'create', + // True when this session began as a NEW document (create route). Stays true after the header is + // saved and `mode` flips to 'edit' for adding line items, so the create flow shows Finish while an + // existing document opened for editing shows Save (issue #7403). + createFlow: false, id: null, record: {}, // the loaded master (drives the read-only totals footer + calculated header fields) @@ -337,6 +341,7 @@ document.addEventListener('alpine:init', () => { // 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'); + this.createFlow = this.mode === 'create'; // 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; 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 9803df4e983..7b865a71003 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 @@ -573,12 +573,19 @@ - - + + From a006f885bc809d6ec8eb6ad114c99fd61eb55039 Mon Sep 17 00:00:00 2001 From: Nikol Georgieva Date: Wed, 16 Sep 2026 00:47:17 +0300 Subject: [PATCH 4/5] ui: the document's edit-mode Save saves and returns to the list (#7403) Editing an existing document showed Save, but it saved and stayed on the page (the #7359 behaviour) and greyed out when nothing had changed - so after opening a saved invoice there was no working primary that returned to the list. Point the edit-mode Save at finish() (save any header change, then back to the list; a failed check keeps the user on the page) and stop greying it. Create still stays on the document so line items can be added; Finish (create flow) and Save (editing) now both save-and-return, differing only in label. Power, my and partner document views. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ui/my/my-document-view.html.template | 7 ++++--- .../ui/partner/partner-document-view.html.template | 7 ++++--- .../ui/perspective/document/document-view.html.template | 7 ++++--- 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-view.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-view.html.template index 2acc244c5bc..70f615aa26c 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-view.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/my/my-document-view.html.template @@ -382,9 +382,10 @@ - - diff --git a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template index 51e2b0b9696..12a9779a6c1 100644 --- a/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template +++ b/components/template/template-application-ui-harmonia-java/src/main/resources/META-INF/dirigible/template-application-ui-harmonia-java/ui/partner/partner-document-view.html.template @@ -236,9 +236,10 @@ - - 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 7b865a71003..8752d727437 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 @@ -580,9 +580,10 @@ - - From 2132e4ac46dad4c0c01af933976359746027bfb5 Mon Sep 17 00:00:00 2001 From: Nikol Georgieva Date: Wed, 16 Sep 2026 00:52:40 +0300 Subject: [PATCH 5/5] ui: Finish survives the create-flow navigation (power document view) (#7403) The power Create button navigates to the /edit route, which re-mounts the page with an id present, so createFlow re-computed to false and Finish never appeared - the add-items phase looked identical to editing an existing document. Carry the signal across the route change with a ?created=1 flag the Create navigation adds and init reads, so the re-mounted /edit page still shows Finish while its line items are added; reopening the document later from the list has no flag and shows Save. The my/partner variants use a silent replaceState and were unaffected. Co-Authored-By: Claude Opus 4.8 (1M context) --- .../ui/perspective/document/document-page.js.template | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) 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 5efad5a8c1e..bfd906cb0d5 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 @@ -341,7 +341,9 @@ document.addEventListener('alpine:init', () => { // 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'); - this.createFlow = this.mode === 'create'; + // The create flow: either the /create route, or the /edit page the Create button just navigated to + // carrying ?created=1 (the header is saved, its line items are being added). Both show Finish. + this.createFlow = this.mode === 'create' || this.queryParam('created') === '1'; // 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; @@ -632,7 +634,9 @@ document.addEventListener('alpine:init', () => { // The write landed, so there is nothing left to protect: clear the guard before the page // navigates itself, or it would veto its own route change. this.clearPristine(); - window.PineconeRouter.navigate('/${name}/' + encodeURIComponent(newId) + '/edit'); + // ?created=1 marks this as the create flow across the route change, so the re-mounted page + // (now at /edit) still shows Finish while its line items are added, not Save (issue #7403). + window.PineconeRouter.navigate('/${name}/' + encodeURIComponent(newId) + '/edit?created=1'); await this.loadHeader(); await this.loadItems(); }