@7365admin1/layer-common 3.2.2-staging.91 → 3.2.2-staging.93
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/.changeset/pm-sidebar-grouping-and-list-scaffold.md +27 -0
- package/assets/css/primitives.css +147 -0
- package/components/AppKpiTile.vue +65 -0
- package/components/AppSegmented.vue +38 -0
- package/components/Avatar/Main.vue +13 -1
- package/components/DashboardMain.vue +69 -124
- package/components/FeedbackMain.vue +33 -36
- package/components/InvitationMain.vue +45 -62
- package/components/Layout/Header.vue +16 -2
- package/components/Layout/NavigationDrawer.vue +4 -3
- package/components/ServiceProviderMain.vue +105 -135
- package/components/SwitchContext.vue +33 -1
- package/components/WorkOrder/Main.vue +42 -51
- package/package.json +1 -1
- package/utils/nav-sections.test.ts +70 -11
- package/utils/nav-sections.ts +48 -25
|
@@ -28,16 +28,17 @@ const SECURITY = [
|
|
|
28
28
|
].map((title) => ({ title }));
|
|
29
29
|
|
|
30
30
|
/**
|
|
31
|
-
* THE RULE THAT MATTERS.
|
|
32
|
-
*
|
|
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
33
|
*/
|
|
34
|
-
test("
|
|
34
|
+
test("every menu item comes back exactly once, and nothing else does", () => {
|
|
35
35
|
const out = withSections(SECURITY);
|
|
36
36
|
|
|
37
37
|
assert.equal(out.length, SECURITY.length);
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
38
|
+
assert.deepEqual(
|
|
39
|
+
new Set(out.map((e) => e.item)),
|
|
40
|
+
new Set(SECURITY)
|
|
41
|
+
);
|
|
41
42
|
});
|
|
42
43
|
|
|
43
44
|
test("Security is labelled the way the design draws it", () => {
|
|
@@ -102,10 +103,10 @@ test("an unmapped FIRST item prints no heading rather than a blank one", () => {
|
|
|
102
103
|
|
|
103
104
|
/**
|
|
104
105
|
* The applications do not agree on order: Landscape lists Feedbacks after its
|
|
105
|
-
* equipment modules.
|
|
106
|
-
*
|
|
106
|
+
* equipment modules. Those two Feedbacks/Work Orders items are collected under
|
|
107
|
+
* ONE SERVICE DESK heading instead of printing the heading twice.
|
|
107
108
|
*/
|
|
108
|
-
test("a section that comes back later is
|
|
109
|
+
test("a section that comes back later is grouped, not labelled twice", () => {
|
|
109
110
|
const out = withSections([
|
|
110
111
|
{ title: "Feedbacks" },
|
|
111
112
|
{ title: "Equipment Items" },
|
|
@@ -113,8 +114,66 @@ test("a section that comes back later is labelled again, not orphaned", () => {
|
|
|
113
114
|
]);
|
|
114
115
|
|
|
115
116
|
assert.deepEqual(
|
|
116
|
-
out.map((e) => e.section),
|
|
117
|
-
[
|
|
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
|
+
]
|
|
118
177
|
);
|
|
119
178
|
});
|
|
120
179
|
|
package/utils/nav-sections.ts
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* THE GROUPED SIDEBAR - section
|
|
2
|
+
* THE GROUPED SIDEBAR - one heading per section, each printed once.
|
|
3
3
|
*
|
|
4
4
|
* The design draws the sidebar in labelled sections (OVERVIEW, SERVICE DESK,
|
|
5
5
|
* PROPERTY, SECURITY OPERATIONS, COMMUNITY, WORKFORCE, ADMINISTRATION). Each
|
|
6
6
|
* application builds its own menu array in its `layouts/default.vue`, gated
|
|
7
|
-
* item by item on permissions
|
|
7
|
+
* item by item on permissions.
|
|
8
8
|
*
|
|
9
|
-
*
|
|
9
|
+
* The applications do not agree on the order they list their modules in
|
|
10
|
+
* (Property Management interleaves five sections; Landscape puts Feedbacks
|
|
11
|
+
* after Equipment). Walking that order and printing a heading whenever the
|
|
12
|
+
* section changed - what this file used to do - made Property Management draw
|
|
13
|
+
* SERVICE DESK, PROPERTY and SECURITY OPERATIONS TWICE each. It reads as a
|
|
14
|
+
* bug, so the items are now GROUPED:
|
|
10
15
|
*
|
|
11
|
-
* -
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* disappearing or forcing a stray
|
|
19
|
-
*
|
|
20
|
-
*
|
|
16
|
+
* - every item is collected under its section, and each heading is printed
|
|
17
|
+
* exactly once, in the order the design lists the sections (which is the
|
|
18
|
+
* order they are declared in the map below).
|
|
19
|
+
* - inside a section the application's own order is preserved, so items that
|
|
20
|
+
* belong together stay in the sequence their author chose.
|
|
21
|
+
* - a title this map has never heard of inherits the section of the item
|
|
22
|
+
* above it, so a new menu item added by any of the eleven applications is
|
|
23
|
+
* grouped with its neighbours rather than disappearing or forcing a stray
|
|
24
|
+
* heading.
|
|
25
|
+
* - an item with no section at all (an unmapped FIRST item) leads the rail
|
|
26
|
+
* with no heading, exactly as before.
|
|
21
27
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* and printing the heading again is honest, where suppressing it would leave a
|
|
26
|
-
* run of items sitting under a heading that is not theirs.
|
|
28
|
+
* This changes what ORDER the items are drawn in and nothing else. No item is
|
|
29
|
+
* added, hidden, renamed, re-routed or re-gated - the array that comes out
|
|
30
|
+
* holds the same objects as the array that went in.
|
|
27
31
|
*/
|
|
28
32
|
|
|
29
33
|
export const NAV_SECTIONS: Record<string, string> = {
|
|
@@ -110,19 +114,38 @@ export const NAV_SECTIONS: Record<string, string> = {
|
|
|
110
114
|
|
|
111
115
|
export type TSectionedNavItem<T> = { item: T; section: string };
|
|
112
116
|
|
|
117
|
+
/** The design's section order - the order they are declared above. */
|
|
118
|
+
export const SECTION_ORDER: string[] = [
|
|
119
|
+
...new Set(Object.values(NAV_SECTIONS)),
|
|
120
|
+
];
|
|
121
|
+
|
|
113
122
|
/**
|
|
114
|
-
*
|
|
115
|
-
*
|
|
123
|
+
* Groups the menu by section and tags each item with the heading to print
|
|
124
|
+
* above it, or "" when the heading is already printed. Same length, same
|
|
125
|
+
* objects; only the order changes.
|
|
116
126
|
*/
|
|
117
127
|
export function withSections<T extends { title?: string }>(
|
|
118
128
|
items: T[]
|
|
119
129
|
): Array<TSectionedNavItem<T>> {
|
|
130
|
+
// An unmapped title inherits the section of the item above it.
|
|
120
131
|
let current = "";
|
|
132
|
+
const resolved = items.map((item, index) => {
|
|
133
|
+
current = NAV_SECTIONS[String(item?.title ?? "")] ?? current;
|
|
134
|
+
return { item, section: current, index };
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Sectionless items (an unmapped first item) rank -1 and lead the rail.
|
|
138
|
+
// Inside a section the application's own order is kept.
|
|
139
|
+
const grouped = [...resolved].sort(
|
|
140
|
+
(a, b) =>
|
|
141
|
+
SECTION_ORDER.indexOf(a.section) - SECTION_ORDER.indexOf(b.section) ||
|
|
142
|
+
a.index - b.index
|
|
143
|
+
);
|
|
121
144
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
return { item, section:
|
|
145
|
+
let printed = "";
|
|
146
|
+
return grouped.map(({ item, section }) => {
|
|
147
|
+
const label = section === printed ? "" : section;
|
|
148
|
+
printed = section;
|
|
149
|
+
return { item, section: label };
|
|
127
150
|
});
|
|
128
151
|
}
|