@richardmcquiston01/dashboard-widgets-toolkit 0.8.0 → 0.9.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/dist/react.cjs CHANGED
@@ -524,6 +524,19 @@ var DEFAULT_LABELS = {
524
524
  moveLater: (title) => `Move ${title} later`,
525
525
  hiddenWidgets: "Hidden:",
526
526
  minimizedWidgets: "Minimized:",
527
+ customize: "Customize",
528
+ done: "Done",
529
+ reset: "Reset layout",
530
+ revertChanges: "Revert changes",
531
+ confirmReset: "Reset the layout to the default?",
532
+ confirmRevert: "Revert to how this looked before you started editing?",
533
+ confirmYes: "Yes",
534
+ confirmNo: "No",
535
+ editingOn: "Editing dashboard. Use the buttons on each card to reorder or hide it.",
536
+ editingOff: "Finished editing.",
537
+ dashboardControls: "Dashboard controls",
538
+ locked: (title) => `${title} is locked`,
539
+ lockedForViewers: (title) => `${title} is locked for viewers`,
527
540
  opensInNewTab: "(opens in a new tab)",
528
541
  view: (title) => `View ${title}`,
529
542
  close: "Close",
@@ -1394,6 +1407,7 @@ function WidgetCard({
1394
1407
  columnSpan,
1395
1408
  width,
1396
1409
  widgetKey,
1410
+ editing = false,
1397
1411
  headingLevel = 2,
1398
1412
  className,
1399
1413
  children
@@ -1438,6 +1452,7 @@ function WidgetCard({
1438
1452
  "dwt-card",
1439
1453
  `dwt-card--${status}`,
1440
1454
  minimized && "dwt-card--minimized",
1455
+ editing && "dwt-card--editing",
1441
1456
  size !== void 0 && `dwt-card--size-${size}`,
1442
1457
  fillsHeight(fill) && "dwt-card--fill-height",
1443
1458
  fillsWidth(fill) && "dwt-card--fill-width",
@@ -2139,6 +2154,57 @@ function DetailHost({
2139
2154
  }
2140
2155
  ) });
2141
2156
  }
2157
+ function InlineConfirm({
2158
+ message,
2159
+ onAnswer
2160
+ }) {
2161
+ const slot = useSlotClassName();
2162
+ const { labels } = useWidgetSettings();
2163
+ const noRef = react.useRef(null);
2164
+ react.useEffect(() => {
2165
+ noRef.current?.focus();
2166
+ }, []);
2167
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2168
+ "span",
2169
+ {
2170
+ role: "group",
2171
+ "aria-label": message,
2172
+ className: "dwt-confirm",
2173
+ onKeyDown: (event) => {
2174
+ if (event.key === "Escape") {
2175
+ event.stopPropagation();
2176
+ onAnswer(false);
2177
+ }
2178
+ },
2179
+ children: [
2180
+ /* @__PURE__ */ jsxRuntime.jsx("span", { role: "alert", className: "dwt-confirm-message", children: message }),
2181
+ /* @__PURE__ */ jsxRuntime.jsx(
2182
+ "button",
2183
+ {
2184
+ type: "button",
2185
+ className: slot("button", "dwt-button", "dwt-icon-button"),
2186
+ "aria-label": labels.confirmYes,
2187
+ title: labels.confirmYes,
2188
+ onClick: () => onAnswer(true),
2189
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2713" })
2190
+ }
2191
+ ),
2192
+ /* @__PURE__ */ jsxRuntime.jsx(
2193
+ "button",
2194
+ {
2195
+ ref: noRef,
2196
+ type: "button",
2197
+ className: slot("button", "dwt-button", "dwt-icon-button"),
2198
+ "aria-label": labels.confirmNo,
2199
+ title: labels.confirmNo,
2200
+ onClick: () => onAnswer(false),
2201
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2715" })
2202
+ }
2203
+ )
2204
+ ]
2205
+ }
2206
+ );
2207
+ }
2142
2208
  function withoutLock(definition) {
2143
2209
  if (definition.locked === void 0) return definition;
2144
2210
  const copy = { ...definition };
@@ -2150,6 +2216,12 @@ function DashboardInner({
2150
2216
  layout: savedLayout = EMPTY_LAYOUT,
2151
2217
  onLayoutChange,
2152
2218
  overrideLocks = false,
2219
+ editMode = "always",
2220
+ editing: editingProp,
2221
+ defaultEditing = false,
2222
+ onEditingChange,
2223
+ defaultLayout,
2224
+ toolbar = true,
2153
2225
  onRetry,
2154
2226
  loadDetail,
2155
2227
  onOpenDetail,
@@ -2168,6 +2240,25 @@ function DashboardInner({
2168
2240
  const visible = visibleWidgets(definitions, layout);
2169
2241
  const hidden = hiddenWidgets(definitions, layout);
2170
2242
  const editable = onLayoutChange !== void 0;
2243
+ const toggleMode = editMode === "toggle";
2244
+ const [editingState, setEditingState] = react.useState(defaultEditing);
2245
+ const editing = editingProp ?? editingState;
2246
+ const controlsShown = editable && (!toggleMode || editing);
2247
+ const [snapshot, setSnapshot] = react.useState(
2248
+ void 0
2249
+ );
2250
+ if (toggleMode && editable && editing) {
2251
+ if (snapshot === void 0) setSnapshot(savedLayout);
2252
+ } else if (snapshot !== void 0) {
2253
+ setSnapshot(void 0);
2254
+ }
2255
+ const [confirming, setConfirming] = react.useState(
2256
+ void 0
2257
+ );
2258
+ const pending = editing ? confirming : void 0;
2259
+ const [announcement, setAnnouncement] = react.useState("");
2260
+ const toggleRef = react.useRef(null);
2261
+ const resetRef = react.useRef(null);
2171
2262
  const minimized = editable ? visible.filter((definition) => isMinimized(layout, definition.key)) : [];
2172
2263
  const shown = editable ? visible.filter((definition) => !isMinimized(layout, definition.key)) : visible;
2173
2264
  const [detailKey, setDetailKey] = react.useState(void 0);
@@ -2181,142 +2272,267 @@ function DashboardInner({
2181
2272
  function change(next) {
2182
2273
  if (next !== layout) onLayoutChange?.(next);
2183
2274
  }
2184
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: slot("dashboard", "dwt-dashboard", className), children: [
2185
- editable && hidden.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: slot("hiddenBar", "dwt-hidden-bar"), children: [
2186
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-hidden-label", children: labels.hiddenWidgets }),
2187
- hidden.map((definition) => /* @__PURE__ */ jsxRuntime.jsxs(
2188
- "button",
2189
- {
2190
- type: "button",
2191
- className: slot("button", "dwt-button", "dwt-show-button"),
2192
- "aria-label": labels.show(definition.title),
2193
- onClick: () => change(showWidget(layout, definition.key)),
2194
- children: [
2195
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "+ " }),
2196
- definition.title
2197
- ]
2198
- },
2199
- definition.key
2200
- ))
2201
- ] }),
2202
- minimized.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
2203
- "div",
2204
- {
2205
- className: slot("hiddenBar", "dwt-hidden-bar", "dwt-minimized-bar"),
2206
- children: [
2207
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-hidden-label", children: labels.minimizedWidgets }),
2208
- minimized.map((definition) => /* @__PURE__ */ jsxRuntime.jsxs(
2275
+ function setEditing(next) {
2276
+ if (editingProp === void 0) setEditingState(next);
2277
+ onEditingChange?.(next);
2278
+ setAnnouncement(next ? labels.editingOn : labels.editingOff);
2279
+ setConfirming(void 0);
2280
+ }
2281
+ function answerConfirmation(yes) {
2282
+ const which = pending;
2283
+ setConfirming(void 0);
2284
+ if (yes && which === "reset") {
2285
+ change(enforceLocks(definitions, defaultLayout ?? EMPTY_LAYOUT));
2286
+ } else if (yes && which === "revert" && snapshot !== void 0) {
2287
+ change(snapshot);
2288
+ }
2289
+ (which === "revert" ? toggleRef : resetRef).current?.focus();
2290
+ }
2291
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2292
+ "div",
2293
+ {
2294
+ className: slot(
2295
+ "dashboard",
2296
+ "dwt-dashboard",
2297
+ toggleMode && controlsShown && "dwt-dashboard--editing",
2298
+ className
2299
+ ),
2300
+ children: [
2301
+ editable && toggleMode && toolbar && /* @__PURE__ */ jsxRuntime.jsxs(
2302
+ "div",
2303
+ {
2304
+ role: "group",
2305
+ "aria-label": labels.dashboardControls,
2306
+ className: slot("toolbar", "dwt-toolbar"),
2307
+ children: [
2308
+ /* @__PURE__ */ jsxRuntime.jsx(
2309
+ "button",
2310
+ {
2311
+ ref: toggleRef,
2312
+ type: "button",
2313
+ "aria-pressed": editing,
2314
+ className: slot("button", "dwt-button", "dwt-toolbar-toggle"),
2315
+ onClick: () => setEditing(!editing),
2316
+ children: editing ? labels.done : labels.customize
2317
+ }
2318
+ ),
2319
+ editing && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2320
+ /* @__PURE__ */ jsxRuntime.jsx(
2321
+ "button",
2322
+ {
2323
+ ref: resetRef,
2324
+ type: "button",
2325
+ className: slot("button", "dwt-button"),
2326
+ onClick: () => setConfirming("reset"),
2327
+ children: labels.reset
2328
+ }
2329
+ ),
2330
+ /* @__PURE__ */ jsxRuntime.jsx(
2331
+ "button",
2332
+ {
2333
+ type: "button",
2334
+ className: slot("button", "dwt-button"),
2335
+ disabled: snapshot === void 0 || savedLayout === snapshot,
2336
+ onClick: () => setConfirming("revert"),
2337
+ children: labels.revertChanges
2338
+ }
2339
+ )
2340
+ ] }),
2341
+ pending !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
2342
+ InlineConfirm,
2343
+ {
2344
+ message: pending === "reset" ? labels.confirmReset : labels.confirmRevert,
2345
+ onAnswer: answerConfirmation
2346
+ }
2347
+ ),
2348
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-visually-hidden", "aria-live": "polite", children: announcement })
2349
+ ]
2350
+ }
2351
+ ),
2352
+ controlsShown && hidden.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: slot("hiddenBar", "dwt-hidden-bar"), children: [
2353
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-hidden-label", children: labels.hiddenWidgets }),
2354
+ hidden.map((definition) => /* @__PURE__ */ jsxRuntime.jsxs(
2209
2355
  "button",
2210
2356
  {
2211
2357
  type: "button",
2212
2358
  className: slot("button", "dwt-button", "dwt-show-button"),
2213
- "aria-label": labels.expand(definition.title),
2214
- onClick: () => change(toggleMinimized(layout, definition.key)),
2359
+ "aria-label": labels.show(definition.title),
2360
+ onClick: () => change(showWidget(layout, definition.key)),
2215
2361
  children: [
2216
- /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u25B8 " }),
2362
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "+ " }),
2217
2363
  definition.title
2218
2364
  ]
2219
2365
  },
2220
2366
  definition.key
2221
2367
  ))
2222
- ]
2223
- }
2224
- ),
2225
- visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: slot("empty", "dwt-empty", "dwt-dashboard-empty"), children: definitions.length === 0 ? labels.noWidgets : labels.allHidden }) : shown.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(
2226
- "div",
2227
- {
2228
- ref: gridRef,
2229
- className: slot("grid", "dwt-grid", twelve && "dwt-grid--twelve"),
2230
- children: shown.map((definition, index) => {
2231
- const widget = byKey.get(
2232
- definition.key
2233
- );
2234
- if (widget === void 0) return null;
2235
- const key = definition.key;
2236
- const title = definition.title;
2237
- const lock = resolveWidgetLock(definition);
2238
- const canMoveEarlier = !lock.move && moveWidgetBy(definitions, layout, key, -1) !== layout;
2239
- const canMoveLater = !lock.move && moveWidgetBy(definitions, layout, key, 1) !== layout;
2240
- const actions = editable ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2241
- !lock.move && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2242
- /* @__PURE__ */ jsxRuntime.jsx(
2368
+ ] }),
2369
+ minimized.length > 0 && /* @__PURE__ */ jsxRuntime.jsxs(
2370
+ "div",
2371
+ {
2372
+ className: slot("hiddenBar", "dwt-hidden-bar", "dwt-minimized-bar"),
2373
+ children: [
2374
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "dwt-hidden-label", children: labels.minimizedWidgets }),
2375
+ minimized.map((definition) => /* @__PURE__ */ jsxRuntime.jsxs(
2243
2376
  "button",
2244
2377
  {
2245
2378
  type: "button",
2246
- className: slot(
2379
+ className: slot("button", "dwt-button", "dwt-show-button"),
2380
+ "aria-label": labels.expand(definition.title),
2381
+ onClick: () => change(toggleMinimized(layout, definition.key)),
2382
+ children: [
2383
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u25B8 " }),
2384
+ definition.title
2385
+ ]
2386
+ },
2387
+ definition.key
2388
+ ))
2389
+ ]
2390
+ }
2391
+ ),
2392
+ visible.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: slot("empty", "dwt-empty", "dwt-dashboard-empty"), children: definitions.length === 0 ? labels.noWidgets : labels.allHidden }) : shown.length === 0 ? null : /* @__PURE__ */ jsxRuntime.jsx(
2393
+ "div",
2394
+ {
2395
+ ref: gridRef,
2396
+ className: slot("grid", "dwt-grid", twelve && "dwt-grid--twelve"),
2397
+ children: shown.map((definition, index) => {
2398
+ const widget = byKey.get(
2399
+ definition.key
2400
+ );
2401
+ if (widget === void 0) return null;
2402
+ const key = definition.key;
2403
+ const title = definition.title;
2404
+ const lock = resolveWidgetLock(definition);
2405
+ const ownLock = resolveWidgetLock(
2406
+ widget.definition
2407
+ );
2408
+ const isLocked = ownLock.move || ownLock.hide || ownLock.minimize;
2409
+ const lockLabel = overrideLocks ? labels.lockedForViewers(title) : labels.locked(title);
2410
+ const canMoveEarlier = !lock.move && moveWidgetBy(definitions, layout, key, -1) !== layout;
2411
+ const canMoveLater = !lock.move && moveWidgetBy(definitions, layout, key, 1) !== layout;
2412
+ const actions = controlsShown ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2413
+ isLocked && /* @__PURE__ */ jsxRuntime.jsx(
2414
+ "span",
2415
+ {
2416
+ role: "img",
2417
+ className: "dwt-lock",
2418
+ "aria-label": lockLabel,
2419
+ title: lockLabel,
2420
+ children: /* @__PURE__ */ jsxRuntime.jsxs(
2421
+ "svg",
2422
+ {
2423
+ viewBox: "0 0 16 16",
2424
+ width: "14",
2425
+ height: "14",
2426
+ "aria-hidden": "true",
2427
+ focusable: "false",
2428
+ children: [
2429
+ /* @__PURE__ */ jsxRuntime.jsx(
2430
+ "rect",
2431
+ {
2432
+ x: "3",
2433
+ y: "7",
2434
+ width: "10",
2435
+ height: "7",
2436
+ rx: "1.5",
2437
+ fill: "currentColor"
2438
+ }
2439
+ ),
2440
+ /* @__PURE__ */ jsxRuntime.jsx(
2441
+ "path",
2442
+ {
2443
+ d: "M5.5 7V5a2.5 2.5 0 0 1 5 0v2",
2444
+ fill: "none",
2445
+ stroke: "currentColor",
2446
+ strokeWidth: "1.4"
2447
+ }
2448
+ )
2449
+ ]
2450
+ }
2451
+ )
2452
+ }
2453
+ ),
2454
+ !lock.move && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2455
+ /* @__PURE__ */ jsxRuntime.jsx(
2247
2456
  "button",
2248
- "dwt-button",
2249
- "dwt-icon-button"
2457
+ {
2458
+ type: "button",
2459
+ className: slot(
2460
+ "button",
2461
+ "dwt-button",
2462
+ "dwt-icon-button"
2463
+ ),
2464
+ "aria-label": labels.moveEarlier(title),
2465
+ title: labels.moveEarlier(title),
2466
+ disabled: index === 0 || !canMoveEarlier,
2467
+ onClick: () => change(moveWidgetBy(definitions, layout, key, -1)),
2468
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2191" })
2469
+ }
2250
2470
  ),
2251
- "aria-label": labels.moveEarlier(title),
2252
- title: labels.moveEarlier(title),
2253
- disabled: index === 0 || !canMoveEarlier,
2254
- onClick: () => change(moveWidgetBy(definitions, layout, key, -1)),
2255
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2191" })
2256
- }
2257
- ),
2258
- /* @__PURE__ */ jsxRuntime.jsx(
2259
- "button",
2260
- {
2261
- type: "button",
2262
- className: slot(
2471
+ /* @__PURE__ */ jsxRuntime.jsx(
2263
2472
  "button",
2264
- "dwt-button",
2265
- "dwt-icon-button"
2266
- ),
2267
- "aria-label": labels.moveLater(title),
2268
- title: labels.moveLater(title),
2269
- disabled: index === shown.length - 1 || !canMoveLater,
2270
- onClick: () => change(moveWidgetBy(definitions, layout, key, 1)),
2271
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2193" })
2272
- }
2273
- )
2274
- ] }),
2275
- !lock.hide && /* @__PURE__ */ jsxRuntime.jsx(
2276
- "button",
2277
- {
2278
- type: "button",
2279
- className: slot("button", "dwt-button", "dwt-icon-button"),
2280
- "aria-label": labels.hide(title),
2281
- title: labels.hide(title),
2282
- onClick: () => change(hideWidget(layout, key)),
2283
- children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\xD7" })
2284
- }
2285
- )
2286
- ] }) : void 0;
2287
- const viewable = resolveDetailOptions(definition) !== void 0 && (onOpenDetail !== void 0 || loadDetail !== void 0 || widget.status === "ok" && deriveDetailData(widget.data) !== void 0);
2288
- return /* @__PURE__ */ jsxRuntime.jsx(
2289
- ResolvedWidgetCard,
2290
- {
2291
- widget,
2292
- ...viewable ? {
2293
- onView: () => onOpenDetail === void 0 ? setDetailKey(key) : onOpenDetail(key)
2294
- } : {},
2295
- ...spanProps(spans, key),
2296
- ...widthProps(twelve, definition),
2297
- minimized: isMinimized(layout, key),
2298
- ...actions === void 0 ? {} : { actions },
2299
- ...editable && !lock.minimize ? {
2300
- onToggleMinimized: () => change(toggleMinimized(layout, key))
2301
- } : {},
2302
- ...headingLevel === void 0 ? {} : { headingLevel },
2303
- ...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(key) }
2304
- },
2305
- key
2306
- );
2307
- })
2308
- }
2309
- ),
2310
- detailKey !== void 0 && byKey.get(detailKey) !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
2311
- DetailHost,
2312
- {
2313
- widget: byKey.get(detailKey),
2314
- loadDetail,
2315
- onClose: () => setDetailKey(void 0)
2316
- },
2317
- detailKey
2318
- )
2319
- ] });
2473
+ {
2474
+ type: "button",
2475
+ className: slot(
2476
+ "button",
2477
+ "dwt-button",
2478
+ "dwt-icon-button"
2479
+ ),
2480
+ "aria-label": labels.moveLater(title),
2481
+ title: labels.moveLater(title),
2482
+ disabled: index === shown.length - 1 || !canMoveLater,
2483
+ onClick: () => change(moveWidgetBy(definitions, layout, key, 1)),
2484
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\u2193" })
2485
+ }
2486
+ )
2487
+ ] }),
2488
+ !lock.hide && /* @__PURE__ */ jsxRuntime.jsx(
2489
+ "button",
2490
+ {
2491
+ type: "button",
2492
+ className: slot("button", "dwt-button", "dwt-icon-button"),
2493
+ "aria-label": labels.hide(title),
2494
+ title: labels.hide(title),
2495
+ onClick: () => change(hideWidget(layout, key)),
2496
+ children: /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": "true", children: "\xD7" })
2497
+ }
2498
+ )
2499
+ ] }) : void 0;
2500
+ const viewable = resolveDetailOptions(definition) !== void 0 && (onOpenDetail !== void 0 || loadDetail !== void 0 || widget.status === "ok" && deriveDetailData(widget.data) !== void 0);
2501
+ return /* @__PURE__ */ jsxRuntime.jsx(
2502
+ ResolvedWidgetCard,
2503
+ {
2504
+ widget,
2505
+ ...viewable ? {
2506
+ onView: () => onOpenDetail === void 0 ? setDetailKey(key) : onOpenDetail(key)
2507
+ } : {},
2508
+ ...spanProps(spans, key),
2509
+ ...widthProps(twelve, definition),
2510
+ minimized: isMinimized(layout, key),
2511
+ editing: toggleMode && controlsShown,
2512
+ ...actions === void 0 ? {} : { actions },
2513
+ ...editable && !lock.minimize ? {
2514
+ onToggleMinimized: () => change(toggleMinimized(layout, key))
2515
+ } : {},
2516
+ ...headingLevel === void 0 ? {} : { headingLevel },
2517
+ ...onRetry === void 0 || widget.status !== "error" ? {} : { onRetry: () => onRetry(key) }
2518
+ },
2519
+ key
2520
+ );
2521
+ })
2522
+ }
2523
+ ),
2524
+ detailKey !== void 0 && byKey.get(detailKey) !== void 0 && /* @__PURE__ */ jsxRuntime.jsx(
2525
+ DetailHost,
2526
+ {
2527
+ widget: byKey.get(detailKey),
2528
+ loadDetail,
2529
+ onClose: () => setDetailKey(void 0)
2530
+ },
2531
+ detailKey
2532
+ )
2533
+ ]
2534
+ }
2535
+ );
2320
2536
  }
2321
2537
  function Dashboard({
2322
2538
  locale,