@7365admin1/layer-common 3.2.7 → 3.2.8-staging.201
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/css/primitives.css +1113 -0
- package/assets/css/screens.css +1097 -0
- package/assets/css/shell.css +258 -0
- package/assets/css/tokens.css +236 -0
- package/components/AcceptDialog.vue +17 -18
- package/components/AccessCard/AvailableStats.vue +24 -16
- package/components/AccessCardAddForm.vue +42 -42
- package/components/AccessCardAssignToUnitForm.vue +13 -21
- package/components/AccessCardDeleteDialog.vue +41 -39
- package/components/AccessCardDetailsDialog.vue +125 -79
- package/components/AccessCardPreviewDialog.vue +58 -84
- package/components/AccessCardQrTagging.vue +60 -63
- package/components/AccessCardReplaceForm.vue +27 -23
- package/components/AccessManagement.vue +86 -85
- package/components/AddEqupmentForm.vue +18 -22
- package/components/AddPassKeyToVisitor.vue +95 -73
- package/components/AppButton.vue +62 -0
- package/components/AppCard.vue +20 -0
- package/components/AppDateField.vue +49 -0
- package/components/AppField.vue +76 -0
- package/components/AppKpiTile.vue +65 -0
- package/components/AppSegmented.vue +38 -0
- package/components/AppSelect.vue +247 -0
- package/components/AreaChecklistHistoryLogs.vue +51 -44
- package/components/AreaChecklistHistoryMain.vue +14 -7
- package/components/AreaFormDialog.vue +71 -59
- package/components/AreaMain.vue +73 -107
- package/components/AttachmentsViewer.vue +84 -22
- package/components/AttendanceCheckInOutDialog.vue +85 -88
- package/components/AttendanceDetailsDialog.vue +57 -63
- package/components/AttendanceMain.vue +4 -3
- package/components/AttendanceMapSearchDialog.vue +42 -44
- package/components/AttendanceSettingsDialog.vue +79 -63
- package/components/Avatar/Main.vue +54 -2
- package/components/BillingMain.vue +26 -30
- package/components/BtnUploadFile.vue +53 -11
- package/components/BuildingForm.vue +34 -27
- package/components/BuildingManagement/buildings.vue +39 -39
- package/components/BuildingManagement/units.vue +26 -42
- package/components/BuildingUnitFormAdd.vue +20 -23
- package/components/BuildingUnitFormEdit.vue +8 -4
- package/components/BulletinBoardForm.vue +19 -24
- package/components/BulletinBoardManagement.vue +49 -57
- package/components/BulletinBoardView.vue +9 -6
- package/components/BulletinExpirationChip.vue +13 -4
- package/components/Button/Close.vue +2 -2
- package/components/CameraForm.vue +21 -22
- package/components/CameraMain.vue +50 -49
- package/components/Card/DeleteConfirmation.vue +24 -22
- package/components/Card/MemberInfoSummary.vue +28 -3
- package/components/Card/Toggle.vue +15 -3
- package/components/CardToolbar.vue +37 -0
- package/components/Carousel.vue +56 -36
- package/components/Chat/Bubbles.vue +43 -14
- package/components/Chat/Information.vue +49 -32
- package/components/Chat/ListCard.vue +38 -9
- package/components/Chat/Message.vue +41 -15
- package/components/Chat/Navigation.vue +27 -15
- package/components/Chat/SkeletonLoader.vue +9 -2
- package/components/ChecklistItemRow.vue +25 -1
- package/components/CleaningScheduleMain.vue +44 -49
- package/components/ClientDetailForm.vue +81 -56
- package/components/ClientMain.vue +92 -82
- package/components/ConfirmDialog.vue +14 -8
- package/components/Container/Standard.vue +9 -7
- package/components/CreateSubsciptionPlan.vue +148 -89
- package/components/DashboardEmptyState.vue +48 -3
- package/components/DashboardMain.vue +924 -676
- package/components/DashboardPanel.vue +84 -21
- package/components/DeliveryCompany.vue +34 -20
- package/components/Dialog/DeleteConfirmation.vue +20 -21
- package/components/Dialog/ReplaceAutofillPrompt.vue +19 -26
- package/components/Dialog/ReusablePrompt.vue +30 -29
- package/components/Dialog/UpdateMoreAction.vue +62 -59
- package/components/DocumentForm.vue +14 -21
- package/components/DocumentManagement.vue +162 -108
- package/components/DocumentViewer.vue +29 -12
- package/components/DrawImage.vue +29 -21
- package/components/EntryPass/QrTemplatePreview.vue +27 -16
- package/components/EntryPassInformation.vue +40 -10
- package/components/EntryPassMain.vue +49 -27
- package/components/EquipmentItemMain.vue +84 -97
- package/components/EquipmentManagementMain.vue +81 -103
- package/components/Facility/BookingSetup.vue +43 -52
- package/components/Feedback/Form.vue +26 -12
- package/components/FeedbackMain.vue +35 -49
- package/components/FileInput.vue +75 -58
- package/components/FileInputWithList.vue +59 -12
- package/components/FormDialog.vue +60 -21
- package/components/HidAccessLogDashboard.vue +512 -490
- package/components/HidCameraCaptureDialog.vue +216 -0
- package/components/HidEnabledGate.vue +67 -9
- package/components/HidIntercomManagement.vue +1322 -653
- package/components/HidQrCodeConfiguration.vue +1030 -258
- package/components/HidReaderForm.vue +142 -59
- package/components/HidReaderManagement.vue +211 -323
- package/components/HidServiceSettingsPanel.vue +44 -13
- package/components/HidUserEnrollment.vue +1185 -412
- package/components/HygieneUpdateMoreAction.vue +44 -44
- package/components/IncidentReport/Authorities.vue +30 -18
- package/components/IncidentReport/IncidentInformation.vue +10 -10
- package/components/IncidentReport/IncidentInformationDownload.vue +3 -4
- package/components/IncidentReport/affectedEntities.vue +41 -20
- package/components/Input/Date.vue +3 -0
- package/components/Input/DatePicker.vue +1 -2
- package/components/Input/DateTimePicker.vue +1 -1
- package/components/Input/File.vue +55 -10
- package/components/Input/FileV2.vue +39 -6
- package/components/Input/InputPhoneNumberV2.vue +2 -1
- package/components/Input/ListGroupSelection.vue +56 -8
- package/components/Input/NRICNumber.vue +1 -0
- package/components/Input/NewDate.vue +1 -0
- package/components/Input/Number.vue +1 -0
- package/components/Input/Password.vue +1 -0
- package/components/Input/PhoneNumber.vue +21 -1
- package/components/Input/VehicleNumber.vue +1 -0
- package/components/InputLabel.vue +2 -2
- package/components/InvitationClientForm.vue +21 -19
- package/components/InvitationForm.vue +15 -21
- package/components/InvitationMain.vue +46 -61
- package/components/Layout/Header.vue +263 -36
- package/components/Layout/NavigationDrawer.vue +300 -30
- package/components/ListItem.vue +33 -3
- package/components/LocalPagination.vue +27 -3
- package/components/ManageChecklistMain.vue +136 -86
- package/components/MemberInformation.vue +32 -16
- package/components/MemberMain.vue +113 -93
- package/components/MyAttendanceMain.vue +3 -5
- package/components/NavigationItem.vue +83 -3
- package/components/Nfc/NFCPatrolReportMain.vue +47 -33
- package/components/Nfc/NFCPatrolRouteForm.vue +18 -20
- package/components/Nfc/NFCPatrolRouteMain.vue +116 -103
- package/components/Nfc/NFCPatrolSettings.vue +14 -4
- package/components/Nfc/NFCTagForm.vue +22 -8
- package/components/Nfc/NFCTagMain.vue +41 -43
- package/components/Nfc/PatrolReport/DailyReportTab.vue +8 -1
- package/components/Nfc/PatrolReport/MonthlyReportTab.vue +8 -1
- package/components/Nfc/PatrolReport/MonthlyReportTable.vue +5 -3
- package/components/Nfc/PatrolReport/PatrolActivityTable.vue +26 -6
- package/components/Nfc/PatrolReport/PatrolReportTab.vue +8 -0
- package/components/Nfc/PatrolReport/PatrolRouteSummary.vue +41 -9
- package/components/Nfc/PatrolReport/RemarksDialog.vue +39 -9
- package/components/Nfc/PatrolReport/ReportEmptyState.vue +29 -9
- package/components/Nfc/PatrolReport/ReportFilters.vue +19 -10
- package/components/Nfc/PatrolReport/ReportLocationHeader.vue +32 -6
- package/components/Nfc/PatrolReport/SummaryReportTable.vue +28 -6
- package/components/NotificationSettings.vue +373 -0
- package/components/NumberSettingField.vue +9 -2
- package/components/OnlineFormConfigurationForm.vue +725 -237
- package/components/OnlineFormFill.vue +213 -106
- package/components/OnlineFormRenderPreview.vue +25 -30
- package/components/OnlineFormsConfiguration.vue +113 -109
- package/components/OrgViewDialog.vue +34 -16
- package/components/OvernightParkingAvailability.vue +49 -26
- package/components/OvernightParkingManagement.vue +78 -18
- package/components/PageHeader.vue +43 -0
- package/components/PassInformation.vue +109 -53
- package/components/PasswordConfirmation.vue +44 -26
- package/components/PeopleForm.vue +41 -20
- package/components/PhotoUpload.vue +110 -48
- package/components/PlaceholderComponent.vue +35 -19
- package/components/PlanActionsMenu.vue +12 -2
- package/components/PlanStatusBadge.vue +7 -8
- package/components/PlateNumberDisplay.vue +9 -6
- package/components/QrTemplate/PrintDialog.vue +66 -43
- package/components/RolePermissionFormCreate.vue +104 -79
- package/components/RolePermissionFormPreviewUpdate.vue +111 -109
- package/components/RolePermissionMain.vue +183 -81
- package/components/ScanVisitorQRCode.vue +99 -35
- package/components/ScheduleAreaMain.vue +34 -59
- package/components/ScheduleTaskForm.vue +61 -42
- package/components/ScheduleTaskMain.vue +56 -69
- package/components/SearchVehicleNumberUser.vue +39 -37
- package/components/ServiceProviderFormCreate.vue +29 -20
- package/components/ServiceProviderInvitationPrompt.vue +155 -0
- package/components/ServiceProviderMain.vue +601 -432
- package/components/Signature.vue +40 -34
- package/components/SignaturePad.vue +5 -29
- package/components/SiteSettings.vue +41 -11
- package/components/SiteSettingsWorkOrder.vue +61 -30
- package/components/SlideCardGroup.vue +35 -11
- package/components/Snackbar.vue +36 -3
- package/components/SpecificAttr.vue +18 -8
- package/components/StatusChip.vue +156 -0
- package/components/StockCard.vue +17 -12
- package/components/SubscriptionPlanTable.vue +207 -140
- package/components/SwitchContext.vue +201 -9
- package/components/TableHygiene.vue +36 -46
- package/components/TableList.vue +10 -10
- package/components/TableListSecondary.vue +105 -54
- package/components/TableMain.vue +251 -78
- package/components/TableV3.vue +61 -70
- package/components/TiptapEditor.vue +33 -40
- package/components/TiptapEditorQr.vue +5 -2
- package/components/Tooltip/Info.vue +69 -24
- package/components/UnitMain.vue +40 -60
- package/components/UnitPersonCard.vue +42 -13
- package/components/VehicleAddSelection.vue +48 -32
- package/components/VehicleForm.vue +112 -129
- package/components/VehicleManagement.vue +26 -12
- package/components/VehicleUpdateMoreAction.vue +59 -46
- package/components/VisitorDataFromScannedQRCodeForm.vue +90 -65
- package/components/VisitorForm.vue +774 -210
- package/components/VisitorFormSelection.vue +40 -37
- package/components/VisitorManagement.vue +239 -82
- package/components/VisitorPassKeyQRScanner.vue +65 -18
- package/components/VisitorSearchResultSummary.vue +60 -16
- package/components/VisitorSocketPopUp.vue +22 -14
- package/components/VisitorsReportPreview.vue +44 -29
- package/components/WorkOrder/Create.vue +26 -17
- package/components/WorkOrder/ListView.vue +38 -7
- package/components/WorkOrder/Main.vue +62 -59
- package/composables/useFeedback.ts +3 -3
- package/composables/useHidAmico.ts +269 -0
- package/composables/useHidNavigation.ts +2 -9
- package/composables/useMember.ts +3 -3
- package/composables/useNFCPatrolDailyReport.ts +13 -0
- package/composables/useNFCPatrolMonthlyReport.ts +22 -56
- package/composables/useNFCPatrolReport.ts +13 -0
- package/composables/useNotificationPreference.ts +87 -0
- package/composables/useOnlineFormPages.ts +2 -0
- package/composables/useRole.ts +22 -0
- package/composables/useServiceProvider.ts +3 -3
- package/composables/useServiceProviderInvitation.ts +145 -0
- package/composables/useSipWebPhone.ts +336 -0
- package/composables/useSubscriptionPlan.ts +62 -0
- package/composables/useThemePreference.ts +63 -0
- package/composables/useVisitor.ts +6 -1
- package/composables/useWebUsb.ts +127 -37
- package/composables/useWorkOrder.ts +17 -3
- package/error.vue +30 -6
- package/nuxt.config.ts +36 -0
- package/package.json +25 -4
- package/pages/[org]/[site]/access-mgmt/administrator/index.vue +2 -2
- package/pages/[org]/[site]/access-mgmt/{identity-mapping → hid-cards}/index.vue +2 -2
- package/pages/[org]/[site]/access-mgmt/intercom/index.vue +1 -1
- package/pages/notification-settings.vue +19 -0
- package/pages/payment-method-linked.vue +34 -10
- package/pages/require-customer.vue +48 -10
- package/pages/require-organization-membership.vue +32 -8
- package/pages/unauthorized.vue +29 -4
- package/plugins/secure-member.client.ts +21 -56
- package/plugins/vuetify.ts +69 -2
- package/types/nfc-patrol-report.ts +3 -2
- package/types/site.d.ts +71 -0
- package/types/subscription.ts +18 -11
- package/utils/breadcrumb.test.ts +108 -0
- package/utils/breadcrumb.ts +82 -0
- package/utils/dashboard.test.ts +118 -0
- package/utils/dashboard.ts +53 -0
- package/utils/data.test.ts +95 -0
- package/utils/data.ts +40 -2
- package/utils/hid-discover.test.ts +102 -0
- package/utils/list-page.test.ts +60 -0
- package/utils/list-page.ts +38 -0
- package/utils/materialSymbols.ts +363 -0
- package/utils/nav-sections.test.ts +190 -0
- package/utils/nav-sections.ts +151 -0
- package/utils/nfc-patrol-report.test.ts +130 -0
- package/utils/nfc-patrol-report.ts +101 -0
- package/utils/role.test.ts +69 -0
- package/utils/role.ts +10 -0
- package/utils/route-name.test.ts +85 -0
- package/utils/route-name.ts +24 -0
- package/utils/status.test.ts +110 -0
- package/utils/status.ts +135 -0
- package/utils/table-card.test.ts +84 -0
- package/utils/theme-aa-ledger.ts +148 -0
- package/utils/theme.test.ts +485 -7
- package/utils/theme.ts +295 -110
- package/.changeset/README.md +0 -8
- package/.changeset/config.json +0 -11
- package/.editorconfig +0 -12
- package/.github/workflows/main.yml +0 -17
- package/.github/workflows/publish-staging.yml +0 -47
- package/.github/workflows/publish.yml +0 -39
- package/PUBLISHING.md +0 -269
- package/components/HidIdentityMapping.vue +0 -975
- package/components/ScheduleTaskAreaFormDialog.vue +0 -144
- package/components/ScheduleTaskAreaUpdateMoreAction.vue +0 -109
- package/components/ScheduleTastTicketMain.vue +0 -182
- package/components/TableWithButton.vue +0 -94
- package/test/visitor-socket.test.mjs +0 -36
|
@@ -0,0 +1,363 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* mdi -> Material Symbols Outlined.
|
|
3
|
+
*
|
|
4
|
+
* The design handoff draws every icon with Google's variable
|
|
5
|
+
* `Material Symbols Outlined` font (`opsz,wght,FILL,GRAD@20..48,300..700,0..1,0`),
|
|
6
|
+
* using the icon's name as the element's text and letting the font's ligature
|
|
7
|
+
* table turn it into a glyph. The product ships Material Design Icons (`mdi`)
|
|
8
|
+
* instead - a different, heavier family - so every screen mixes two icon
|
|
9
|
+
* languages.
|
|
10
|
+
*
|
|
11
|
+
* Rather than rewrite ~680 call sites across this package (and again in eleven
|
|
12
|
+
* applications), the Vuetify icon set in `plugins/vuetify.ts` translates on the
|
|
13
|
+
* way out: a component still asks for `mdi-close`, this table answers `close`,
|
|
14
|
+
* and the span renders the Material Symbols glyph. Vuetify's own internal
|
|
15
|
+
* aliases (`$dropdown`, `$checkboxOn`, `$next`, ...) resolve to `mdi-*` strings
|
|
16
|
+
* too, so they are listed here as well and convert with everything else.
|
|
17
|
+
*
|
|
18
|
+
* Anything NOT in this table falls back to the previous Iconify rendering, so
|
|
19
|
+
* an unmapped name draws its old icon rather than a blank box.
|
|
20
|
+
*
|
|
21
|
+
* Every value below was checked against Google's published codepoint list for
|
|
22
|
+
* the variable font, so no entry is a name that does not exist.
|
|
23
|
+
*
|
|
24
|
+
* Where mdi draws something Material Symbols has no equivalent for, the entry
|
|
25
|
+
* is marked NEAREST with what was lost. Those are deliberate, not oversights.
|
|
26
|
+
*/
|
|
27
|
+
export const MDI_TO_SYMBOL: Record<string, string> = {
|
|
28
|
+
// --- navigation & chevrons ---
|
|
29
|
+
"mdi-chevron-left": "chevron_left",
|
|
30
|
+
"mdi-chevron-right": "chevron_right",
|
|
31
|
+
"mdi-chevron-up": "expand_less",
|
|
32
|
+
"mdi-chevron-down": "expand_more",
|
|
33
|
+
"mdi-chevron-down-box-outline": "expand_more", // NEAREST: no boxed chevron
|
|
34
|
+
"mdi-menu": "menu",
|
|
35
|
+
"mdi-menu-down": "arrow_drop_down",
|
|
36
|
+
"mdi-menu-right": "arrow_right",
|
|
37
|
+
"mdi-unfold-more-horizontal": "unfold_more",
|
|
38
|
+
"mdi-arrow-left": "arrow_back",
|
|
39
|
+
"mdi-arrow-right": "arrow_forward",
|
|
40
|
+
"mdi-arrow-up": "arrow_upward",
|
|
41
|
+
"mdi-arrow-down": "arrow_downward",
|
|
42
|
+
"mdi-arrow-u-left-top": "undo",
|
|
43
|
+
"mdi-page-first": "first_page",
|
|
44
|
+
"mdi-page-last": "last_page",
|
|
45
|
+
"mdi-open-in-new": "open_in_new",
|
|
46
|
+
"mdi-swap-horizontal": "swap_horiz",
|
|
47
|
+
"mdi-drag": "drag_indicator",
|
|
48
|
+
"mdi-dots-vertical": "more_vert",
|
|
49
|
+
"mdi-dots-horizontal": "more_horiz",
|
|
50
|
+
|
|
51
|
+
// --- actions ---
|
|
52
|
+
"mdi-close": "close",
|
|
53
|
+
"mdi-close-circle": "cancel",
|
|
54
|
+
"mdi-close-circle-outline": "cancel",
|
|
55
|
+
"mdi-check": "check",
|
|
56
|
+
"mdi-check-circle": "check_circle",
|
|
57
|
+
"mdi-check-circle-outline": "check_circle",
|
|
58
|
+
"mdi-plus": "add",
|
|
59
|
+
"mdi-minus": "remove",
|
|
60
|
+
"mdi-minus-box": "indeterminate_check_box",
|
|
61
|
+
"mdi-refresh": "refresh",
|
|
62
|
+
"mdi-cached": "cached",
|
|
63
|
+
"mdi-restore": "restore",
|
|
64
|
+
"mdi-magnify": "search",
|
|
65
|
+
"mdi-magnify-close": "search_off",
|
|
66
|
+
"mdi-pencil": "edit",
|
|
67
|
+
"mdi-pencil-outline": "edit",
|
|
68
|
+
"mdi-square-edit-outline": "edit_square",
|
|
69
|
+
"mdi-delete": "delete",
|
|
70
|
+
"mdi-delete-outline": "delete",
|
|
71
|
+
"mdi-trash-outline": "delete",
|
|
72
|
+
"mdi-trash-can-outline": "delete",
|
|
73
|
+
"mdi-content-save": "save",
|
|
74
|
+
"mdi-content-copy": "content_copy",
|
|
75
|
+
"mdi-download": "download",
|
|
76
|
+
"mdi-download-outline": "download",
|
|
77
|
+
"mdi-upload": "upload",
|
|
78
|
+
"mdi-tray-arrow-up": "file_upload",
|
|
79
|
+
"mdi-export": "output",
|
|
80
|
+
"mdi-printer": "print",
|
|
81
|
+
"mdi-printer-alert": "print_error",
|
|
82
|
+
"mdi-printer-check": "print", // NEAREST: no printer-with-tick
|
|
83
|
+
"mdi-draw": "draw",
|
|
84
|
+
"mdi-tune-variant": "tune",
|
|
85
|
+
"mdi-cog": "settings",
|
|
86
|
+
"mdi-cog-outline": "settings",
|
|
87
|
+
"mdi-backspace": "backspace",
|
|
88
|
+
"mdi-eyedropper": "colorize",
|
|
89
|
+
"mdi-palette": "palette",
|
|
90
|
+
"mdi-sort-alphabetical-ascending": "sort_by_alpha",
|
|
91
|
+
|
|
92
|
+
// --- status & feedback ---
|
|
93
|
+
"mdi-alert": "warning",
|
|
94
|
+
"mdi-alert-outline": "warning",
|
|
95
|
+
"mdi-alert-circle": "error",
|
|
96
|
+
"mdi-alert-circle-outline": "error",
|
|
97
|
+
"mdi-information": "info",
|
|
98
|
+
"mdi-information-outline": "info",
|
|
99
|
+
"mdi-information-symbol": "info",
|
|
100
|
+
"mdi-help-circle": "help",
|
|
101
|
+
"mdi-loading": "progress_activity",
|
|
102
|
+
"mdi-progress-clock": "pending", // NEAREST: no clock-with-progress-arc
|
|
103
|
+
"mdi-history": "history",
|
|
104
|
+
"mdi-trending-up": "trending_up",
|
|
105
|
+
"mdi-flag": "flag",
|
|
106
|
+
"mdi-flash": "bolt",
|
|
107
|
+
"mdi-bug": "bug_report",
|
|
108
|
+
"mdi-bug-outline": "bug_report",
|
|
109
|
+
"mdi-radar": "radar",
|
|
110
|
+
"mdi-emoticon-happy-outline": "sentiment_satisfied",
|
|
111
|
+
"mdi-star": "star",
|
|
112
|
+
"mdi-star-outline": "star",
|
|
113
|
+
"mdi-star-half-full": "star_half",
|
|
114
|
+
"mdi-circle": "circle",
|
|
115
|
+
"mdi-circle-outline": "radio_button_unchecked",
|
|
116
|
+
|
|
117
|
+
// --- form controls (Vuetify's internal aliases live here) ---
|
|
118
|
+
"mdi-checkbox-marked": "check_box",
|
|
119
|
+
"mdi-checkbox-blank-outline": "check_box_outline_blank",
|
|
120
|
+
"mdi-checkbox-multiple-outline": "checklist", // NEAREST: no stacked checkboxes
|
|
121
|
+
"mdi-radiobox-marked": "radio_button_checked",
|
|
122
|
+
"mdi-radiobox-blank": "radio_button_unchecked",
|
|
123
|
+
"mdi-form-textbox": "text_fields",
|
|
124
|
+
"mdi-text": "subject",
|
|
125
|
+
"mdi-format-list-bulleted": "format_list_bulleted",
|
|
126
|
+
"mdi-format-list-numbered": "format_list_numbered",
|
|
127
|
+
"mdi-format-header-1": "format_h1",
|
|
128
|
+
"mdi-keyboard-return": "keyboard_return",
|
|
129
|
+
"mdi-keyboard-space": "space_bar",
|
|
130
|
+
"mdi-apple-keyboard-command": "keyboard_command_key",
|
|
131
|
+
"mdi-apple-keyboard-control": "keyboard_control_key",
|
|
132
|
+
"mdi-apple-keyboard-option": "keyboard_option_key",
|
|
133
|
+
"mdi-apple-keyboard-shift": "shift",
|
|
134
|
+
|
|
135
|
+
// --- time & calendar ---
|
|
136
|
+
"mdi-calendar": "calendar_month",
|
|
137
|
+
"mdi-calendar-month-outline": "calendar_month",
|
|
138
|
+
"mdi-calendar-range": "date_range",
|
|
139
|
+
"mdi-calendar-check": "event_available",
|
|
140
|
+
"mdi-calendar-remove": "event_busy",
|
|
141
|
+
"mdi-calendar-clock": "calendar_clock",
|
|
142
|
+
"mdi-calendar-start": "today", // NEAREST: no start/end calendar pair
|
|
143
|
+
"mdi-calendar-end": "event", // NEAREST: no start/end calendar pair
|
|
144
|
+
"mdi-clock-outline": "schedule",
|
|
145
|
+
"mdi-clock-check": "update",
|
|
146
|
+
"mdi-clock-check-outline": "update",
|
|
147
|
+
"mdi-clock-time-four-outline": "schedule", // NEAREST: no per-hour clock faces
|
|
148
|
+
"mdi-clock-time-eight-outline": "schedule", // NEAREST: no per-hour clock faces
|
|
149
|
+
"mdi-timer-outline": "timer",
|
|
150
|
+
|
|
151
|
+
// --- files & documents ---
|
|
152
|
+
"mdi-file": "draft",
|
|
153
|
+
"mdi-file-outline": "draft",
|
|
154
|
+
"mdi-file-document-outline": "description",
|
|
155
|
+
"mdi-file-document-remove-outline": "scan_delete",
|
|
156
|
+
"mdi-file-question-outline": "unknown_document",
|
|
157
|
+
"mdi-file-pdf": "picture_as_pdf",
|
|
158
|
+
"mdi-file-pdf-box": "picture_as_pdf",
|
|
159
|
+
"mdi-file-pdf-outline": "picture_as_pdf",
|
|
160
|
+
"mdi-file-word-box": "description", // NEAREST: no per-format document icons
|
|
161
|
+
"mdi-file-excel": "table_chart", // NEAREST: no per-format document icons
|
|
162
|
+
"mdi-file-excel-box": "table_chart", // NEAREST: no per-format document icons
|
|
163
|
+
"mdi-file-powerpoint-box": "slideshow", // NEAREST: no per-format document icons
|
|
164
|
+
"mdi-file-csv": "csv",
|
|
165
|
+
"mdi-file-delimited-outline": "csv",
|
|
166
|
+
"mdi-folder": "folder",
|
|
167
|
+
"mdi-folder-plus-outline": "create_new_folder",
|
|
168
|
+
"mdi-folder-zip-outline": "folder_zip",
|
|
169
|
+
"mdi-zip-box-outline": "folder_zip",
|
|
170
|
+
"mdi-paperclip": "attach_file",
|
|
171
|
+
"mdi-clipboard-list": "assignment",
|
|
172
|
+
"mdi-clipboard-text-outline": "assignment",
|
|
173
|
+
"mdi-clipboard-check-outline": "assignment_turned_in",
|
|
174
|
+
"mdi-cloud-upload": "cloud_upload",
|
|
175
|
+
"mdi-cloud-upload-outline": "cloud_upload",
|
|
176
|
+
"mdi-database-sync-outline": "sync", // NEAREST: no database-with-sync
|
|
177
|
+
"mdi-database-search-outline": "manage_search", // NEAREST: no database-with-search
|
|
178
|
+
|
|
179
|
+
// --- media & camera ---
|
|
180
|
+
"mdi-camera": "photo_camera",
|
|
181
|
+
"mdi-camera-outline": "photo_camera",
|
|
182
|
+
"mdi-camera-off": "no_photography",
|
|
183
|
+
"mdi-camera-off-outline": "no_photography",
|
|
184
|
+
"mdi-camera-plus-outline": "add_a_photo",
|
|
185
|
+
"mdi-camera-retake": "flip_camera_android", // NEAREST: retake reads as flip
|
|
186
|
+
"mdi-camera-switch": "cameraswitch",
|
|
187
|
+
"mdi-cctv": "videocam", // NEAREST: no dome/CCTV camera
|
|
188
|
+
"mdi-video": "videocam",
|
|
189
|
+
"mdi-image": "image",
|
|
190
|
+
"mdi-image-broken": "broken_image",
|
|
191
|
+
"mdi-play": "play_arrow",
|
|
192
|
+
"mdi-play-circle-outline": "play_circle",
|
|
193
|
+
"mdi-pause": "pause",
|
|
194
|
+
"mdi-fullscreen": "fullscreen",
|
|
195
|
+
"mdi-fullscreen-exit": "fullscreen_exit",
|
|
196
|
+
"mdi-microphone": "mic",
|
|
197
|
+
"mdi-microphone-off": "mic_off",
|
|
198
|
+
"mdi-volume-high": "volume_up",
|
|
199
|
+
"mdi-volume-medium": "volume_down",
|
|
200
|
+
"mdi-volume-low": "volume_mute",
|
|
201
|
+
"mdi-volume-variant-off": "volume_off",
|
|
202
|
+
"mdi-eye": "visibility",
|
|
203
|
+
"mdi-eye-outline": "visibility",
|
|
204
|
+
"mdi-eye-off": "visibility_off",
|
|
205
|
+
"mdi-eye-off-outline": "visibility_off",
|
|
206
|
+
"mdi-view-grid": "grid_view",
|
|
207
|
+
|
|
208
|
+
// --- people & accounts ---
|
|
209
|
+
"mdi-account": "person",
|
|
210
|
+
"mdi-user": "person",
|
|
211
|
+
"mdi-account-circle": "account_circle",
|
|
212
|
+
"mdi-account-plus": "person_add",
|
|
213
|
+
"mdi-account-off": "person_off",
|
|
214
|
+
"mdi-account-search-outline": "person_search",
|
|
215
|
+
"mdi-account-cog-outline": "manage_accounts",
|
|
216
|
+
"mdi-account-arrow-right": "how_to_reg", // NEAREST: person-with-arrow reads as check-in
|
|
217
|
+
"mdi-account-multiple": "group",
|
|
218
|
+
"mdi-account-group": "groups",
|
|
219
|
+
"mdi-account-badge": "badge",
|
|
220
|
+
"mdi-card-account-details": "badge",
|
|
221
|
+
"mdi-card-account-details-outline": "badge",
|
|
222
|
+
"mdi-card-account-details-star": "badge", // NEAREST: no starred ID card
|
|
223
|
+
"mdi-card-bulleted-outline": "badge", // NEAREST: access card reads as badge
|
|
224
|
+
"mdi-credit-card-outline": "credit_card",
|
|
225
|
+
"mdi-face-recognition": "face", // NEAREST: no face-recognition frame
|
|
226
|
+
"mdi-briefcase": "work",
|
|
227
|
+
"mdi-login": "login",
|
|
228
|
+
"mdi-logout": "logout",
|
|
229
|
+
|
|
230
|
+
// --- communication ---
|
|
231
|
+
"mdi-phone": "call",
|
|
232
|
+
"mdi-phone-outline": "call",
|
|
233
|
+
"mdi-phone-hangup": "call_end",
|
|
234
|
+
"mdi-phone-incoming": "call_received",
|
|
235
|
+
"mdi-phone-outgoing": "call_made",
|
|
236
|
+
"mdi-phone-in-talk": "phone_in_talk",
|
|
237
|
+
"mdi-phone-in-talk-outline": "phone_in_talk",
|
|
238
|
+
"mdi-email": "mail",
|
|
239
|
+
"mdi-message": "chat_bubble",
|
|
240
|
+
"mdi-message-outline": "chat_bubble",
|
|
241
|
+
"mdi-comment-multiple": "forum",
|
|
242
|
+
"mdi-link-variant": "link",
|
|
243
|
+
"mdi-lan-connect": "lan",
|
|
244
|
+
"mdi-lan-disconnect": "link_off", // NEAREST: no disconnected-LAN glyph
|
|
245
|
+
"mdi-bluetooth": "bluetooth",
|
|
246
|
+
"mdi-nfc": "nfc",
|
|
247
|
+
|
|
248
|
+
// --- places, security & operations ---
|
|
249
|
+
"mdi-office-building": "apartment",
|
|
250
|
+
"mdi-office-building-marker-outline": "location_city",
|
|
251
|
+
"mdi-building": "apartment",
|
|
252
|
+
"mdi-domain": "domain",
|
|
253
|
+
"mdi-home-city-outline": "home_work",
|
|
254
|
+
"mdi-warehouse": "warehouse",
|
|
255
|
+
"mdi-storefront-outline": "storefront",
|
|
256
|
+
"mdi-map-marker": "location_on",
|
|
257
|
+
"mdi-map-search": "travel_explore", // NEAREST: no map-with-magnifier
|
|
258
|
+
"mdi-door-open": "door_open",
|
|
259
|
+
"mdi-key": "key",
|
|
260
|
+
"mdi-lock": "lock",
|
|
261
|
+
"mdi-lock-outline": "lock",
|
|
262
|
+
"mdi-shield-outline": "shield",
|
|
263
|
+
"mdi-shield-check": "verified_user",
|
|
264
|
+
"mdi-shield-crown": "admin_panel_settings", // NEAREST: no crowned shield
|
|
265
|
+
"mdi-qrcode": "qr_code",
|
|
266
|
+
"mdi-qrcode-scan": "qr_code_scanner",
|
|
267
|
+
"mdi-barcode-scan": "barcode_scanner",
|
|
268
|
+
"mdi-car": "directions_car",
|
|
269
|
+
"mdi-car-back": "directions_car", // NEAREST: no rear-view car
|
|
270
|
+
"mdi-truck": "local_shipping",
|
|
271
|
+
"mdi-cart-plus": "add_shopping_cart",
|
|
272
|
+
"mdi-pool": "pool",
|
|
273
|
+
"mdi-broom": "cleaning_services",
|
|
274
|
+
"mdi-spray-bottle": "sanitizer",
|
|
275
|
+
"mdi-tools": "handyman",
|
|
276
|
+
"mdi-tree-outline": "park",
|
|
277
|
+
"mdi-flower": "local_florist",
|
|
278
|
+
"mdi-weather-sunny": "light_mode",
|
|
279
|
+
"mdi-weather-night": "dark_mode",
|
|
280
|
+
|
|
281
|
+
// mdi's deliberate spacer. No glyph, but `.v-icon` still holds the 1em box.
|
|
282
|
+
"mdi-blank": "",
|
|
283
|
+
|
|
284
|
+
// ------------------------------------------------------------------
|
|
285
|
+
// Names this package never uses, but the eleven applications do.
|
|
286
|
+
// ------------------------------------------------------------------
|
|
287
|
+
// The applications draw their icons through this same set, so a name
|
|
288
|
+
// missing here is an mdi glyph sitting next to a Material Symbols one on
|
|
289
|
+
// the same screen - the exact split the sweep exists to remove. Adding
|
|
290
|
+
// them here means no application repository needs a change of its own.
|
|
291
|
+
"mdi-view-dashboard": "dashboard",
|
|
292
|
+
"mdi-chart-bar": "bar_chart",
|
|
293
|
+
"mdi-update": "update",
|
|
294
|
+
"mdi-calendar-clock-outline": "calendar_clock",
|
|
295
|
+
"mdi-calendar-check-outline": "event_available",
|
|
296
|
+
"mdi-timer-check-outline": "timer", // NEAREST: no timer-with-tick
|
|
297
|
+
"mdi-timer-remove-outline": "timer_off",
|
|
298
|
+
"mdi-progress-check": "task_alt", // NEAREST: no progress-arc family
|
|
299
|
+
"mdi-progress-alert": "error", // NEAREST: no progress-arc family
|
|
300
|
+
"mdi-progress-question": "help", // NEAREST: no progress-arc family
|
|
301
|
+
"mdi-comment-outline": "chat_bubble",
|
|
302
|
+
"mdi-message-text": "chat",
|
|
303
|
+
"mdi-email-outline": "mail",
|
|
304
|
+
"mdi-email-fast-outline": "forward_to_inbox",
|
|
305
|
+
"mdi-bullhorn-outline": "campaign",
|
|
306
|
+
"mdi-web": "language",
|
|
307
|
+
"mdi-cellphone": "smartphone",
|
|
308
|
+
"mdi-cellphone-cog": "phonelink_setup",
|
|
309
|
+
"mdi-nfc-variant": "nfc",
|
|
310
|
+
"mdi-nfc-tap": "contactless",
|
|
311
|
+
"mdi-handshake": "handshake",
|
|
312
|
+
"mdi-hand-coin-outline": "payments", // NEAREST: no hand-holding-coin
|
|
313
|
+
"mdi-wallet-outline": "account_balance_wallet",
|
|
314
|
+
"mdi-credit-card": "credit_card",
|
|
315
|
+
"mdi-account-credit-card-outline": "credit_card", // NEAREST: no person-with-card
|
|
316
|
+
"mdi-sale-outline": "sell",
|
|
317
|
+
"mdi-rocket-launch": "rocket_launch",
|
|
318
|
+
"mdi-rocket-launch-outline": "rocket_launch",
|
|
319
|
+
"mdi-robot-happy-outline": "smart_toy",
|
|
320
|
+
"mdi-account-hard-hat": "engineering",
|
|
321
|
+
"mdi-account-wrench": "engineering", // NEAREST: no person-with-spanner
|
|
322
|
+
"mdi-wrench-clock": "build", // NEAREST: no spanner-with-clock
|
|
323
|
+
"mdi-account-clock": "pending_actions", // NEAREST: no person-with-clock
|
|
324
|
+
"mdi-account-clock-outline": "pending_actions", // NEAREST: no person-with-clock
|
|
325
|
+
"mdi-account-remove": "person_remove",
|
|
326
|
+
"mdi-account-cog": "manage_accounts",
|
|
327
|
+
"mdi-account-multiple-outline": "group",
|
|
328
|
+
"mdi-account-group-outline": "groups",
|
|
329
|
+
"mdi-account-multiple-check-outline": "how_to_reg", // NEAREST: no group-with-tick
|
|
330
|
+
"mdi-badge-account-outline": "badge",
|
|
331
|
+
"mdi-shield": "shield",
|
|
332
|
+
"mdi-shield-account": "admin_panel_settings",
|
|
333
|
+
"mdi-shield-account-outline": "admin_panel_settings",
|
|
334
|
+
"mdi-shield-search": "policy",
|
|
335
|
+
"mdi-office-building-outline": "apartment",
|
|
336
|
+
"mdi-office-building-marker": "location_city",
|
|
337
|
+
"mdi-office-building-cog-outline": "apartment", // NEAREST: no building-with-cog
|
|
338
|
+
"mdi-home-modern": "house",
|
|
339
|
+
"mdi-sign-text": "signpost",
|
|
340
|
+
"mdi-car-side": "directions_car", // NEAREST: one car glyph for all views
|
|
341
|
+
"mdi-car-clock": "directions_car", // NEAREST: no car-with-clock
|
|
342
|
+
"mdi-car-emergency": "emergency",
|
|
343
|
+
"mdi-key-variant": "key",
|
|
344
|
+
"mdi-pencil-box": "edit_square",
|
|
345
|
+
"mdi-trash": "delete",
|
|
346
|
+
"mdi-delete-forever-outline": "delete_forever",
|
|
347
|
+
"mdi-close-box": "disabled_by_default",
|
|
348
|
+
"mdi-circle-slice-8": "circle",
|
|
349
|
+
"mdi-help-circle-outline": "help",
|
|
350
|
+
"mdi-folder-alert": "folder", // NEAREST: no folder-with-alert
|
|
351
|
+
"mdi-note-text-outline": "description",
|
|
352
|
+
"mdi-card-text-outline": "article",
|
|
353
|
+
"mdi-list-box-outline": "list_alt",
|
|
354
|
+
"mdi-form-select": "dynamic_form", // NEAREST: no form-with-select
|
|
355
|
+
"mdi-microsoft-excel": "table_chart", // NEAREST: no per-format document icons
|
|
356
|
+
"mdi-tray-arrow-down": "file_download",
|
|
357
|
+
"mdi-image-off-outline": "hide_image",
|
|
358
|
+
"mdi-eye-arrow-right-outline": "visibility", // NEAREST: no eye-with-arrow
|
|
359
|
+
|
|
360
|
+
// Landed on staging while this branch was open (the HID screens).
|
|
361
|
+
"mdi-account-off-outline": "person_off",
|
|
362
|
+
"mdi-deskphone": "deskphone",
|
|
363
|
+
};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { test } from "node:test";
|
|
3
|
+
|
|
4
|
+
import { NAV_SECTIONS, withSections } from "./nav-sections.ts";
|
|
5
|
+
|
|
6
|
+
/** The Security menu, item for item and in `web-app-security`'s own order. */
|
|
7
|
+
const SECURITY = [
|
|
8
|
+
"Dashboard",
|
|
9
|
+
"Feedbacks",
|
|
10
|
+
"Work Orders",
|
|
11
|
+
"Vehicle Mgmt",
|
|
12
|
+
"Building Mgmt",
|
|
13
|
+
"Visitor Mgmt",
|
|
14
|
+
"Pass & Key Mgmt",
|
|
15
|
+
"HID Face Reader",
|
|
16
|
+
"Daily Occurrence Books",
|
|
17
|
+
"Manpower",
|
|
18
|
+
"Virtual Patrol",
|
|
19
|
+
"Robot Mgmt",
|
|
20
|
+
"Incident Reports",
|
|
21
|
+
"Bulletin Board",
|
|
22
|
+
"Attendance",
|
|
23
|
+
"My Attendance",
|
|
24
|
+
"Invitations",
|
|
25
|
+
"Members",
|
|
26
|
+
"Roles & Permissions",
|
|
27
|
+
"Settings",
|
|
28
|
+
].map((title) => ({ title }));
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* THE RULE THAT MATTERS. Grouping may reorder the rail; it may never change
|
|
32
|
+
* the menu. Same objects, same count - nothing added, hidden or duplicated.
|
|
33
|
+
*/
|
|
34
|
+
test("every menu item comes back exactly once, and nothing else does", () => {
|
|
35
|
+
const out = withSections(SECURITY);
|
|
36
|
+
|
|
37
|
+
assert.equal(out.length, SECURITY.length);
|
|
38
|
+
assert.deepEqual(
|
|
39
|
+
new Set(out.map((e) => e.item)),
|
|
40
|
+
new Set(SECURITY)
|
|
41
|
+
);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test("Security is labelled the way the design draws it", () => {
|
|
45
|
+
const labelled = withSections(SECURITY)
|
|
46
|
+
.filter((e) => e.section)
|
|
47
|
+
.map((e) => `${e.section}: ${e.item.title}`);
|
|
48
|
+
|
|
49
|
+
assert.deepEqual(labelled, [
|
|
50
|
+
"OVERVIEW: Dashboard",
|
|
51
|
+
"SERVICE DESK: Feedbacks",
|
|
52
|
+
"PROPERTY: Vehicle Mgmt",
|
|
53
|
+
"SECURITY OPERATIONS: HID Face Reader",
|
|
54
|
+
"COMMUNITY: Bulletin Board",
|
|
55
|
+
"WORKFORCE: Attendance",
|
|
56
|
+
"ADMINISTRATION: Invitations",
|
|
57
|
+
]);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* A permission-gated menu is a SUBSET, and every application's is different.
|
|
62
|
+
* Dropping the items a user cannot see must not leave a heading behind or move
|
|
63
|
+
* one onto the wrong item.
|
|
64
|
+
*/
|
|
65
|
+
test("a user who can only see three modules gets three correct headings", () => {
|
|
66
|
+
const out = withSections(
|
|
67
|
+
[{ title: "Dashboard" }, { title: "Work Orders" }, { title: "Settings" }]
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
assert.deepEqual(
|
|
71
|
+
out.map((e) => e.section),
|
|
72
|
+
["OVERVIEW", "SERVICE DESK", "ADMINISTRATION"]
|
|
73
|
+
);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* The eleven applications add menu items without touching this layer. An
|
|
78
|
+
* unknown title must appear where its author put it, under the heading it
|
|
79
|
+
* follows - never suppressed, and never given a heading of its own.
|
|
80
|
+
*/
|
|
81
|
+
test("an unmapped module inherits the section above it", () => {
|
|
82
|
+
const out = withSections([
|
|
83
|
+
{ title: "Dashboard" },
|
|
84
|
+
{ title: "Something New" },
|
|
85
|
+
{ title: "Members" },
|
|
86
|
+
]);
|
|
87
|
+
|
|
88
|
+
assert.deepEqual(
|
|
89
|
+
out.map((e) => e.section),
|
|
90
|
+
["OVERVIEW", "", "ADMINISTRATION"]
|
|
91
|
+
);
|
|
92
|
+
assert.equal(out[1].item.title, "Something New");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("an unmapped FIRST item prints no heading rather than a blank one", () => {
|
|
96
|
+
const out = withSections([{ title: "Something New" }, { title: "Members" }]);
|
|
97
|
+
|
|
98
|
+
assert.deepEqual(
|
|
99
|
+
out.map((e) => e.section),
|
|
100
|
+
["", "ADMINISTRATION"]
|
|
101
|
+
);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The applications do not agree on order: Landscape lists Feedbacks after its
|
|
106
|
+
* equipment modules. Those two Feedbacks/Work Orders items are collected under
|
|
107
|
+
* ONE SERVICE DESK heading instead of printing the heading twice.
|
|
108
|
+
*/
|
|
109
|
+
test("a section that comes back later is grouped, not labelled twice", () => {
|
|
110
|
+
const out = withSections([
|
|
111
|
+
{ title: "Feedbacks" },
|
|
112
|
+
{ title: "Equipment Items" },
|
|
113
|
+
{ title: "Work Orders" },
|
|
114
|
+
]);
|
|
115
|
+
|
|
116
|
+
assert.deepEqual(
|
|
117
|
+
out.map((e) => `${e.section}|${e.item.title}`),
|
|
118
|
+
[
|
|
119
|
+
"SERVICE DESK|Feedbacks",
|
|
120
|
+
"|Work Orders",
|
|
121
|
+
"EQUIPMENT|Equipment Items",
|
|
122
|
+
]
|
|
123
|
+
);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Property Management is the screen that showed the defect: its own menu order
|
|
128
|
+
* printed SERVICE DESK, PROPERTY and SECURITY OPERATIONS twice each.
|
|
129
|
+
*/
|
|
130
|
+
test("Property Management prints each heading exactly once", () => {
|
|
131
|
+
const PM = [
|
|
132
|
+
"Dashboard",
|
|
133
|
+
"Service Providers",
|
|
134
|
+
"Feedbacks",
|
|
135
|
+
"Work Orders",
|
|
136
|
+
"Facility Mgmt",
|
|
137
|
+
"Pass & Key Mgmt",
|
|
138
|
+
"HID Face Reader",
|
|
139
|
+
"Online Forms",
|
|
140
|
+
"NFC Patrol",
|
|
141
|
+
"Bulletin Board",
|
|
142
|
+
"Bulletin Videos",
|
|
143
|
+
"Visitor Mgmt",
|
|
144
|
+
"Document Mgmt",
|
|
145
|
+
"Access Mgmt",
|
|
146
|
+
].map((title) => ({ title }));
|
|
147
|
+
|
|
148
|
+
const out = withSections(PM);
|
|
149
|
+
const headings = out.map((e) => e.section).filter(Boolean);
|
|
150
|
+
|
|
151
|
+
assert.deepEqual(headings, [
|
|
152
|
+
"OVERVIEW",
|
|
153
|
+
"SERVICE DESK",
|
|
154
|
+
"PROPERTY",
|
|
155
|
+
"SECURITY OPERATIONS",
|
|
156
|
+
"COMMUNITY",
|
|
157
|
+
]);
|
|
158
|
+
assert.equal(new Set(headings).size, headings.length);
|
|
159
|
+
assert.deepEqual(
|
|
160
|
+
out.map((e) => e.item.title),
|
|
161
|
+
[
|
|
162
|
+
"Dashboard",
|
|
163
|
+
"Service Providers",
|
|
164
|
+
"Feedbacks",
|
|
165
|
+
"Work Orders",
|
|
166
|
+
"Online Forms",
|
|
167
|
+
"Facility Mgmt",
|
|
168
|
+
"Pass & Key Mgmt",
|
|
169
|
+
"Visitor Mgmt",
|
|
170
|
+
"Document Mgmt",
|
|
171
|
+
"Access Mgmt",
|
|
172
|
+
"HID Face Reader",
|
|
173
|
+
"NFC Patrol",
|
|
174
|
+
"Bulletin Board",
|
|
175
|
+
"Bulletin Videos",
|
|
176
|
+
]
|
|
177
|
+
);
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("a missing or empty title does not throw", () => {
|
|
181
|
+
const out = withSections([{}, { title: "" }] as Array<{ title?: string }>);
|
|
182
|
+
assert.equal(out.length, 2);
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
/** Every section name is the uppercase form the type scale is drawn for. */
|
|
186
|
+
test("section names are uppercase", () => {
|
|
187
|
+
for (const section of Object.values(NAV_SECTIONS)) {
|
|
188
|
+
assert.equal(section, section.toUpperCase(), section);
|
|
189
|
+
}
|
|
190
|
+
});
|