@omnibase/shadcn 0.2.0 → 0.4.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/index.cjs +283 -62
- package/dist/index.d.cts +41 -1
- package/dist/index.d.ts +41 -1
- package/dist/index.js +281 -61
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -32,7 +32,8 @@ var index_exports = {};
|
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
CustomFlowForm: () => CustomFlowForm,
|
|
34
34
|
PricingTable: () => PricingTable,
|
|
35
|
-
SwitchActiveTenant: () => SwitchActiveTenant
|
|
35
|
+
SwitchActiveTenant: () => SwitchActiveTenant,
|
|
36
|
+
TenantCreator: () => TenantCreator
|
|
36
37
|
});
|
|
37
38
|
module.exports = __toCommonJS(index_exports);
|
|
38
39
|
|
|
@@ -307,84 +308,144 @@ function isUiNodeInputAttributes(attributes) {
|
|
|
307
308
|
return attributes && typeof attributes === "object" && "name" in attributes && "type" in attributes;
|
|
308
309
|
}
|
|
309
310
|
function CustomFlowForm({ flow, Header }) {
|
|
311
|
+
const nodesByGroup = flow.ui.nodes.reduce((groups, node) => {
|
|
312
|
+
const group = node.group || "default";
|
|
313
|
+
if (!groups[group]) {
|
|
314
|
+
groups[group] = [];
|
|
315
|
+
}
|
|
316
|
+
groups[group].push(node);
|
|
317
|
+
return groups;
|
|
318
|
+
}, {});
|
|
319
|
+
const oidcNodes = nodesByGroup.oidc || [];
|
|
320
|
+
const regularNodes = Object.entries(nodesByGroup).filter(([group]) => group !== "oidc").flatMap(([, nodes]) => nodes);
|
|
321
|
+
const csrfToken = regularNodes.find(
|
|
322
|
+
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.name === "csrf_token"
|
|
323
|
+
);
|
|
310
324
|
const hasSubmitButton = flow.ui.nodes.some(
|
|
311
325
|
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.type === "submit"
|
|
312
326
|
);
|
|
313
327
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
314
328
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Messages, { flow }),
|
|
315
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.
|
|
316
|
-
Header && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardTitle, { className: "text-center pb-
|
|
317
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(CardContent, { className: "space-y-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
const isHiddenField = node.attributes.type === "hidden";
|
|
322
|
-
const isVisibleField = !isHiddenField && !isSubmitButton;
|
|
323
|
-
if (isHiddenField) {
|
|
324
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
325
|
-
"input",
|
|
326
|
-
{
|
|
327
|
-
name: node.attributes.name,
|
|
328
|
-
type: "hidden",
|
|
329
|
-
value: node.attributes.value || "",
|
|
330
|
-
readOnly: true
|
|
331
|
-
},
|
|
332
|
-
node.attributes.name
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
if (isSubmitButton) {
|
|
336
|
-
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
337
|
-
Button,
|
|
338
|
-
{
|
|
339
|
-
type: "submit",
|
|
340
|
-
name: node.attributes.name,
|
|
341
|
-
value: node.attributes.value || "",
|
|
342
|
-
className: "w-full mt-2",
|
|
343
|
-
children: node.meta.label?.text || node.attributes.value || "Submit"
|
|
344
|
-
},
|
|
345
|
-
node.attributes.name
|
|
346
|
-
);
|
|
347
|
-
}
|
|
348
|
-
if (isVisibleField && [
|
|
349
|
-
"default",
|
|
350
|
-
"password",
|
|
351
|
-
"code",
|
|
352
|
-
"webauthn",
|
|
353
|
-
"passkey",
|
|
354
|
-
"totp",
|
|
355
|
-
"lookup_secret"
|
|
356
|
-
].includes(node.group)) {
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Card, { className: "w-full max-w-md mx-auto", children: [
|
|
330
|
+
Header && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardHeader, { children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(CardTitle, { className: "text-center pb-1", children: Header }) }),
|
|
331
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(CardContent, { className: "space-y-6", children: [
|
|
332
|
+
oidcNodes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "space-y-3", children: [
|
|
333
|
+
oidcNodes.map((node, index) => {
|
|
334
|
+
if (isUiNodeInputAttributes(node.attributes) && node.attributes.type === "submit") {
|
|
357
335
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
358
|
-
"
|
|
336
|
+
"form",
|
|
359
337
|
{
|
|
360
|
-
|
|
338
|
+
action: flow.ui.action,
|
|
339
|
+
method: flow.ui.method,
|
|
340
|
+
className: "w-full",
|
|
361
341
|
children: [
|
|
362
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
342
|
+
csrfToken && isUiNodeInputAttributes(csrfToken.attributes) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
343
|
+
"input",
|
|
344
|
+
{
|
|
345
|
+
name: csrfToken.attributes.name,
|
|
346
|
+
type: "hidden",
|
|
347
|
+
value: csrfToken.attributes.value || "",
|
|
348
|
+
readOnly: true
|
|
349
|
+
}
|
|
350
|
+
),
|
|
366
351
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
367
|
-
|
|
352
|
+
Button,
|
|
368
353
|
{
|
|
369
|
-
|
|
354
|
+
type: "submit",
|
|
370
355
|
name: node.attributes.name,
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
356
|
+
value: node.attributes.value || "",
|
|
357
|
+
variant: "outline",
|
|
358
|
+
className: "w-full",
|
|
359
|
+
children: node.meta.label?.text || node.attributes.value || "Sign in"
|
|
375
360
|
}
|
|
376
361
|
)
|
|
377
362
|
]
|
|
378
363
|
},
|
|
379
|
-
|
|
364
|
+
`oidc-${index}`
|
|
380
365
|
);
|
|
381
366
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
367
|
+
return null;
|
|
368
|
+
}),
|
|
369
|
+
regularNodes.some(
|
|
370
|
+
(node) => isUiNodeInputAttributes(node.attributes) && !["hidden", "submit"].includes(node.attributes.type)
|
|
371
|
+
) && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "relative my-6", children: [
|
|
372
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "w-full border-t border-border" }) }),
|
|
373
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "bg-background px-3 text-muted-foreground font-medium", children: "Or continue with email" }) })
|
|
374
|
+
] })
|
|
375
|
+
] }),
|
|
376
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("form", { action: flow.ui.action, method: flow.ui.method, children: [
|
|
377
|
+
regularNodes.map((node) => {
|
|
378
|
+
if (isUiNodeInputAttributes(node.attributes)) {
|
|
379
|
+
const isSubmitButton = node.attributes.type === "submit";
|
|
380
|
+
const isHiddenField = node.attributes.type === "hidden";
|
|
381
|
+
const isVisibleField = !isHiddenField && !isSubmitButton;
|
|
382
|
+
if (isHiddenField) {
|
|
383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
384
|
+
"input",
|
|
385
|
+
{
|
|
386
|
+
name: node.attributes.name,
|
|
387
|
+
type: "hidden",
|
|
388
|
+
value: node.attributes.value || "",
|
|
389
|
+
readOnly: true
|
|
390
|
+
},
|
|
391
|
+
node.attributes.name
|
|
392
|
+
);
|
|
393
|
+
}
|
|
394
|
+
if (isSubmitButton) {
|
|
395
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
396
|
+
Button,
|
|
397
|
+
{
|
|
398
|
+
type: "submit",
|
|
399
|
+
name: node.attributes.name,
|
|
400
|
+
value: node.attributes.value || "",
|
|
401
|
+
className: "w-full mt-2",
|
|
402
|
+
children: node.meta.label?.text || node.attributes.value || "Submit"
|
|
403
|
+
},
|
|
404
|
+
node.attributes.name
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
if (isVisibleField && [
|
|
408
|
+
"default",
|
|
409
|
+
"password",
|
|
410
|
+
"code",
|
|
411
|
+
"webauthn",
|
|
412
|
+
"passkey",
|
|
413
|
+
"totp",
|
|
414
|
+
"lookup_secret",
|
|
415
|
+
"profile"
|
|
416
|
+
].includes(node.group)) {
|
|
417
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
418
|
+
"div",
|
|
419
|
+
{
|
|
420
|
+
className: "space-y-2 mb-4",
|
|
421
|
+
children: [
|
|
422
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(Label, { htmlFor: node.attributes.name, children: [
|
|
423
|
+
node.meta.label?.text,
|
|
424
|
+
node.attributes.required && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "text-destructive ml-1", children: "*" })
|
|
425
|
+
] }),
|
|
426
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
427
|
+
Input,
|
|
428
|
+
{
|
|
429
|
+
id: node.attributes.name,
|
|
430
|
+
name: node.attributes.name,
|
|
431
|
+
type: node.attributes.type,
|
|
432
|
+
defaultValue: node.attributes.value || "",
|
|
433
|
+
required: node.attributes.required,
|
|
434
|
+
placeholder: `Enter your ${node.meta.label?.text?.toLowerCase() || node.attributes.name}`
|
|
435
|
+
}
|
|
436
|
+
)
|
|
437
|
+
]
|
|
438
|
+
},
|
|
439
|
+
node.meta.label?.id || node.attributes.name
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return null;
|
|
444
|
+
}),
|
|
445
|
+
!hasSubmitButton && !oidcNodes.length && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { type: "submit", className: "w-full", children: "Submit" })
|
|
446
|
+
] })
|
|
386
447
|
] })
|
|
387
|
-
] })
|
|
448
|
+
] })
|
|
388
449
|
] });
|
|
389
450
|
}
|
|
390
451
|
|
|
@@ -879,9 +940,169 @@ function PricingTable({
|
|
|
879
940
|
/* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "hidden lg:block", children: sortedProducts.length <= 3 ? staticLayout : desktopCarousel })
|
|
880
941
|
] });
|
|
881
942
|
}
|
|
943
|
+
|
|
944
|
+
// src/tenant-creator/index.tsx
|
|
945
|
+
var import_react = require("react");
|
|
946
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
947
|
+
function TenantCreator({
|
|
948
|
+
config = {},
|
|
949
|
+
formActions = {},
|
|
950
|
+
className
|
|
951
|
+
}) {
|
|
952
|
+
const [mode, setMode] = (0, import_react.useState)(
|
|
953
|
+
config.defaultMode || "create"
|
|
954
|
+
);
|
|
955
|
+
const [isLoading, setIsLoading] = (0, import_react.useState)(false);
|
|
956
|
+
const [organizationName, setOrganizationName] = (0, import_react.useState)(
|
|
957
|
+
config.createForm?.organizationName?.defaultValue || ""
|
|
958
|
+
);
|
|
959
|
+
const [billingEmail, setBillingEmail] = (0, import_react.useState)(
|
|
960
|
+
config.createForm?.billingEmail?.defaultValue || ""
|
|
961
|
+
);
|
|
962
|
+
const [token, setToken] = (0, import_react.useState)(
|
|
963
|
+
config.joinForm?.token?.defaultValue || ""
|
|
964
|
+
);
|
|
965
|
+
const handleCreateSubmit = async (e) => {
|
|
966
|
+
e.preventDefault();
|
|
967
|
+
if (!formActions.onCreateOrganization) return;
|
|
968
|
+
setIsLoading(true);
|
|
969
|
+
try {
|
|
970
|
+
await formActions.onCreateOrganization({
|
|
971
|
+
organizationName,
|
|
972
|
+
billingEmail
|
|
973
|
+
});
|
|
974
|
+
} finally {
|
|
975
|
+
setIsLoading(false);
|
|
976
|
+
}
|
|
977
|
+
};
|
|
978
|
+
const handleJoinSubmit = async (e) => {
|
|
979
|
+
e.preventDefault();
|
|
980
|
+
if (!formActions.onJoinOrganization) return;
|
|
981
|
+
setIsLoading(true);
|
|
982
|
+
try {
|
|
983
|
+
await formActions.onJoinOrganization({
|
|
984
|
+
token
|
|
985
|
+
});
|
|
986
|
+
} finally {
|
|
987
|
+
setIsLoading(false);
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Card, { className: cn("w-full max-w-md mx-auto", className), children: [
|
|
991
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(CardHeader, { children: [
|
|
992
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CardTitle, { children: "Organization Setup" }),
|
|
993
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(CardDescription, { children: "Choose how you want to get started with your organization." })
|
|
994
|
+
] }),
|
|
995
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(CardContent, { className: "space-y-6", children: [
|
|
996
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "grid grid-cols-2 rounded-lg bg-muted p-1", children: [
|
|
997
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
998
|
+
"label",
|
|
999
|
+
{
|
|
1000
|
+
className: cn(
|
|
1001
|
+
"flex cursor-pointer items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-all",
|
|
1002
|
+
mode === "create" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
|
|
1003
|
+
isLoading && "pointer-events-none opacity-50"
|
|
1004
|
+
),
|
|
1005
|
+
children: [
|
|
1006
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1007
|
+
"input",
|
|
1008
|
+
{
|
|
1009
|
+
type: "radio",
|
|
1010
|
+
name: "mode",
|
|
1011
|
+
value: "create",
|
|
1012
|
+
checked: mode === "create",
|
|
1013
|
+
onChange: () => setMode("create"),
|
|
1014
|
+
className: "sr-only",
|
|
1015
|
+
disabled: isLoading
|
|
1016
|
+
}
|
|
1017
|
+
),
|
|
1018
|
+
config.createOrganizationText || "Create Organization"
|
|
1019
|
+
]
|
|
1020
|
+
}
|
|
1021
|
+
),
|
|
1022
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
|
|
1023
|
+
"label",
|
|
1024
|
+
{
|
|
1025
|
+
className: cn(
|
|
1026
|
+
"flex cursor-pointer items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-all",
|
|
1027
|
+
mode === "join" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
|
|
1028
|
+
isLoading && "pointer-events-none opacity-50"
|
|
1029
|
+
),
|
|
1030
|
+
children: [
|
|
1031
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1032
|
+
"input",
|
|
1033
|
+
{
|
|
1034
|
+
type: "radio",
|
|
1035
|
+
name: "mode",
|
|
1036
|
+
value: "join",
|
|
1037
|
+
checked: mode === "join",
|
|
1038
|
+
onChange: () => setMode("join"),
|
|
1039
|
+
className: "sr-only",
|
|
1040
|
+
disabled: isLoading
|
|
1041
|
+
}
|
|
1042
|
+
),
|
|
1043
|
+
config.joinOrganizationText || "Join Organization"
|
|
1044
|
+
]
|
|
1045
|
+
}
|
|
1046
|
+
)
|
|
1047
|
+
] }),
|
|
1048
|
+
mode === "create" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("form", { onSubmit: handleCreateSubmit, className: "space-y-4", children: [
|
|
1049
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "space-y-2", children: [
|
|
1050
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Label, { htmlFor: "organizationName", children: config.createForm?.organizationName?.label || "Organization Name" }),
|
|
1051
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1052
|
+
Input,
|
|
1053
|
+
{
|
|
1054
|
+
id: "organizationName",
|
|
1055
|
+
type: "text",
|
|
1056
|
+
placeholder: config.createForm?.organizationName?.placeholder || "Enter organization name",
|
|
1057
|
+
value: organizationName,
|
|
1058
|
+
onChange: (e) => setOrganizationName(e.target.value),
|
|
1059
|
+
required: true,
|
|
1060
|
+
disabled: isLoading
|
|
1061
|
+
}
|
|
1062
|
+
)
|
|
1063
|
+
] }),
|
|
1064
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "space-y-2", children: [
|
|
1065
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Label, { htmlFor: "billingEmail", children: config.createForm?.billingEmail?.label || "Billing Email" }),
|
|
1066
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1067
|
+
Input,
|
|
1068
|
+
{
|
|
1069
|
+
id: "billingEmail",
|
|
1070
|
+
type: "email",
|
|
1071
|
+
placeholder: config.createForm?.billingEmail?.placeholder || "Enter billing email",
|
|
1072
|
+
value: billingEmail,
|
|
1073
|
+
onChange: (e) => setBillingEmail(e.target.value),
|
|
1074
|
+
required: true,
|
|
1075
|
+
disabled: isLoading
|
|
1076
|
+
}
|
|
1077
|
+
)
|
|
1078
|
+
] }),
|
|
1079
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? "Creating..." : "Create Organization" })
|
|
1080
|
+
] }),
|
|
1081
|
+
mode === "join" && /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("form", { onSubmit: handleJoinSubmit, className: "space-y-4", children: [
|
|
1082
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: "space-y-2", children: [
|
|
1083
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Label, { htmlFor: "token", children: config.joinForm?.token?.label || "Invitation Token" }),
|
|
1084
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1085
|
+
Input,
|
|
1086
|
+
{
|
|
1087
|
+
id: "token",
|
|
1088
|
+
type: "text",
|
|
1089
|
+
placeholder: config.joinForm?.token?.placeholder || "Enter invitation token",
|
|
1090
|
+
value: token,
|
|
1091
|
+
onChange: (e) => setToken(e.target.value),
|
|
1092
|
+
required: true,
|
|
1093
|
+
disabled: isLoading
|
|
1094
|
+
}
|
|
1095
|
+
)
|
|
1096
|
+
] }),
|
|
1097
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? "Joining..." : "Join Organization" })
|
|
1098
|
+
] })
|
|
1099
|
+
] })
|
|
1100
|
+
] });
|
|
1101
|
+
}
|
|
882
1102
|
// Annotate the CommonJS export names for ESM import in node:
|
|
883
1103
|
0 && (module.exports = {
|
|
884
1104
|
CustomFlowForm,
|
|
885
1105
|
PricingTable,
|
|
886
|
-
SwitchActiveTenant
|
|
1106
|
+
SwitchActiveTenant,
|
|
1107
|
+
TenantCreator
|
|
887
1108
|
});
|
package/dist/index.d.cts
CHANGED
|
@@ -49,4 +49,44 @@ interface PricingTableProps {
|
|
|
49
49
|
}
|
|
50
50
|
declare function PricingTable({ products, selectedPriceId, onPriceSelect, className, showPricingToggle, defaultInterval, }: PricingTableProps): react_jsx_runtime.JSX.Element;
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
interface TenantCreatorConfig {
|
|
53
|
+
createOrganizationText?: string;
|
|
54
|
+
joinOrganizationText?: string;
|
|
55
|
+
defaultMode?: "create" | "join";
|
|
56
|
+
createForm?: {
|
|
57
|
+
organizationName?: {
|
|
58
|
+
label?: string;
|
|
59
|
+
placeholder?: string;
|
|
60
|
+
defaultValue?: string;
|
|
61
|
+
};
|
|
62
|
+
billingEmail?: {
|
|
63
|
+
label?: string;
|
|
64
|
+
placeholder?: string;
|
|
65
|
+
defaultValue?: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
joinForm?: {
|
|
69
|
+
token?: {
|
|
70
|
+
label?: string;
|
|
71
|
+
placeholder?: string;
|
|
72
|
+
defaultValue?: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
interface TenantCreatorFormActions {
|
|
77
|
+
onCreateOrganization?: (data: {
|
|
78
|
+
organizationName: string;
|
|
79
|
+
billingEmail: string;
|
|
80
|
+
}) => void | Promise<void>;
|
|
81
|
+
onJoinOrganization?: (data: {
|
|
82
|
+
token: string;
|
|
83
|
+
}) => void | Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
interface TenantCreatorProps {
|
|
86
|
+
config?: TenantCreatorConfig;
|
|
87
|
+
formActions?: TenantCreatorFormActions;
|
|
88
|
+
className?: string;
|
|
89
|
+
}
|
|
90
|
+
declare function TenantCreator({ config, formActions, className, }: TenantCreatorProps): react_jsx_runtime.JSX.Element;
|
|
91
|
+
|
|
92
|
+
export { CustomFlowForm, type CustomFormProps, type FlowType, PricingTable, type PricingTableProps, SwitchActiveTenant, type SwitchActiveTenantProps, TenantCreator, type TenantCreatorConfig, type TenantCreatorFormActions, type TenantCreatorProps };
|
package/dist/index.d.ts
CHANGED
|
@@ -49,4 +49,44 @@ interface PricingTableProps {
|
|
|
49
49
|
}
|
|
50
50
|
declare function PricingTable({ products, selectedPriceId, onPriceSelect, className, showPricingToggle, defaultInterval, }: PricingTableProps): react_jsx_runtime.JSX.Element;
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
interface TenantCreatorConfig {
|
|
53
|
+
createOrganizationText?: string;
|
|
54
|
+
joinOrganizationText?: string;
|
|
55
|
+
defaultMode?: "create" | "join";
|
|
56
|
+
createForm?: {
|
|
57
|
+
organizationName?: {
|
|
58
|
+
label?: string;
|
|
59
|
+
placeholder?: string;
|
|
60
|
+
defaultValue?: string;
|
|
61
|
+
};
|
|
62
|
+
billingEmail?: {
|
|
63
|
+
label?: string;
|
|
64
|
+
placeholder?: string;
|
|
65
|
+
defaultValue?: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
joinForm?: {
|
|
69
|
+
token?: {
|
|
70
|
+
label?: string;
|
|
71
|
+
placeholder?: string;
|
|
72
|
+
defaultValue?: string;
|
|
73
|
+
};
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
interface TenantCreatorFormActions {
|
|
77
|
+
onCreateOrganization?: (data: {
|
|
78
|
+
organizationName: string;
|
|
79
|
+
billingEmail: string;
|
|
80
|
+
}) => void | Promise<void>;
|
|
81
|
+
onJoinOrganization?: (data: {
|
|
82
|
+
token: string;
|
|
83
|
+
}) => void | Promise<void>;
|
|
84
|
+
}
|
|
85
|
+
interface TenantCreatorProps {
|
|
86
|
+
config?: TenantCreatorConfig;
|
|
87
|
+
formActions?: TenantCreatorFormActions;
|
|
88
|
+
className?: string;
|
|
89
|
+
}
|
|
90
|
+
declare function TenantCreator({ config, formActions, className, }: TenantCreatorProps): react_jsx_runtime.JSX.Element;
|
|
91
|
+
|
|
92
|
+
export { CustomFlowForm, type CustomFormProps, type FlowType, PricingTable, type PricingTableProps, SwitchActiveTenant, type SwitchActiveTenantProps, TenantCreator, type TenantCreatorConfig, type TenantCreatorFormActions, type TenantCreatorProps };
|
package/dist/index.js
CHANGED
|
@@ -269,84 +269,144 @@ function isUiNodeInputAttributes(attributes) {
|
|
|
269
269
|
return attributes && typeof attributes === "object" && "name" in attributes && "type" in attributes;
|
|
270
270
|
}
|
|
271
271
|
function CustomFlowForm({ flow, Header }) {
|
|
272
|
+
const nodesByGroup = flow.ui.nodes.reduce((groups, node) => {
|
|
273
|
+
const group = node.group || "default";
|
|
274
|
+
if (!groups[group]) {
|
|
275
|
+
groups[group] = [];
|
|
276
|
+
}
|
|
277
|
+
groups[group].push(node);
|
|
278
|
+
return groups;
|
|
279
|
+
}, {});
|
|
280
|
+
const oidcNodes = nodesByGroup.oidc || [];
|
|
281
|
+
const regularNodes = Object.entries(nodesByGroup).filter(([group]) => group !== "oidc").flatMap(([, nodes]) => nodes);
|
|
282
|
+
const csrfToken = regularNodes.find(
|
|
283
|
+
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.name === "csrf_token"
|
|
284
|
+
);
|
|
272
285
|
const hasSubmitButton = flow.ui.nodes.some(
|
|
273
286
|
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.type === "submit"
|
|
274
287
|
);
|
|
275
288
|
return /* @__PURE__ */ jsxs("div", { children: [
|
|
276
289
|
/* @__PURE__ */ jsx7(Messages, { flow }),
|
|
277
|
-
/* @__PURE__ */
|
|
278
|
-
Header && /* @__PURE__ */ jsx7(CardHeader, { children: /* @__PURE__ */ jsx7(CardTitle, { className: "text-center pb-
|
|
279
|
-
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
const isHiddenField = node.attributes.type === "hidden";
|
|
284
|
-
const isVisibleField = !isHiddenField && !isSubmitButton;
|
|
285
|
-
if (isHiddenField) {
|
|
286
|
-
return /* @__PURE__ */ jsx7(
|
|
287
|
-
"input",
|
|
288
|
-
{
|
|
289
|
-
name: node.attributes.name,
|
|
290
|
-
type: "hidden",
|
|
291
|
-
value: node.attributes.value || "",
|
|
292
|
-
readOnly: true
|
|
293
|
-
},
|
|
294
|
-
node.attributes.name
|
|
295
|
-
);
|
|
296
|
-
}
|
|
297
|
-
if (isSubmitButton) {
|
|
298
|
-
return /* @__PURE__ */ jsx7(
|
|
299
|
-
Button,
|
|
300
|
-
{
|
|
301
|
-
type: "submit",
|
|
302
|
-
name: node.attributes.name,
|
|
303
|
-
value: node.attributes.value || "",
|
|
304
|
-
className: "w-full mt-2",
|
|
305
|
-
children: node.meta.label?.text || node.attributes.value || "Submit"
|
|
306
|
-
},
|
|
307
|
-
node.attributes.name
|
|
308
|
-
);
|
|
309
|
-
}
|
|
310
|
-
if (isVisibleField && [
|
|
311
|
-
"default",
|
|
312
|
-
"password",
|
|
313
|
-
"code",
|
|
314
|
-
"webauthn",
|
|
315
|
-
"passkey",
|
|
316
|
-
"totp",
|
|
317
|
-
"lookup_secret"
|
|
318
|
-
].includes(node.group)) {
|
|
290
|
+
/* @__PURE__ */ jsxs(Card, { className: "w-full max-w-md mx-auto", children: [
|
|
291
|
+
Header && /* @__PURE__ */ jsx7(CardHeader, { children: /* @__PURE__ */ jsx7(CardTitle, { className: "text-center pb-1", children: Header }) }),
|
|
292
|
+
/* @__PURE__ */ jsxs(CardContent, { className: "space-y-6", children: [
|
|
293
|
+
oidcNodes.length > 0 && /* @__PURE__ */ jsxs("div", { className: "space-y-3", children: [
|
|
294
|
+
oidcNodes.map((node, index) => {
|
|
295
|
+
if (isUiNodeInputAttributes(node.attributes) && node.attributes.type === "submit") {
|
|
319
296
|
return /* @__PURE__ */ jsxs(
|
|
320
|
-
"
|
|
297
|
+
"form",
|
|
321
298
|
{
|
|
322
|
-
|
|
299
|
+
action: flow.ui.action,
|
|
300
|
+
method: flow.ui.method,
|
|
301
|
+
className: "w-full",
|
|
323
302
|
children: [
|
|
324
|
-
/* @__PURE__ */
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
303
|
+
csrfToken && isUiNodeInputAttributes(csrfToken.attributes) && /* @__PURE__ */ jsx7(
|
|
304
|
+
"input",
|
|
305
|
+
{
|
|
306
|
+
name: csrfToken.attributes.name,
|
|
307
|
+
type: "hidden",
|
|
308
|
+
value: csrfToken.attributes.value || "",
|
|
309
|
+
readOnly: true
|
|
310
|
+
}
|
|
311
|
+
),
|
|
328
312
|
/* @__PURE__ */ jsx7(
|
|
329
|
-
|
|
313
|
+
Button,
|
|
330
314
|
{
|
|
331
|
-
|
|
315
|
+
type: "submit",
|
|
332
316
|
name: node.attributes.name,
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
317
|
+
value: node.attributes.value || "",
|
|
318
|
+
variant: "outline",
|
|
319
|
+
className: "w-full",
|
|
320
|
+
children: node.meta.label?.text || node.attributes.value || "Sign in"
|
|
337
321
|
}
|
|
338
322
|
)
|
|
339
323
|
]
|
|
340
324
|
},
|
|
341
|
-
|
|
325
|
+
`oidc-${index}`
|
|
342
326
|
);
|
|
343
327
|
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
328
|
+
return null;
|
|
329
|
+
}),
|
|
330
|
+
regularNodes.some(
|
|
331
|
+
(node) => isUiNodeInputAttributes(node.attributes) && !["hidden", "submit"].includes(node.attributes.type)
|
|
332
|
+
) && /* @__PURE__ */ jsxs("div", { className: "relative my-6", children: [
|
|
333
|
+
/* @__PURE__ */ jsx7("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ jsx7("span", { className: "w-full border-t border-border" }) }),
|
|
334
|
+
/* @__PURE__ */ jsx7("div", { className: "relative flex justify-center text-xs uppercase", children: /* @__PURE__ */ jsx7("span", { className: "bg-background px-3 text-muted-foreground font-medium", children: "Or continue with email" }) })
|
|
335
|
+
] })
|
|
336
|
+
] }),
|
|
337
|
+
/* @__PURE__ */ jsxs("form", { action: flow.ui.action, method: flow.ui.method, children: [
|
|
338
|
+
regularNodes.map((node) => {
|
|
339
|
+
if (isUiNodeInputAttributes(node.attributes)) {
|
|
340
|
+
const isSubmitButton = node.attributes.type === "submit";
|
|
341
|
+
const isHiddenField = node.attributes.type === "hidden";
|
|
342
|
+
const isVisibleField = !isHiddenField && !isSubmitButton;
|
|
343
|
+
if (isHiddenField) {
|
|
344
|
+
return /* @__PURE__ */ jsx7(
|
|
345
|
+
"input",
|
|
346
|
+
{
|
|
347
|
+
name: node.attributes.name,
|
|
348
|
+
type: "hidden",
|
|
349
|
+
value: node.attributes.value || "",
|
|
350
|
+
readOnly: true
|
|
351
|
+
},
|
|
352
|
+
node.attributes.name
|
|
353
|
+
);
|
|
354
|
+
}
|
|
355
|
+
if (isSubmitButton) {
|
|
356
|
+
return /* @__PURE__ */ jsx7(
|
|
357
|
+
Button,
|
|
358
|
+
{
|
|
359
|
+
type: "submit",
|
|
360
|
+
name: node.attributes.name,
|
|
361
|
+
value: node.attributes.value || "",
|
|
362
|
+
className: "w-full mt-2",
|
|
363
|
+
children: node.meta.label?.text || node.attributes.value || "Submit"
|
|
364
|
+
},
|
|
365
|
+
node.attributes.name
|
|
366
|
+
);
|
|
367
|
+
}
|
|
368
|
+
if (isVisibleField && [
|
|
369
|
+
"default",
|
|
370
|
+
"password",
|
|
371
|
+
"code",
|
|
372
|
+
"webauthn",
|
|
373
|
+
"passkey",
|
|
374
|
+
"totp",
|
|
375
|
+
"lookup_secret",
|
|
376
|
+
"profile"
|
|
377
|
+
].includes(node.group)) {
|
|
378
|
+
return /* @__PURE__ */ jsxs(
|
|
379
|
+
"div",
|
|
380
|
+
{
|
|
381
|
+
className: "space-y-2 mb-4",
|
|
382
|
+
children: [
|
|
383
|
+
/* @__PURE__ */ jsxs(Label, { htmlFor: node.attributes.name, children: [
|
|
384
|
+
node.meta.label?.text,
|
|
385
|
+
node.attributes.required && /* @__PURE__ */ jsx7("span", { className: "text-destructive ml-1", children: "*" })
|
|
386
|
+
] }),
|
|
387
|
+
/* @__PURE__ */ jsx7(
|
|
388
|
+
Input,
|
|
389
|
+
{
|
|
390
|
+
id: node.attributes.name,
|
|
391
|
+
name: node.attributes.name,
|
|
392
|
+
type: node.attributes.type,
|
|
393
|
+
defaultValue: node.attributes.value || "",
|
|
394
|
+
required: node.attributes.required,
|
|
395
|
+
placeholder: `Enter your ${node.meta.label?.text?.toLowerCase() || node.attributes.name}`
|
|
396
|
+
}
|
|
397
|
+
)
|
|
398
|
+
]
|
|
399
|
+
},
|
|
400
|
+
node.meta.label?.id || node.attributes.name
|
|
401
|
+
);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return null;
|
|
405
|
+
}),
|
|
406
|
+
!hasSubmitButton && !oidcNodes.length && /* @__PURE__ */ jsx7(Button, { type: "submit", className: "w-full", children: "Submit" })
|
|
407
|
+
] })
|
|
348
408
|
] })
|
|
349
|
-
] })
|
|
409
|
+
] })
|
|
350
410
|
] });
|
|
351
411
|
}
|
|
352
412
|
|
|
@@ -841,8 +901,168 @@ function PricingTable({
|
|
|
841
901
|
/* @__PURE__ */ jsx10("div", { className: "hidden lg:block", children: sortedProducts.length <= 3 ? staticLayout : desktopCarousel })
|
|
842
902
|
] });
|
|
843
903
|
}
|
|
904
|
+
|
|
905
|
+
// src/tenant-creator/index.tsx
|
|
906
|
+
import { useState as useState3 } from "react";
|
|
907
|
+
import { jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
908
|
+
function TenantCreator({
|
|
909
|
+
config = {},
|
|
910
|
+
formActions = {},
|
|
911
|
+
className
|
|
912
|
+
}) {
|
|
913
|
+
const [mode, setMode] = useState3(
|
|
914
|
+
config.defaultMode || "create"
|
|
915
|
+
);
|
|
916
|
+
const [isLoading, setIsLoading] = useState3(false);
|
|
917
|
+
const [organizationName, setOrganizationName] = useState3(
|
|
918
|
+
config.createForm?.organizationName?.defaultValue || ""
|
|
919
|
+
);
|
|
920
|
+
const [billingEmail, setBillingEmail] = useState3(
|
|
921
|
+
config.createForm?.billingEmail?.defaultValue || ""
|
|
922
|
+
);
|
|
923
|
+
const [token, setToken] = useState3(
|
|
924
|
+
config.joinForm?.token?.defaultValue || ""
|
|
925
|
+
);
|
|
926
|
+
const handleCreateSubmit = async (e) => {
|
|
927
|
+
e.preventDefault();
|
|
928
|
+
if (!formActions.onCreateOrganization) return;
|
|
929
|
+
setIsLoading(true);
|
|
930
|
+
try {
|
|
931
|
+
await formActions.onCreateOrganization({
|
|
932
|
+
organizationName,
|
|
933
|
+
billingEmail
|
|
934
|
+
});
|
|
935
|
+
} finally {
|
|
936
|
+
setIsLoading(false);
|
|
937
|
+
}
|
|
938
|
+
};
|
|
939
|
+
const handleJoinSubmit = async (e) => {
|
|
940
|
+
e.preventDefault();
|
|
941
|
+
if (!formActions.onJoinOrganization) return;
|
|
942
|
+
setIsLoading(true);
|
|
943
|
+
try {
|
|
944
|
+
await formActions.onJoinOrganization({
|
|
945
|
+
token
|
|
946
|
+
});
|
|
947
|
+
} finally {
|
|
948
|
+
setIsLoading(false);
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
return /* @__PURE__ */ jsxs5(Card, { className: cn("w-full max-w-md mx-auto", className), children: [
|
|
952
|
+
/* @__PURE__ */ jsxs5(CardHeader, { children: [
|
|
953
|
+
/* @__PURE__ */ jsx11(CardTitle, { children: "Organization Setup" }),
|
|
954
|
+
/* @__PURE__ */ jsx11(CardDescription, { children: "Choose how you want to get started with your organization." })
|
|
955
|
+
] }),
|
|
956
|
+
/* @__PURE__ */ jsxs5(CardContent, { className: "space-y-6", children: [
|
|
957
|
+
/* @__PURE__ */ jsxs5("div", { className: "grid grid-cols-2 rounded-lg bg-muted p-1", children: [
|
|
958
|
+
/* @__PURE__ */ jsxs5(
|
|
959
|
+
"label",
|
|
960
|
+
{
|
|
961
|
+
className: cn(
|
|
962
|
+
"flex cursor-pointer items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-all",
|
|
963
|
+
mode === "create" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
|
|
964
|
+
isLoading && "pointer-events-none opacity-50"
|
|
965
|
+
),
|
|
966
|
+
children: [
|
|
967
|
+
/* @__PURE__ */ jsx11(
|
|
968
|
+
"input",
|
|
969
|
+
{
|
|
970
|
+
type: "radio",
|
|
971
|
+
name: "mode",
|
|
972
|
+
value: "create",
|
|
973
|
+
checked: mode === "create",
|
|
974
|
+
onChange: () => setMode("create"),
|
|
975
|
+
className: "sr-only",
|
|
976
|
+
disabled: isLoading
|
|
977
|
+
}
|
|
978
|
+
),
|
|
979
|
+
config.createOrganizationText || "Create Organization"
|
|
980
|
+
]
|
|
981
|
+
}
|
|
982
|
+
),
|
|
983
|
+
/* @__PURE__ */ jsxs5(
|
|
984
|
+
"label",
|
|
985
|
+
{
|
|
986
|
+
className: cn(
|
|
987
|
+
"flex cursor-pointer items-center justify-center rounded-md px-3 py-2 text-sm font-medium transition-all",
|
|
988
|
+
mode === "join" ? "bg-background text-foreground shadow-sm" : "text-muted-foreground hover:text-foreground",
|
|
989
|
+
isLoading && "pointer-events-none opacity-50"
|
|
990
|
+
),
|
|
991
|
+
children: [
|
|
992
|
+
/* @__PURE__ */ jsx11(
|
|
993
|
+
"input",
|
|
994
|
+
{
|
|
995
|
+
type: "radio",
|
|
996
|
+
name: "mode",
|
|
997
|
+
value: "join",
|
|
998
|
+
checked: mode === "join",
|
|
999
|
+
onChange: () => setMode("join"),
|
|
1000
|
+
className: "sr-only",
|
|
1001
|
+
disabled: isLoading
|
|
1002
|
+
}
|
|
1003
|
+
),
|
|
1004
|
+
config.joinOrganizationText || "Join Organization"
|
|
1005
|
+
]
|
|
1006
|
+
}
|
|
1007
|
+
)
|
|
1008
|
+
] }),
|
|
1009
|
+
mode === "create" && /* @__PURE__ */ jsxs5("form", { onSubmit: handleCreateSubmit, className: "space-y-4", children: [
|
|
1010
|
+
/* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
|
|
1011
|
+
/* @__PURE__ */ jsx11(Label, { htmlFor: "organizationName", children: config.createForm?.organizationName?.label || "Organization Name" }),
|
|
1012
|
+
/* @__PURE__ */ jsx11(
|
|
1013
|
+
Input,
|
|
1014
|
+
{
|
|
1015
|
+
id: "organizationName",
|
|
1016
|
+
type: "text",
|
|
1017
|
+
placeholder: config.createForm?.organizationName?.placeholder || "Enter organization name",
|
|
1018
|
+
value: organizationName,
|
|
1019
|
+
onChange: (e) => setOrganizationName(e.target.value),
|
|
1020
|
+
required: true,
|
|
1021
|
+
disabled: isLoading
|
|
1022
|
+
}
|
|
1023
|
+
)
|
|
1024
|
+
] }),
|
|
1025
|
+
/* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
|
|
1026
|
+
/* @__PURE__ */ jsx11(Label, { htmlFor: "billingEmail", children: config.createForm?.billingEmail?.label || "Billing Email" }),
|
|
1027
|
+
/* @__PURE__ */ jsx11(
|
|
1028
|
+
Input,
|
|
1029
|
+
{
|
|
1030
|
+
id: "billingEmail",
|
|
1031
|
+
type: "email",
|
|
1032
|
+
placeholder: config.createForm?.billingEmail?.placeholder || "Enter billing email",
|
|
1033
|
+
value: billingEmail,
|
|
1034
|
+
onChange: (e) => setBillingEmail(e.target.value),
|
|
1035
|
+
required: true,
|
|
1036
|
+
disabled: isLoading
|
|
1037
|
+
}
|
|
1038
|
+
)
|
|
1039
|
+
] }),
|
|
1040
|
+
/* @__PURE__ */ jsx11(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? "Creating..." : "Create Organization" })
|
|
1041
|
+
] }),
|
|
1042
|
+
mode === "join" && /* @__PURE__ */ jsxs5("form", { onSubmit: handleJoinSubmit, className: "space-y-4", children: [
|
|
1043
|
+
/* @__PURE__ */ jsxs5("div", { className: "space-y-2", children: [
|
|
1044
|
+
/* @__PURE__ */ jsx11(Label, { htmlFor: "token", children: config.joinForm?.token?.label || "Invitation Token" }),
|
|
1045
|
+
/* @__PURE__ */ jsx11(
|
|
1046
|
+
Input,
|
|
1047
|
+
{
|
|
1048
|
+
id: "token",
|
|
1049
|
+
type: "text",
|
|
1050
|
+
placeholder: config.joinForm?.token?.placeholder || "Enter invitation token",
|
|
1051
|
+
value: token,
|
|
1052
|
+
onChange: (e) => setToken(e.target.value),
|
|
1053
|
+
required: true,
|
|
1054
|
+
disabled: isLoading
|
|
1055
|
+
}
|
|
1056
|
+
)
|
|
1057
|
+
] }),
|
|
1058
|
+
/* @__PURE__ */ jsx11(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? "Joining..." : "Join Organization" })
|
|
1059
|
+
] })
|
|
1060
|
+
] })
|
|
1061
|
+
] });
|
|
1062
|
+
}
|
|
844
1063
|
export {
|
|
845
1064
|
CustomFlowForm,
|
|
846
1065
|
PricingTable,
|
|
847
|
-
SwitchActiveTenant
|
|
1066
|
+
SwitchActiveTenant,
|
|
1067
|
+
TenantCreator
|
|
848
1068
|
};
|