fix(intent): a view is an additional page, not a replacement — and a document's calendar line items render (#6547, #6482) - #6624
Conversation
…calendar line items render (#6547, #6482) Two ways a `view: calendar` declaration silently cost the author something. #6547 - the calendar REPLACED the entity's layout. `view: calendar|range` was emitted as `layoutType: MANAGE_CALENDAR`, overriding whatever layout the entity had resolved, so a `function: Document` master browsed on a calendar lost its whole document surface: line items, Print, inline process tasks (approvals fell back to the Inbox). Authors had to choose between the calendar and the document. The calendar is now an ADDITIONAL page. `EdmIntentGenerator` emits the entity attribute `calendarView` and leaves `layoutType` at the natural MANAGE / MANAGE_MASTER / MANAGE_DOCUMENT, so every page that layout brings still exists. The landing route stays where it was - no behaviour change for existing calendar apps - and the layout's own browse page moves down one segment: /<Entity> the calendar /<Entity>/list the layout's list / master / document list /<Entity>/create the layout's own editor (the document page for a document) /<Entity>/:id/edit likewise Both browse pages carry a switch to the other; the personal surface mirrors it (/my/<Entity> calendar, /my/<Entity>/list list). `view: slots` deliberately still replaces the layout - a slot picker is an authoring surface, not a second way to browse. `MANAGE_CALENDAR` is gone from every consumer; it was intent-only and never offered by the entity editor, so nothing hand-authored carries it. #6482 - a document's LINE-ITEMS child declaring `view: calendar` emitted the panel markup and was then filtered out of `secondaryDetails` by name (the items child has its own section), so the declaration produced nothing at all: parsed, generated, every status green, feature absent. The master now carries `documentItemsLayout: calendar` (derived from the child - the `calendar:` config belongs to the child) and the items PANE renders as an x-h-calendar on all three document surfaces: the same rows and the same line dialog, event-click edits, empty-day click adds with the date preset, Delete moves into the dialog. It is mutually exclusive with `documentItemsLayout: chat` - parser-rejected, since both claim that pane. The row-to-event mapping is now one shared implementation (application-core `services/calendarEvents.js`), and the calendar's own config is read at runtime from the child's detail registration, so the document page still never enumerates the child at generation time. Covered by EdmIntentGeneratorTest / IntentParserTest and the emission oracle (IntentEmissionCoverageIT): the routes, the toggles, the items calendar on the power and personal surfaces, and the calendar root keeping its own list + form. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Verified in a browser as well (the layer the emission oracle cannot reach), against a local instance with a generated + published fixture app — a #6482 — the items pane ( #6547 — the additional page ( No console errors or exceptions on either page. |
…irs the #6624 merge left behind (#6629) * fix(intent): the slot picker is an additional page too, and a view no longer double-registers its perspective Follow-up to the calendar change, closing the same hole for `view: slots`. `view: slots` was left replacing the layout on the argument that a picker is an authoring surface rather than a second way to browse. That does not survive contact with a booking document: the picker is how a booking is CREATED, the document page is how it is worked with afterwards, and an author needs both - exactly the choice #6547 was about. So the picker gets the calendar's treatment: `EdmIntentGenerator` emits `slotsView` instead of `layoutType: MANAGE_SLOTS`, `uiSlotsModels` keys on it, `slots.js` stops emitting the shared manage form (the layout owns the editor, so slot-click on a document master now lands on the DOCUMENT create page prefilled with the chosen datetime), the picker takes over /<Entity> while the layout browses at /<Entity>/list, and the two carry a Slots/List switch. `MANAGE_SLOTS` is gone from every consumer; like MANAGE_CALENDAR it was intent-only and never offered by the entity editor. It also fixes a defect the calendar commit introduced, which extending the rule to slots made obvious: `navigation.js`'s PERSPECTIVE_COLLECTIONS listed `uiCalendarModels`/`uiSlotsModels` alongside the LAYOUT collections. Now that a view entity keeps its layout it is a member of both, so its perspective was generated TWICE - the same rename path written twice and a duplicate application-perspectives contribution. The two view collections are dropped from that list; a view entity is always in exactly one layout collection. Covered by EdmIntentGeneratorTest (a slots document master keeps MANAGE_DOCUMENT and carries slotsView + the slot* metadata) and the emission oracle, whose fixture gained a slots document: the /Visit picker landing route, /Visit/list, /Visit/create resolving to the DOCUMENT editor, and both toggles. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(ide-template): the Java generation port keeps parity on the additional-page views #6628 ported generateUtils.js to Java about an hour after #6624 merged, against the pre-#6624 logic: uiCalendarModels / uiSlotsModels / personalCalendarModels / personalListModels still keyed on MANAGE_CALENDAR / MANAGE_SLOTS, which EdmIntentGenerator no longer emits. Nothing is broken today - both paths are live and no consumer is switched, so the JS path executes - but the moment consumers flip, calendar and slots pages would silently stop being generated: an empty partition writes no files and raises no error. GenerationParityIT could not catch it either, because no parity fixture declares a view, so all four partitions can disagree while every fixture matches. Key the Java collections on calendarView / slotsView (and drop the calendar exclusion from personalListModels, matching the JS), and add a views.model fixture - one calendar entity, one slot-picker entity, both keeping their MANAGE layout - as a parity case. Confirmed it is a real guard: with the ModelGenerator change reverted the case fails naming the absent AppointmentSlotsPage.js and Appointment-slots.html; with it, both pipelines agree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…generation port keeps parity (#6632) * fix(intent): the slot picker is an additional page too, and a view no longer double-registers its perspective Follow-up to the calendar change, closing the same hole for `view: slots`. `view: slots` was left replacing the layout on the argument that a picker is an authoring surface rather than a second way to browse. That does not survive contact with a booking document: the picker is how a booking is CREATED, the document page is how it is worked with afterwards, and an author needs both - exactly the choice #6547 was about. So the picker gets the calendar's treatment: `EdmIntentGenerator` emits `slotsView` instead of `layoutType: MANAGE_SLOTS`, `uiSlotsModels` keys on it, `slots.js` stops emitting the shared manage form (the layout owns the editor, so slot-click on a document master now lands on the DOCUMENT create page prefilled with the chosen datetime), the picker takes over /<Entity> while the layout browses at /<Entity>/list, and the two carry a Slots/List switch. `MANAGE_SLOTS` is gone from every consumer; like MANAGE_CALENDAR it was intent-only and never offered by the entity editor. It also fixes a defect the calendar commit introduced, which extending the rule to slots made obvious: `navigation.js`'s PERSPECTIVE_COLLECTIONS listed `uiCalendarModels`/`uiSlotsModels` alongside the LAYOUT collections. Now that a view entity keeps its layout it is a member of both, so its perspective was generated TWICE - the same rename path written twice and a duplicate application-perspectives contribution. The two view collections are dropped from that list; a view entity is always in exactly one layout collection. Covered by EdmIntentGeneratorTest (a slots document master keeps MANAGE_DOCUMENT and carries slotsView + the slot* metadata) and the emission oracle, whose fixture gained a slots document: the /Visit picker landing route, /Visit/list, /Visit/create resolving to the DOCUMENT editor, and both toggles. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(ide-template): the Java generation port keeps parity on the additional-page views #6628 ported generateUtils.js to Java about an hour after #6624 merged, against the pre-#6624 logic: uiCalendarModels / uiSlotsModels / personalCalendarModels / personalListModels still keyed on MANAGE_CALENDAR / MANAGE_SLOTS, which EdmIntentGenerator no longer emits. Nothing is broken today - both paths are live and no consumer is switched, so the JS path executes - but the moment consumers flip, calendar and slots pages would silently stop being generated: an empty partition writes no files and raises no error. GenerationParityIT could not catch it either, because no parity fixture declares a view, so all four partitions can disagree while every fixture matches. Key the Java collections on calendarView / slotsView (and drop the calendar exclusion from personalListModels, matching the JS), and add a views.model fixture - one calendar entity, one slot-picker entity, both keeping their MANAGE layout - as a parity case. Confirmed it is a real guard: with the ModelGenerator change reverted the case fails naming the absent AppointmentSlotsPage.js and Appointment-slots.html; with it, both pipelines agree. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Closes #6547. Closes #6482.
Three ways a
view:declaration silently cost the author something. All are the same failure class — the attribute parses, the generation is green, and the promise is simply absent from the running app.#6547 — the calendar replaced the entity's layout
view: calendar|rangewas emitted aslayoutType: MANAGE_CALENDAR, which overrode whatever layout the entity had resolved. For afunction: Documentmaster that meant losing the document surface entirely: line items, Print, inline process tasks (approvals fell back to the Inbox). Authors had to choose between the calendar and the document.The calendar is now an additional page.
EdmIntentGeneratoremits the entity attributecalendarViewand leaveslayoutTypeat the naturalMANAGE/MANAGE_MASTER/MANAGE_DOCUMENT, so every page that layout brings still exists. The landing route stays where it always was — no behaviour change for existing calendar apps — and the layout's own browse page moves down one segment:/<Entity>/<Entity>/list/<Entity>/create,/<Entity>/:id/edit,/:id/previewBoth browse pages carry a switch to the other (
goCalendar()/goList()); the personal surface mirrors it (/my/<Entity>calendar,/my/<Entity>/listlist, sopersonalListModelsno longer excludes calendar roots).calendar.jsno longer emits the shared manage form — the layout owns it.view: slotsgets the same treatment (second commit). It was initially left replacing the layout on the argument that a picker is an authoring surface rather than a second way to browse — which does not survive contact with a booking document: the picker is how a booking is created, the document page is how it is worked with afterwards, and an author needs both. SoslotsViewreplaceslayoutType: MANAGE_SLOTS,slots.jsstops emitting the shared form, and slot-click on a document master now lands on the document create page prefilled with the chosen datetime./<Entity>is the picker,/<Entity>/listthe layout's browse page, with a Slots⇄List toggle pair. Nothing about a view replaces a layout any more.MANAGE_CALENDAR(andMANAGE_SLOTS) is gone from every consumer (uiCalendarModels/personalCalendarModelsnow key oncalendarView; the shell template,calendar.jsand the AppTest manifest's layout token follow). It was intent-only and never offered by the entity editor, so no hand-authored.edmcan still carry it.#6482 — a document's calendar line items rendered nothing
The line-items child declaring
view: calendaremitted its panel markup and was then filtered out ofsecondaryDetailsby name — correct on its own terms (the items have their own section), but it meant the calendar could only ever apply to a secondary child, and the declaration produced nothing at all.The issue's option 1: the items pane honours it. The master now carries
documentItemsLayout: calendar, derived from the child (thecalendar:config belongs to the child, so it is never authored on the master), and the pane renders as anx-h-calendaron all three document surfaces (power, personal, partner): the same rows and the same line dialog — event-click edits that line, empty-day click adds one with the date preset, and Delete moves into the dialog since a calendar has no per-row menu. Mutually exclusive withdocumentItemsLayout: chat(both claim that pane), parser-rejected with a message naming both.The row→event mapping is now one shared implementation —
application-core/shell/js/services/calendarEvents.js(window.HarmoniaCalendar) — rather than a third, fourth and fifth copy of the Jacksonjava.timenormalization. The calendar's own configuration is read at runtime from the child's detail registration, so the document page still never enumerates the child at generation time.Verification
engine-intent, including the rewrittendocumentMasterWithACalendarViewKeepsTheDocumentLayoutAndAddsTheCalendar, a newdocumentWhoseItemsChildIsACalendarRendersTheItemsPaneAsACalendar, andchatDocumentRejectsAnItemsChildThatIsAlsoACalendar.IntentEngineIT: 39 green.IntentEmissionCoverageIT(the emission oracle) green with new assertions: the/Leavecalendar landing route,/Leave/list,/Leave/create,/my/Leave/list, both toggles, and the items calendar on the power and personal document surfaces (x-h-calendar="itemsCalCfg",HarmoniaCalendar.events,itemsDef.calendar, the dialog Delete, and the items table gone). The fixture gained aRoster/RosterItemdocument pair for it.Document+view: calendar, and a document whose items child is a calendar) — 0 problems for the project, healthReady, and the generated shell carries/Booking→ calendar,/Booking/list→ the document list,/Booking/:id/edit→ the document editor, plusRoster-document.htmlwith the items calendar.mvn formatter:validateclean; the release-profile javadoc build clean.A defect this surfaced, worth calling out
Extending the rule to slots made a mistake in the first commit obvious:
navigation.js'sPERSPECTIVE_COLLECTIONSlisteduiCalendarModels/uiSlotsModelsalongside the layout collections. Once a view entity keeps its layout it is a member of both, so its perspective was generated twice — the same rename path written twice and a duplicateapplication-perspectivescontribution. Harmless on disk (identical content overwriting itself) but wrong; both view collections are dropped from that list, since a view entity is always in exactly one layout collection. Verified after the fix: exactly oneperspectives/<Entity>/per entity in the generated app.Verified in a browser
Both views were driven end to end on a local instance against a generated + published fixture app (0 problems, health
Ready), with no console errors:Edit lineon that row with the dialog Delete, empty-day click opensAdd linewith the date preset. Header, totals and Print untouched./<Entity>lands on the calendar with a List toggle,/<Entity>/listshows the document list with a Calendar toggle, and the event-click opens the document editor./<Entity>lands on the 3-day picker (honouringopen/close/step) with a List toggle; a free slot opens/<Entity>/create?<Start>=…on the document editor, and the saved record's edit page carriesVisit Items+ Add, the totals footer and Print — exactly what a slots entity used to lose.The partner document surface is a mechanical mirror of the personal one and is not separately asserted (the fixture has no partner-owned document).