bcquality/microsoft/knowledge/ui/page-client-expression-must-not-use-in-list.good.al
Michael Dieringer 0867171b1a
2 AL/BC UI patterns: client-expression in-list (AL0573) and Role Center AccessByPermission (#207)
* Add UI knowledge: client-expression in-list and Role Center AccessByPermission

Two ui articles with compiled good/bad samples:
- page-client-expression-must-not-use-in-list: an `in [...]` list in
  Enabled/Visible/Editable/StyleExpr is rejected (AL0573 on actions,
  groups and parts; AL0322 on fields); remediate with an or-chain or a
  global Boolean, not a procedure call. Plain comparisons stay valid.
- rolecenter-permission-gating-must-use-accessbypermission: Role Center
  pages and pageextensions of them cannot host triggers/procedures
  (AL0378/AL0569); gate parts by permission with AccessByPermission,
  with the UI Elements Removal and non-security-boundary caveats.

Wired into al-ui-review worklist tokens and 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: OnAfterGetCurrRecord for action state, RC gating nits

- page-client-expression-must-not-use-in-list: recompute action/group/part
  state in OnAfterGetCurrRecord (OnAfterGetRecord runs per row), cite
  EDocumentLogs and concrete or-chain examples, note HideValue and that
  the property list is not exhaustive; good sample uses OnAfterGetCurrRecord.
- rolecenter-permission-gating-must-use-accessbypermission: clarify
  LicenseFile vs LicenseFileAndUserPermissions removal, cite Business
  Manager RC Control96, samples gate a part the RC does not already have.
- al-ui-review: add ReadPermission/WritePermission tokens.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-02 09:53:14 +02:00

83 lines
1.8 KiB
AL

enum 50700 "Sample Request Status"
{
Extensible = false;
value(0; New) { Caption = 'New'; }
value(1; "Needs Review") { Caption = 'Needs Review'; }
value(2; Approved) { Caption = 'Approved'; }
}
table 50700 "Sample Request"
{
DataClassification = CustomerContent;
fields
{
field(1; "No."; Code[20]) { }
field(2; Status; Enum "Sample Request Status") { }
}
keys
{
key(PK; "No.") { Clustered = true; }
}
}
page 50700 "Sample Request Card"
{
PageType = Card;
SourceTable = "Sample Request";
ApplicationArea = All;
layout
{
area(Content)
{
field("No."; Rec."No.")
{
// A plain field comparison is a valid client expression.
Editable = Rec.Status = Rec.Status::New;
}
field(Status; Rec.Status)
{
trigger OnValidate()
begin
UpdateActionStates();
end;
}
}
}
actions
{
area(Processing)
{
action(Approve)
{
Caption = 'Approve';
// The list membership is computed in AL and exposed as a global Boolean.
Enabled = ApproveEnabled;
trigger OnAction()
begin
Rec.Status := Rec.Status::Approved;
Rec.Modify(true);
UpdateActionStates();
end;
}
}
}
var
ApproveEnabled: Boolean;
trigger OnAfterGetCurrRecord()
begin
UpdateActionStates();
end;
local procedure UpdateActionStates()
begin
ApproveEnabled := Rec.Status in [Rec.Status::New, Rec.Status::"Needs Review"];
end;
}