@flamingo-stack/openframe-frontend-core 0.0.852 → 0.0.854
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/build/export-map.json +1 -1
- package/dist/{chunk-G7GF4PWA.cjs → chunk-2IJMHBOK.cjs} +3 -3
- package/dist/{chunk-IC4IJJB2.cjs → chunk-3WXHPD6N.cjs} +55 -55
- package/dist/{chunk-UV45EPXN.cjs → chunk-4LTLEUY5.cjs} +5 -5
- package/dist/{chunk-BNHTBLAG.cjs → chunk-4O5N5CGK.cjs} +17 -17
- package/dist/{chunk-COWMXUHN.cjs → chunk-4SSJ3T3N.cjs} +3 -1
- package/dist/{chunk-IUDBG3HJ.cjs → chunk-5HMENXSR.cjs} +3 -3
- package/dist/{chunk-COJG2ATY.cjs → chunk-5OENPMRU.cjs} +43 -43
- package/dist/{chunk-IO6NN3SL.cjs → chunk-5TXE7BXT.cjs} +46 -46
- package/dist/{chunk-EIACEY2L.cjs → chunk-63ZV3UGG.cjs} +10 -10
- package/dist/{chunk-HTYJUMFB.cjs → chunk-6DCUGIGU.cjs} +2 -2
- package/dist/{chunk-GEZ3UXCA.cjs → chunk-6XU3RCK3.cjs} +18 -18
- package/dist/{chunk-3ZQESOPJ.cjs → chunk-7J5NSWJG.cjs} +87 -87
- package/dist/{chunk-MXY2OGEV.cjs → chunk-7MOBD44H.cjs} +28 -28
- package/dist/{chunk-U767P4JU.cjs → chunk-ACPOJE32.cjs} +9 -9
- package/dist/{chunk-CHGIACIP.cjs → chunk-BAA3YCLT.cjs} +72 -72
- package/dist/{chunk-VUHHLRAY.cjs → chunk-D2XGRWPW.cjs} +73 -73
- package/dist/{chunk-5RMBLOJ5.cjs → chunk-EIHMPQRQ.cjs} +9 -9
- package/dist/{chunk-3SJVF3HW.cjs → chunk-ETQNMR2K.cjs} +5 -5
- package/dist/{chunk-2W22LY3W.cjs → chunk-FBANHIAG.cjs} +9 -9
- package/dist/{chunk-P63CRPWI.cjs → chunk-FJXSKMQJ.cjs} +20 -20
- package/dist/{chunk-QOW2GP3V.cjs → chunk-GVHCQRUE.cjs} +21 -21
- package/dist/{chunk-KNN2GCMW.cjs → chunk-H3GBPYPS.cjs} +18 -18
- package/dist/{chunk-FW7RKWPY.cjs → chunk-JKBNK5U6.cjs} +3 -3
- package/dist/{chunk-W7OFAROY.cjs → chunk-KA3L6D5N.cjs} +3 -3
- package/dist/{chunk-USPUZO53.cjs → chunk-LQDAB5V5.cjs} +4 -4
- package/dist/{chunk-KHOB3TES.cjs → chunk-ONYANAMA.cjs} +4 -4
- package/dist/{chunk-D3H6AI7O.cjs → chunk-PRJZMZ3X.cjs} +1182 -746
- package/dist/chunk-QD727QFI.cjs +62 -0
- package/dist/{chunk-X3WIOMEE.cjs → chunk-RMI6O3AE.cjs} +32 -32
- package/dist/{chunk-MFDRCTM3.cjs → chunk-S5P6CF5R.cjs} +47 -47
- package/dist/{chunk-477P6AQH.cjs → chunk-TMPLHUUU.cjs} +6 -6
- package/dist/{chunk-UO2EJGRJ.cjs → chunk-UPQ4MAR7.cjs} +14 -14
- package/dist/{chunk-LFEURIZN.cjs → chunk-VMAOZA2V.cjs} +215 -215
- package/dist/{chunk-NMWLXHFH.cjs → chunk-YY3WP2YQ.cjs} +30 -30
- package/dist/{chunk-WFAZMASF.cjs → chunk-ZDPPNHA2.cjs} +3 -3
- package/dist/{cloud-tenants-O33HCUYB.cjs → cloud-tenants-5RNK4ZAT.cjs} +19 -19
- package/dist/components/case-studies/index.cjs +33 -33
- package/dist/components/chat/index.cjs +13 -13
- package/dist/components/contact/index.cjs +20 -20
- package/dist/components/docs/index.cjs +23 -23
- package/dist/components/embeds/index.cjs +20 -20
- package/dist/components/faq/index.cjs +21 -21
- package/dist/components/features/cloud-tenants/index.d.ts +7 -5
- package/dist/components/features/cloud-tenants/index.d.ts.map +1 -1
- package/dist/components/features/cloud-tenants/index.js +8 -1
- package/dist/components/features/cloud-tenants/single-customer-tenants-table-view.d.ts +26 -0
- package/dist/components/features/cloud-tenants/single-customer-tenants-table-view.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/single-customer-tenants-table-view.js +176 -0
- package/dist/components/features/cloud-tenants/tenant-access-cell.d.ts +4 -2
- package/dist/components/features/cloud-tenants/tenant-access-cell.d.ts.map +1 -1
- package/dist/components/features/cloud-tenants/tenant-access-cell.js +3 -2
- package/dist/components/features/cloud-tenants/tenant-customer-cell.d.ts +12 -5
- package/dist/components/features/cloud-tenants/tenant-customer-cell.d.ts.map +1 -1
- package/dist/components/features/cloud-tenants/tenant-customer-cell.js +38 -7
- package/dist/components/features/cloud-tenants/tenant-licenses-cell.d.ts +7 -0
- package/dist/components/features/cloud-tenants/tenant-licenses-cell.d.ts.map +1 -0
- package/dist/components/features/cloud-tenants/tenant-licenses-cell.js +17 -0
- package/dist/components/features/cloud-tenants/tenant-presentation.d.ts +19 -0
- package/dist/components/features/cloud-tenants/tenant-presentation.d.ts.map +1 -1
- package/dist/components/features/cloud-tenants/tenant-presentation.js +24 -3
- package/dist/components/features/cloud-tenants/tenant-row.d.ts +35 -8
- package/dist/components/features/cloud-tenants/tenant-row.d.ts.map +1 -1
- package/dist/components/features/cloud-tenants/tenants-table-columns.d.ts +9 -3
- package/dist/components/features/cloud-tenants/tenants-table-columns.d.ts.map +1 -1
- package/dist/components/features/cloud-tenants/tenants-table-columns.js +5 -3
- package/dist/components/features/cloud-tenants/tenants-table-view.d.ts +27 -6
- package/dist/components/features/cloud-tenants/tenants-table-view.d.ts.map +1 -1
- package/dist/components/features/cloud-tenants/tenants-table-view.js +75 -17
- package/dist/components/features/devices/device-directory.d.ts +18 -0
- package/dist/components/features/devices/device-directory.d.ts.map +1 -0
- package/dist/components/features/devices/device-directory.js +35 -0
- package/dist/components/features/devices/devices-filter-toolbar.d.ts +3 -1
- package/dist/components/features/devices/devices-filter-toolbar.d.ts.map +1 -1
- package/dist/components/features/devices/devices-filter-toolbar.js +2 -1
- package/dist/components/features/devices/devices-panel-view.d.ts +3 -1
- package/dist/components/features/devices/devices-panel-view.d.ts.map +1 -1
- package/dist/components/features/devices/devices-panel-view.js +11 -2
- package/dist/components/features/devices/devices-table-columns.d.ts +17 -3
- package/dist/components/features/devices/devices-table-columns.d.ts.map +1 -1
- package/dist/components/features/devices/devices-table-columns.js +80 -10
- package/dist/components/features/devices/index.d.ts +1 -0
- package/dist/components/features/devices/index.d.ts.map +1 -1
- package/dist/components/features/devices/index.js +8 -0
- package/dist/components/features/devices/types.d.ts +14 -0
- package/dist/components/features/devices/types.d.ts.map +1 -1
- package/dist/components/features/devices/use-tag-filter-modal.d.ts +1 -0
- package/dist/components/features/devices/use-tag-filter-modal.d.ts.map +1 -1
- package/dist/components/features/devices/use-tag-filter-modal.js +13 -8
- package/dist/components/features/index.cjs +33 -19
- package/dist/components/help-center-pages/index.cjs +120 -120
- package/dist/components/help-center-pages/trust-center-page.d.ts +1 -1
- package/dist/components/index.cjs +96 -76
- package/dist/components/meeting-scheduler/index.cjs +82 -82
- package/dist/components/navigation/app-layout.js +2 -2
- package/dist/components/navigation/index.cjs +22 -22
- package/dist/components/onboarding-guides/index.cjs +22 -22
- package/dist/components/platform/tool-badge-mark.d.ts +1 -1
- package/dist/components/product-demo/index.cjs +30 -30
- package/dist/components/related-content/index.cjs +8 -8
- package/dist/components/tickets/index.cjs +24 -24
- package/dist/components/ui/data-attribution.d.ts +8 -3
- package/dist/components/ui/data-attribution.d.ts.map +1 -1
- package/dist/components/ui/data-attribution.js +17 -6
- package/dist/components/ui/date-picker.d.ts +2 -0
- package/dist/components/ui/date-picker.d.ts.map +1 -1
- package/dist/components/ui/date-picker.js +19 -6
- package/dist/components/ui/index.cjs +25 -19
- package/dist/components/ui/index.d.ts +1 -0
- package/dist/components/ui/index.d.ts.map +1 -1
- package/dist/components/ui/index.js +1 -0
- package/dist/{devices-2RGGMC2B.cjs → devices-44O5PZOW.cjs} +20 -20
- package/dist/{embeddable-chat-SJEEJI4N.cjs → embeddable-chat-W3CLMGC3.cjs} +90 -90
- package/dist/hooks/index.cjs +11 -7
- package/dist/hooks/ui/use-content-breakpoint.d.ts +8 -0
- package/dist/hooks/ui/use-content-breakpoint.d.ts.map +1 -1
- package/dist/hooks/ui/use-content-breakpoint.js +17 -3
- package/dist/hooks/ui/use-media-query.d.ts +1 -0
- package/dist/hooks/ui/use-media-query.d.ts.map +1 -1
- package/dist/hooks/ui/use-media-query.js +3 -1
- package/dist/index.cjs +44 -24
- package/dist/{knowledge-5TJIXVMD.cjs → knowledge-UUU3WVO3.cjs} +20 -20
- package/dist/{logs-HGQOTRKZ.cjs → logs-DFHNSODA.cjs} +26 -26
- package/dist/{policies-GWFSLVSM.cjs → policies-RGFUGDBP.cjs} +23 -23
- package/dist/{remote-session-SG44CNOK.cjs → remote-session-U3H77HKR.cjs} +10 -10
- package/dist/{scripts-PGJNAZF4.cjs → scripts-KOVO5DHW.cjs} +26 -26
- package/dist/{software-update-KKLSYHDI.cjs → software-update-4EKHVV5W.cjs} +23 -23
- package/dist/{tickets-board-SQY2Y6QV.cjs → tickets-board-YIFOVMDX.cjs} +10 -10
- package/dist/types/data-sync.d.ts +4 -1
- package/dist/types/data-sync.d.ts.map +1 -1
- package/dist/types/data-sync.js +4 -1
- package/dist/types/index.cjs +4 -1
- package/dist/utils/presentation-for.d.ts +6 -0
- package/dist/utils/presentation-for.d.ts.map +1 -0
- package/dist/utils/presentation-for.js +7 -0
- package/package.json +1 -1
- package/src/components/features/cloud-tenants/index.ts +8 -3
- package/src/components/features/cloud-tenants/single-customer-tenants-table-view.tsx +234 -0
- package/src/components/features/cloud-tenants/tenant-access-cell.tsx +12 -5
- package/src/components/features/cloud-tenants/tenant-customer-cell.tsx +48 -12
- package/src/components/features/cloud-tenants/tenant-licenses-cell.tsx +28 -0
- package/src/components/features/cloud-tenants/tenant-presentation.ts +46 -4
- package/src/components/features/cloud-tenants/tenant-row.ts +38 -8
- package/src/components/features/cloud-tenants/tenants-table-columns.ts +8 -5
- package/src/components/features/cloud-tenants/tenants-table-view.tsx +123 -28
- package/src/components/features/devices/device-directory.ts +55 -0
- package/src/components/features/devices/devices-filter-toolbar.tsx +4 -1
- package/src/components/features/devices/devices-panel-view.tsx +12 -2
- package/src/components/features/devices/devices-table-columns.tsx +123 -8
- package/src/components/features/devices/index.ts +7 -0
- package/src/components/features/devices/types.ts +14 -0
- package/src/components/features/devices/use-tag-filter-modal.ts +32 -14
- package/src/components/help-center-pages/trust-center-page.tsx +1 -1
- package/src/components/navigation/app-layout.tsx +4 -4
- package/src/components/platform/tool-badge-mark.ts +1 -1
- package/src/components/ui/data-attribution.tsx +20 -8
- package/src/components/ui/date-picker.tsx +21 -3
- package/src/components/ui/index.ts +2 -0
- package/src/hooks/ui/use-content-breakpoint.ts +21 -2
- package/src/hooks/ui/use-media-query.ts +1 -0
- package/src/types/data-sync.ts +4 -1
- package/src/utils/presentation-for.ts +10 -0
- package/dist/chunk-UAI4VMEF.cjs +0 -46
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useMemo } from "react";
|
|
4
|
+
import { cn } from "../../../utils/cn.js";
|
|
5
|
+
import { openInNewTab } from "../../../utils/open-in-new-tab.js";
|
|
6
|
+
import { ArrowRightUpIcon } from "../../icons-v2-generated/arrows/arrow-right-up-icon.js";
|
|
7
|
+
import { Button } from "../../ui/button/index.js";
|
|
8
|
+
import { DataTable, dataTableLoadingRows, useDataTable } from "../../ui/data-table/index.js";
|
|
9
|
+
import { useLoadingScope } from "../../ui/loading-scope.js";
|
|
10
|
+
import { SquareAvatar } from "../../ui/square-avatar.js";
|
|
11
|
+
import { Tag } from "../../ui/tag.js";
|
|
12
|
+
import { TruncateText } from "../../ui/truncate-text.js";
|
|
13
|
+
import { TenantCell } from "./tenant-cell.js";
|
|
14
|
+
import { accessStateTag, formatLastRead, usersCountLabel } from "./tenant-presentation.js";
|
|
15
|
+
const SINGLE_CUSTOMER_TENANT_COLUMNS = {
|
|
16
|
+
tenant: { id: "tenant", header: "Tenant", width: "flex-1 min-w-0" },
|
|
17
|
+
customer: { id: "customer", header: "Customers", width: "w-[220px] content-lg:w-[340px]", hideAt: "md" },
|
|
18
|
+
access: { id: "access", header: "Access", width: "w-[200px] content-lg:w-[216px]" },
|
|
19
|
+
open: { id: "open", width: "w-12 shrink-0 flex-none", hideAt: "md", align: "right" }
|
|
20
|
+
};
|
|
21
|
+
const getRowId = (row) => row.id;
|
|
22
|
+
const columnMeta = ({ width, hideAt, align }) => ({ width, hideAt, align });
|
|
23
|
+
const loadingTenant = (id) => ({
|
|
24
|
+
id,
|
|
25
|
+
name: "",
|
|
26
|
+
provider: "",
|
|
27
|
+
customer: { name: "" },
|
|
28
|
+
accessState: ""
|
|
29
|
+
});
|
|
30
|
+
function SingleCustomerTenantCustomerCell({
|
|
31
|
+
name,
|
|
32
|
+
imageUrl,
|
|
33
|
+
userCount
|
|
34
|
+
}) {
|
|
35
|
+
const loading = useLoadingScope();
|
|
36
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col justify-center", children: [
|
|
37
|
+
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-[var(--spacing-system-xxs)]", children: [
|
|
38
|
+
/* @__PURE__ */ jsx(SquareAvatar, { src: imageUrl ?? void 0, alt: name, fallback: name, size: "xs", variant: "square" }),
|
|
39
|
+
/* @__PURE__ */ jsx(TruncateText, { children: name })
|
|
40
|
+
] }),
|
|
41
|
+
/* @__PURE__ */ jsx(TruncateText, { variant: "h6", tone: "secondary", loading, children: usersCountLabel(userCount) })
|
|
42
|
+
] });
|
|
43
|
+
}
|
|
44
|
+
function SingleCustomerTenantAccessCell({
|
|
45
|
+
accessState,
|
|
46
|
+
lastReadAt,
|
|
47
|
+
now
|
|
48
|
+
}) {
|
|
49
|
+
const loading = useLoadingScope();
|
|
50
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col justify-center gap-[var(--spacing-system-xxs)]", children: [
|
|
51
|
+
/* @__PURE__ */ jsx(Tag, { ...accessStateTag(accessState), loading, className: "self-start" }),
|
|
52
|
+
/* @__PURE__ */ jsx(TruncateText, { variant: "h6", tone: "secondary", loading, children: `Last read: ${formatLastRead(lastReadAt, now)}` })
|
|
53
|
+
] });
|
|
54
|
+
}
|
|
55
|
+
function OpenTenantButton({ href, name }) {
|
|
56
|
+
const loading = useLoadingScope();
|
|
57
|
+
return (
|
|
58
|
+
// The row itself is the details link; a nested `<a>` is invalid, so this opens the same href.
|
|
59
|
+
/* @__PURE__ */ jsx("div", { "data-no-row-click": true, className: "pointer-events-auto flex items-center justify-end", children: /* @__PURE__ */ jsx(
|
|
60
|
+
Button,
|
|
61
|
+
{
|
|
62
|
+
onClick: loading ? void 0 : openInNewTab(href),
|
|
63
|
+
disabled: loading,
|
|
64
|
+
variant: "outline",
|
|
65
|
+
size: "icon",
|
|
66
|
+
leftIcon: /* @__PURE__ */ jsx(ArrowRightUpIcon, { className: "h-5 w-5" }),
|
|
67
|
+
"aria-label": `Open ${name} in new tab`,
|
|
68
|
+
className: "bg-ods-card"
|
|
69
|
+
}
|
|
70
|
+
) })
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
const TENANTS_TABLE_SKELETON_ROWS = 20;
|
|
74
|
+
function SingleCustomerTenantsTableView({
|
|
75
|
+
rows,
|
|
76
|
+
getHref,
|
|
77
|
+
search = "",
|
|
78
|
+
isPending = false,
|
|
79
|
+
totalCount,
|
|
80
|
+
stickyHeaderOffset,
|
|
81
|
+
skeletonRows = TENANTS_TABLE_SKELETON_ROWS,
|
|
82
|
+
hasNextPage = false,
|
|
83
|
+
isFetchingNextPage = false,
|
|
84
|
+
onLoadMore,
|
|
85
|
+
now
|
|
86
|
+
}) {
|
|
87
|
+
const columns = useMemo(
|
|
88
|
+
() => [
|
|
89
|
+
{
|
|
90
|
+
id: SINGLE_CUSTOMER_TENANT_COLUMNS.tenant.id,
|
|
91
|
+
header: SINGLE_CUSTOMER_TENANT_COLUMNS.tenant.header,
|
|
92
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(TenantCell, { provider: row.original.provider, name: row.original.name, domain: row.original.domain }),
|
|
93
|
+
enableSorting: false,
|
|
94
|
+
meta: columnMeta(SINGLE_CUSTOMER_TENANT_COLUMNS.tenant)
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: SINGLE_CUSTOMER_TENANT_COLUMNS.customer.id,
|
|
98
|
+
header: SINGLE_CUSTOMER_TENANT_COLUMNS.customer.header,
|
|
99
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(
|
|
100
|
+
SingleCustomerTenantCustomerCell,
|
|
101
|
+
{
|
|
102
|
+
name: row.original.customer.name,
|
|
103
|
+
imageUrl: row.original.customer.imageUrl,
|
|
104
|
+
userCount: row.original.userCount
|
|
105
|
+
}
|
|
106
|
+
),
|
|
107
|
+
enableSorting: false,
|
|
108
|
+
meta: columnMeta(SINGLE_CUSTOMER_TENANT_COLUMNS.customer)
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
id: SINGLE_CUSTOMER_TENANT_COLUMNS.access.id,
|
|
112
|
+
header: SINGLE_CUSTOMER_TENANT_COLUMNS.access.header,
|
|
113
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(
|
|
114
|
+
SingleCustomerTenantAccessCell,
|
|
115
|
+
{
|
|
116
|
+
accessState: row.original.accessState,
|
|
117
|
+
lastReadAt: row.original.lastReadAt,
|
|
118
|
+
now
|
|
119
|
+
}
|
|
120
|
+
),
|
|
121
|
+
enableSorting: false,
|
|
122
|
+
meta: columnMeta(SINGLE_CUSTOMER_TENANT_COLUMNS.access)
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: SINGLE_CUSTOMER_TENANT_COLUMNS.open.id,
|
|
126
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(OpenTenantButton, { href: getHref(row.original), name: row.original.name }),
|
|
127
|
+
enableSorting: false,
|
|
128
|
+
meta: columnMeta(SINGLE_CUSTOMER_TENANT_COLUMNS.open)
|
|
129
|
+
}
|
|
130
|
+
],
|
|
131
|
+
[getHref, now]
|
|
132
|
+
);
|
|
133
|
+
const loading = useLoadingScope();
|
|
134
|
+
const loadingRows = useMemo(
|
|
135
|
+
() => loading ? dataTableLoadingRows(skeletonRows, loadingTenant) : null,
|
|
136
|
+
[loading, skeletonRows]
|
|
137
|
+
);
|
|
138
|
+
const table = useDataTable({ data: loadingRows ?? rows, columns, getRowId, enableSorting: false });
|
|
139
|
+
return (
|
|
140
|
+
// Dim, don't unmount, the stale rows while a deferred search refetches.
|
|
141
|
+
/* @__PURE__ */ jsx("div", { className: cn("transition-opacity duration-200", isPending && "opacity-60"), children: /* @__PURE__ */ jsxs(DataTable, { table, children: [
|
|
142
|
+
/* @__PURE__ */ jsx(
|
|
143
|
+
DataTable.Header,
|
|
144
|
+
{
|
|
145
|
+
stickyHeader: stickyHeaderOffset !== void 0,
|
|
146
|
+
stickyHeaderOffset,
|
|
147
|
+
rightSlot: /* @__PURE__ */ jsx(DataTable.RowCount, { itemName: "result", totalCount: totalCount ?? rows.length, loading })
|
|
148
|
+
}
|
|
149
|
+
),
|
|
150
|
+
/* @__PURE__ */ jsx(
|
|
151
|
+
DataTable.Body,
|
|
152
|
+
{
|
|
153
|
+
loadingCells: true,
|
|
154
|
+
skeletonRows,
|
|
155
|
+
emptyState: {
|
|
156
|
+
title: "No tenants match",
|
|
157
|
+
description: `Nothing matches "${search}". Try a different name, domain or customer.`
|
|
158
|
+
},
|
|
159
|
+
rowClassName: "mb-[var(--spacing-system-xxs)]",
|
|
160
|
+
rowHref: getHref
|
|
161
|
+
}
|
|
162
|
+
),
|
|
163
|
+
rows.length > 0 && onLoadMore && /* @__PURE__ */ jsx(
|
|
164
|
+
DataTable.InfiniteFooter,
|
|
165
|
+
{
|
|
166
|
+
hasNextPage,
|
|
167
|
+
isFetchingNextPage,
|
|
168
|
+
onLoadMore
|
|
169
|
+
}
|
|
170
|
+
)
|
|
171
|
+
] }) })
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
export {
|
|
175
|
+
SingleCustomerTenantsTableView
|
|
176
|
+
};
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
export interface TenantAccessCellProps {
|
|
2
2
|
accessState: string;
|
|
3
3
|
lastReadAt?: string | null;
|
|
4
|
+
/** A person paused the sync: said instead of the last read. */
|
|
5
|
+
syncPaused?: boolean;
|
|
4
6
|
/** The clock "Last read" is relative to. Default: the moment of the render. */
|
|
5
7
|
now?: Date;
|
|
6
8
|
}
|
|
7
|
-
/** ACCESS column: the access tag over "Last read: ...". */
|
|
8
|
-
export declare function TenantAccessCell({ accessState, lastReadAt, now }: TenantAccessCellProps): import("react").JSX.Element;
|
|
9
|
+
/** ACCESS column: the access tag over "Last read: ..." or "Sync paused"; a phone keeps the tag alone (Figma 3033-9343). */
|
|
10
|
+
export declare function TenantAccessCell({ accessState, lastReadAt, syncPaused, now }: TenantAccessCellProps): import("react").JSX.Element;
|
|
9
11
|
//# sourceMappingURL=tenant-access-cell.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-access-cell.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-access-cell.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+EAA+E;IAC/E,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,
|
|
1
|
+
{"version":3,"file":"tenant-access-cell.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-access-cell.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,+DAA+D;IAC/D,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,2HAA2H;AAC3H,wBAAgB,gBAAgB,CAAC,EAAE,WAAW,EAAE,UAAU,EAAE,UAAkB,EAAE,GAAG,EAAE,EAAE,qBAAqB,+BAgB3G"}
|
|
@@ -4,11 +4,12 @@ import { useLoadingScope } from "../../ui/loading-scope.js";
|
|
|
4
4
|
import { Tag } from "../../ui/tag.js";
|
|
5
5
|
import { TruncateText } from "../../ui/truncate-text.js";
|
|
6
6
|
import { accessStateTag, formatLastRead } from "./tenant-presentation.js";
|
|
7
|
-
function TenantAccessCell({ accessState, lastReadAt, now }) {
|
|
7
|
+
function TenantAccessCell({ accessState, lastReadAt, syncPaused = false, now }) {
|
|
8
8
|
const loading = useLoadingScope();
|
|
9
|
+
const line = syncPaused ? "Sync paused" : lastReadAt ? `Last read: ${formatLastRead(lastReadAt, now)}` : null;
|
|
9
10
|
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col justify-center gap-[var(--spacing-system-xxs)]", children: [
|
|
10
11
|
/* @__PURE__ */ jsx(Tag, { ...accessStateTag(accessState), loading, className: "self-start" }),
|
|
11
|
-
/* @__PURE__ */ jsx(TruncateText, { variant: "h6", tone: "secondary", loading, children:
|
|
12
|
+
(loading || line) && /* @__PURE__ */ jsx("div", { className: "hidden min-w-0 content-md:block", children: /* @__PURE__ */ jsx(TruncateText, { variant: "h6", tone: "secondary", loading, children: line ?? "" }) })
|
|
12
13
|
] });
|
|
13
14
|
}
|
|
14
15
|
export {
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
import type { TenantCustomer } from './tenant-row';
|
|
1
2
|
export interface TenantCustomerCellProps {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
imageUrl?: string | null;
|
|
3
|
+
/** In the host's order: the cell names the first and counts the rest. */
|
|
4
|
+
customers: readonly TenantCustomer[];
|
|
5
5
|
userCount?: number | null;
|
|
6
|
+
/** Users no customer's rule claims: while there are any, the count line says how many, in the warning colour. */
|
|
7
|
+
unattributedUserCount?: number | null;
|
|
8
|
+
/** Nothing has been read from this directory yet: the count line says so. */
|
|
9
|
+
neverRead?: boolean;
|
|
6
10
|
}
|
|
7
|
-
/**
|
|
8
|
-
|
|
11
|
+
/**
|
|
12
|
+
* CUSTOMERS column: the first customer's logo + name and "+N" for the rest, over the synced user count — or
|
|
13
|
+
* "30 of 412 unattributed" while some users belong to no customer, or "Never read" before the first read.
|
|
14
|
+
*/
|
|
15
|
+
export declare function TenantCustomerCell({ customers, userCount, unattributedUserCount, neverRead, }: TenantCustomerCellProps): import("react").JSX.Element;
|
|
9
16
|
//# sourceMappingURL=tenant-customer-cell.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-customer-cell.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-customer-cell.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tenant-customer-cell.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-customer-cell.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,uBAAuB;IACtC,yEAAyE;IACzE,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;IACrC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iHAAiH;IACjH,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,SAAS,EACT,SAAS,EACT,qBAAqB,EACrB,SAAiB,GAClB,EAAE,uBAAuB,+BAsCzB"}
|
|
@@ -3,15 +3,46 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { useLoadingScope } from "../../ui/loading-scope.js";
|
|
4
4
|
import { SquareAvatar } from "../../ui/square-avatar.js";
|
|
5
5
|
import { TruncateText } from "../../ui/truncate-text.js";
|
|
6
|
-
import {
|
|
7
|
-
function TenantCustomerCell({
|
|
6
|
+
import { lowercaseUsersCountLabel, TENANT_EMPTY_VALUE, unattributedLabel } from "./tenant-presentation.js";
|
|
7
|
+
function TenantCustomerCell({
|
|
8
|
+
customers,
|
|
9
|
+
userCount,
|
|
10
|
+
unattributedUserCount,
|
|
11
|
+
neverRead = false
|
|
12
|
+
}) {
|
|
8
13
|
const loading = useLoadingScope();
|
|
14
|
+
const [first] = customers;
|
|
15
|
+
const more = customers.length - 1;
|
|
16
|
+
const unattributed = unattributedLabel(unattributedUserCount, userCount);
|
|
9
17
|
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col justify-center", children: [
|
|
10
|
-
/* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-[var(--spacing-system-xxs)]", children: [
|
|
11
|
-
/* @__PURE__ */ jsx(
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
18
|
+
first ? /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-[var(--spacing-system-xxs)]", children: [
|
|
19
|
+
/* @__PURE__ */ jsx(
|
|
20
|
+
SquareAvatar,
|
|
21
|
+
{
|
|
22
|
+
src: first.imageUrl ?? void 0,
|
|
23
|
+
alt: first.name,
|
|
24
|
+
fallback: first.name,
|
|
25
|
+
size: "xs",
|
|
26
|
+
variant: "square"
|
|
27
|
+
}
|
|
28
|
+
),
|
|
29
|
+
/* @__PURE__ */ jsx(TruncateText, { children: first.name }),
|
|
30
|
+
more > 0 && /* @__PURE__ */ jsxs("span", { className: "shrink-0 text-ods-text-secondary text-h4", children: [
|
|
31
|
+
"+",
|
|
32
|
+
more,
|
|
33
|
+
/* @__PURE__ */ jsx("span", { className: "sr-only", children: more === 1 ? " more customer" : " more customers" })
|
|
34
|
+
] })
|
|
35
|
+
] }) : /* @__PURE__ */ jsx(TruncateText, { children: TENANT_EMPTY_VALUE }),
|
|
36
|
+
/* @__PURE__ */ jsx(
|
|
37
|
+
TruncateText,
|
|
38
|
+
{
|
|
39
|
+
variant: "h6",
|
|
40
|
+
tone: "secondary",
|
|
41
|
+
loading,
|
|
42
|
+
className: unattributed ? "text-ods-warning" : void 0,
|
|
43
|
+
children: unattributed ?? (neverRead ? "Never read" : lowercaseUsersCountLabel(userCount))
|
|
44
|
+
}
|
|
45
|
+
)
|
|
15
46
|
] });
|
|
16
47
|
}
|
|
17
48
|
export {
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TenantLicenseSummary } from './tenant-row';
|
|
2
|
+
export interface TenantLicensesCellProps {
|
|
3
|
+
licenses?: TenantLicenseSummary | null;
|
|
4
|
+
}
|
|
5
|
+
/** LICENCES column: assigned of purchased over what is unused (Figma 3025-3536). */
|
|
6
|
+
export declare function TenantLicensesCell({ licenses }: TenantLicensesCellProps): import("react").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=tenant-licenses-cell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tenant-licenses-cell.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-licenses-cell.tsx"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CACxC;AAED,oFAAoF;AACpF,wBAAgB,kBAAkB,CAAC,EAAE,QAAQ,EAAE,EAAE,uBAAuB,+BAcvE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { cn } from "../../../utils/cn.js";
|
|
4
|
+
import { useLoadingScope } from "../../ui/loading-scope.js";
|
|
5
|
+
import { TruncateText } from "../../ui/truncate-text.js";
|
|
6
|
+
import { licenseSummaryLines } from "./tenant-presentation.js";
|
|
7
|
+
function TenantLicensesCell({ licenses }) {
|
|
8
|
+
const loading = useLoadingScope();
|
|
9
|
+
const { value, detail, warning } = licenseSummaryLines(licenses);
|
|
10
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 flex-col justify-center", children: [
|
|
11
|
+
/* @__PURE__ */ jsx(TruncateText, { loading, children: value }),
|
|
12
|
+
(loading || detail) && /* @__PURE__ */ jsx(TruncateText, { variant: "h6", tone: "secondary", loading, className: cn(warning && "text-ods-warning"), children: detail ?? "" })
|
|
13
|
+
] });
|
|
14
|
+
}
|
|
15
|
+
export {
|
|
16
|
+
TenantLicensesCell
|
|
17
|
+
};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ComponentType, SVGProps } from 'react';
|
|
2
2
|
import type { TagProps } from '../../ui/tag';
|
|
3
|
+
import type { TenantLicenseSummary } from './tenant-row';
|
|
3
4
|
/** What a cell shows when it has no value. */
|
|
4
5
|
export declare const TENANT_EMPTY_VALUE = "\u2014";
|
|
5
6
|
type TagVariant = NonNullable<TagProps['variant']>;
|
|
@@ -38,5 +39,23 @@ export declare function lastReadAt(connection: {
|
|
|
38
39
|
export declare function formatLastRead(iso: string | null | undefined, now?: Date): string;
|
|
39
40
|
/** "227 Users" under the customer, the empty mark before the first read. */
|
|
40
41
|
export declare function usersCountLabel(count: number | null | undefined): string;
|
|
42
|
+
/** The multi-customer list's count line (Figma 3025-3536): "227 users", the empty mark before the first read. */
|
|
43
|
+
export declare function lowercaseUsersCountLabel(count: number | null | undefined): string;
|
|
44
|
+
/**
|
|
45
|
+
* "30 of 412 unattributed" while some synced users belong to no customer (no customer's rule claims them), or `null`
|
|
46
|
+
* while every user is attributed or nothing has been read.
|
|
47
|
+
*/
|
|
48
|
+
export declare function unattributedLabel(unattributed: number | null | undefined, users: number | null | undefined): string | null;
|
|
49
|
+
export interface TenantLicenseLines {
|
|
50
|
+
value: string;
|
|
51
|
+
detail: string | null;
|
|
52
|
+
/** The detail is worth a look: draw it in the warning colour. */
|
|
53
|
+
warning: boolean;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The LICENCES cell: "118 of 120" over "2 unused"; "88 assigned" over "Total not available" where the provider reports
|
|
57
|
+
* no purchased seats; the empty mark until the numbers have been read.
|
|
58
|
+
*/
|
|
59
|
+
export declare function licenseSummaryLines(summary: TenantLicenseSummary | null | undefined): TenantLicenseLines;
|
|
41
60
|
export {};
|
|
42
61
|
//# sourceMappingURL=tenant-presentation.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-presentation.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-presentation.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"tenant-presentation.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-presentation.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAOrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAEzD,8CAA8C;AAC9C,eAAO,MAAM,kBAAkB,WAAM,CAAC;AAEtC,KAAK,UAAU,GAAG,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,UAAU,CAAC;CACrB;AAED,2DAA2D;AAC3D,MAAM,MAAM,iBAAiB,GAC3B,cAAc,GAAG,gBAAgB,GAAG,iBAAiB,GAAG,WAAW,GAAG,iBAAiB,GAAG,eAAe,CAAC;AAE5G,oDAAoD;AACpD,MAAM,MAAM,cAAc,GAAG,eAAe,GAAG,kBAAkB,CAAC;AAelE,iFAAiF;AACjF,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,eAAe,CAEhF;AAED,kGAAkG;AAClG,MAAM,MAAM,YAAY,GAAG,aAAa,CACtC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,CAC7F,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,YAAY,CAAC;CACpB;AAOD,iGAAiG;AACjG,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,YAAY,CAE9E;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,UAAU,EAAE;IAAE,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,GAAG,IAAI,CAEvF;AAaD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG,GAAE,IAAiB,GAAG,MAAM,CAI7F;AAED,4EAA4E;AAC5E,wBAAgB,eAAe,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGxE;AAED,iHAAiH;AACjH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAGjF;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACvC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAC/B,MAAM,GAAG,IAAI,CAGf;AAKD,MAAM,WAAW,kBAAkB;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iEAAiE;IACjE,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,IAAI,GAAG,SAAS,GAAG,kBAAkB,CAUxG"}
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { formatRelativeTimeFrom } from "../../../utils/date-utils.js";
|
|
3
3
|
import { formatDate } from "../../../utils/format-date.js";
|
|
4
|
+
import { presentationFor } from "../../../utils/presentation-for.js";
|
|
4
5
|
import { GoogleLogoIcon } from "../../icons-v2-generated/brand-logos/google-logo-icon.js";
|
|
5
6
|
import { Office365LogoIcon } from "../../icons-v2-generated/brand-logos/office-365-logo-icon.js";
|
|
6
7
|
import { CodingForkIcon } from "../../icons-v2-generated/coding/coding-fork-icon.js";
|
|
7
8
|
const TENANT_EMPTY_VALUE = "\u2014";
|
|
8
|
-
function presentationFor(map, key) {
|
|
9
|
-
return key != null && key in map ? map[key] : void 0;
|
|
10
|
-
}
|
|
11
9
|
const ACCESS_STATE_PRESENTATION = {
|
|
12
10
|
DISCONNECTED: { label: "Disconnected", variant: "error" },
|
|
13
11
|
NOT_AUTHORISED: { label: "Not authorised", variant: "error" },
|
|
@@ -45,11 +43,34 @@ function usersCountLabel(count) {
|
|
|
45
43
|
if (count == null) return TENANT_EMPTY_VALUE;
|
|
46
44
|
return `${count} ${count === 1 ? "User" : "Users"}`;
|
|
47
45
|
}
|
|
46
|
+
function lowercaseUsersCountLabel(count) {
|
|
47
|
+
if (count == null) return TENANT_EMPTY_VALUE;
|
|
48
|
+
return `${count} ${count === 1 ? "user" : "users"}`;
|
|
49
|
+
}
|
|
50
|
+
function unattributedLabel(unattributed, users) {
|
|
51
|
+
if (unattributed == null || unattributed <= 0) return null;
|
|
52
|
+
return users == null ? `${unattributed} unattributed` : `${unattributed} of ${users} unattributed`;
|
|
53
|
+
}
|
|
54
|
+
const UNUSED_WARNING_SHARE = 0.1;
|
|
55
|
+
function licenseSummaryLines(summary) {
|
|
56
|
+
if (!summary) return { value: TENANT_EMPTY_VALUE, detail: null, warning: false };
|
|
57
|
+
const { assigned, purchased } = summary;
|
|
58
|
+
if (purchased == null) return { value: `${assigned} assigned`, detail: "Total not available", warning: false };
|
|
59
|
+
const unused = summary.unused ?? purchased - assigned;
|
|
60
|
+
return {
|
|
61
|
+
value: `${assigned} of ${purchased}`,
|
|
62
|
+
detail: unused < 0 ? `${-unused} over` : `${unused} unused`,
|
|
63
|
+
warning: unused > 0 && unused / purchased >= UNUSED_WARNING_SHARE
|
|
64
|
+
};
|
|
65
|
+
}
|
|
48
66
|
export {
|
|
49
67
|
TENANT_EMPTY_VALUE,
|
|
50
68
|
accessStateTag,
|
|
51
69
|
formatLastRead,
|
|
52
70
|
lastReadAt,
|
|
71
|
+
licenseSummaryLines,
|
|
72
|
+
lowercaseUsersCountLabel,
|
|
53
73
|
providerMark,
|
|
74
|
+
unattributedLabel,
|
|
54
75
|
usersCountLabel
|
|
55
76
|
};
|
|
@@ -1,17 +1,24 @@
|
|
|
1
|
-
/**
|
|
2
|
-
export interface
|
|
1
|
+
/** A customer a tenant's directory serves. */
|
|
2
|
+
export interface TenantCustomer {
|
|
3
|
+
name: string;
|
|
4
|
+
/** A URL the browser can load as is. */
|
|
5
|
+
imageUrl?: string | null;
|
|
6
|
+
}
|
|
7
|
+
/** A directory's seats over its paid SKUs. */
|
|
8
|
+
export interface TenantLicenseSummary {
|
|
9
|
+
assigned: number;
|
|
10
|
+
/** Absent when the provider does not report purchased seats (Google Workspace). */
|
|
11
|
+
purchased?: number | null;
|
|
12
|
+
/** Purchased minus assigned; negative when the provider counts suspended seats as assigned. */
|
|
13
|
+
unused?: number | null;
|
|
14
|
+
}
|
|
15
|
+
interface TenantRowBase {
|
|
3
16
|
id: string;
|
|
4
17
|
/** The tenant's own name in its directory. */
|
|
5
18
|
name: string;
|
|
6
19
|
/** The directory provider (`MICROSOFT_365`, `GOOGLE_WORKSPACE`); an unknown value keeps its raw name. */
|
|
7
20
|
provider: string;
|
|
8
21
|
domain?: string | null;
|
|
9
|
-
/** The customer the tenant belongs to. */
|
|
10
|
-
customer: {
|
|
11
|
-
name: string;
|
|
12
|
-
/** A URL the browser can load as is. */
|
|
13
|
-
imageUrl?: string | null;
|
|
14
|
-
};
|
|
15
22
|
/** Users read from the directory; absent before the first read. */
|
|
16
23
|
userCount?: number | null;
|
|
17
24
|
/** What the last access probe found (`WRITE_ENABLED`, `DISCONNECTED`, ...). */
|
|
@@ -19,4 +26,24 @@ export interface TenantRow {
|
|
|
19
26
|
/** When the directory was last read; absent when it never was. */
|
|
20
27
|
lastReadAt?: string | null;
|
|
21
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* A tenant of the single-customer list, `TenantsTableView`'s default variant, which accepts no other row: a
|
|
31
|
+
* multi-customer host that forgets `variant` does not compile. Deleted with that variant.
|
|
32
|
+
*/
|
|
33
|
+
export interface TenantRow extends TenantRowBase {
|
|
34
|
+
/** The customer the tenant belongs to. */
|
|
35
|
+
customer: TenantCustomer;
|
|
36
|
+
}
|
|
37
|
+
/** A tenant of the multi-customer list (`variant="multi-customer"`): a directory serving any number of customers. */
|
|
38
|
+
export interface MultiCustomerTenantRow extends TenantRowBase {
|
|
39
|
+
/** The customers the directory serves, in the order the host shows them; empty while it serves none. */
|
|
40
|
+
customers: readonly TenantCustomer[];
|
|
41
|
+
/** Of the users read, the users no customer's rule claims; absent before the first read. */
|
|
42
|
+
unattributedUserCount?: number | null;
|
|
43
|
+
/** A person paused the sync: the row says so instead of when it was last read. */
|
|
44
|
+
syncPaused?: boolean;
|
|
45
|
+
/** Absent until the licence numbers have been read. */
|
|
46
|
+
licenses?: TenantLicenseSummary | null;
|
|
47
|
+
}
|
|
48
|
+
export {};
|
|
22
49
|
//# sourceMappingURL=tenant-row.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenant-row.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-row.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"tenant-row.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenant-row.ts"],"names":[],"mappings":"AAAA,8CAA8C;AAC9C,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,mFAAmF;IACnF,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+FAA+F;IAC/F,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED,UAAU,aAAa;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,8CAA8C;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,yGAAyG;IACzG,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,mEAAmE;IACnE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,+EAA+E;IAC/E,WAAW,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,SAAU,SAAQ,aAAa;IAC9C,0CAA0C;IAC1C,QAAQ,EAAE,cAAc,CAAC;CAC1B;AAED,qHAAqH;AACrH,MAAM,WAAW,sBAAuB,SAAQ,aAAa;IAC3D,wGAAwG;IACxG,SAAS,EAAE,SAAS,cAAc,EAAE,CAAC;IACrC,4FAA4F;IAC5F,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,kFAAkF;IAClF,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,oBAAoB,GAAG,IAAI,CAAC;CACxC"}
|
|
@@ -8,8 +8,9 @@ export interface TenantsTableColumn {
|
|
|
8
8
|
align?: 'right';
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
11
|
-
* Column layout of the tenants list (Figma
|
|
12
|
-
*
|
|
11
|
+
* Column layout of the tenants list (Figma 3025-3536: Tenant, Customers, Licences, Access, open). A tablet drops the
|
|
12
|
+
* licence cells and keeps the funnel (3032-4579); a phone keeps the tenant, the access tag and open (3033-9343).
|
|
13
|
+
* Data-only on purpose: the live table and the route skeleton
|
|
13
14
|
* read the SAME widths, so nothing shifts when the rows arrive, and a skeleton
|
|
14
15
|
* never imports the table's cell renderers.
|
|
15
16
|
*/
|
|
@@ -25,6 +26,12 @@ export declare const TENANT_COLUMNS: {
|
|
|
25
26
|
width: string;
|
|
26
27
|
hideAt: "md";
|
|
27
28
|
};
|
|
29
|
+
licenses: {
|
|
30
|
+
id: string;
|
|
31
|
+
header: string;
|
|
32
|
+
width: string;
|
|
33
|
+
hideAt: "lg";
|
|
34
|
+
};
|
|
28
35
|
access: {
|
|
29
36
|
id: string;
|
|
30
37
|
header: string;
|
|
@@ -33,7 +40,6 @@ export declare const TENANT_COLUMNS: {
|
|
|
33
40
|
open: {
|
|
34
41
|
id: string;
|
|
35
42
|
width: string;
|
|
36
|
-
hideAt: "md";
|
|
37
43
|
align: "right";
|
|
38
44
|
};
|
|
39
45
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenants-table-columns.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenants-table-columns.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED
|
|
1
|
+
{"version":3,"file":"tenants-table-columns.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenants-table-columns.ts"],"names":[],"mappings":"AAAA,oGAAoG;AACpG,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uCAAuC;IACvC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,CAAC;IACpC,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAMmB,CAAC;AAE/C,2CAA2C;AAC3C,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAM9D,CAAC"}
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
const TENANT_COLUMNS = {
|
|
3
3
|
tenant: { id: "tenant", header: "Tenant", width: "flex-1 min-w-0" },
|
|
4
|
-
customer: { id: "customer", header: "Customers", width: "w-[220px] content-lg:w-[
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
customer: { id: "customer", header: "Customers", width: "w-[220px] content-lg:w-[280px]", hideAt: "md" },
|
|
5
|
+
licenses: { id: "licenses", header: "Licences", width: "w-[150px]", hideAt: "lg" },
|
|
6
|
+
access: { id: "access", header: "Access", width: "flex-none content-md:w-[200px] content-lg:w-[216px]" },
|
|
7
|
+
open: { id: "open", width: "w-12 shrink-0 flex-none", align: "right" }
|
|
7
8
|
};
|
|
8
9
|
const TENANTS_TABLE_COLUMNS = [
|
|
9
10
|
TENANT_COLUMNS.tenant,
|
|
10
11
|
TENANT_COLUMNS.customer,
|
|
12
|
+
TENANT_COLUMNS.licenses,
|
|
11
13
|
TENANT_COLUMNS.access,
|
|
12
14
|
TENANT_COLUMNS.open
|
|
13
15
|
];
|
|
@@ -1,14 +1,32 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type DataTableFilterOption } from '../../ui/data-table';
|
|
2
|
+
import { type SingleCustomerTenantsTableViewProps } from './single-customer-tenants-table-view';
|
|
3
|
+
import type { MultiCustomerTenantRow } from './tenant-row';
|
|
4
|
+
/** The columns whose header carries a funnel (Figma 3036-4860). */
|
|
5
|
+
export declare const TENANTS_TABLE_FILTER_COLUMNS: readonly ["tenant", "customer", "licenses", "access"];
|
|
6
|
+
export type TenantsTableFilterColumn = (typeof TENANTS_TABLE_FILTER_COLUMNS)[number];
|
|
7
|
+
/** Each column's funnel: what it offers, what is ticked. The host narrows the rows; the view only draws. */
|
|
8
|
+
export interface TenantsTableFilters {
|
|
9
|
+
/** A column the host leaves out has no funnel; one with no options draws its bare label. */
|
|
10
|
+
options: Partial<Record<TenantsTableFilterColumn, DataTableFilterOption[]>>;
|
|
11
|
+
selections: Readonly<Record<TenantsTableFilterColumn, readonly string[]>>;
|
|
12
|
+
onChange: (next: Record<TenantsTableFilterColumn, string[]>) => void;
|
|
13
|
+
/** The options are in flight: the funnels draw, inert. */
|
|
14
|
+
pending?: boolean;
|
|
15
|
+
}
|
|
2
16
|
/**
|
|
3
17
|
* Click handler that opens `href` in a new tab. The row is itself the details
|
|
4
18
|
* link and an `<a>` cannot be nested in an `<a>`, so the button opens it by script.
|
|
5
19
|
*/
|
|
6
|
-
|
|
7
|
-
|
|
20
|
+
interface MultiCustomerTenantsTableViewProps {
|
|
21
|
+
/** A directory per row that serves any number of customers, with its licences and the column funnels. */
|
|
22
|
+
variant: 'multi-customer';
|
|
23
|
+
rows: MultiCustomerTenantRow[];
|
|
8
24
|
/** Where a row leads: the row is a link to it, and its last cell opens it in a new tab. */
|
|
9
|
-
getHref: (row:
|
|
25
|
+
getHref: (row: MultiCustomerTenantRow) => string;
|
|
10
26
|
/** The search the rows answer; named by the "no match" message. */
|
|
11
27
|
search?: string;
|
|
28
|
+
/** The funnels of the column headers. Absent: none, as on the product page. */
|
|
29
|
+
filters?: TenantsTableFilters;
|
|
12
30
|
/** The rows on screen are the previous result of a search still loading: they dim. */
|
|
13
31
|
isPending?: boolean;
|
|
14
32
|
/** All matching tenants, loaded or not. Default: the rows given. */
|
|
@@ -21,6 +39,9 @@ export interface TenantsTableViewProps {
|
|
|
21
39
|
/** The clock "Last read" is relative to. Default: the moment of the render. */
|
|
22
40
|
now?: Date;
|
|
23
41
|
}
|
|
24
|
-
/** The
|
|
25
|
-
export
|
|
42
|
+
/** The single-customer list unless `variant` is 'multi-customer', the one that takes funnels and needs its own rows. */
|
|
43
|
+
export type TenantsTableViewProps = SingleCustomerTenantsTableViewProps | MultiCustomerTenantsTableViewProps;
|
|
44
|
+
/** The tenants list, in the layout its `variant` names. */
|
|
45
|
+
export declare function TenantsTableView(props: TenantsTableViewProps): import("react").JSX.Element;
|
|
46
|
+
export {};
|
|
26
47
|
//# sourceMappingURL=tenants-table-view.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tenants-table-view.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenants-table-view.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tenants-table-view.d.ts","sourceRoot":"","sources":["../../../../src/components/features/cloud-tenants/tenants-table-view.tsx"],"names":[],"mappings":"AAOA,OAAO,EAIL,KAAK,qBAAqB,EAI3B,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAEL,KAAK,mCAAmC,EACzC,MAAM,sCAAsC,CAAC;AAK9C,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAmC3D,mEAAmE;AACnE,eAAO,MAAM,4BAA4B,uDAAwD,CAAC;AAElG,MAAM,MAAM,wBAAwB,GAAG,CAAC,OAAO,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC;AAErF,4GAA4G;AAC5G,MAAM,WAAW,mBAAmB;IAClC,4FAA4F;IAC5F,OAAO,EAAE,OAAO,CAAC,MAAM,CAAC,wBAAwB,EAAE,qBAAqB,EAAE,CAAC,CAAC,CAAC;IAC5E,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,wBAAwB,EAAE,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;IAC1E,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,wBAAwB,EAAE,MAAM,EAAE,CAAC,KAAK,IAAI,CAAC;IACrE,0DAA0D;IAC1D,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;GAGG;AACH,UAAU,kCAAkC;IAC1C,yGAAyG;IACzG,OAAO,EAAE,gBAAgB,CAAC;IAC1B,IAAI,EAAE,sBAAsB,EAAE,CAAC;IAC/B,2FAA2F;IAC3F,OAAO,EAAE,CAAC,GAAG,EAAE,sBAAsB,KAAK,MAAM,CAAC;IACjD,mEAAmE;IACnE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,+EAA+E;IAC/E,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,sFAAsF;IACtF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB,+EAA+E;IAC/E,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wHAAwH;AACxH,MAAM,MAAM,qBAAqB,GAAG,mCAAmC,GAAG,kCAAkC,CAAC;AAE7G,2DAA2D;AAC3D,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,qBAAqB,+BAM5D"}
|