@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
package/components/TableMain.vue
CHANGED
|
@@ -1,92 +1,197 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
PHASE 3 - THE STANDARD TABLE CARD.
|
|
3
|
+
|
|
4
|
+
The redesign is, more than anything else, a table card: toolbar row (refresh,
|
|
5
|
+
optional in-card search, pagination) -> uppercase header row -> rows. This is
|
|
6
|
+
the shared one, so this file is where that pattern is drawn once.
|
|
7
|
+
|
|
8
|
+
VISUAL ONLY, and that matters more here than anywhere. Every column, filter,
|
|
9
|
+
sort, action, slot, prop, emit and page still behaves exactly as it did:
|
|
10
|
+
the headers are the caller's, the items are the caller's, every slot is still
|
|
11
|
+
forwarded to `v-data-table` untouched, and no prop's default has changed. The
|
|
12
|
+
empty state is the same wording `v-data-table` already showed, with the icon
|
|
13
|
+
the design draws above it - and it is only supplied when the caller has NOT
|
|
14
|
+
passed its own `no-data` slot.
|
|
15
|
+
-->
|
|
1
16
|
<template>
|
|
2
|
-
<v-row no-gutters>
|
|
3
|
-
<!--
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
17
|
+
<v-row no-gutters class="table-card__shrink">
|
|
18
|
+
<!--
|
|
19
|
+
THE DESIGN'S PAGE TITLE (Phase 9).
|
|
20
|
+
|
|
21
|
+
The design opens every screen with a 22px/800 heading. This shared table
|
|
22
|
+
card is mounted by 17 module screens, and none of them had one - four of
|
|
23
|
+
them (Units, Areas, Equipment Item, Equipment Management) were already
|
|
24
|
+
PASSING `:title` to this component, which had no `title` prop, so the
|
|
25
|
+
string was landing on the root element as a plain HTML `title` attribute:
|
|
26
|
+
a browser tooltip nobody asked for. It now draws the heading it was
|
|
27
|
+
always meant to draw.
|
|
28
|
+
|
|
29
|
+
Placement only. No caller changes, no slot moves, no behaviour: a screen
|
|
30
|
+
that passes no title renders exactly what it rendered before.
|
|
31
|
+
-->
|
|
32
|
+
<!--
|
|
33
|
+
The actions used to be drawn on a SECOND row underneath that heading,
|
|
34
|
+
which is not where the design puts them - the design's title row is the
|
|
35
|
+
page name on the left and the screen's actions on the right of the SAME
|
|
36
|
+
line, which is why every screen converted so far had to bypass this
|
|
37
|
+
component and draw its own `PageHeader` above it. They are on the title
|
|
38
|
+
row now, in `PageHeader`'s own `actions` slot.
|
|
39
|
+
|
|
40
|
+
Same buttons, same slot name, same content, same events - one row instead
|
|
41
|
+
of two. A screen with no title still gets its actions at the left, where
|
|
42
|
+
they have always been, because the title block is not drawn at all.
|
|
43
|
+
-->
|
|
44
|
+
<v-col cols="12" v-if="title || canCreate || $slots.actions">
|
|
45
|
+
<PageHeader :title="title">
|
|
46
|
+
<template v-if="canCreate || $slots.actions" #actions>
|
|
47
|
+
<slot name="actions">
|
|
48
|
+
<!--
|
|
49
|
+
The design's primary button: the accent fill that may carry a
|
|
50
|
+
white label (`--accent-strong`; white on `--accent` is 3.23:1),
|
|
51
|
+
40px, 10px radius, leading icon. Same click, same label.
|
|
52
|
+
-->
|
|
53
|
+
<v-btn
|
|
54
|
+
v-if="canCreate"
|
|
55
|
+
class="text-none table-card__primary"
|
|
56
|
+
variant="flat"
|
|
57
|
+
prepend-icon="mdi-plus"
|
|
58
|
+
@click="emits('create')"
|
|
59
|
+
>
|
|
60
|
+
{{ createLabel }}
|
|
61
|
+
</v-btn>
|
|
62
|
+
<v-text-field
|
|
63
|
+
v-if="canSearch"
|
|
64
|
+
v-model="searchInput"
|
|
65
|
+
density="compact"
|
|
66
|
+
placeholder="Search"
|
|
67
|
+
clearable
|
|
68
|
+
max-width="300"
|
|
69
|
+
append-inner-icon="mdi-magnify"
|
|
70
|
+
hide-details
|
|
71
|
+
class="table-card__search"
|
|
72
|
+
/>
|
|
73
|
+
<!-- Ghost/secondary, as the design specifies for Scan QR Code. -->
|
|
74
|
+
<v-btn
|
|
75
|
+
v-if="canScanVisitorQRCode"
|
|
76
|
+
text="Scan QR Code"
|
|
77
|
+
class="text-none table-card__ghost"
|
|
78
|
+
variant="outlined"
|
|
79
|
+
@click="emits('scan')"
|
|
80
|
+
/>
|
|
81
|
+
</slot>
|
|
82
|
+
</template>
|
|
83
|
+
</PageHeader>
|
|
42
84
|
</v-col>
|
|
43
85
|
|
|
44
86
|
<!-- Table Card -->
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
87
|
+
<!--
|
|
88
|
+
`table-card__shrink` is the fix for the wide-table blowout: this column is a
|
|
89
|
+
flex item, and a flex item's automatic minimum size is its CONTENT's, so
|
|
90
|
+
a table with enough columns set a floor the column would not shrink below
|
|
91
|
+
and the whole page scrolled sideways at 360 and 768. The table scrolls
|
|
92
|
+
inside the card instead - see `.table-card__shrink` in `screens.css`.
|
|
93
|
+
-->
|
|
94
|
+
<v-col cols="12" class="table-card__shrink">
|
|
95
|
+
<!--
|
|
96
|
+
THE DESIGN'S CARD AND ITS IN-CARD TOP ROW (Phase 9).
|
|
97
|
+
|
|
98
|
+
Was a `v-card` + `v-toolbar`. `v-card` brings its own radius, elevation
|
|
99
|
+
and surface at a specificity a class has to fight, and `v-toolbar` puts
|
|
100
|
+
its `extension` on a SECOND stacked row. `AppCard` + `CardToolbar` are
|
|
101
|
+
the primitives the design is drawn with, already proven on
|
|
102
|
+
`ServiceProviderMain` / `MemberMain`.
|
|
103
|
+
|
|
104
|
+
Placement only. The refresh button, the `prepend-additional` slot, the
|
|
105
|
+
page range, the pager, the `extension` slot and the `footer` slot are
|
|
106
|
+
the same controls, emitting the same events, in the same order. The
|
|
107
|
+
`loading` bar `v-card` used to draw is drawn explicitly so a loading
|
|
108
|
+
screen still says so.
|
|
109
|
+
-->
|
|
110
|
+
<AppCard class="table-card">
|
|
111
|
+
<v-progress-linear
|
|
112
|
+
v-if="loading"
|
|
113
|
+
indeterminate
|
|
114
|
+
height="2"
|
|
115
|
+
class="table-card__loading"
|
|
116
|
+
/>
|
|
117
|
+
|
|
53
118
|
<!-- Toolbar -->
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
119
|
+
<CardToolbar :count="pageRange">
|
|
120
|
+
<!--
|
|
121
|
+
The design draws a screen's tabs ON the toolbar row, not on a
|
|
122
|
+
stacked strip above the table. `CardToolbar` has always had the
|
|
123
|
+
slot; `TableMain` simply never forwarded it, so callers put their
|
|
124
|
+
`v-tabs` in `extension` and got a second row. Purely additive: a
|
|
125
|
+
caller that passes no `tabs` renders exactly what it rendered.
|
|
126
|
+
-->
|
|
127
|
+
<template v-if="$slots.tabs" #tabs>
|
|
128
|
+
<slot name="tabs" />
|
|
129
|
+
</template>
|
|
130
|
+
|
|
131
|
+
<template #left>
|
|
132
|
+
<!--
|
|
133
|
+
THE REFRESH BUTTON HAD NO BUSY STATE.
|
|
134
|
+
|
|
135
|
+
It emitted `refresh` and then looked identical for the whole
|
|
136
|
+
request. When the reload returned the same rows, NOTHING on the
|
|
137
|
+
screen changed - so there was no way to tell whether the click
|
|
138
|
+
had registered, which is exactly what QA reported on Work Orders
|
|
139
|
+
and on the Duty Officer Book (both fire the request; neither
|
|
140
|
+
showed it). `loading` is the caller's own in-flight flag, the
|
|
141
|
+
same one the bar above already reads: while it is true the button
|
|
142
|
+
is disabled, so the click is acknowledged and a second one cannot
|
|
143
|
+
stack another request on the first.
|
|
144
|
+
|
|
145
|
+
A caller that passes no `loading` renders exactly what it renders
|
|
146
|
+
today (the prop defaults to false).
|
|
147
|
+
-->
|
|
148
|
+
<v-btn
|
|
149
|
+
fab
|
|
150
|
+
icon
|
|
151
|
+
density="comfortable"
|
|
152
|
+
variant="text"
|
|
153
|
+
:disabled="loading"
|
|
154
|
+
@click="emits('refresh')"
|
|
155
|
+
>
|
|
61
156
|
<v-icon>mdi-refresh</v-icon>
|
|
62
157
|
</v-btn>
|
|
63
158
|
<slot name="prepend-additional" />
|
|
64
159
|
</template>
|
|
65
160
|
|
|
66
|
-
<template #
|
|
67
|
-
<
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
v-model="internalPage"
|
|
73
|
-
:length="pages"
|
|
74
|
-
@update:value="emits('update:page', internalPage)"
|
|
75
|
-
/>
|
|
76
|
-
</v-row>
|
|
161
|
+
<template #right>
|
|
162
|
+
<local-pagination
|
|
163
|
+
v-model="internalPage"
|
|
164
|
+
:length="pages"
|
|
165
|
+
@update:value="emits('update:page', internalPage)"
|
|
166
|
+
/>
|
|
77
167
|
</template>
|
|
168
|
+
</CardToolbar>
|
|
78
169
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
170
|
+
<!--
|
|
171
|
+
The callers' `extension` is a FILTER row (selects, date ranges), not
|
|
172
|
+
tabs - it is full-width by construction, so it keeps its own line
|
|
173
|
+
under the toolbar rather than being folded into it, which would push
|
|
174
|
+
the pager off the end of the row.
|
|
175
|
+
-->
|
|
176
|
+
<div v-if="$slots.extension" class="table-card__extension">
|
|
177
|
+
<slot name="extension" />
|
|
178
|
+
</div>
|
|
83
179
|
|
|
84
180
|
<!-- Data Table -->
|
|
181
|
+
<!--
|
|
182
|
+
`tableHeaders`, not `headers`, and the two are the SAME ARRAY unless a
|
|
183
|
+
caller has opted into fixed proportions by putting `weight` on a
|
|
184
|
+
column. See `columnsAreWeighted` below.
|
|
185
|
+
-->
|
|
85
186
|
<v-data-table
|
|
187
|
+
v-model="selectedItems"
|
|
86
188
|
:headers="headers"
|
|
189
|
+
:class="columnsAreWeighted ? 'table-card__fixed' : undefined"
|
|
190
|
+
:headers="tableHeaders"
|
|
87
191
|
:items="items"
|
|
88
192
|
:item-value="itemValue"
|
|
89
193
|
:items-per-page="itemsPerPage"
|
|
194
|
+
:show-select="showSelect"
|
|
90
195
|
fixed-header
|
|
91
196
|
hide-default-footer
|
|
92
197
|
:hide-default-header="!showHeader"
|
|
@@ -94,17 +199,40 @@
|
|
|
94
199
|
:style="`max-height: calc(100vh - (${offset}px))`"
|
|
95
200
|
>
|
|
96
201
|
<template v-for="(_, slotName) in $slots" #[slotName]="slotProps">
|
|
97
|
-
|
|
202
|
+
<!--
|
|
203
|
+
Vuetify invokes argument-less slots such as `no-data` with null
|
|
204
|
+
props. Vue's dynamic `renderSlot` expects an object and otherwise
|
|
205
|
+
crashes while reading `props.key`, leaving the previous route on
|
|
206
|
+
screen even though Vue Router has already updated the URL.
|
|
207
|
+
-->
|
|
208
|
+
<slot :name="slotName" v-bind="slotProps ?? {}" />
|
|
209
|
+
</template>
|
|
210
|
+
|
|
211
|
+
<!--
|
|
212
|
+
The design's empty state. Same sentence the table already showed;
|
|
213
|
+
only supplied when the caller has not passed its own, so nobody's
|
|
214
|
+
existing empty state is replaced.
|
|
215
|
+
-->
|
|
216
|
+
<template v-if="!$slots['no-data']" #no-data>
|
|
217
|
+
<div class="table-card__empty">
|
|
218
|
+
<v-icon icon="mdi-magnify-close" size="32" />
|
|
219
|
+
<span>No data available</span>
|
|
220
|
+
</div>
|
|
98
221
|
</template>
|
|
99
222
|
</v-data-table>
|
|
100
223
|
<slot name="footer" />
|
|
101
|
-
</
|
|
224
|
+
</AppCard>
|
|
102
225
|
</v-col>
|
|
103
226
|
</v-row>
|
|
104
227
|
</template>
|
|
105
228
|
|
|
106
229
|
<script lang="ts" setup>
|
|
107
230
|
const props = defineProps({
|
|
231
|
+
// The design's page heading. Empty = no heading, i.e. exactly today's markup.
|
|
232
|
+
title: {
|
|
233
|
+
type: String,
|
|
234
|
+
default: "",
|
|
235
|
+
},
|
|
108
236
|
headers: {
|
|
109
237
|
type: Array as PropType<Array<Record<string, any>>>,
|
|
110
238
|
required: true,
|
|
@@ -157,6 +285,10 @@ const props = defineProps({
|
|
|
157
285
|
type: Boolean,
|
|
158
286
|
default: false,
|
|
159
287
|
},
|
|
288
|
+
showSelect: {
|
|
289
|
+
type: Boolean,
|
|
290
|
+
default: false,
|
|
291
|
+
},
|
|
160
292
|
extensionHeight: {
|
|
161
293
|
type: Number,
|
|
162
294
|
default: 50,
|
|
@@ -167,6 +299,49 @@ const props = defineProps({
|
|
|
167
299
|
},
|
|
168
300
|
});
|
|
169
301
|
|
|
302
|
+
/**
|
|
303
|
+
* THE DESIGN'S FIXED COLUMN PROPORTIONS, AND WHY THEY ARE OPT-IN.
|
|
304
|
+
*
|
|
305
|
+
* Every table in the prototype is a CSS grid with an explicit, per-table
|
|
306
|
+
* `grid-template-columns` - `0.9fr 1.5fr 1.7fr 0.8fr 1fr 1.1fr` on Feedbacks,
|
|
307
|
+
* `2fr 1fr 1fr` on Units, `1.6fr 1fr 1.3fr 1.6fr 48px` on Pass & Key. Those
|
|
308
|
+
* ratios are a per-screen design decision. Nothing in a caller's `headers`
|
|
309
|
+
* array carries that information, so this shared component cannot derive them,
|
|
310
|
+
* and inventing one set of proportions for 21 components and 18 app pages would
|
|
311
|
+
* be worse than the automatic layout they have now.
|
|
312
|
+
*
|
|
313
|
+
* So it is stated, not guessed: a header may carry `weight: 1.5` and this turns
|
|
314
|
+
* the weights into percentage widths and switches the table to
|
|
315
|
+
* `table-layout: fixed`, which is what makes a width binding rather than a hint.
|
|
316
|
+
* A column with NO weight is left exactly as the caller wrote it, so an
|
|
317
|
+
* existing `width` (an action column pinned at 48px, say) survives untouched
|
|
318
|
+
* and only the weighted columns share out what is left.
|
|
319
|
+
*
|
|
320
|
+
* NO caller changes. With no weights anywhere, `tableHeaders` IS `props.headers`
|
|
321
|
+
* - the same array reference - and the table renders exactly what it renders
|
|
322
|
+
* today, automatic widths and all.
|
|
323
|
+
*/
|
|
324
|
+
const columnsAreWeighted = computed(() =>
|
|
325
|
+
props.headers.some((h) => Number(h?.weight) > 0)
|
|
326
|
+
);
|
|
327
|
+
|
|
328
|
+
const tableHeaders = computed(() => {
|
|
329
|
+
if (!columnsAreWeighted.value) return props.headers;
|
|
330
|
+
|
|
331
|
+
// Columns with no weight keep whatever width they already had (often none,
|
|
332
|
+
// e.g. a 48px action column), and only the weighted ones share what is left.
|
|
333
|
+
const total = props.headers.reduce(
|
|
334
|
+
(sum, h) => sum + (Number(h?.weight) > 0 ? Number(h.weight) : 0),
|
|
335
|
+
0
|
|
336
|
+
);
|
|
337
|
+
|
|
338
|
+
return props.headers.map((h) =>
|
|
339
|
+
Number(h?.weight) > 0
|
|
340
|
+
? { ...h, width: `${((Number(h.weight) / total) * 100).toFixed(4)}%` }
|
|
341
|
+
: h
|
|
342
|
+
);
|
|
343
|
+
});
|
|
344
|
+
|
|
170
345
|
const emits = defineEmits([
|
|
171
346
|
"create",
|
|
172
347
|
"scan",
|
|
@@ -176,6 +351,10 @@ const emits = defineEmits([
|
|
|
176
351
|
]);
|
|
177
352
|
|
|
178
353
|
const searchInput = defineModel("search", { default: "" });
|
|
354
|
+
const selectedItems = defineModel("selected", {
|
|
355
|
+
type: Array as PropType<any[]>,
|
|
356
|
+
default: () => [],
|
|
357
|
+
});
|
|
179
358
|
|
|
180
359
|
const internalPage = ref(props.page);
|
|
181
360
|
watch(
|
|
@@ -185,9 +364,3 @@ watch(
|
|
|
185
364
|
}
|
|
186
365
|
);
|
|
187
366
|
</script>
|
|
188
|
-
|
|
189
|
-
<style scoped>
|
|
190
|
-
.v-data-table :deep(thead th) {
|
|
191
|
-
font-weight: bold !important;
|
|
192
|
-
}
|
|
193
|
-
</style>
|
package/components/TableV3.vue
CHANGED
|
@@ -5,43 +5,39 @@
|
|
|
5
5
|
border="thin"
|
|
6
6
|
rounded="lg"
|
|
7
7
|
:loading="loading"
|
|
8
|
-
class="table-v3"
|
|
8
|
+
class="table-v3 table-card"
|
|
9
9
|
>
|
|
10
|
-
<
|
|
11
|
-
<
|
|
10
|
+
<div class="app-toolbar app-toolbar--plain">
|
|
11
|
+
<v-btn
|
|
12
|
+
icon
|
|
13
|
+
variant="text"
|
|
14
|
+
density="comfortable"
|
|
15
|
+
class="table-v3__refresh-btn"
|
|
16
|
+
@click="emit('refresh')"
|
|
17
|
+
>
|
|
18
|
+
<v-icon size="24">mdi-history</v-icon>
|
|
19
|
+
</v-btn>
|
|
20
|
+
|
|
21
|
+
<div class="app-toolbar__spacer" />
|
|
22
|
+
|
|
23
|
+
<div class="app-toolbar__right">
|
|
24
|
+
<span class="table-card__range">{{ pageRange }}</span>
|
|
12
25
|
<v-btn
|
|
13
|
-
icon
|
|
26
|
+
icon="mdi-chevron-left"
|
|
14
27
|
variant="text"
|
|
15
28
|
density="comfortable"
|
|
16
|
-
|
|
17
|
-
@click="
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
<v-btn
|
|
29
|
-
icon="mdi-chevron-left"
|
|
30
|
-
variant="text"
|
|
31
|
-
density="comfortable"
|
|
32
|
-
:disabled="!canGoPrev"
|
|
33
|
-
@click="goPrev"
|
|
34
|
-
/>
|
|
35
|
-
<v-btn
|
|
36
|
-
icon="mdi-chevron-right"
|
|
37
|
-
variant="text"
|
|
38
|
-
density="comfortable"
|
|
39
|
-
:disabled="!canGoNext"
|
|
40
|
-
@click="goNext"
|
|
41
|
-
/>
|
|
42
|
-
</v-row>
|
|
43
|
-
</template>
|
|
44
|
-
</v-toolbar>
|
|
29
|
+
:disabled="!canGoPrev"
|
|
30
|
+
@click="goPrev"
|
|
31
|
+
/>
|
|
32
|
+
<v-btn
|
|
33
|
+
icon="mdi-chevron-right"
|
|
34
|
+
variant="text"
|
|
35
|
+
density="comfortable"
|
|
36
|
+
:disabled="!canGoNext"
|
|
37
|
+
@click="goNext"
|
|
38
|
+
/>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
45
41
|
|
|
46
42
|
<div v-if="$slots.breadcrumb" class="table-v3__breadcrumb">
|
|
47
43
|
<slot name="breadcrumb" />
|
|
@@ -62,29 +58,27 @@
|
|
|
62
58
|
</template>
|
|
63
59
|
</v-data-table>
|
|
64
60
|
|
|
65
|
-
<
|
|
66
|
-
<
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
</template>
|
|
87
|
-
</v-toolbar>
|
|
61
|
+
<div class="app-toolbar app-toolbar--plain table-v3__footer">
|
|
62
|
+
<div class="app-toolbar__spacer" />
|
|
63
|
+
|
|
64
|
+
<div class="app-toolbar__right">
|
|
65
|
+
<span class="table-card__range">{{ pageRange }}</span>
|
|
66
|
+
<v-btn
|
|
67
|
+
icon="mdi-chevron-left"
|
|
68
|
+
variant="text"
|
|
69
|
+
density="comfortable"
|
|
70
|
+
:disabled="!canGoPrev"
|
|
71
|
+
@click="goPrev"
|
|
72
|
+
/>
|
|
73
|
+
<v-btn
|
|
74
|
+
icon="mdi-chevron-right"
|
|
75
|
+
variant="text"
|
|
76
|
+
density="comfortable"
|
|
77
|
+
:disabled="!canGoNext"
|
|
78
|
+
@click="goNext"
|
|
79
|
+
/>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
88
82
|
</v-card>
|
|
89
83
|
</template>
|
|
90
84
|
|
|
@@ -161,19 +155,16 @@ watch(
|
|
|
161
155
|
</script>
|
|
162
156
|
|
|
163
157
|
<style scoped>
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
.table-v3 :deep(tbody td) {
|
|
172
|
-
height: 54px;
|
|
173
|
-
}
|
|
174
|
-
|
|
158
|
+
/*
|
|
159
|
+
* The header row is no longer drawn here. It was `#f5f5f5` on `#6b7280`,
|
|
160
|
+
* both literal, so in the dark theme the fixed-header rule won the background
|
|
161
|
+
* and the header read 3.45:1. `.table-card` on the root gives this table the
|
|
162
|
+
* same tokenised header, cell and hover treatment as every other table in the
|
|
163
|
+
* product, which measures 4.77:1 light / 4.71:1 dark.
|
|
164
|
+
*/
|
|
175
165
|
.table-v3__footer {
|
|
176
|
-
border-top: 1px solid
|
|
166
|
+
border-top: 1px solid var(--border);
|
|
167
|
+
border-bottom: 0;
|
|
177
168
|
}
|
|
178
169
|
|
|
179
170
|
.table-v3__refresh-btn {
|
|
@@ -182,8 +173,8 @@ watch(
|
|
|
182
173
|
}
|
|
183
174
|
|
|
184
175
|
.table-v3__breadcrumb {
|
|
185
|
-
border-bottom: 1px solid
|
|
186
|
-
background-color:
|
|
176
|
+
border-bottom: 1px solid var(--border);
|
|
177
|
+
background-color: var(--card);
|
|
187
178
|
padding: 6px 12px;
|
|
188
179
|
}
|
|
189
180
|
</style>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
|
|
3
|
+
<!-- AppCard, not VCard: the design's 14px radius and 1px rule, without
|
|
4
|
+
Vuetify's own elevation and 4px corner fighting the class for it. -->
|
|
5
|
+
<AppCard>
|
|
4
6
|
<VuetifyTiptap v-model="content" />
|
|
5
|
-
</
|
|
7
|
+
</AppCard>
|
|
6
8
|
</div>
|
|
7
9
|
</template>
|
|
8
10
|
|
|
@@ -39,35 +41,37 @@ const updateContent = () => {
|
|
|
39
41
|
</script>
|
|
40
42
|
|
|
41
43
|
<style scoped>
|
|
42
|
-
|
|
44
|
+
/*
|
|
45
|
+
* The rich-text tables. Every colour here used to be a literal - #333 borders,
|
|
46
|
+
* #fff and #f8f8f8 cells, #f0f0f0 headers, #000 header text, #e6f3ff hover -
|
|
47
|
+
* so an editor opened in the dark theme drew a white table with black text on
|
|
48
|
+
* a dark page. They are the same tokens every other table in the product uses,
|
|
49
|
+
* so the editor content now follows the theme it is opened in.
|
|
50
|
+
*
|
|
51
|
+
* The selectors were also written twice, once with :deep() and again with the
|
|
52
|
+
* deprecated /deep/, matching the same two roots. One copy is enough.
|
|
53
|
+
*/
|
|
54
|
+
:deep(.vuetify-pro-tiptap-editor__content) {
|
|
43
55
|
padding: 15px;
|
|
44
56
|
}
|
|
45
57
|
|
|
46
|
-
/* Table styles with strong visible borders */
|
|
47
58
|
:deep(.vuetify-pro-tiptap-editor__content table),
|
|
48
|
-
:deep(.ProseMirror table)
|
|
49
|
-
/deep/ .vuetify-pro-tiptap-editor__content table,
|
|
50
|
-
/deep/ .ProseMirror table {
|
|
59
|
+
:deep(.ProseMirror table) {
|
|
51
60
|
border-collapse: collapse;
|
|
52
61
|
border-spacing: 0;
|
|
53
|
-
border: 2px solid
|
|
62
|
+
border: 2px solid var(--border) !important;
|
|
54
63
|
width: 100%;
|
|
55
64
|
margin: 16px 0;
|
|
56
|
-
background-color:
|
|
65
|
+
background-color: var(--card);
|
|
57
66
|
display: table !important;
|
|
58
|
-
font-size:
|
|
67
|
+
font-size: var(--fs-cell);
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
/* Cell borders - very visible */
|
|
62
70
|
:deep(.vuetify-pro-tiptap-editor__content table th),
|
|
63
71
|
:deep(.vuetify-pro-tiptap-editor__content table td),
|
|
64
72
|
:deep(.ProseMirror table th),
|
|
65
|
-
:deep(.ProseMirror table td)
|
|
66
|
-
|
|
67
|
-
/deep/ .vuetify-pro-tiptap-editor__content table td,
|
|
68
|
-
/deep/ .ProseMirror table th,
|
|
69
|
-
/deep/ .ProseMirror table td {
|
|
70
|
-
border: 1px solid #333333 !important;
|
|
73
|
+
:deep(.ProseMirror table td) {
|
|
74
|
+
border: 1px solid var(--border) !important;
|
|
71
75
|
padding: 8px 12px;
|
|
72
76
|
text-align: left;
|
|
73
77
|
vertical-align: top;
|
|
@@ -75,38 +79,27 @@ const updateContent = () => {
|
|
|
75
79
|
box-sizing: border-box;
|
|
76
80
|
}
|
|
77
81
|
|
|
78
|
-
/* Header styling */
|
|
79
82
|
:deep(.vuetify-pro-tiptap-editor__content table th),
|
|
80
|
-
:deep(.ProseMirror table th)
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
color: #000000;
|
|
86
|
-
border-bottom: 2px solid #333333 !important;
|
|
83
|
+
:deep(.ProseMirror table th) {
|
|
84
|
+
font-weight: var(--fw-table-head);
|
|
85
|
+
background-color: var(--thead);
|
|
86
|
+
color: var(--text);
|
|
87
|
+
border-bottom: 2px solid var(--border) !important;
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
/* Regular cells */
|
|
90
90
|
:deep(.vuetify-pro-tiptap-editor__content table td),
|
|
91
|
-
:deep(.ProseMirror table td)
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
background-color: #ffffff;
|
|
91
|
+
:deep(.ProseMirror table td) {
|
|
92
|
+
background-color: var(--card);
|
|
93
|
+
color: var(--text);
|
|
95
94
|
}
|
|
96
95
|
|
|
97
|
-
/* Alternating row colors */
|
|
98
96
|
:deep(.vuetify-pro-tiptap-editor__content table tr:nth-child(2n) td),
|
|
99
|
-
:deep(.ProseMirror table tr:nth-child(2n) td)
|
|
100
|
-
|
|
101
|
-
/deep/ .ProseMirror table tr:nth-child(2n) td {
|
|
102
|
-
background-color: #f8f8f8;
|
|
97
|
+
:deep(.ProseMirror table tr:nth-child(2n) td) {
|
|
98
|
+
background-color: var(--thead);
|
|
103
99
|
}
|
|
104
100
|
|
|
105
|
-
/* Hover effects */
|
|
106
101
|
:deep(.vuetify-pro-tiptap-editor__content table tr:hover td),
|
|
107
|
-
:deep(.ProseMirror table tr:hover td)
|
|
108
|
-
|
|
109
|
-
/deep/ .ProseMirror table tr:hover td {
|
|
110
|
-
background-color: #e6f3ff !important;
|
|
102
|
+
:deep(.ProseMirror table tr:hover td) {
|
|
103
|
+
background-color: var(--hover) !important;
|
|
111
104
|
}
|
|
112
105
|
</style>
|