* Add UI knowledge: notification recall Id and Page Management document routing Two ui articles with compiled good/bad samples: - notification-recall-needs-known-id: a notification that the code also recalls needs a fixed Id (single instance; recall before re-send) or per-record tracking through codeunit "Notification Lifecycle Mgt." (SendNotification[WithAdditionalContext] / RecallNotificationsForRecord, HandleDelayedInsert semantics). Never-recalled notifications are exempt. - list-page-document-routing-uses-page-management: open documents from a mixed-type list with PageManagement.PageRun(Rec) instead of a hand-written case "Document Type" / Page.Run; register new tables through OnConditionalCardPageIDNotFound. Single-type opens and tables Page Management does not route are exempt. Wired into al-ui-review (entry gate now covers notification send/recall outside pages, tokens, high-signal mappings) and registered both pairs in the ui review-fixtures override. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address review: scope shared notification Ids, routed-table definition, pinned links - notification-recall-needs-known-id: a fixed Id shared across records is valid for one-at-a-time warnings (Sales Line blocked-item, Over-Receipt Mgt. pass a fixed Id to SendNotification after Recall); the per-record anti-pattern now requires several records' notifications to be visible at once. Recall wording follows Learn (including its false-return reasons) and cites Base App's recall-before-send practice. - list-page-document-routing-uses-page-management: definition covers opening a routed table directly or after Get; cite archive line lists, Copy Document Mgt. ShowSalesDoc/ShowPurchDoc and Office handler; no "document types added later" overclaim (GetSalesHeaderPageID has no else for the extensible enum); full GetPageID resolution order; drop the IRS single-page subscriber. - al-ui-review: non-page files admitted by the notification clause are checked only against notification knowledge; description updated; drop the "Document Type" token; case-insensitive token matching; cues aligned with both articles. - Pin BCApps links to 837ef802485ee457e52310d2ecaa08b93d0122fd. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Address review: notification recall defect is a lost identity, not an unassigned or generated Id - notification-recall-needs-known-id: the defect is a Recall() whose Id cannot be the sent one (fresh local Notification, new CreateGuid at recall time) while neither the sent instance nor its Id is kept. A retained global instance (CreateGuid once in OnOpenPage, or Id left for Send to assign), a generated Id saved after Send and reassigned before Recall, and correctly tracked per-record Ids are explicitly not findings. Findings require evidence that the recalled identity differs from or cannot recover the sent identity. Notification Lifecycle Mgt. is recommended for per-record tracking, not mandatory. Cites VAT Bus. Post. Grp. Part, Certificate, and Data Search Lines, and the lifecycle helper's Send-then-read-Id sequence. - good sample: adds a page with a retained global Notification (CreateGuid in OnOpenPage, Send in an action, Recall in a later action and OnClosePage) and a pageextension that saves the Send-assigned Id and recalls it from a later action. Bad sample comments name the lost identity. - al-ui-review: notification cue requires that evidence and lists the retained-instance, saved-Id, and direct per-record tracking controls as exclusions. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
6.8 KiB
| bc-version | domain | keywords | technologies | countries | application-area | |||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
ui |
|
|
|
|
Open documents from a mixed-type list through Page Management
Description
Some tables back several document pages, chosen by a type field. Sales Header rows open as Sales Quote, Sales Order, Sales Invoice, Sales Credit Memo, Blanket Sales Order, or Sales Return Order, depending on Document Type. A list over such a table cannot use one CardPageID. Codeunit 700 "Page Management" already holds that mapping. PageRun(Rec) resolves the page through GetPageID, in this order: GetConditionalCardPageID, then the default card page (only for an existing record), then GetConditionalListPageID, then the table's lookup page. GetConditionalCardPageID handles Sales Header, Purchase Header, their archives, general and item journal batches and lines, requisition worksheets, and several other tables. Base App's own lists call it: the Show Document actions on Sales List and Purchase List, Sales Lines (after getting the header), and Navigate for posted documents.
A hand-written case Rec."Document Type" of ... Page.Run(Page::"Sales Order", Rec) copies that mapping into a single action. It misses mappings that Microsoft later adds to Page Management, and routing that extensions add through its events (OnBeforeGetConditionalCardPageID, OnAfterGetPageID, OnPageRunAtFieldOnBeforeRunPage). Page Management does not route new values of an extended Sales Document Type enum by itself either, so those still need a subscriber.
Best Practice
In the list's open-document action, call PageManagement.PageRun(Rec), or PageRunModal or PageRunList as needed. PageRun returns false without opening anything when GuiAllowed is false or no page resolves. See sample: list-page-document-routing-uses-page-management.good.al.
For a new table whose rows map to different pages, register the mapping once and then use PageRun everywhere. Subscribe to OnConditionalCardPageIDNotFound, which is raised only for tables the codeunit does not route itself. Microsoft's Sustainability app routes its journal batch and line tables this way. OnBeforeGetConditionalCardPageID is the IsHandled alternative, used by the Quality Management app.
Anti Pattern
A page action that opens a record of a table Page Management routes, directly or after a Get, by switching on its Document Type (or a similar type field) and calling Page.Run(Page::...) in each branch. Base App still does this in several places, for example the Show Document actions of Sales Line Archive List and Purchase Line Archive List, and Copy Document Mgt. ShowSalesDoc/ShowPurchDoc. The result is a duplicated mapping, not a runtime error, so report it as minor. The same switch in a codeunit helper is outside this review's page scope. See sample: list-page-document-routing-uses-page-management.bad.al.
Not this pattern:
- Opening one known document type directly.
Opportunitycreates a quote and runsSales Quote, and a single-type list such asSales Order ListsetsCardPageID = "Sales Order". - A table that Page Management does not route.
Assembly Listswitches onAssembly Header."Document Type"itself. Registering the table throughOnConditionalCardPageIDNotFoundis an improvement there, not a defect fix.
References
- PageManagement.Codeunit.al:
PageRun(lines 44-47),PageRunAtFieldwith theGuiAllowedexit (75-100),GetPageIDresolution order (112-138, order at 121-133),GetConditionalCardPageID(194-263; unrouted tables raiseOnConditionalCardPageIDNotFoundat 258),GetSalesHeaderPageIDwith noelsebranch (289-315), integration events (671-719). SalesDocumentType.Enum.al isExtensible(line 12). - Callers: SalesList.Page.al (
ShowDocument, lines 188-202; noCardPageID), PurchaseList.Page.al (line 200), SalesLines.Page.al (lines 224-230), Navigate.Page.al (from line 1564). - Subscribers: SustWorkflowEventHandling.Codeunit.al (lines 184-193), QltyUtilitiesIntegration.Codeunit.al (lines 20-28).
- Remaining hand-rolled routing of routed tables: SalesLineArchiveList.Page.al (lines 106-121), PurchaseLineArchiveList.Page.al (from line 109), CopyDocumentMgt.Codeunit.al (lines 1369-1409), OfficeDocumentHandler.Codeunit.al (lines 342-348).
- Not this pattern: AssemblyList.Page.al (lines 111-121), Opportunity.Table.al (lines 1221-1223), SalesOrderList.Page.al (line 44).