@visns-studio/visns-components 6.6.3 → 6.15.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.
Files changed (100) hide show
  1. package/README.md +1658 -18
  2. package/package.json +10 -4
  3. package/src/components/DataGrid.jsx +619 -158
  4. package/src/components/Fetch.jsx +80 -3
  5. package/src/components/Form.jsx +9 -0
  6. package/src/components/Navigation.jsx +109 -50
  7. package/src/components/Notification.jsx +279 -9
  8. package/src/components/TableFilter.jsx +14 -1
  9. package/src/components/auth/AuthBrandPanel.jsx +43 -0
  10. package/src/components/auth/AuthLoading.jsx +78 -0
  11. package/src/components/auth/AuthShell.jsx +59 -0
  12. package/src/components/auth/ClientAuth.jsx +161 -0
  13. package/src/components/auth/ClientAuthFrame.jsx +59 -0
  14. package/src/components/auth/ClientLogin.jsx +266 -55
  15. package/src/components/auth/ClientOTPVerify.jsx +587 -115
  16. package/src/components/auth/ImpersonateGate.jsx +254 -0
  17. package/src/components/auth/Login.jsx +134 -41
  18. package/src/components/auth/LogoutScreen.jsx +112 -0
  19. package/src/components/auth/Reset.jsx +134 -77
  20. package/src/components/auth/TwoFactorAuth.jsx +475 -297
  21. package/src/components/auth/Verify.jsx +237 -126
  22. package/src/components/auth/authEndpoints.js +105 -0
  23. package/src/components/auth/authFont.js +23 -0
  24. package/src/components/auth/authHelpers.js +465 -0
  25. package/src/components/auth/clientAuthProtocols.js +240 -0
  26. package/src/components/auth/useOptionalRouter.js +49 -0
  27. package/src/components/callQueue/CallQueuePop.jsx +1502 -0
  28. package/src/components/callQueue/CallQueueSettings.jsx +508 -0
  29. package/src/components/callQueue/callQueueHelpers.js +280 -0
  30. package/src/components/callQueue/callQueueSettingsHelpers.js +75 -0
  31. package/src/components/columns/AutoGrowCell.jsx +141 -0
  32. package/src/components/columns/ColumnRenderers.jsx +53 -7
  33. package/src/components/generic/GenericAuth.jsx +163 -96
  34. package/src/components/generic/GenericDetail.jsx +215 -90
  35. package/src/components/generic/GenericIndex.jsx +20 -47
  36. package/src/components/generic/GenericMain.jsx +5 -0
  37. package/src/components/generic/GroupedReportRenderer.jsx +1 -5
  38. package/src/components/generic/StandardModal.jsx +17 -5
  39. package/src/components/generic/reportSemanticSteps/SemanticEntityStep.jsx +1 -6
  40. package/src/components/generic/reportSemanticSteps/SemanticFieldsStep.jsx +4 -11
  41. package/src/components/generic/reportSemanticSteps/SemanticFiltersStep.jsx +9 -27
  42. package/src/components/generic/reportSemanticSteps/SemanticGroupingStep.jsx +5 -13
  43. package/src/components/generic/reportSemanticSteps/SemanticParameterPrompt.jsx +5 -13
  44. package/src/components/generic/reportSemanticSteps/SemanticPreviewStep.jsx +14 -31
  45. package/src/components/generic/reportSemanticSteps/SemanticRelationsStep.jsx +3 -9
  46. package/src/components/generic/reportSemanticSteps/SemanticValueInput.jsx +2 -15
  47. package/src/components/navActive.js +60 -0
  48. package/src/components/notify/desktopNotifications.js +256 -0
  49. package/src/components/sketch/SketchField.jsx +12 -2
  50. package/src/components/sms/SmsComposeModal.jsx +495 -0
  51. package/src/components/sms/SmsInbox.jsx +596 -0
  52. package/src/components/sms/SmsInboxBadge.jsx +468 -0
  53. package/src/components/sms/SmsLineSettings.jsx +854 -0
  54. package/src/components/sms/SmsThreadPanel.jsx +1184 -0
  55. package/src/components/sms/smsEndpoints.js +56 -0
  56. package/src/components/sms/smsHelpers.js +1075 -0
  57. package/src/components/sms/smsLiveState.js +132 -0
  58. package/src/components/sms/useSmsLive.js +307 -0
  59. package/src/components/styles/CallQueuePop.module.scss +646 -0
  60. package/src/components/styles/CallQueueSettings.module.scss +460 -0
  61. package/src/components/styles/ClientAuth.module.scss +229 -0
  62. package/src/components/styles/DataGrid.module.scss +10 -0
  63. package/src/components/styles/GenericDetail.module.scss +153 -26
  64. package/src/components/styles/GenericIndex.module.scss +13 -0
  65. package/src/components/styles/GenericMain.module.scss +19 -2
  66. package/src/components/styles/ImpersonateGate.module.scss +85 -0
  67. package/src/components/styles/Login.module.scss +13 -122
  68. package/src/components/styles/LogoutScreen.module.scss +89 -0
  69. package/src/components/styles/Navigation.module.scss +509 -223
  70. package/src/components/styles/Notification.module.scss +103 -0
  71. package/src/components/styles/Reset.module.scss +52 -186
  72. package/src/components/styles/Sms.module.scss +2382 -0
  73. package/src/components/styles/TableFilter.module.scss +118 -98
  74. package/src/components/styles/TwoFactorAuth.module.scss +115 -176
  75. package/src/components/styles/Vault.module.scss +1983 -0
  76. package/src/components/styles/Verify.module.scss +57 -180
  77. package/src/components/styles/_authBrandPanel.scss +163 -0
  78. package/src/components/styles/_authShell.scss +369 -0
  79. package/src/components/styles/global-datagrid.css +29 -0
  80. package/src/components/utils/buildEnv.js +67 -0
  81. package/src/components/utils/displayValue.js +94 -0
  82. package/src/components/utils/useDensity.js +345 -9
  83. package/src/components/vault/OtpChip.jsx +208 -0
  84. package/src/components/vault/PasswordGenerator.jsx +145 -0
  85. package/src/components/vault/QrScanner.jsx +326 -0
  86. package/src/components/vault/VaultAccessLog.jsx +225 -0
  87. package/src/components/vault/VaultConfirmPanel.jsx +113 -0
  88. package/src/components/vault/VaultEntryForm.jsx +740 -0
  89. package/src/components/vault/VaultManager.jsx +1000 -0
  90. package/src/components/vault/VaultQuickSearch.jsx +681 -0
  91. package/src/components/vault/qrDecode.js +257 -0
  92. package/src/components/vault/useDebouncedValue.js +22 -0
  93. package/src/components/vault/useVaultReveal.js +160 -0
  94. package/src/components/vault/vaultClipboard.js +33 -0
  95. package/src/components/vault/vaultEndpoints.js +40 -0
  96. package/src/components/vault/vaultFit.js +116 -0
  97. package/src/components/vault/vaultHelpers.js +547 -0
  98. package/src/components/vault/vaultNavigation.jsx +58 -0
  99. package/src/components/vault/vaultOtp.js +105 -0
  100. package/src/index.js +233 -1
@@ -21,66 +21,34 @@ import Verify from '../auth/Verify';
21
21
  import TwoFactorAuth from '../auth/TwoFactorAuth';
22
22
  import ClientLogin from '../auth/ClientLogin';
23
23
  import ClientOTPVerify from '../auth/ClientOTPVerify';
24
-
25
- // Shown while the profile check is in flight. Rendering null there leaves a
26
- // blank white page between the sign-in redirect and the first authenticated
27
- // paint. Self-contained: SMIL animation, no stylesheet dependency, and the
28
- // consuming app's design tokens with neutral fallbacks.
29
- const AuthLoading = ({ label }) => (
30
- <div
31
- role="status"
32
- aria-label="Loading"
33
- style={{
34
- position: 'fixed',
35
- inset: 0,
36
- display: 'flex',
37
- flexDirection: 'column',
38
- gap: '1rem',
39
- alignItems: 'center',
40
- justifyContent: 'center',
41
- background: 'var(--bg-color, #f4f4f5)',
42
- // Above every app surface — this is a curtain, not a page.
43
- zIndex: 2000,
44
- }}
45
- >
46
- <svg width="42" height="42" viewBox="0 0 42 42" fill="none">
47
- <circle
48
- cx="21"
49
- cy="21"
50
- r="18"
51
- stroke="var(--border-color, #dfe3eb)"
52
- strokeWidth="4"
53
- />
54
- <path
55
- d="M39 21a18 18 0 0 0-18-18"
56
- stroke="var(--primary-color, #52525b)"
57
- strokeWidth="4"
58
- strokeLinecap="round"
59
- >
60
- <animateTransform
61
- attributeName="transform"
62
- type="rotate"
63
- from="0 21 21"
64
- to="360 21 21"
65
- dur="0.9s"
66
- repeatCount="indefinite"
67
- />
68
- </path>
69
- </svg>
70
- {label ? (
71
- <p
72
- style={{
73
- margin: 0,
74
- fontFamily: 'var(--font-family, inherit)',
75
- fontSize: 'var(--font-size-md, 0.9375rem)',
76
- color: 'var(--paragraph-color, #52525b)',
77
- }}
78
- >
79
- {label}
80
- </p>
81
- ) : null}
82
- </div>
83
- );
24
+ import {
25
+ resolveAuthEndpoints,
26
+ resolveClientPaths,
27
+ } from '../auth/authEndpoints';
28
+ // The please-wait curtain. Lives in auth/ now because the auth screens raise
29
+ // the same one for the transitions they own; identical object, so a screen's
30
+ // curtain and this one are indistinguishable when both are up.
31
+ import AuthLoading from '../auth/AuthLoading';
32
+
33
+ /**
34
+ * Path segments that mean "an auth screen that hands off to the app".
35
+ *
36
+ * Reaching one of these with a live session is the sign-in transition, and it
37
+ * ends with this component navigating to '/'. `2fa` joined `login` in 6.8.1:
38
+ * TwoFactorAuth used to finish by hard-reloading the browser, so it never
39
+ * needed this file to move it, and that reload was exactly the unannounced
40
+ * blank screen the curtain exists to prevent.
41
+ */
42
+ const AUTH_HANDOFF_SEGMENTS = ['login', '2fa'];
43
+
44
+ /**
45
+ * The live pathname, not the router hook's — this is read after a screen has
46
+ * already navigated, and a hook value captured in a closure would still hold
47
+ * the old one.
48
+ */
49
+ const onAuthHandoffScreen = () =>
50
+ typeof window !== 'undefined' &&
51
+ AUTH_HANDOFF_SEGMENTS.includes(window.location.pathname.split('/')[1]);
84
52
 
85
53
  const ProtectedRoute = ({ user, loading, redirectPath = '/login' }) => {
86
54
  const location = useLocation();
@@ -129,9 +97,25 @@ const GenericAuth = ({
129
97
  clientPortalConfig = null, // Configuration for client portal with component and URLs
130
98
  config = {}, // Configuration object for auth features
131
99
  density = 'default', // 'default' | 'large' — app-wide display density
100
+ // Every URL the auth journey talks to, merged over the 6.6.3 literals.
101
+ // Threaded from here into each screen so one object configures the lot.
102
+ // See auth/authEndpoints.js for the keys and their defaults.
103
+ endpoints,
104
+ // The authenticated shell. Defaults to GenericMain, which is what every
105
+ // 6.6.x consumer gets; an app with its own chrome can pass its own
106
+ // component here and still keep this file's route table, ProtectedRoute
107
+ // and please-wait curtain. Receives exactly the props GenericMain does.
108
+ mainComponent = GenericMain,
109
+ // Extra props handed to whatever `mainComponent` is, for a custom shell
110
+ // that needs something GenericMain does not take.
111
+ mainComponentProps = {},
132
112
  }) => {
133
113
  const navigate = useNavigate();
134
114
  const location = useLocation();
115
+ const urls = resolveAuthEndpoints(endpoints);
116
+ // Route paths for the client half. `/client/*` unless a consumer says
117
+ // otherwise — the Next.js portal mounts the same screens at `/portal/*`.
118
+ const clientPaths = resolveClientPaths(clientPortalConfig?.paths);
135
119
  const [userProfile, setUserProfile] = useState({});
136
120
  const [clientProfile, setClientProfile] = useState({});
137
121
  const [isLoading, setIsLoading] = useState(true);
@@ -162,19 +146,16 @@ const GenericAuth = ({
162
146
  const updateAuthStatus = async () => {
163
147
  // The loading curtain covers two moments and stays down for neither
164
148
  // more nor less: the first profile check of a page load (no usable
165
- // profile yet), and the sign-in transition (still on the login
166
- // screen) — the user asked for "everything behind a please-wait
167
- // screen, then the dashboard", not a settled page interrupted by a
168
- // background re-check.
169
- if (
170
- !userProfile.id ||
171
- window.location.pathname.split('/')[1] === 'login'
172
- ) {
149
+ // profile yet), and the sign-in transition (still on an auth screen)
150
+ // — the user asked for "everything behind a please-wait screen, then
151
+ // the dashboard", not a settled page interrupted by a background
152
+ // re-check.
153
+ if (!userProfile.id || onAuthHandoffScreen()) {
173
154
  setIsLoading(true);
174
155
  }
175
156
 
176
157
  try {
177
- const { data } = await CustomFetch('/ajax/user/profile', 'GET');
158
+ const { data } = await CustomFetch(urls.profile, 'GET');
178
159
 
179
160
  if (data && data.id) {
180
161
  setUserProfile(data);
@@ -183,11 +164,11 @@ const GenericAuth = ({
183
164
  setIsLoading(false);
184
165
 
185
166
  // The live pathname, not the router hook's: this resolves after
186
- // Login has already navigated, and the closure still holds
167
+ // the screen has already navigated, and the closure still holds
187
168
  // '/login' from the render that created the effect — firing a
188
169
  // second navigate('/') over the settled dashboard, whose route
189
170
  // re-render is the sub-second flicker after sign-in.
190
- if (window.location.pathname.split('/')[1] === 'login') {
171
+ if (onAuthHandoffScreen()) {
191
172
  navigate('/', { replace: true });
192
173
  }
193
174
  } catch (error) {
@@ -235,28 +216,21 @@ const GenericAuth = ({
235
216
  }
236
217
  setIsClientLoading(false);
237
218
 
238
- // Get login and verify URLs from config
239
- const loginPath = '/client/login';
240
- const verifyPath = '/client/verify';
241
-
242
219
  // If on client login page but already authenticated, redirect to portal
243
220
  if (
244
221
  isClientAuthenticated &&
245
- (location.pathname === loginPath ||
246
- location.pathname === verifyPath)
222
+ (location.pathname === clientPaths.login ||
223
+ location.pathname === clientPaths.verify)
247
224
  ) {
248
- navigate('/client/portal', { replace: true });
225
+ navigate(clientPaths.portal, { replace: true });
249
226
  }
250
227
  } catch (error) {
251
228
  setIsClientLoading(false);
252
229
  setIsClientAuthenticated(false);
253
230
 
254
- // Get login path
255
- const loginPath = '/client/login';
256
-
257
231
  // Only redirect if currently on a client portal page
258
- if (location.pathname.startsWith('/client/portal')) {
259
- navigate(loginPath, {
232
+ if (location.pathname.startsWith(clientPaths.portal)) {
233
+ navigate(clientPaths.login, {
260
234
  state: { previousUrl: location.pathname },
261
235
  });
262
236
  }
@@ -288,6 +262,7 @@ const GenericAuth = ({
288
262
  setIsAuthenticated={setIsAuthenticated}
289
263
  setUserProfile={setUserProfile}
290
264
  config={config}
265
+ endpoints={endpoints}
291
266
  />
292
267
  }
293
268
  />
@@ -299,6 +274,8 @@ const GenericAuth = ({
299
274
  loginBg={loginBg}
300
275
  logo={logo}
301
276
  setIsAuthenticated={setIsAuthenticated}
277
+ config={config}
278
+ endpoints={endpoints}
302
279
  />
303
280
  }
304
281
  />
@@ -309,6 +286,8 @@ const GenericAuth = ({
309
286
  loginBg={loginBg}
310
287
  logo={logo}
311
288
  setIsAuthenticated={setIsAuthenticated}
289
+ config={config}
290
+ endpoints={endpoints}
312
291
  />
313
292
  }
314
293
  />
@@ -320,12 +299,15 @@ const GenericAuth = ({
320
299
  logo={logo}
321
300
  setIsAuthenticated={setIsAuthenticated}
322
301
  setUserProfile={setUserProfile}
302
+ config={config}
303
+ endpoints={endpoints}
304
+ mode={config.twoFactorMode}
323
305
  />
324
306
  }
325
307
  />
326
308
  {/* Client Portal Routes and Protected Routes */}
327
309
  {clientPortalConfig && (
328
- <Route path="client">
310
+ <Route path={clientPaths.base}>
329
311
  {/* Client Auth Routes */}
330
312
  <Route
331
313
  path="login"
@@ -338,6 +320,8 @@ const GenericAuth = ({
338
320
  }
339
321
  setUserProfile={setClientProfile}
340
322
  urls={clientPortalConfig.urls}
323
+ paths={clientPaths}
324
+ options={clientPortalConfig.login}
341
325
  />
342
326
  }
343
327
  />
@@ -352,6 +336,8 @@ const GenericAuth = ({
352
336
  }
353
337
  setUserProfile={setClientProfile}
354
338
  urls={clientPortalConfig.urls}
339
+ paths={clientPaths}
340
+ options={clientPortalConfig.verify}
355
341
  />
356
342
  }
357
343
  />
@@ -363,6 +349,7 @@ const GenericAuth = ({
363
349
  <ClientProtectedRoute
364
350
  clientUser={clientProfile}
365
351
  loading={isClientLoading}
352
+ redirectPath={clientPaths.login}
366
353
  />
367
354
  }
368
355
  >
@@ -401,7 +388,8 @@ const GenericAuth = ({
401
388
  <Route
402
389
  path="/*"
403
390
  element={
404
- <GenericMain
391
+ <MainShell
392
+ component={mainComponent}
405
393
  layout={layout}
406
394
  logo={headerLogo}
407
395
  navigation={navigation}
@@ -412,6 +400,7 @@ const GenericAuth = ({
412
400
  userProfile={userProfile}
413
401
  enforce2FA={enforce2FA}
414
402
  density={density}
403
+ {...mainComponentProps}
415
404
  />
416
405
  }
417
406
  />
@@ -430,13 +419,43 @@ const GenericAuth = ({
430
419
  theme="dark"
431
420
  transition={Flip}
432
421
  />
433
- <Tooltip id="system-tooltip" />
422
+ {/* react-tooltip sets no z-index of its own; the header is
423
+ position: fixed with a z-index, so a tooltip for a header chip
424
+ would otherwise paint underneath it. */}
425
+ <Tooltip id="system-tooltip" style={{ zIndex: 10050 }} />
434
426
  </>
435
427
  );
436
428
  };
437
429
 
430
+ /**
431
+ * The authenticated shell, whichever one the app chose.
432
+ *
433
+ * `component` is normally GenericMain. A consumer that keeps its own chrome
434
+ * passes its own component and still gets the route table, ProtectedRoute and
435
+ * the please-wait curtain from this file. An already-created element is
436
+ * accepted too and cloned with the shell props, so `mainComponent={<MyApp
437
+ * theme="dark" />}` works as well as `mainComponent={MyApp}`.
438
+ */
439
+ const MainShell = ({ component, ...props }) => {
440
+ const Component = component || GenericMain;
441
+
442
+ if (React.isValidElement(Component)) {
443
+ return React.cloneElement(Component, props);
444
+ }
445
+
446
+ return <Component {...props} />;
447
+ };
448
+
438
449
  const LoginComponent = React.memo(
439
- ({ loginBg, logo, providers, setIsAuthenticated, setUserProfile, config }) => (
450
+ ({
451
+ loginBg,
452
+ logo,
453
+ providers,
454
+ setIsAuthenticated,
455
+ setUserProfile,
456
+ config,
457
+ endpoints,
458
+ }) => (
440
459
  <Login
441
460
  loginBg={loginBg}
442
461
  logo={logo}
@@ -444,49 +463,97 @@ const LoginComponent = React.memo(
444
463
  setSystemAuth={setIsAuthenticated}
445
464
  setUserProfile={setUserProfile}
446
465
  config={config}
466
+ endpoints={endpoints}
447
467
  />
448
468
  )
449
469
  );
450
470
 
451
- const ResetComponent = React.memo(({ loginBg, logo, setIsAuthenticated }) => (
452
- <Reset loginBg={loginBg} logo={logo} setSystemAuth={setIsAuthenticated} />
453
- ));
471
+ const ResetComponent = React.memo(
472
+ ({ loginBg, logo, setIsAuthenticated, config, endpoints }) => (
473
+ <Reset
474
+ loginBg={loginBg}
475
+ logo={logo}
476
+ setSystemAuth={setIsAuthenticated}
477
+ config={config}
478
+ endpoints={endpoints}
479
+ />
480
+ )
481
+ );
454
482
 
455
- const VerifyComponent = React.memo(({ loginBg, logo, setIsAuthenticated }) => (
456
- <Verify loginBg={loginBg} logo={logo} setSystemAuth={setIsAuthenticated} />
457
- ));
483
+ const VerifyComponent = React.memo(
484
+ ({ loginBg, logo, setIsAuthenticated, config, endpoints }) => (
485
+ <Verify
486
+ loginBg={loginBg}
487
+ logo={logo}
488
+ setSystemAuth={setIsAuthenticated}
489
+ config={config}
490
+ endpoints={endpoints}
491
+ />
492
+ )
493
+ );
458
494
 
459
495
  const TwoFactorAuthComponent = React.memo(
460
- ({ loginBg, logo, setIsAuthenticated, setUserProfile }) => (
496
+ ({
497
+ loginBg,
498
+ logo,
499
+ setIsAuthenticated,
500
+ setUserProfile,
501
+ config,
502
+ endpoints,
503
+ mode,
504
+ }) => (
461
505
  <TwoFactorAuth
462
506
  loginBg={loginBg}
463
507
  logo={logo}
464
508
  setSystemAuth={setIsAuthenticated}
465
509
  setUserProfile={setUserProfile}
510
+ config={config}
511
+ endpoints={endpoints}
512
+ {...(mode ? { mode } : {})}
466
513
  />
467
514
  )
468
515
  );
469
516
 
470
517
  const ClientLoginComponent = React.memo(
471
- ({ loginBg, logo, setIsAuthenticated, setUserProfile, urls }) => (
518
+ ({
519
+ loginBg,
520
+ logo,
521
+ setIsAuthenticated,
522
+ setUserProfile,
523
+ urls,
524
+ paths,
525
+ options,
526
+ }) => (
472
527
  <ClientLogin
473
528
  loginBg={loginBg}
474
529
  logo={logo}
475
530
  setSystemAuth={setIsAuthenticated}
476
531
  setUserProfile={setUserProfile}
477
532
  urls={urls}
533
+ paths={paths}
534
+ {...(options || {})}
478
535
  />
479
536
  )
480
537
  );
481
538
 
482
539
  const ClientOTPVerifyComponent = React.memo(
483
- ({ loginBg, logo, setIsAuthenticated, setUserProfile, urls }) => (
540
+ ({
541
+ loginBg,
542
+ logo,
543
+ setIsAuthenticated,
544
+ setUserProfile,
545
+ urls,
546
+ paths,
547
+ options,
548
+ }) => (
484
549
  <ClientOTPVerify
485
550
  loginBg={loginBg}
486
551
  logo={logo}
487
552
  setSystemAuth={setIsAuthenticated}
488
553
  setUserProfile={setUserProfile}
489
554
  urls={urls}
555
+ paths={paths}
556
+ {...(options || {})}
490
557
  />
491
558
  )
492
559
  );