From 5f59801430417e7859a1c4b56c3ee4786ba7474d Mon Sep 17 00:00:00 2001 From: "FENWICK\\ben.plunkett" <42510084+BenPlunk@users.noreply.github.com> Date: Tue, 3 Feb 2026 14:43:18 +1100 Subject: [PATCH 1/8] Add views and update workspace assembly paths --- .../App/User Details/src/UserDetails.Page.al | 68 ++++++++++++++++++- .../App/User Details/src/UserDetails.Table.al | 33 +++++++++ src/SystemApplication.code-workspace | 14 +++- 3 files changed, 113 insertions(+), 2 deletions(-) diff --git a/src/System Application/App/User Details/src/UserDetails.Page.al b/src/System Application/App/User Details/src/UserDetails.Page.al index da33aaece1..e1570696a3 100644 --- a/src/System Application/App/User Details/src/UserDetails.Page.al +++ b/src/System Application/App/User Details/src/UserDetails.Page.al @@ -6,6 +6,8 @@ namespace System.Security.User; using System.Environment; +using System.Security.AccessControl; +using System.Utilities; /// /// Shows detailed user information, such as unique identifiers, information about permission sets etc. @@ -15,7 +17,7 @@ page 774 "User Details" AboutText = 'View the additional information about users in a list view, which allows for easy searching and filtering.'; AboutTitle = 'About the users detailed view'; ApplicationArea = Basic, Suite; - Caption = 'Users'; + Caption = 'Users (detailed view)'; DeleteAllowed = false; Editable = false; InsertAllowed = false; @@ -67,6 +69,36 @@ page 774 "User Details" ToolTip = 'Specifies ID assigned to the user in Microsoft Entra.'; Visible = IsSaaS; } + field("Last Login Date"; Rec."Last Login Date") + { + Caption = 'Last Login Date'; + ToolTip = 'Specifies the date and time when the user last logged in.'; + } + field("InactiveDays"; InactiveDays) + { + Caption = 'Inactive (days)'; + ToolTip = 'Specifies the number of days since the user last logged in.'; + } + field(SystemCreatedAt; SystemCreatedAt) + { + Caption = 'Created On'; + ToolTip = 'Specifies the date and time when the user record was created.'; + } + field(CreatedBy; CreatedByUser."User Name") + { + Caption = 'Created By'; + ToolTip = 'Specifies the user who created the user record.'; + } + field(SystemModifiedAt; SystemModifiedAt) + { + Caption = 'Modified On'; + ToolTip = 'Specifies the date and time when the user record was last modified.'; + } + field(ModifiedBy; ModifiedByUser."User Name") + { + Caption = 'Modified By'; + ToolTip = 'Specifies the user who last modified the user record.'; + } // Can be added with "Personalize" field("Has SUPER permission set"; Rec."Has SUPER permission set") { @@ -89,6 +121,21 @@ page 774 "User Details" Caption = 'Users with SUPER permission set'; Filters = where("Has SUPER permission set" = const(true)); } + view("7 Days") + { + Caption = '7 days (last week)'; + Filters = where("Last Login Date" = field("7 Days Date Filter")); + } + view("30 Days") + { + Caption = '30 days (last month)'; + Filters = where("Last Login Date" = field("30 Days Date Filter")); + } + view("90 Days") + { + Caption = '90 days (quarter)'; + Filters = where("Last Login Date" = field("90 Days Date Filter")); + } } trigger OnOpenPage() @@ -98,8 +145,27 @@ page 774 "User Details" begin IsSaaS := EnvironmentInformation.IsSaaS(); UserDetails.Get(Rec); + + Rec.SetFilter("7 Days Date Filter", '>%1', CreateDateTime(CalcDate('<-7D>', Today()), CurrentDateTime().Time)); + Rec.SetFilter("30 Days Date Filter", '>%1', CreateDateTime(CalcDate('<-30D>', Today()), CurrentDateTime().Time)); + Rec.SetFilter("90 Days Date Filter", '>%1', CreateDateTime(CalcDate('<-90D>', Today()), CurrentDateTime().Time)); end; + trigger OnAfterGetRecord() + var + Math: Codeunit Math; + begin + if CreatedByUser.Get(Rec.SystemCreatedBy) then; + if ModifiedByUser.Get(Rec.SystemModifiedBy) then; + if Rec."Last Login Date".Date <> 0D then + InactiveDays := Math.Floor(Today() - Rec."Last Login Date".Date); + end; + + var + CreatedByUser: Record User; + ModifiedByUser: Record User; + InactiveDays: Integer; + protected var IsSaaS: Boolean; } \ No newline at end of file diff --git a/src/System Application/App/User Details/src/UserDetails.Table.al b/src/System Application/App/User Details/src/UserDetails.Table.al index 34100bacc4..c208fe1231 100644 --- a/src/System Application/App/User Details/src/UserDetails.Table.al +++ b/src/System Application/App/User Details/src/UserDetails.Table.al @@ -116,6 +116,39 @@ table 774 "User Details" Editable = false; FieldClass = FlowField; } + /// + /// The last login date of the user. + /// + field(24; "Last Login Date"; DateTime) + { + Caption = 'Last Login Date'; + FieldClass = FlowField; + CalcFormula = Lookup("User Login"."Last Login Date" where("User SID" = field("User Security ID"))); + } + /// + /// Flow filter for determining users who logged in within the last 7 days. + /// + field(25; "7 Days Date Filter"; DateTime) + { + Caption = 'Last 7 Days Filter'; + FieldClass = FlowFilter; + } + /// + /// Flow filter for determining users who logged in within the last 30 days. + /// + field(26; "30 Days Date Filter"; DateTime) + { + Caption = 'Last 30 Days Filter'; + FieldClass = FlowFilter; + } + /// + /// Flow filter for determining users who logged in within the last 90 days. + /// + field(27; "90 Days Date Filter"; DateTime) + { + Caption = 'Last 90 Days Filter'; + FieldClass = FlowFilter; + } } keys diff --git a/src/SystemApplication.code-workspace b/src/SystemApplication.code-workspace index f08e9feb23..498209c59d 100644 --- a/src/SystemApplication.code-workspace +++ b/src/SystemApplication.code-workspace @@ -32,5 +32,17 @@ "name": "System Application Tests", "path": "System Application\\Test" } - ] + ], + "settings": { + "al.assemblyProbingPaths": [ + "./.netpackages", + "C:/Users/ben.plunkett/Business central installs/260.29145/Service/Add-ins", + "C:/Users/ben.plunkett/Business central installs/260.29145/Service/Admin", + "C:/Users/ben.plunkett/Business central installs/280.42318/ServiceTier/PFiles64/Microsoft Dynamics NAV/280/Service", + "C:/Users/ben.plunkett/Business central installs/280.42318/ServiceTier/PFiles64/Microsoft Dynamics NAV/280/Service/Add-ins", + "C:/Users/ben.plunkett/Business central installs/280.42318/ServiceTier/PFiles64/Microsoft Dynamics NAV/280/Service/Admin", + "C:/Program Files/dotnet/shared/Microsoft.AspNetCore.App/8.0.22", + "C:/Program Files/dotnet/shared/Microsoft.NETCore.App/8.0.22" + ], + } } \ No newline at end of file From f07de3374d42dd810beb097b6adaac186fbec34b Mon Sep 17 00:00:00 2001 From: "FENWICK\\ben.plunkett" <42510084+BenPlunk@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:00:53 +1100 Subject: [PATCH 2/8] Update User Detail views --- .../src/UserDetailDateFilter.Enum.al | 19 +++++++++ .../App/User Details/src/UserDetails.Page.al | 42 ++++++++++++++----- .../App/User Details/src/UserDetails.Table.al | 22 ++-------- 3 files changed, 54 insertions(+), 29 deletions(-) create mode 100644 src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al diff --git a/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al b/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al new file mode 100644 index 0000000000..a2ae63c74c --- /dev/null +++ b/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al @@ -0,0 +1,19 @@ +enum 774 "User Detail Date Filter" +{ + value(0; Blank) + { + } + + value(1; "7Days") + { + Caption = '7 Days'; + } + value(2; "30Days") + { + Caption = '30 Days'; + } + value(3; "90Days") + { + Caption = '90 Days'; + } +} \ No newline at end of file diff --git a/src/System Application/App/User Details/src/UserDetails.Page.al b/src/System Application/App/User Details/src/UserDetails.Page.al index e1570696a3..d7c26905d5 100644 --- a/src/System Application/App/User Details/src/UserDetails.Page.al +++ b/src/System Application/App/User Details/src/UserDetails.Page.al @@ -14,7 +14,7 @@ using System.Utilities; /// page 774 "User Details" { - AboutText = 'View the additional information about users in a list view, which allows for easy searching and filtering.'; + AboutText = 'View detailed user information, such as unique identifiers, information about permission sets, login activity etc. in a list view, which allows for easy searching and filtering.'; AboutTitle = 'About the users detailed view'; ApplicationArea = Basic, Suite; Caption = 'Users (detailed view)'; @@ -123,18 +123,18 @@ page 774 "User Details" } view("7 Days") { - Caption = '7 days (last week)'; - Filters = where("Last Login Date" = field("7 Days Date Filter")); + Caption = 'Inactive 7 days'; + Filters = where("Inactive Days Date Filter" = const("7Days")); } view("30 Days") { - Caption = '30 days (last month)'; - Filters = where("Last Login Date" = field("30 Days Date Filter")); + Caption = 'Inactive 30 days'; + Filters = where("Inactive Days Date Filter" = const("30Days")); } view("90 Days") { - Caption = '90 days (quarter)'; - Filters = where("Last Login Date" = field("90 Days Date Filter")); + Caption = 'Inactive 90 days'; + Filters = where("Inactive Days Date Filter" = const("90Days")); } } @@ -145,10 +145,27 @@ page 774 "User Details" begin IsSaaS := EnvironmentInformation.IsSaaS(); UserDetails.Get(Rec); + end; + + trigger OnFindRecord(Which: Text): Boolean + var + UserDetails: Record "User Details"; + begin + Rec.SetRange("Last Login Date"); + if Rec.GetFilter("Inactive Days Date Filter") <> '' then + if Evaluate(UserDetails."Inactive Days Date Filter", Rec.GetFilter("Inactive Days Date Filter")) then + case UserDetails."Inactive Days Date Filter" of + Rec."Inactive Days Date Filter"::"7Days": + Rec.SetFilter("Last Login Date", '<=%1', CreateDateTime(CalcDate('<-7D>', Today()), CurrentDateTime().Time)); + Rec."Inactive Days Date Filter"::"30Days": + Rec.SetFilter("Last Login Date", '<=%1', CreateDateTime(CalcDate('<-30D>', Today()), CurrentDateTime().Time)); + Rec."Inactive Days Date Filter"::"90Days": + Rec.SetFilter("Last Login Date", '<=%1', CreateDateTime(CalcDate('<-90D>', Today()), CurrentDateTime().Time)); + else + OnInactiveDaysFilterCaseElse(UserDetails."Inactive Days Date Filter", Rec); + end; - Rec.SetFilter("7 Days Date Filter", '>%1', CreateDateTime(CalcDate('<-7D>', Today()), CurrentDateTime().Time)); - Rec.SetFilter("30 Days Date Filter", '>%1', CreateDateTime(CalcDate('<-30D>', Today()), CurrentDateTime().Time)); - Rec.SetFilter("90 Days Date Filter", '>%1', CreateDateTime(CalcDate('<-90D>', Today()), CurrentDateTime().Time)); + exit(Rec.Find(Which)); end; trigger OnAfterGetRecord() @@ -168,4 +185,9 @@ page 774 "User Details" protected var IsSaaS: Boolean; + + [IntegrationEvent(false, false)] + local procedure OnInactiveDaysFilterCaseElse(DateFilter: Enum "User Detail Date Filter"; var Rec: Record "User Details") + begin + end; } \ No newline at end of file diff --git a/src/System Application/App/User Details/src/UserDetails.Table.al b/src/System Application/App/User Details/src/UserDetails.Table.al index c208fe1231..7c62dc0176 100644 --- a/src/System Application/App/User Details/src/UserDetails.Table.al +++ b/src/System Application/App/User Details/src/UserDetails.Table.al @@ -126,27 +126,11 @@ table 774 "User Details" CalcFormula = Lookup("User Login"."Last Login Date" where("User SID" = field("User Security ID"))); } /// - /// Flow filter for determining users who logged in within the last 7 days. + /// Flow filter for filtering users based on Last Login Date. /// - field(25; "7 Days Date Filter"; DateTime) + field(25; "Inactive Days Date Filter"; Enum "User Detail Date Filter") { - Caption = 'Last 7 Days Filter'; - FieldClass = FlowFilter; - } - /// - /// Flow filter for determining users who logged in within the last 30 days. - /// - field(26; "30 Days Date Filter"; DateTime) - { - Caption = 'Last 30 Days Filter'; - FieldClass = FlowFilter; - } - /// - /// Flow filter for determining users who logged in within the last 90 days. - /// - field(27; "90 Days Date Filter"; DateTime) - { - Caption = 'Last 90 Days Filter'; + Caption = 'Inactive Days Date Filter'; FieldClass = FlowFilter; } } From c00c4d75019877f6297bf7bfa46145a174c0fc81 Mon Sep 17 00:00:00 2001 From: "FENWICK\\ben.plunkett" <42510084+BenPlunk@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:02:20 +1100 Subject: [PATCH 3/8] Add copyright --- .../App/User Details/src/UserDetailDateFilter.Enum.al | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al b/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al index a2ae63c74c..4968ccac74 100644 --- a/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al +++ b/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al @@ -1,3 +1,8 @@ +// ------------------------------------------------------------------------------------------------ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// ------------------------------------------------------------------------------------------------ + enum 774 "User Detail Date Filter" { value(0; Blank) From b860295c7b9de518e77cf927d84cae276f47fdf4 Mon Sep 17 00:00:00 2001 From: "FENWICK\\ben.plunkett" <42510084+BenPlunk@users.noreply.github.com> Date: Wed, 4 Feb 2026 13:41:37 +1100 Subject: [PATCH 4/8] Removed assembly paths --- src/SystemApplication.code-workspace | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/SystemApplication.code-workspace b/src/SystemApplication.code-workspace index 498209c59d..f08e9feb23 100644 --- a/src/SystemApplication.code-workspace +++ b/src/SystemApplication.code-workspace @@ -32,17 +32,5 @@ "name": "System Application Tests", "path": "System Application\\Test" } - ], - "settings": { - "al.assemblyProbingPaths": [ - "./.netpackages", - "C:/Users/ben.plunkett/Business central installs/260.29145/Service/Add-ins", - "C:/Users/ben.plunkett/Business central installs/260.29145/Service/Admin", - "C:/Users/ben.plunkett/Business central installs/280.42318/ServiceTier/PFiles64/Microsoft Dynamics NAV/280/Service", - "C:/Users/ben.plunkett/Business central installs/280.42318/ServiceTier/PFiles64/Microsoft Dynamics NAV/280/Service/Add-ins", - "C:/Users/ben.plunkett/Business central installs/280.42318/ServiceTier/PFiles64/Microsoft Dynamics NAV/280/Service/Admin", - "C:/Program Files/dotnet/shared/Microsoft.AspNetCore.App/8.0.22", - "C:/Program Files/dotnet/shared/Microsoft.NETCore.App/8.0.22" - ], - } + ] } \ No newline at end of file From 34370f7d16cdfdc25467c9e6415f24f33584d48d Mon Sep 17 00:00:00 2001 From: "FENWICK\\ben.plunkett" <42510084+BenPlunk@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:52:45 +1100 Subject: [PATCH 5/8] Updates from review --- .../App/User Details/src/UserDetailDateFilter.Enum.al | 7 +++---- .../App/User Details/src/UserDetails.Page.al | 2 +- .../App/User Details/src/UserDetails.Table.al | 4 ++++ 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al b/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al index 4968ccac74..172afcd188 100644 --- a/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al +++ b/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al @@ -8,16 +8,15 @@ enum 774 "User Detail Date Filter" value(0; Blank) { } - - value(1; "7Days") + value(1; "7 Days") { Caption = '7 Days'; } - value(2; "30Days") + value(2; "30 Days") { Caption = '30 Days'; } - value(3; "90Days") + value(3; "90 Days") { Caption = '90 Days'; } diff --git a/src/System Application/App/User Details/src/UserDetails.Page.al b/src/System Application/App/User Details/src/UserDetails.Page.al index d7c26905d5..0f6f8c9371 100644 --- a/src/System Application/App/User Details/src/UserDetails.Page.al +++ b/src/System Application/App/User Details/src/UserDetails.Page.al @@ -74,7 +74,7 @@ page 774 "User Details" Caption = 'Last Login Date'; ToolTip = 'Specifies the date and time when the user last logged in.'; } - field("InactiveDays"; InactiveDays) + field("Inactive Days"; InactiveDays) { Caption = 'Inactive (days)'; ToolTip = 'Specifies the number of days since the user last logged in.'; diff --git a/src/System Application/App/User Details/src/UserDetails.Table.al b/src/System Application/App/User Details/src/UserDetails.Table.al index 7c62dc0176..3f4b015a0c 100644 --- a/src/System Application/App/User Details/src/UserDetails.Table.al +++ b/src/System Application/App/User Details/src/UserDetails.Table.al @@ -121,7 +121,9 @@ table 774 "User Details" /// field(24; "Last Login Date"; DateTime) { + Access = Internal; Caption = 'Last Login Date'; + Editable = false; FieldClass = FlowField; CalcFormula = Lookup("User Login"."Last Login Date" where("User SID" = field("User Security ID"))); } @@ -130,7 +132,9 @@ table 774 "User Details" /// field(25; "Inactive Days Date Filter"; Enum "User Detail Date Filter") { + Access = Internal; Caption = 'Inactive Days Date Filter'; + Editable = false; FieldClass = FlowFilter; } } From f92b98ef35e6318819df80e4cffaa976d6693559 Mon Sep 17 00:00:00 2001 From: "FENWICK\\ben.plunkett" <42510084+BenPlunk@users.noreply.github.com> Date: Mon, 9 Feb 2026 17:54:42 +1100 Subject: [PATCH 6/8] User details date filter update --- .../App/User Details/src/UserDetailDateFilter.Enum.al | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al b/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al index 172afcd188..a865626d40 100644 --- a/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al +++ b/src/System Application/App/User Details/src/UserDetailDateFilter.Enum.al @@ -3,6 +3,12 @@ // Licensed under the MIT License. See License.txt in the project root for license information. // ------------------------------------------------------------------------------------------------ +namespace System.Security.User; + + +/// +/// Used for setting date flow filters against the Last Login time field on the user details page. +/// enum 774 "User Detail Date Filter" { value(0; Blank) From eabdc32dc1459e19356e5b3aa2a830028cfe90cf Mon Sep 17 00:00:00 2001 From: "FENWICK\\ben.plunkett" <42510084+BenPlunk@users.noreply.github.com> Date: Tue, 10 Feb 2026 09:24:56 +1100 Subject: [PATCH 7/8] Fix enums --- .../App/User Details/src/UserDetails.Page.al | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/System Application/App/User Details/src/UserDetails.Page.al b/src/System Application/App/User Details/src/UserDetails.Page.al index 0f6f8c9371..e4853d3b8c 100644 --- a/src/System Application/App/User Details/src/UserDetails.Page.al +++ b/src/System Application/App/User Details/src/UserDetails.Page.al @@ -124,17 +124,17 @@ page 774 "User Details" view("7 Days") { Caption = 'Inactive 7 days'; - Filters = where("Inactive Days Date Filter" = const("7Days")); + Filters = where("Inactive Days Date Filter" = const("7 Days")); } view("30 Days") { Caption = 'Inactive 30 days'; - Filters = where("Inactive Days Date Filter" = const("30Days")); + Filters = where("Inactive Days Date Filter" = const("30 Days")); } view("90 Days") { Caption = 'Inactive 90 days'; - Filters = where("Inactive Days Date Filter" = const("90Days")); + Filters = where("Inactive Days Date Filter" = const("90 Days")); } } From 83c765f18d8f1e424eb57184bad7d7b3e0a6a89d Mon Sep 17 00:00:00 2001 From: "FENWICK\\ben.plunkett" <42510084+BenPlunk@users.noreply.github.com> Date: Tue, 10 Feb 2026 16:00:42 +1100 Subject: [PATCH 8/8] Update caption capitalisation --- src/System Application/App/User Details/src/UserDetails.Page.al | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/System Application/App/User Details/src/UserDetails.Page.al b/src/System Application/App/User Details/src/UserDetails.Page.al index e4853d3b8c..2363a794a5 100644 --- a/src/System Application/App/User Details/src/UserDetails.Page.al +++ b/src/System Application/App/User Details/src/UserDetails.Page.al @@ -17,7 +17,7 @@ page 774 "User Details" AboutText = 'View detailed user information, such as unique identifiers, information about permission sets, login activity etc. in a list view, which allows for easy searching and filtering.'; AboutTitle = 'About the users detailed view'; ApplicationArea = Basic, Suite; - Caption = 'Users (detailed view)'; + Caption = 'Users (Detailed View)'; DeleteAllowed = false; Editable = false; InsertAllowed = false;