@visns-studio/visns-components 6.21.0 → 6.23.0
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/package.json +1 -1
- package/src/components/DataGrid.jsx +15 -2
- package/src/components/Navigation.jsx +10 -1
- package/src/components/columns/SelectFilterEditor.jsx +372 -0
- package/src/components/controls/DataGridSearch.jsx +6 -1
- package/src/components/phone/ZoomPhoneBadge.jsx +625 -0
- package/src/components/phone/phonePresenceEndpoints.js +34 -0
- package/src/components/phone/phonePresenceHelpers.js +298 -0
- package/src/components/phone/useZoomPhoneLive.js +165 -0
- package/src/components/sms/SmsClientConversations.jsx +8 -0
- package/src/components/sms/SmsInbox.jsx +11 -0
- package/src/components/sms/SmsThreadPanel.jsx +258 -29
- package/src/components/sms/smsHelpers.js +37 -0
- package/src/components/styles/DataGrid.module.scss +10 -0
- package/src/components/styles/GenericDetail.module.scss +12 -2
- package/src/components/styles/Sms.module.scss +131 -0
- package/src/components/styles/Vault.module.scss +46 -0
- package/src/components/styles/ZoomPhone.module.scss +550 -0
- package/src/components/styles/global-datagrid.css +23 -0
- package/src/components/vault/VaultAccessLog.jsx +24 -0
- package/src/components/vault/VaultShareModal.jsx +126 -5
- package/src/components/vault/vaultShares.js +67 -3
- package/src/index.js +41 -2
|
@@ -0,0 +1,550 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Zoom Phone presence (components/phone/*)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// The header chip and its popover: every Zoom Phone extension, who is free, who
|
|
5
|
+
// is on a call, and which client that call is with.
|
|
6
|
+
//
|
|
7
|
+
// Every brand value is a CSS custom property with a neutral fallback, exactly
|
|
8
|
+
// as in Sms.module.scss and Vault.module.scss, so the library carries no
|
|
9
|
+
// palette of its own.
|
|
10
|
+
//
|
|
11
|
+
// IMPORTANT — why every control below restates its colour, background, border,
|
|
12
|
+
// font-size AND box size:
|
|
13
|
+
//
|
|
14
|
+
// The popover mounts INSIDE `.hactions > ul`, whose chip rules reach every
|
|
15
|
+
// descendant `a` and `button` and hand it white text, a fixed 36px box and a
|
|
16
|
+
// pill radius. On a white panel that renders as blank boxes.
|
|
17
|
+
// Navigation.module.scss excludes `[data-nav-overlay] *` from those rules,
|
|
18
|
+
// which is the real fix — but a component that survives only because its host
|
|
19
|
+
// is well behaved is a component that breaks the next time it is mounted
|
|
20
|
+
// somewhere new. So nothing here inherits anything it actually needs, and no
|
|
21
|
+
// `!important` was required to do it.
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
|
|
24
|
+
@mixin zp-tokens {
|
|
25
|
+
--zp-primary: var(--primary-color, #00386c);
|
|
26
|
+
--zp-paragraph: var(--paragraph-color, #2b2b2b);
|
|
27
|
+
--zp-background: var(--background-color, #fff);
|
|
28
|
+
|
|
29
|
+
--zp-line: color-mix(in srgb, var(--zp-paragraph) 18%, transparent);
|
|
30
|
+
// 76% of the body colour over white lands around #5b5b5b — roughly 6:1,
|
|
31
|
+
// comfortably past 4.5:1 on the small type this file is full of.
|
|
32
|
+
--zp-muted: color-mix(in srgb, var(--zp-paragraph) 76%, transparent);
|
|
33
|
+
--zp-surface: color-mix(
|
|
34
|
+
in srgb,
|
|
35
|
+
var(--zp-paragraph) 4%,
|
|
36
|
+
var(--zp-background)
|
|
37
|
+
);
|
|
38
|
+
--zp-hover: color-mix(in srgb, var(--zp-primary) 9%, var(--zp-background));
|
|
39
|
+
|
|
40
|
+
// The three states, and only three: free, ringing, talking. Chosen to be
|
|
41
|
+
// distinguishable without relying on hue alone — every dot is paired with
|
|
42
|
+
// its word, because a roster read by somebody with deuteranopia has to
|
|
43
|
+
// work too.
|
|
44
|
+
--zp-free: rgb(31, 122, 71);
|
|
45
|
+
--zp-ringing: rgb(163, 106, 20);
|
|
46
|
+
--zp-busy: rgb(190, 62, 62);
|
|
47
|
+
--zp-bad: rgb(190, 62, 62);
|
|
48
|
+
--zp-warn: rgb(163, 106, 20);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
@mixin zp-reset {
|
|
52
|
+
box-sizing: border-box;
|
|
53
|
+
width: auto;
|
|
54
|
+
height: auto;
|
|
55
|
+
min-width: 0;
|
|
56
|
+
min-height: 0;
|
|
57
|
+
max-width: none;
|
|
58
|
+
margin: 0;
|
|
59
|
+
font-family: inherit;
|
|
60
|
+
font-weight: 400;
|
|
61
|
+
line-height: 1.3;
|
|
62
|
+
letter-spacing: normal;
|
|
63
|
+
text-transform: none;
|
|
64
|
+
text-decoration: none;
|
|
65
|
+
text-align: left;
|
|
66
|
+
appearance: none;
|
|
67
|
+
outline: none;
|
|
68
|
+
transform: none;
|
|
69
|
+
box-shadow: none;
|
|
70
|
+
// The host's chip rules transition `all`, which makes a control visibly
|
|
71
|
+
// resize on hover once its box is no longer fixed.
|
|
72
|
+
transition:
|
|
73
|
+
background-color 0.15s ease,
|
|
74
|
+
color 0.15s ease,
|
|
75
|
+
border-color 0.15s ease;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
@mixin zp-focus {
|
|
79
|
+
&:focus-visible {
|
|
80
|
+
outline: 2px solid var(--zp-primary);
|
|
81
|
+
outline-offset: 2px;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
@keyframes zpSpin {
|
|
86
|
+
to {
|
|
87
|
+
transform: rotate(360deg);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
@keyframes zpPopIn {
|
|
92
|
+
from {
|
|
93
|
+
opacity: 0;
|
|
94
|
+
transform: translateY(-4px);
|
|
95
|
+
}
|
|
96
|
+
to {
|
|
97
|
+
opacity: 1;
|
|
98
|
+
transform: translateY(0);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.spin {
|
|
103
|
+
animation: zpSpin 0.9s linear infinite;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
// The header chip
|
|
108
|
+
// ---------------------------------------------------------------------------
|
|
109
|
+
|
|
110
|
+
.zoomPhone {
|
|
111
|
+
@include zp-tokens;
|
|
112
|
+
|
|
113
|
+
position: relative;
|
|
114
|
+
align-items: center;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
// Deliberately the same shape as Notification's, the vault's and the SMS
|
|
118
|
+
// badge's triggers: these sit side by side in the action pill and must read as
|
|
119
|
+
// one row of chips, not four designs. This one DOES inherit the header's
|
|
120
|
+
// colour, which is correct — it is a chip.
|
|
121
|
+
.trigger {
|
|
122
|
+
@include zp-focus;
|
|
123
|
+
|
|
124
|
+
position: relative;
|
|
125
|
+
display: flex;
|
|
126
|
+
align-items: center;
|
|
127
|
+
justify-content: center;
|
|
128
|
+
width: 40px;
|
|
129
|
+
height: 40px;
|
|
130
|
+
padding: 8px;
|
|
131
|
+
border: none;
|
|
132
|
+
border-radius: 50%;
|
|
133
|
+
background: transparent;
|
|
134
|
+
color: var(--paragraph-color, #333);
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
transition: all 0.2s ease;
|
|
137
|
+
|
|
138
|
+
&:hover {
|
|
139
|
+
background-color: rgba(var(--primary-color-rgb, 0, 86, 179), 0.1);
|
|
140
|
+
color: var(--primary-color, #0056b3);
|
|
141
|
+
transform: scale(1.05);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&:active {
|
|
145
|
+
transform: scale(0.95);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Matches Notification's and the SMS badge's, down to the offsets: three counts
|
|
150
|
+
// side by side in the header have to sit on the same line as each other.
|
|
151
|
+
.badge {
|
|
152
|
+
position: absolute;
|
|
153
|
+
top: -2px;
|
|
154
|
+
right: -2px;
|
|
155
|
+
display: flex;
|
|
156
|
+
align-items: center;
|
|
157
|
+
justify-content: center;
|
|
158
|
+
box-sizing: border-box;
|
|
159
|
+
min-width: 16px;
|
|
160
|
+
height: 16px;
|
|
161
|
+
padding: 0 4px;
|
|
162
|
+
border-radius: 8px;
|
|
163
|
+
background-color: var(--secondary-color, #c1272d);
|
|
164
|
+
color: #fff;
|
|
165
|
+
font-size: 10px;
|
|
166
|
+
font-weight: 600;
|
|
167
|
+
font-variant-numeric: tabular-nums;
|
|
168
|
+
line-height: 1;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// The popover
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
.popoverWrapper {
|
|
176
|
+
position: absolute;
|
|
177
|
+
top: 100%;
|
|
178
|
+
right: 0;
|
|
179
|
+
z-index: 1100;
|
|
180
|
+
margin-top: 10px;
|
|
181
|
+
// The host's chip `li` is a centring flex container. The popover is
|
|
182
|
+
// absolutely positioned so it escapes the flexbox, but `text-align` is
|
|
183
|
+
// inherited and would centre every line of prose inside it.
|
|
184
|
+
text-align: left;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.popover {
|
|
188
|
+
@include zp-tokens;
|
|
189
|
+
|
|
190
|
+
display: flex;
|
|
191
|
+
flex-direction: column;
|
|
192
|
+
box-sizing: border-box;
|
|
193
|
+
width: 380px;
|
|
194
|
+
max-width: calc(100vw - 2rem);
|
|
195
|
+
border: 1px solid var(--zp-line);
|
|
196
|
+
border-radius: 10px;
|
|
197
|
+
// Opaque, and stated: the header behind this is a dark brand bar, and a
|
|
198
|
+
// panel that inherits any of it is unreadable.
|
|
199
|
+
background: var(--zp-background);
|
|
200
|
+
color: var(--zp-paragraph);
|
|
201
|
+
font-size: 0.85rem;
|
|
202
|
+
text-align: left;
|
|
203
|
+
box-shadow:
|
|
204
|
+
0 12px 32px rgba(0, 0, 0, 0.22),
|
|
205
|
+
0 2px 6px rgba(0, 0, 0, 0.12);
|
|
206
|
+
overflow: hidden;
|
|
207
|
+
animation: zpPopIn 0.18s ease-out;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.popoverHead {
|
|
211
|
+
display: flex;
|
|
212
|
+
gap: 0.75rem;
|
|
213
|
+
align-items: center;
|
|
214
|
+
justify-content: space-between;
|
|
215
|
+
padding: 0.7rem 0.85rem;
|
|
216
|
+
border-bottom: 1px solid var(--zp-line);
|
|
217
|
+
background: var(--zp-surface);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
.popoverTitle {
|
|
221
|
+
display: inline-flex;
|
|
222
|
+
gap: 0.4rem;
|
|
223
|
+
align-items: center;
|
|
224
|
+
color: var(--zp-paragraph);
|
|
225
|
+
font-size: 0.95rem;
|
|
226
|
+
font-weight: 700;
|
|
227
|
+
|
|
228
|
+
svg {
|
|
229
|
+
color: var(--zp-primary);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
.iconButton {
|
|
234
|
+
@include zp-reset;
|
|
235
|
+
@include zp-focus;
|
|
236
|
+
|
|
237
|
+
display: inline-flex;
|
|
238
|
+
align-items: center;
|
|
239
|
+
justify-content: center;
|
|
240
|
+
width: 28px;
|
|
241
|
+
height: 28px;
|
|
242
|
+
padding: 0;
|
|
243
|
+
border: 1px solid var(--zp-line);
|
|
244
|
+
border-radius: 6px;
|
|
245
|
+
background: var(--zp-background);
|
|
246
|
+
color: var(--zp-muted);
|
|
247
|
+
cursor: pointer;
|
|
248
|
+
|
|
249
|
+
&:hover {
|
|
250
|
+
background: var(--zp-hover);
|
|
251
|
+
color: var(--zp-primary);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// ---------------------------------------------------------------------------
|
|
256
|
+
// The roster
|
|
257
|
+
// ---------------------------------------------------------------------------
|
|
258
|
+
|
|
259
|
+
.rows {
|
|
260
|
+
max-height: 380px;
|
|
261
|
+
margin: 0;
|
|
262
|
+
padding: 0;
|
|
263
|
+
list-style: none;
|
|
264
|
+
overflow-y: auto;
|
|
265
|
+
|
|
266
|
+
// Two hosts reach in here with bare element selectors: Navigation's
|
|
267
|
+
// `.hactions > ul li` and the CRM's own `ul { padding-left: … }` in
|
|
268
|
+
// main.scss. Restated so the list is a list wherever it is mounted.
|
|
269
|
+
> li {
|
|
270
|
+
min-width: 0;
|
|
271
|
+
min-height: 0;
|
|
272
|
+
margin: 0;
|
|
273
|
+
padding: 0;
|
|
274
|
+
position: static;
|
|
275
|
+
list-style: none;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// Specificity, deliberately: `.hactions > ul li` is 0,1,2 and no single class
|
|
280
|
+
// can outrank it. This restates the row's BOX at 0,2,0, where it wins. Paint
|
|
281
|
+
// stays in `.row` below; only geometry is repeated.
|
|
282
|
+
.rows > .row {
|
|
283
|
+
display: grid;
|
|
284
|
+
grid-template-columns: 30px minmax(0, 1fr) auto;
|
|
285
|
+
column-gap: 0.6rem;
|
|
286
|
+
align-items: center;
|
|
287
|
+
justify-content: normal;
|
|
288
|
+
box-sizing: border-box;
|
|
289
|
+
min-width: 0;
|
|
290
|
+
min-height: 0;
|
|
291
|
+
margin: 0;
|
|
292
|
+
padding: 0.55rem 0.85rem;
|
|
293
|
+
position: static;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
.rows > .row > .rowMain {
|
|
297
|
+
display: block;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// One extension, one row: avatar, name + what they are doing, status.
|
|
301
|
+
//
|
|
302
|
+
// Three columns, and only the middle one gives way — it is the only part of the
|
|
303
|
+
// row that can be any length. Fixed tracks either side keep a list of mixed
|
|
304
|
+
// rows measured identically, so nothing zig-zags down the edge.
|
|
305
|
+
.row {
|
|
306
|
+
display: grid;
|
|
307
|
+
grid-template-columns: 30px minmax(0, 1fr) auto;
|
|
308
|
+
column-gap: 0.6rem;
|
|
309
|
+
align-items: center;
|
|
310
|
+
padding: 0.55rem 0.85rem;
|
|
311
|
+
border: none;
|
|
312
|
+
border-bottom: 1px solid color-mix(in srgb, var(--zp-line) 55%, transparent);
|
|
313
|
+
background: var(--zp-background);
|
|
314
|
+
|
|
315
|
+
&:last-child {
|
|
316
|
+
border-bottom: none;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
&:hover {
|
|
320
|
+
background: var(--zp-hover);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.avatar {
|
|
325
|
+
display: flex;
|
|
326
|
+
align-items: center;
|
|
327
|
+
justify-content: center;
|
|
328
|
+
box-sizing: border-box;
|
|
329
|
+
width: 30px;
|
|
330
|
+
height: 30px;
|
|
331
|
+
border-radius: 50%;
|
|
332
|
+
background: color-mix(in srgb, var(--zp-primary) 14%, var(--zp-background));
|
|
333
|
+
color: var(--zp-primary);
|
|
334
|
+
font-size: 0.7rem;
|
|
335
|
+
font-weight: 700;
|
|
336
|
+
letter-spacing: 0.02em;
|
|
337
|
+
// Fixed, so a two-letter avatar and a one-letter one are the same size and
|
|
338
|
+
// the column of them does not ripple.
|
|
339
|
+
flex: 0 0 30px;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
.rowMain {
|
|
343
|
+
// `min-width: 0` is the load-bearing declaration: without it a grid item
|
|
344
|
+
// refuses to shrink below its content and the ellipsis never engages.
|
|
345
|
+
min-width: 0;
|
|
346
|
+
justify-self: stretch;
|
|
347
|
+
overflow: hidden;
|
|
348
|
+
color: var(--zp-paragraph);
|
|
349
|
+
line-height: 1.35;
|
|
350
|
+
text-align: left;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.rowTop {
|
|
354
|
+
display: flex;
|
|
355
|
+
gap: 0.4rem;
|
|
356
|
+
align-items: baseline;
|
|
357
|
+
min-width: 0;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.rowName {
|
|
361
|
+
overflow: hidden;
|
|
362
|
+
font-size: 0.85rem;
|
|
363
|
+
font-weight: 600;
|
|
364
|
+
text-overflow: ellipsis;
|
|
365
|
+
white-space: nowrap;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.extension {
|
|
369
|
+
flex: 0 0 auto;
|
|
370
|
+
color: var(--zp-muted);
|
|
371
|
+
font-size: 0.72rem;
|
|
372
|
+
font-variant-numeric: tabular-nums;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
.idleLine {
|
|
376
|
+
display: block;
|
|
377
|
+
color: var(--zp-muted);
|
|
378
|
+
font-size: 0.76rem;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// The busy line: what they are doing, the number, the queue, the timer. Wraps
|
|
382
|
+
// rather than ellipsing, because every part of it is load bearing and the row
|
|
383
|
+
// is allowed to be two lines tall.
|
|
384
|
+
.callLine {
|
|
385
|
+
display: flex;
|
|
386
|
+
flex-wrap: wrap;
|
|
387
|
+
gap: 0.35rem;
|
|
388
|
+
align-items: baseline;
|
|
389
|
+
min-width: 0;
|
|
390
|
+
font-size: 0.76rem;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
.callSummary {
|
|
394
|
+
overflow: hidden;
|
|
395
|
+
color: var(--zp-paragraph);
|
|
396
|
+
text-overflow: ellipsis;
|
|
397
|
+
white-space: nowrap;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
.callNumber {
|
|
401
|
+
color: var(--zp-muted);
|
|
402
|
+
font-variant-numeric: tabular-nums;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.queueTag {
|
|
406
|
+
padding: 0 0.3rem;
|
|
407
|
+
border-radius: 4px;
|
|
408
|
+
background: color-mix(in srgb, var(--zp-primary) 10%, var(--zp-background));
|
|
409
|
+
color: var(--zp-primary);
|
|
410
|
+
font-size: 0.68rem;
|
|
411
|
+
font-weight: 600;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// Tabular figures, so a timer counting up does not shuffle the row sideways
|
|
415
|
+
// every time a digit changes width.
|
|
416
|
+
.duration {
|
|
417
|
+
margin-left: auto;
|
|
418
|
+
color: var(--zp-muted);
|
|
419
|
+
font-variant-numeric: tabular-nums;
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
.clientLine {
|
|
423
|
+
display: flex;
|
|
424
|
+
gap: 0.4rem;
|
|
425
|
+
align-items: baseline;
|
|
426
|
+
min-width: 0;
|
|
427
|
+
font-size: 0.76rem;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
.clientLink {
|
|
431
|
+
@include zp-reset;
|
|
432
|
+
@include zp-focus;
|
|
433
|
+
|
|
434
|
+
overflow: hidden;
|
|
435
|
+
padding: 0;
|
|
436
|
+
border: none;
|
|
437
|
+
background: none;
|
|
438
|
+
color: var(--zp-primary);
|
|
439
|
+
font-size: 0.76rem;
|
|
440
|
+
font-weight: 600;
|
|
441
|
+
text-overflow: ellipsis;
|
|
442
|
+
white-space: nowrap;
|
|
443
|
+
cursor: pointer;
|
|
444
|
+
|
|
445
|
+
&:hover {
|
|
446
|
+
text-decoration: underline;
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
.clientFlat {
|
|
451
|
+
overflow: hidden;
|
|
452
|
+
color: var(--zp-primary);
|
|
453
|
+
font-weight: 600;
|
|
454
|
+
text-overflow: ellipsis;
|
|
455
|
+
white-space: nowrap;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.clientMeta {
|
|
459
|
+
flex: 0 0 auto;
|
|
460
|
+
color: var(--zp-muted);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// The status cell. The dot is never alone — the word beside it is what makes
|
|
464
|
+
// the roster readable without relying on hue.
|
|
465
|
+
.status {
|
|
466
|
+
display: inline-flex;
|
|
467
|
+
gap: 0.35rem;
|
|
468
|
+
align-items: center;
|
|
469
|
+
flex: 0 0 auto;
|
|
470
|
+
color: var(--zp-muted);
|
|
471
|
+
font-size: 0.72rem;
|
|
472
|
+
font-weight: 600;
|
|
473
|
+
white-space: nowrap;
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.dot {
|
|
477
|
+
display: inline-block;
|
|
478
|
+
width: 8px;
|
|
479
|
+
height: 8px;
|
|
480
|
+
border-radius: 50%;
|
|
481
|
+
background: currentColor;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
.status_free {
|
|
485
|
+
color: var(--zp-free);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.status_ringing {
|
|
489
|
+
color: var(--zp-ringing);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
.status_busy {
|
|
493
|
+
color: var(--zp-busy);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
.status_muted {
|
|
497
|
+
color: var(--zp-muted);
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
// ---------------------------------------------------------------------------
|
|
501
|
+
// Empty, notes, footer
|
|
502
|
+
// ---------------------------------------------------------------------------
|
|
503
|
+
|
|
504
|
+
.empty {
|
|
505
|
+
padding: 1.4rem 0.85rem;
|
|
506
|
+
color: var(--zp-muted);
|
|
507
|
+
text-align: center;
|
|
508
|
+
|
|
509
|
+
p {
|
|
510
|
+
margin: 0;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
.statusNote {
|
|
515
|
+
display: flex;
|
|
516
|
+
gap: 0.4rem;
|
|
517
|
+
align-items: center;
|
|
518
|
+
margin: 0;
|
|
519
|
+
padding: 0.5rem 0.85rem;
|
|
520
|
+
border-top: 1px solid var(--zp-line);
|
|
521
|
+
background: color-mix(in srgb, var(--zp-warn) 8%, var(--zp-background));
|
|
522
|
+
color: var(--zp-warn);
|
|
523
|
+
font-size: 0.75rem;
|
|
524
|
+
|
|
525
|
+
svg {
|
|
526
|
+
flex: 0 0 auto;
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
.statusNoteBad {
|
|
531
|
+
background: color-mix(in srgb, var(--zp-bad) 8%, var(--zp-background));
|
|
532
|
+
color: var(--zp-bad);
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
.footer {
|
|
536
|
+
display: flex;
|
|
537
|
+
gap: 0.75rem;
|
|
538
|
+
align-items: center;
|
|
539
|
+
justify-content: space-between;
|
|
540
|
+
padding: 0.45rem 0.85rem;
|
|
541
|
+
border-top: 1px solid var(--zp-line);
|
|
542
|
+
background: var(--zp-surface);
|
|
543
|
+
color: var(--zp-muted);
|
|
544
|
+
font-size: 0.72rem;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
.footerHint,
|
|
548
|
+
.footerStamp {
|
|
549
|
+
white-space: nowrap;
|
|
550
|
+
}
|
|
@@ -761,6 +761,29 @@ body.tablet-mode .InovuaReactDataGrid__cell.cell-word-wrap > div {
|
|
|
761
761
|
background: none !important;
|
|
762
762
|
}
|
|
763
763
|
|
|
764
|
+
/* The keyboard highlight in a dropdown's option list — declared by the
|
|
765
|
+
vendored theme, then painted with nothing.
|
|
766
|
+
|
|
767
|
+
Arrow keys have always worked in these filters: the combo tracks an active
|
|
768
|
+
item, scrolls it into view, Enter selects it and Escape closes. But the
|
|
769
|
+
theme's ONLY rule for that active item is `border: 1px solid transparent`,
|
|
770
|
+
while hover and selected both get a background — so navigating with the
|
|
771
|
+
arrows changed nothing on screen and the keys read as dead.
|
|
772
|
+
|
|
773
|
+
Colouring the border the theme already reserves is why this cannot shift the
|
|
774
|
+
list: every item carries that 1px border, active or not. Scoped to the same
|
|
775
|
+
theme selector the invisible rule uses, so it lands exactly where that rule
|
|
776
|
+
lands and nowhere else.
|
|
777
|
+
|
|
778
|
+
`--primary-color` rather than one of the `--dgx-*` tokens above: those are
|
|
779
|
+
defined on `.InovuaReactDataGrid`, and the option list is rendered outside
|
|
780
|
+
the grid element, where they would not resolve. */
|
|
781
|
+
.inovua-react-toolkit-combo-box__list--theme-default-light
|
|
782
|
+
.inovua-react-toolkit-combo-box__list__item--active {
|
|
783
|
+
border-color: color-mix(in srgb, var(--primary-color, #1b3933) 55%, transparent) !important;
|
|
784
|
+
background: color-mix(in srgb, var(--primary-color, #1b3933) 12%, transparent) !important;
|
|
785
|
+
}
|
|
786
|
+
|
|
764
787
|
/* The native date filter is the odd one out in the row.
|
|
765
788
|
|
|
766
789
|
Measured on /tickets: every other filter editor is 28px tall with a 6px
|
|
@@ -24,11 +24,34 @@ export const VAULT_ACTIONS = {
|
|
|
24
24
|
update: 'edited the entry',
|
|
25
25
|
delete: 'deleted the entry',
|
|
26
26
|
restore: 'restored the entry',
|
|
27
|
+
share_create: 'created a share link',
|
|
28
|
+
// The user on a `share_view` row is the person who CREATED the link, not
|
|
29
|
+
// the reader — the reader has no account — so the line is phrased from
|
|
30
|
+
// their side. The IP beside it is the reader's.
|
|
31
|
+
share_view: 'had a share link opened',
|
|
32
|
+
share_revoke: 'revoked a share link',
|
|
27
33
|
};
|
|
28
34
|
|
|
29
35
|
const describeAction = (action) =>
|
|
30
36
|
VAULT_ACTIONS[action] || String(action || '').replace(/_/g, ' ');
|
|
31
37
|
|
|
38
|
+
/**
|
|
39
|
+
* The extra clause a row's `meta` earns, or null.
|
|
40
|
+
*
|
|
41
|
+
* Today the only one: where a share link was emailed. Written as "sent to" or
|
|
42
|
+
* "could not be emailed to" because a link that failed to send still went
|
|
43
|
+
* somewhere in intent, and an incident asks about the address either way.
|
|
44
|
+
*/
|
|
45
|
+
const describeMeta = (row) => {
|
|
46
|
+
const address = row?.meta?.recipient_email;
|
|
47
|
+
|
|
48
|
+
if (!address) return null;
|
|
49
|
+
|
|
50
|
+
return row.meta.emailed === false
|
|
51
|
+
? `could not be emailed to ${address}`
|
|
52
|
+
: `sent to ${address}`;
|
|
53
|
+
};
|
|
54
|
+
|
|
32
55
|
/**
|
|
33
56
|
* Who took what out of the vault, and when.
|
|
34
57
|
*
|
|
@@ -180,6 +203,7 @@ const VaultAccessLog = ({ entry = null, endpoints, isOpen = true, onClose }) =>
|
|
|
180
203
|
)}
|
|
181
204
|
</div>
|
|
182
205
|
<div className={styles.logMeta}>
|
|
206
|
+
{describeMeta(row) && <span>{describeMeta(row)}</span>}
|
|
183
207
|
{row.ip && <span>{row.ip}</span>}
|
|
184
208
|
<span
|
|
185
209
|
data-tooltip-id="system-tooltip"
|