@omnibase/shadcn 0.4.2 → 0.5.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 +1261 -335
- package/dist/index.d.cts +79 -5
- package/dist/index.d.ts +79 -5
- package/dist/index.js +1250 -336
- package/package.json +19 -17
package/dist/index.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
// src/components/ui/card.tsx
|
|
2
4
|
import "react";
|
|
3
5
|
|
|
@@ -77,12 +79,131 @@ function CardFooter({ className, ...props }) {
|
|
|
77
79
|
);
|
|
78
80
|
}
|
|
79
81
|
|
|
82
|
+
// src/components/ui/messages.tsx
|
|
83
|
+
import * as React3 from "react";
|
|
84
|
+
|
|
85
|
+
// src/components/ui/alert.tsx
|
|
86
|
+
import * as React2 from "react";
|
|
87
|
+
import { cva } from "class-variance-authority";
|
|
88
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
89
|
+
var alertVariants = cva(
|
|
90
|
+
"relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7",
|
|
91
|
+
{
|
|
92
|
+
variants: {
|
|
93
|
+
variant: {
|
|
94
|
+
default: "bg-background text-foreground",
|
|
95
|
+
destructive: "border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive",
|
|
96
|
+
warning: "border-yellow-500/50 text-yellow-700 bg-yellow-50 dark:border-yellow-500 dark:text-yellow-200 dark:bg-yellow-950/20 [&>svg]:text-yellow-600 dark:[&>svg]:text-yellow-200",
|
|
97
|
+
success: "border-green-500/50 text-green-700 bg-green-50 dark:border-green-500 dark:text-green-200 dark:bg-green-950/20 [&>svg]:text-green-600 dark:[&>svg]:text-green-200",
|
|
98
|
+
info: "border-blue-500/50 text-blue-700 bg-blue-50 dark:border-blue-500 dark:text-blue-200 dark:bg-blue-950/20 [&>svg]:text-blue-600 dark:[&>svg]:text-blue-200"
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
defaultVariants: {
|
|
102
|
+
variant: "default"
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
var Alert = React2.forwardRef(({ className, variant, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
107
|
+
"div",
|
|
108
|
+
{
|
|
109
|
+
ref,
|
|
110
|
+
role: "alert",
|
|
111
|
+
className: cn(alertVariants({ variant }), className),
|
|
112
|
+
...props
|
|
113
|
+
}
|
|
114
|
+
));
|
|
115
|
+
Alert.displayName = "Alert";
|
|
116
|
+
var AlertTitle = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
117
|
+
"h5",
|
|
118
|
+
{
|
|
119
|
+
ref,
|
|
120
|
+
className: cn("mb-1 font-medium leading-none tracking-tight", className),
|
|
121
|
+
...props
|
|
122
|
+
}
|
|
123
|
+
));
|
|
124
|
+
AlertTitle.displayName = "AlertTitle";
|
|
125
|
+
var AlertDescription = React2.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx2(
|
|
126
|
+
"div",
|
|
127
|
+
{
|
|
128
|
+
ref,
|
|
129
|
+
className: cn("text-sm [&_p]:leading-relaxed", className),
|
|
130
|
+
...props
|
|
131
|
+
}
|
|
132
|
+
));
|
|
133
|
+
AlertDescription.displayName = "AlertDescription";
|
|
134
|
+
|
|
135
|
+
// src/components/ui/messages.tsx
|
|
136
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
137
|
+
var getMessageVariant = (type) => {
|
|
138
|
+
switch (type) {
|
|
139
|
+
case "error":
|
|
140
|
+
return "destructive";
|
|
141
|
+
case "success":
|
|
142
|
+
return "success";
|
|
143
|
+
case "info":
|
|
144
|
+
return "info";
|
|
145
|
+
case "11184809":
|
|
146
|
+
return "warning";
|
|
147
|
+
default:
|
|
148
|
+
return "default";
|
|
149
|
+
}
|
|
150
|
+
};
|
|
151
|
+
var Messages = React3.forwardRef(
|
|
152
|
+
({ flow, className, ...props }, ref) => {
|
|
153
|
+
if (!flow?.ui) return null;
|
|
154
|
+
const allMessages = [];
|
|
155
|
+
if (flow.ui.messages) {
|
|
156
|
+
allMessages.push(...flow.ui.messages);
|
|
157
|
+
}
|
|
158
|
+
if (flow.ui.nodes) {
|
|
159
|
+
flow.ui.nodes.forEach((node) => {
|
|
160
|
+
if (node.messages) {
|
|
161
|
+
allMessages.push(...node.messages);
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
if (allMessages.length === 0) return null;
|
|
166
|
+
return /* @__PURE__ */ jsx3(
|
|
167
|
+
"div",
|
|
168
|
+
{
|
|
169
|
+
ref,
|
|
170
|
+
className: cn("w-full max-w-md mx-auto space-y-2 mb-4", className),
|
|
171
|
+
...props,
|
|
172
|
+
children: allMessages.map((message) => /* @__PURE__ */ jsx3(Alert, { variant: getMessageVariant(message.type), children: /* @__PURE__ */ jsx3(AlertDescription, { children: message.text }) }, message.id))
|
|
173
|
+
}
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
Messages.displayName = "Messages";
|
|
178
|
+
|
|
179
|
+
// src/form/types.ts
|
|
180
|
+
function isUiNodeInputAttributes(attributes) {
|
|
181
|
+
return attributes && typeof attributes === "object" && "name" in attributes && "type" in attributes;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// src/form/components/HiddenInput.tsx
|
|
185
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
186
|
+
function HiddenInput({ node }) {
|
|
187
|
+
if (!isUiNodeInputAttributes(node.attributes)) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return /* @__PURE__ */ jsx4(
|
|
191
|
+
"input",
|
|
192
|
+
{
|
|
193
|
+
name: node.attributes.name,
|
|
194
|
+
type: "hidden",
|
|
195
|
+
value: node.attributes.value || "",
|
|
196
|
+
readOnly: true
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
}
|
|
200
|
+
|
|
80
201
|
// src/components/ui/button.tsx
|
|
81
202
|
import "react";
|
|
82
203
|
import { Slot } from "@radix-ui/react-slot";
|
|
83
|
-
import { cva } from "class-variance-authority";
|
|
84
|
-
import { jsx as
|
|
85
|
-
var buttonVariants =
|
|
204
|
+
import { cva as cva2 } from "class-variance-authority";
|
|
205
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
206
|
+
var buttonVariants = cva2(
|
|
86
207
|
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
|
|
87
208
|
{
|
|
88
209
|
variants: {
|
|
@@ -115,7 +236,7 @@ function Button({
|
|
|
115
236
|
...props
|
|
116
237
|
}) {
|
|
117
238
|
const Comp = asChild ? Slot : "button";
|
|
118
|
-
return /* @__PURE__ */
|
|
239
|
+
return /* @__PURE__ */ jsx5(
|
|
119
240
|
Comp,
|
|
120
241
|
{
|
|
121
242
|
"data-slot": "button",
|
|
@@ -125,11 +246,78 @@ function Button({
|
|
|
125
246
|
);
|
|
126
247
|
}
|
|
127
248
|
|
|
249
|
+
// src/form/components/SubmitButton.tsx
|
|
250
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
251
|
+
function SubmitButton({
|
|
252
|
+
node,
|
|
253
|
+
variant = "default",
|
|
254
|
+
className = "w-full"
|
|
255
|
+
}) {
|
|
256
|
+
if (!isUiNodeInputAttributes(node.attributes)) {
|
|
257
|
+
return null;
|
|
258
|
+
}
|
|
259
|
+
return /* @__PURE__ */ jsx6(
|
|
260
|
+
Button,
|
|
261
|
+
{
|
|
262
|
+
type: "submit",
|
|
263
|
+
name: node.attributes.name,
|
|
264
|
+
value: node.attributes.value || "",
|
|
265
|
+
variant,
|
|
266
|
+
className,
|
|
267
|
+
disabled: node.attributes.disabled,
|
|
268
|
+
children: node.meta.label?.text || node.attributes.value || "Submit"
|
|
269
|
+
}
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// src/form/components/Divider.tsx
|
|
274
|
+
import { jsx as jsx7, jsxs } from "react/jsx-runtime";
|
|
275
|
+
function Divider({ withText = false }) {
|
|
276
|
+
if (withText) {
|
|
277
|
+
return /* @__PURE__ */ jsxs("div", { className: "relative my-6", children: [
|
|
278
|
+
/* @__PURE__ */ jsx7("div", { className: "absolute inset-0 flex items-center", children: /* @__PURE__ */ jsx7("span", { className: "w-full border-t border-border" }) }),
|
|
279
|
+
/* @__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" }) })
|
|
280
|
+
] });
|
|
281
|
+
}
|
|
282
|
+
return /* @__PURE__ */ jsx7("div", { className: "border-t border-border my-6" });
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/form/components/OidcGroup.tsx
|
|
286
|
+
import { jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
287
|
+
function OidcGroup({
|
|
288
|
+
nodes,
|
|
289
|
+
flowAction,
|
|
290
|
+
flowMethod,
|
|
291
|
+
csrfToken,
|
|
292
|
+
groupIndex,
|
|
293
|
+
groupName
|
|
294
|
+
}) {
|
|
295
|
+
const submitButtons = nodes.filter(
|
|
296
|
+
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.type === "submit"
|
|
297
|
+
);
|
|
298
|
+
return /* @__PURE__ */ jsxs2("div", { children: [
|
|
299
|
+
groupIndex > 0 && /* @__PURE__ */ jsx8(Divider, { withText: true }),
|
|
300
|
+
/* @__PURE__ */ jsx8("div", { className: "space-y-3", children: submitButtons.map((node, btnIndex) => /* @__PURE__ */ jsxs2(
|
|
301
|
+
"form",
|
|
302
|
+
{
|
|
303
|
+
action: flowAction,
|
|
304
|
+
method: flowMethod,
|
|
305
|
+
className: "w-full",
|
|
306
|
+
children: [
|
|
307
|
+
csrfToken && /* @__PURE__ */ jsx8(HiddenInput, { node: csrfToken }),
|
|
308
|
+
/* @__PURE__ */ jsx8(SubmitButton, { node, variant: "outline" })
|
|
309
|
+
]
|
|
310
|
+
},
|
|
311
|
+
`${groupName}-${btnIndex}`
|
|
312
|
+
)) })
|
|
313
|
+
] });
|
|
314
|
+
}
|
|
315
|
+
|
|
128
316
|
// src/components/ui/input.tsx
|
|
129
317
|
import "react";
|
|
130
|
-
import { jsx as
|
|
318
|
+
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
131
319
|
function Input({ className, type, ...props }) {
|
|
132
|
-
return /* @__PURE__ */
|
|
320
|
+
return /* @__PURE__ */ jsx9(
|
|
133
321
|
"input",
|
|
134
322
|
{
|
|
135
323
|
type,
|
|
@@ -148,12 +336,12 @@ function Input({ className, type, ...props }) {
|
|
|
148
336
|
// src/components/ui/label.tsx
|
|
149
337
|
import "react";
|
|
150
338
|
import * as LabelPrimitive from "@radix-ui/react-label";
|
|
151
|
-
import { jsx as
|
|
339
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
152
340
|
function Label({
|
|
153
341
|
className,
|
|
154
342
|
...props
|
|
155
343
|
}) {
|
|
156
|
-
return /* @__PURE__ */
|
|
344
|
+
return /* @__PURE__ */ jsx10(
|
|
157
345
|
LabelPrimitive.Root,
|
|
158
346
|
{
|
|
159
347
|
"data-slot": "label",
|
|
@@ -166,109 +354,393 @@ function Label({
|
|
|
166
354
|
);
|
|
167
355
|
}
|
|
168
356
|
|
|
169
|
-
// src/components/
|
|
170
|
-
import
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
357
|
+
// src/form/components/FormInput.tsx
|
|
358
|
+
import { jsx as jsx11, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
359
|
+
function FormInput({ node }) {
|
|
360
|
+
if (!isUiNodeInputAttributes(node.attributes)) {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
return /* @__PURE__ */ jsxs3("div", { className: "space-y-2", children: [
|
|
364
|
+
/* @__PURE__ */ jsxs3(Label, { htmlFor: node.attributes.name, children: [
|
|
365
|
+
node.meta.label?.text,
|
|
366
|
+
node.attributes.required && /* @__PURE__ */ jsx11("span", { className: "text-destructive ml-1", children: "*" })
|
|
367
|
+
] }),
|
|
368
|
+
/* @__PURE__ */ jsx11(
|
|
369
|
+
Input,
|
|
370
|
+
{
|
|
371
|
+
id: node.attributes.name,
|
|
372
|
+
name: node.attributes.name,
|
|
373
|
+
type: node.attributes.type,
|
|
374
|
+
defaultValue: node.attributes.value || "",
|
|
375
|
+
required: node.attributes.required,
|
|
376
|
+
disabled: node.attributes.disabled,
|
|
377
|
+
autoComplete: node.attributes.autocomplete,
|
|
378
|
+
placeholder: `Enter your ${node.meta.label?.text?.toLowerCase() || node.attributes.name}`
|
|
186
379
|
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
380
|
+
)
|
|
381
|
+
] });
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// src/form/utils.ts
|
|
385
|
+
var TYPE_ORDER = {
|
|
386
|
+
hidden: 0,
|
|
387
|
+
text: 1,
|
|
388
|
+
email: 1,
|
|
389
|
+
password: 1,
|
|
390
|
+
checkbox: 1,
|
|
391
|
+
submit: 2
|
|
392
|
+
};
|
|
393
|
+
function sortNodes(nodes) {
|
|
394
|
+
return [...nodes].sort((a, b) => {
|
|
395
|
+
const aIsInput = isUiNodeInputAttributes(a.attributes);
|
|
396
|
+
const bIsInput = isUiNodeInputAttributes(b.attributes);
|
|
397
|
+
if (!aIsInput && !bIsInput) return 0;
|
|
398
|
+
if (!aIsInput) return 1;
|
|
399
|
+
if (!bIsInput) return -1;
|
|
400
|
+
const aAttrs = a.attributes;
|
|
401
|
+
const bAttrs = b.attributes;
|
|
402
|
+
const aOrder = TYPE_ORDER[aAttrs.type] ?? 1;
|
|
403
|
+
const bOrder = TYPE_ORDER[bAttrs.type] ?? 1;
|
|
404
|
+
return aOrder - bOrder;
|
|
405
|
+
});
|
|
406
|
+
}
|
|
407
|
+
function findSubmitButton(nodes) {
|
|
408
|
+
return nodes.find(
|
|
409
|
+
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.type === "submit"
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
function findAnchorNode(nodes) {
|
|
413
|
+
return nodes.find((node) => node.type === "a");
|
|
414
|
+
}
|
|
415
|
+
function filterInputNodes(nodes) {
|
|
416
|
+
return nodes.filter(
|
|
417
|
+
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.type !== "submit" && node.attributes.type !== "hidden"
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
function findCsrfToken(nodes) {
|
|
421
|
+
return nodes.find(
|
|
422
|
+
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.name === "csrf_token"
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
function groupNodesByGroup(nodes) {
|
|
426
|
+
return nodes.reduce((groups, node) => {
|
|
427
|
+
const group = node.group || "default";
|
|
428
|
+
if (!groups[group]) {
|
|
429
|
+
groups[group] = [];
|
|
190
430
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
{
|
|
196
|
-
ref,
|
|
197
|
-
role: "alert",
|
|
198
|
-
className: cn(alertVariants({ variant }), className),
|
|
199
|
-
...props
|
|
200
|
-
}
|
|
201
|
-
));
|
|
202
|
-
Alert.displayName = "Alert";
|
|
203
|
-
var AlertTitle = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
|
|
204
|
-
"h5",
|
|
205
|
-
{
|
|
206
|
-
ref,
|
|
207
|
-
className: cn("mb-1 font-medium leading-none tracking-tight", className),
|
|
208
|
-
...props
|
|
209
|
-
}
|
|
210
|
-
));
|
|
211
|
-
AlertTitle.displayName = "AlertTitle";
|
|
212
|
-
var AlertDescription = React5.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx5(
|
|
213
|
-
"div",
|
|
214
|
-
{
|
|
215
|
-
ref,
|
|
216
|
-
className: cn("text-sm [&_p]:leading-relaxed", className),
|
|
217
|
-
...props
|
|
218
|
-
}
|
|
219
|
-
));
|
|
220
|
-
AlertDescription.displayName = "AlertDescription";
|
|
431
|
+
groups[group].push(node);
|
|
432
|
+
return groups;
|
|
433
|
+
}, {});
|
|
434
|
+
}
|
|
221
435
|
|
|
222
|
-
// src/
|
|
223
|
-
import { jsx as
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
436
|
+
// src/form/login.tsx
|
|
437
|
+
import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
438
|
+
function LoginForm({ flow, Header, register_url }) {
|
|
439
|
+
const nodesByGroup = groupNodesByGroup(flow.ui.nodes);
|
|
440
|
+
const csrfToken = findCsrfToken(flow.ui.nodes);
|
|
441
|
+
const oidcNodes = nodesByGroup.oidc || [];
|
|
442
|
+
const defaultNodes = nodesByGroup.default || [];
|
|
443
|
+
const passwordNodes = nodesByGroup.password || [];
|
|
444
|
+
const identifierNodes = filterInputNodes(sortNodes(defaultNodes));
|
|
445
|
+
const passwordInputNodes = filterInputNodes(sortNodes(passwordNodes));
|
|
446
|
+
const submitButton = findSubmitButton(sortNodes(passwordNodes));
|
|
447
|
+
const registerHref = register_url && flow.return_to ? `${register_url}?return_to=${encodeURIComponent(flow.return_to)}` : register_url;
|
|
448
|
+
return /* @__PURE__ */ jsxs4("div", { children: [
|
|
449
|
+
/* @__PURE__ */ jsx12(Messages, { flow }),
|
|
450
|
+
/* @__PURE__ */ jsxs4(Card, { className: "w-full max-w-md mx-auto", children: [
|
|
451
|
+
Header && /* @__PURE__ */ jsx12(CardHeader, { children: /* @__PURE__ */ jsx12(CardTitle, { className: "text-center pb-1", children: Header }) }),
|
|
452
|
+
/* @__PURE__ */ jsxs4(CardContent, { className: "space-y-6", children: [
|
|
453
|
+
oidcNodes.length > 0 && /* @__PURE__ */ jsx12(
|
|
454
|
+
OidcGroup,
|
|
455
|
+
{
|
|
456
|
+
nodes: sortNodes(oidcNodes),
|
|
457
|
+
flowAction: flow.ui.action,
|
|
458
|
+
flowMethod: flow.ui.method,
|
|
459
|
+
csrfToken,
|
|
460
|
+
groupIndex: 0,
|
|
461
|
+
groupName: "oidc"
|
|
462
|
+
}
|
|
463
|
+
),
|
|
464
|
+
/* @__PURE__ */ jsxs4("div", { children: [
|
|
465
|
+
oidcNodes.length > 0 && /* @__PURE__ */ jsx12(Divider, { withText: true }),
|
|
466
|
+
/* @__PURE__ */ jsx12("form", { action: flow.ui.action, method: flow.ui.method, children: /* @__PURE__ */ jsxs4("div", { className: "space-y-4", children: [
|
|
467
|
+
csrfToken && /* @__PURE__ */ jsx12(HiddenInput, { node: csrfToken }),
|
|
468
|
+
identifierNodes.map((node, idx) => /* @__PURE__ */ jsx12(FormInput, { node }, idx)),
|
|
469
|
+
passwordInputNodes.map((node, idx) => /* @__PURE__ */ jsx12(FormInput, { node }, idx)),
|
|
470
|
+
submitButton && /* @__PURE__ */ jsx12(SubmitButton, { node: submitButton })
|
|
471
|
+
] }) }),
|
|
472
|
+
register_url && /* @__PURE__ */ jsxs4("div", { className: "mt-4 text-center text-sm", children: [
|
|
473
|
+
"Don't have an account?",
|
|
474
|
+
" ",
|
|
475
|
+
/* @__PURE__ */ jsx12(
|
|
476
|
+
"a",
|
|
477
|
+
{
|
|
478
|
+
href: registerHref,
|
|
479
|
+
className: "text-primary underline-offset-4 hover:underline",
|
|
480
|
+
children: "Go to Register"
|
|
481
|
+
}
|
|
482
|
+
)
|
|
483
|
+
] })
|
|
484
|
+
] })
|
|
485
|
+
] })
|
|
486
|
+
] })
|
|
487
|
+
] });
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
// src/form/registration.tsx
|
|
491
|
+
import { jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
492
|
+
function RegistrationForm({
|
|
493
|
+
flow,
|
|
494
|
+
Header,
|
|
495
|
+
login_url
|
|
496
|
+
}) {
|
|
497
|
+
const nodesByGroup = groupNodesByGroup(flow.ui.nodes);
|
|
498
|
+
const csrfToken = findCsrfToken(flow.ui.nodes);
|
|
499
|
+
const oidcNodes = nodesByGroup.oidc || [];
|
|
500
|
+
const defaultNodes = nodesByGroup.default || [];
|
|
501
|
+
const profileNodes = nodesByGroup.profile || [];
|
|
502
|
+
const passwordNodes = nodesByGroup.password || [];
|
|
503
|
+
const inputNodes = filterInputNodes(
|
|
504
|
+
sortNodes([...defaultNodes, ...passwordNodes])
|
|
505
|
+
);
|
|
506
|
+
const hiddenNodes = [...defaultNodes, ...passwordNodes].filter(
|
|
507
|
+
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.type === "hidden" && node.attributes.name !== "csrf_token"
|
|
508
|
+
);
|
|
509
|
+
const submitButton = findSubmitButton(sortNodes(passwordNodes)) || findSubmitButton(sortNodes(profileNodes));
|
|
510
|
+
const loginHref = login_url && flow.return_to ? `${login_url}?return_to=${encodeURIComponent(flow.return_to)}` : login_url;
|
|
511
|
+
return /* @__PURE__ */ jsxs5("div", { children: [
|
|
512
|
+
/* @__PURE__ */ jsx13(Messages, { flow }),
|
|
513
|
+
/* @__PURE__ */ jsxs5(Card, { className: "w-full max-w-md mx-auto", children: [
|
|
514
|
+
Header && /* @__PURE__ */ jsx13(CardHeader, { children: /* @__PURE__ */ jsx13(CardTitle, { className: "text-center pb-1", children: Header }) }),
|
|
515
|
+
/* @__PURE__ */ jsxs5(CardContent, { className: "space-y-6", children: [
|
|
516
|
+
oidcNodes.length > 0 && /* @__PURE__ */ jsx13(
|
|
517
|
+
OidcGroup,
|
|
518
|
+
{
|
|
519
|
+
nodes: sortNodes(oidcNodes),
|
|
520
|
+
flowAction: flow.ui.action,
|
|
521
|
+
flowMethod: flow.ui.method,
|
|
522
|
+
csrfToken,
|
|
523
|
+
groupIndex: 0,
|
|
524
|
+
groupName: "oidc"
|
|
525
|
+
}
|
|
526
|
+
),
|
|
527
|
+
/* @__PURE__ */ jsxs5("div", { children: [
|
|
528
|
+
oidcNodes.length > 0 && /* @__PURE__ */ jsx13(Divider, { withText: true }),
|
|
529
|
+
/* @__PURE__ */ jsx13("form", { action: flow.ui.action, method: flow.ui.method, children: /* @__PURE__ */ jsxs5("div", { className: "space-y-4", children: [
|
|
530
|
+
csrfToken && /* @__PURE__ */ jsx13(HiddenInput, { node: csrfToken }),
|
|
531
|
+
hiddenNodes.map((node, idx) => /* @__PURE__ */ jsx13(HiddenInput, { node }, `hidden-${idx}`)),
|
|
532
|
+
inputNodes.map((node, idx) => /* @__PURE__ */ jsx13(FormInput, { node }, idx)),
|
|
533
|
+
submitButton && /* @__PURE__ */ jsx13(SubmitButton, { node: submitButton })
|
|
534
|
+
] }) }),
|
|
535
|
+
login_url && /* @__PURE__ */ jsxs5("div", { className: "mt-4 text-center text-sm", children: [
|
|
536
|
+
"Already have an account?",
|
|
537
|
+
" ",
|
|
538
|
+
/* @__PURE__ */ jsx13(
|
|
539
|
+
"a",
|
|
540
|
+
{
|
|
541
|
+
href: loginHref,
|
|
542
|
+
className: "text-primary underline-offset-4 hover:underline",
|
|
543
|
+
children: "Go to Login"
|
|
544
|
+
}
|
|
545
|
+
)
|
|
546
|
+
] })
|
|
547
|
+
] })
|
|
548
|
+
] })
|
|
549
|
+
] })
|
|
550
|
+
] });
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
// src/form/verification.tsx
|
|
554
|
+
import * as React8 from "react";
|
|
555
|
+
|
|
556
|
+
// src/form/components/PinInput.tsx
|
|
557
|
+
import * as React7 from "react";
|
|
558
|
+
import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
559
|
+
function PinInput({
|
|
560
|
+
node,
|
|
561
|
+
length = 6,
|
|
562
|
+
initialValue = ""
|
|
563
|
+
}) {
|
|
564
|
+
if (!isUiNodeInputAttributes(node.attributes)) {
|
|
565
|
+
return null;
|
|
236
566
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
567
|
+
const [pins, setPins] = React7.useState(() => {
|
|
568
|
+
if (initialValue) {
|
|
569
|
+
const sanitized = initialValue.replace(/[^0-9]/g, "").slice(0, length);
|
|
570
|
+
const pinArray = Array(length).fill("");
|
|
571
|
+
for (let i = 0; i < sanitized.length; i++) {
|
|
572
|
+
pinArray[i] = sanitized[i];
|
|
573
|
+
}
|
|
574
|
+
return pinArray;
|
|
244
575
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
576
|
+
return Array(length).fill("");
|
|
577
|
+
});
|
|
578
|
+
const inputRefs = React7.useRef([]);
|
|
579
|
+
const handleChange = (index, value) => {
|
|
580
|
+
const sanitizedValue = value.replace(/[^0-9]/g, "").slice(0, 1);
|
|
581
|
+
const newPins = [...pins];
|
|
582
|
+
newPins[index] = sanitizedValue;
|
|
583
|
+
setPins(newPins);
|
|
584
|
+
if (sanitizedValue && index < length - 1) {
|
|
585
|
+
inputRefs.current[index + 1]?.focus();
|
|
251
586
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
587
|
+
};
|
|
588
|
+
const handleKeyDown = (index, e) => {
|
|
589
|
+
if (e.key === "Backspace" && !pins[index] && index > 0) {
|
|
590
|
+
inputRefs.current[index - 1]?.focus();
|
|
591
|
+
}
|
|
592
|
+
if (e.key === "ArrowLeft" && index > 0) {
|
|
593
|
+
inputRefs.current[index - 1]?.focus();
|
|
594
|
+
}
|
|
595
|
+
if (e.key === "ArrowRight" && index < length - 1) {
|
|
596
|
+
inputRefs.current[index + 1]?.focus();
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
const handlePaste = (e) => {
|
|
600
|
+
e.preventDefault();
|
|
601
|
+
const pastedData = e.clipboardData.getData("text").replace(/[^0-9]/g, "");
|
|
602
|
+
const newPins = [...pins];
|
|
603
|
+
for (let i = 0; i < Math.min(pastedData.length, length); i++) {
|
|
604
|
+
newPins[i] = pastedData[i];
|
|
605
|
+
}
|
|
606
|
+
setPins(newPins);
|
|
607
|
+
const nextEmptyIndex = newPins.findIndex((pin) => !pin);
|
|
608
|
+
const focusIndex = nextEmptyIndex === -1 ? length - 1 : nextEmptyIndex;
|
|
609
|
+
inputRefs.current[focusIndex]?.focus();
|
|
610
|
+
};
|
|
611
|
+
const combinedValue = pins.join("");
|
|
612
|
+
return /* @__PURE__ */ jsxs6("div", { className: "space-y-2 mb-6", children: [
|
|
613
|
+
/* @__PURE__ */ jsx14("div", { className: "flex gap-2 justify-center", children: Array.from({ length }).map((_, index) => /* @__PURE__ */ jsx14(
|
|
614
|
+
"input",
|
|
255
615
|
{
|
|
256
|
-
ref,
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
616
|
+
ref: (el) => inputRefs.current[index] = el,
|
|
617
|
+
type: "text",
|
|
618
|
+
inputMode: "numeric",
|
|
619
|
+
maxLength: 1,
|
|
620
|
+
value: pins[index],
|
|
621
|
+
onChange: (e) => handleChange(index, e.target.value),
|
|
622
|
+
onKeyDown: (e) => handleKeyDown(index, e),
|
|
623
|
+
onPaste: index === 0 ? handlePaste : void 0,
|
|
624
|
+
disabled: isUiNodeInputAttributes(node.attributes) ? node.attributes.disabled : false,
|
|
625
|
+
className: cn(
|
|
626
|
+
"w-10 h-12 text-center text-lg font-semibold rounded-md border-2",
|
|
627
|
+
"border-input bg-background shadow-sm transition-all duration-200 outline-none",
|
|
628
|
+
"hover:border-ring/60",
|
|
629
|
+
"focus:border-ring focus:ring-4 focus:ring-ring/20 focus:scale-105",
|
|
630
|
+
"aria-invalid:border-destructive aria-invalid:ring-destructive/20",
|
|
631
|
+
"disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
|
|
632
|
+
pins[index] && "border-primary bg-primary/5"
|
|
633
|
+
),
|
|
634
|
+
"aria-label": `Digit ${index + 1}`
|
|
635
|
+
},
|
|
636
|
+
index
|
|
637
|
+
)) }),
|
|
638
|
+
/* @__PURE__ */ jsx14(
|
|
639
|
+
"input",
|
|
640
|
+
{
|
|
641
|
+
type: "hidden",
|
|
642
|
+
id: node.attributes.name,
|
|
643
|
+
name: node.attributes.name,
|
|
644
|
+
value: combinedValue,
|
|
645
|
+
required: node.attributes.required
|
|
260
646
|
}
|
|
261
|
-
)
|
|
647
|
+
)
|
|
648
|
+
] });
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
// src/form/components/AnchorButton.tsx
|
|
652
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
653
|
+
function AnchorButton({
|
|
654
|
+
node,
|
|
655
|
+
variant = "default",
|
|
656
|
+
className = "w-full"
|
|
657
|
+
}) {
|
|
658
|
+
if (node.type !== "a" || !("href" in node.attributes)) {
|
|
659
|
+
return null;
|
|
262
660
|
}
|
|
263
|
-
|
|
264
|
-
|
|
661
|
+
const href = node.attributes.href;
|
|
662
|
+
const title = node.attributes.title;
|
|
663
|
+
const label = node.meta?.label;
|
|
664
|
+
const buttonText = (typeof title === "object" && title !== null && "text" in title ? title.text : typeof title === "string" ? title : null) || (label && typeof label === "object" && "text" in label ? label.text : null) || "Continue";
|
|
665
|
+
return /* @__PURE__ */ jsx15(Button, { variant, className, asChild: true, children: /* @__PURE__ */ jsx15("a", { href, children: buttonText }) });
|
|
666
|
+
}
|
|
265
667
|
|
|
266
|
-
// src/form/
|
|
267
|
-
import { jsx as
|
|
268
|
-
function
|
|
668
|
+
// src/form/verification.tsx
|
|
669
|
+
import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
670
|
+
function VerificationForm({
|
|
671
|
+
flow,
|
|
672
|
+
Header,
|
|
673
|
+
autoRedirect = true
|
|
674
|
+
}) {
|
|
675
|
+
const nodesByGroup = groupNodesByGroup(flow.ui.nodes);
|
|
676
|
+
const csrfToken = findCsrfToken(flow.ui.nodes);
|
|
677
|
+
const codeNodes = nodesByGroup.code || [];
|
|
678
|
+
const inputNodes = filterInputNodes(sortNodes(codeNodes));
|
|
679
|
+
const submitButton = findSubmitButton(sortNodes(codeNodes));
|
|
680
|
+
const anchorNode = findAnchorNode(sortNodes(codeNodes));
|
|
681
|
+
React8.useEffect(() => {
|
|
682
|
+
if (autoRedirect && anchorNode && anchorNode.type === "a" && "href" in anchorNode.attributes) {
|
|
683
|
+
const href = anchorNode.attributes.href;
|
|
684
|
+
if (href && typeof window !== "undefined") {
|
|
685
|
+
window.location.href = href;
|
|
686
|
+
}
|
|
687
|
+
}
|
|
688
|
+
}, [autoRedirect, anchorNode]);
|
|
689
|
+
return /* @__PURE__ */ jsxs7("div", { children: [
|
|
690
|
+
/* @__PURE__ */ jsx16(Messages, { flow }),
|
|
691
|
+
/* @__PURE__ */ jsxs7(Card, { className: "w-full max-w-md mx-auto", children: [
|
|
692
|
+
/* @__PURE__ */ jsx16(CardHeader, { children: /* @__PURE__ */ jsx16(CardTitle, { className: "text-center pb-1", children: Header || "Verification Code" }) }),
|
|
693
|
+
/* @__PURE__ */ jsx16(CardContent, { children: /* @__PURE__ */ jsx16("form", { action: flow.ui.action, method: flow.ui.method, children: /* @__PURE__ */ jsxs7("div", { className: "space-y-4", children: [
|
|
694
|
+
csrfToken && /* @__PURE__ */ jsx16(HiddenInput, { node: csrfToken }),
|
|
695
|
+
inputNodes.map((node, idx) => {
|
|
696
|
+
const isCodeInput = node.attributes.node_type === "input" && "name" in node.attributes && node.attributes.name === "code";
|
|
697
|
+
const initialValue = isCodeInput && "value" in node.attributes ? String(node.attributes.value || "") : "";
|
|
698
|
+
return isCodeInput ? /* @__PURE__ */ jsx16(
|
|
699
|
+
PinInput,
|
|
700
|
+
{
|
|
701
|
+
node,
|
|
702
|
+
length: 6,
|
|
703
|
+
initialValue
|
|
704
|
+
},
|
|
705
|
+
idx
|
|
706
|
+
) : /* @__PURE__ */ jsx16(FormInput, { node }, idx);
|
|
707
|
+
}),
|
|
708
|
+
submitButton && /* @__PURE__ */ jsx16(SubmitButton, { node: submitButton }),
|
|
709
|
+
!submitButton && anchorNode && /* @__PURE__ */ jsx16(AnchorButton, { node: anchorNode })
|
|
710
|
+
] }) }) })
|
|
711
|
+
] })
|
|
712
|
+
] });
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// src/form/recovery.tsx
|
|
716
|
+
import { jsx as jsx17, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
717
|
+
function RecoveryForm({ flow, Header }) {
|
|
718
|
+
const nodesByGroup = groupNodesByGroup(flow.ui.nodes);
|
|
719
|
+
const csrfToken = findCsrfToken(flow.ui.nodes);
|
|
720
|
+
const codeNodes = nodesByGroup.code || [];
|
|
721
|
+
const linkNodes = nodesByGroup.link || [];
|
|
722
|
+
const activeNodes = codeNodes.length > 0 ? codeNodes : linkNodes;
|
|
723
|
+
const inputNodes = filterInputNodes(sortNodes(activeNodes));
|
|
724
|
+
const submitButton = findSubmitButton(sortNodes(activeNodes));
|
|
725
|
+
return /* @__PURE__ */ jsxs8("div", { children: [
|
|
726
|
+
/* @__PURE__ */ jsx17(Messages, { flow }),
|
|
727
|
+
/* @__PURE__ */ jsxs8(Card, { className: "w-full max-w-md mx-auto", children: [
|
|
728
|
+
Header && /* @__PURE__ */ jsx17(CardHeader, { children: /* @__PURE__ */ jsx17(CardTitle, { className: "text-center pb-1", children: Header }) }),
|
|
729
|
+
/* @__PURE__ */ jsx17(CardContent, { children: /* @__PURE__ */ jsx17("form", { action: flow.ui.action, method: flow.ui.method, children: /* @__PURE__ */ jsxs8("div", { className: "space-y-4", children: [
|
|
730
|
+
csrfToken && /* @__PURE__ */ jsx17(HiddenInput, { node: csrfToken }),
|
|
731
|
+
inputNodes.map((node, idx) => /* @__PURE__ */ jsx17(FormInput, { node }, idx)),
|
|
732
|
+
submitButton && /* @__PURE__ */ jsx17(SubmitButton, { node: submitButton })
|
|
733
|
+
] }) }) })
|
|
734
|
+
] })
|
|
735
|
+
] });
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
// src/form/settings.tsx
|
|
739
|
+
import { jsx as jsx18, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
740
|
+
function isUiNodeInputAttributes2(attributes) {
|
|
269
741
|
return attributes && typeof attributes === "object" && "name" in attributes && "type" in attributes;
|
|
270
742
|
}
|
|
271
|
-
function
|
|
743
|
+
function SettingsForm({ flow }) {
|
|
272
744
|
const nodesByGroup = flow.ui.nodes.reduce((groups, node) => {
|
|
273
745
|
const group = node.group || "default";
|
|
274
746
|
if (!groups[group]) {
|
|
@@ -277,150 +749,128 @@ function CustomFlowForm({ flow, Header }) {
|
|
|
277
749
|
groups[group].push(node);
|
|
278
750
|
return groups;
|
|
279
751
|
}, {});
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
const csrfToken = regularNodes.find(
|
|
283
|
-
(node) => isUiNodeInputAttributes(node.attributes) && node.attributes.name === "csrf_token"
|
|
752
|
+
const csrfToken = flow.ui.nodes.find(
|
|
753
|
+
(node) => isUiNodeInputAttributes2(node.attributes) && node.attributes.name === "csrf_token"
|
|
284
754
|
);
|
|
285
|
-
const
|
|
286
|
-
(
|
|
755
|
+
const settingsGroups = Object.entries(nodesByGroup).filter(
|
|
756
|
+
([group]) => group !== "default" && group !== "oidc"
|
|
287
757
|
);
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
758
|
+
const groupTitles = {
|
|
759
|
+
profile: "Profile",
|
|
760
|
+
password: "Password",
|
|
761
|
+
totp: "Authenticator App",
|
|
762
|
+
webauthn: "Security Keys",
|
|
763
|
+
lookup_secret: "Backup Recovery Codes",
|
|
764
|
+
passkey: "Passkeys"
|
|
765
|
+
};
|
|
766
|
+
return /* @__PURE__ */ jsxs9("div", { className: "space-y-6", children: [
|
|
767
|
+
/* @__PURE__ */ jsx18(Messages, { flow }),
|
|
768
|
+
settingsGroups.map(([groupName, nodes]) => {
|
|
769
|
+
const submitButton = nodes.find(
|
|
770
|
+
(node) => isUiNodeInputAttributes2(node.attributes) && node.attributes.type === "submit"
|
|
771
|
+
);
|
|
772
|
+
const inputNodes = nodes.filter(
|
|
773
|
+
(node) => isUiNodeInputAttributes2(node.attributes) && node.attributes.type !== "submit" && node.attributes.type !== "hidden"
|
|
774
|
+
);
|
|
775
|
+
const imageNodes = nodes.filter((node) => node.type === "img");
|
|
776
|
+
const textNodes = nodes.filter((node) => node.type === "text");
|
|
777
|
+
return /* @__PURE__ */ jsxs9(Card, { className: "w-full max-w-2xl mx-auto", children: [
|
|
778
|
+
/* @__PURE__ */ jsx18(CardHeader, { children: /* @__PURE__ */ jsx18(CardTitle, { children: groupTitles[groupName] || groupName }) }),
|
|
779
|
+
/* @__PURE__ */ jsx18(CardContent, { children: /* @__PURE__ */ jsx18("form", { action: flow.ui.action, method: flow.ui.method, children: /* @__PURE__ */ jsxs9("div", { className: "space-y-4", children: [
|
|
780
|
+
csrfToken && isUiNodeInputAttributes2(csrfToken.attributes) && /* @__PURE__ */ jsx18(
|
|
781
|
+
"input",
|
|
782
|
+
{
|
|
783
|
+
name: csrfToken.attributes.name,
|
|
784
|
+
type: "hidden",
|
|
785
|
+
value: csrfToken.attributes.value || "",
|
|
786
|
+
readOnly: true
|
|
787
|
+
}
|
|
788
|
+
),
|
|
789
|
+
imageNodes.map((node, index) => {
|
|
790
|
+
if (node.type === "img" && "src" in node.attributes) {
|
|
791
|
+
const imgAttrs = node.attributes;
|
|
792
|
+
return /* @__PURE__ */ jsx18(
|
|
793
|
+
"div",
|
|
298
794
|
{
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
"
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
}
|
|
311
|
-
),
|
|
312
|
-
/* @__PURE__ */ jsx7(
|
|
313
|
-
Button,
|
|
314
|
-
{
|
|
315
|
-
type: "submit",
|
|
316
|
-
name: node.attributes.name,
|
|
317
|
-
value: node.attributes.value || "",
|
|
318
|
-
variant: "outline",
|
|
319
|
-
className: "w-full",
|
|
320
|
-
children: node.meta.label?.text || node.attributes.value || "Sign in"
|
|
321
|
-
}
|
|
322
|
-
)
|
|
323
|
-
]
|
|
795
|
+
className: "flex justify-center",
|
|
796
|
+
children: /* @__PURE__ */ jsx18(
|
|
797
|
+
"img",
|
|
798
|
+
{
|
|
799
|
+
src: imgAttrs.src,
|
|
800
|
+
alt: node.meta.label?.text || "QR Code",
|
|
801
|
+
width: imgAttrs.width,
|
|
802
|
+
height: imgAttrs.height,
|
|
803
|
+
className: "border rounded-lg"
|
|
804
|
+
}
|
|
805
|
+
)
|
|
324
806
|
},
|
|
325
|
-
`
|
|
807
|
+
`img-${index}`
|
|
326
808
|
);
|
|
327
809
|
}
|
|
328
810
|
return null;
|
|
329
811
|
}),
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
"
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
value: node.attributes.value || "",
|
|
350
|
-
readOnly: true
|
|
351
|
-
},
|
|
352
|
-
node.attributes.name
|
|
353
|
-
);
|
|
354
|
-
}
|
|
355
|
-
if (isSubmitButton) {
|
|
356
|
-
return /* @__PURE__ */ jsx7(
|
|
357
|
-
Button,
|
|
812
|
+
textNodes.map((node, index) => {
|
|
813
|
+
if (node.type === "text" && "text" in node.attributes) {
|
|
814
|
+
const textContent = typeof node.attributes.text === "string" ? node.attributes.text : node.attributes.text?.text || "";
|
|
815
|
+
return /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
816
|
+
node.meta.label?.text && /* @__PURE__ */ jsx18(Label, { className: "text-sm text-muted-foreground", children: node.meta.label.text }),
|
|
817
|
+
/* @__PURE__ */ jsx18("div", { className: "p-3 bg-muted rounded-md font-mono text-sm break-all", children: textContent })
|
|
818
|
+
] }, `text-${index}`);
|
|
819
|
+
}
|
|
820
|
+
return null;
|
|
821
|
+
}),
|
|
822
|
+
inputNodes.map((node) => {
|
|
823
|
+
if (isUiNodeInputAttributes2(node.attributes)) {
|
|
824
|
+
return /* @__PURE__ */ jsxs9("div", { className: "space-y-2", children: [
|
|
825
|
+
/* @__PURE__ */ jsxs9(Label, { htmlFor: node.attributes.name, children: [
|
|
826
|
+
node.meta.label?.text,
|
|
827
|
+
node.attributes.required && /* @__PURE__ */ jsx18("span", { className: "text-destructive ml-1", children: "*" })
|
|
828
|
+
] }),
|
|
829
|
+
/* @__PURE__ */ jsx18(
|
|
830
|
+
Input,
|
|
358
831
|
{
|
|
359
|
-
|
|
832
|
+
id: node.attributes.name,
|
|
360
833
|
name: node.attributes.name,
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
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
|
-
}
|
|
834
|
+
type: node.attributes.type,
|
|
835
|
+
defaultValue: node.attributes.value || "",
|
|
836
|
+
required: node.attributes.required,
|
|
837
|
+
disabled: node.attributes.disabled,
|
|
838
|
+
autoComplete: node.attributes.autocomplete,
|
|
839
|
+
placeholder: `Enter ${node.meta.label?.text?.toLowerCase() || node.attributes.name}`
|
|
840
|
+
}
|
|
841
|
+
)
|
|
842
|
+
] }, node.attributes.name);
|
|
403
843
|
}
|
|
404
844
|
return null;
|
|
405
845
|
}),
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
846
|
+
submitButton && isUiNodeInputAttributes2(submitButton.attributes) && /* @__PURE__ */ jsx18(
|
|
847
|
+
Button,
|
|
848
|
+
{
|
|
849
|
+
type: "submit",
|
|
850
|
+
name: submitButton.attributes.name,
|
|
851
|
+
value: submitButton.attributes.value || "",
|
|
852
|
+
className: "w-full",
|
|
853
|
+
disabled: submitButton.attributes.disabled,
|
|
854
|
+
children: submitButton.meta.label?.text || submitButton.attributes.value || "Save"
|
|
855
|
+
}
|
|
856
|
+
)
|
|
857
|
+
] }) }) })
|
|
858
|
+
] }, groupName);
|
|
859
|
+
})
|
|
410
860
|
] });
|
|
411
861
|
}
|
|
412
862
|
|
|
413
863
|
// src/tenant-switcher/index.tsx
|
|
414
|
-
import * as
|
|
864
|
+
import * as React10 from "react";
|
|
415
865
|
|
|
416
866
|
// src/components/ui/select.tsx
|
|
417
|
-
import * as
|
|
867
|
+
import * as React9 from "react";
|
|
418
868
|
import * as SelectPrimitive from "@radix-ui/react-select";
|
|
419
869
|
import { Check, ChevronDown, ChevronUp } from "lucide-react";
|
|
420
|
-
import { jsx as
|
|
870
|
+
import { jsx as jsx19, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
421
871
|
var Select = SelectPrimitive.Root;
|
|
422
872
|
var SelectValue = SelectPrimitive.Value;
|
|
423
|
-
var SelectTrigger =
|
|
873
|
+
var SelectTrigger = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs10(
|
|
424
874
|
SelectPrimitive.Trigger,
|
|
425
875
|
{
|
|
426
876
|
ref,
|
|
@@ -431,12 +881,12 @@ var SelectTrigger = React7.forwardRef(({ className, children, ...props }, ref) =
|
|
|
431
881
|
...props,
|
|
432
882
|
children: [
|
|
433
883
|
children,
|
|
434
|
-
/* @__PURE__ */
|
|
884
|
+
/* @__PURE__ */ jsx19(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx19(ChevronDown, { className: "h-4 w-4 opacity-50" }) })
|
|
435
885
|
]
|
|
436
886
|
}
|
|
437
887
|
));
|
|
438
888
|
SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
|
|
439
|
-
var SelectScrollUpButton =
|
|
889
|
+
var SelectScrollUpButton = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
|
|
440
890
|
SelectPrimitive.ScrollUpButton,
|
|
441
891
|
{
|
|
442
892
|
ref,
|
|
@@ -445,11 +895,11 @@ var SelectScrollUpButton = React7.forwardRef(({ className, ...props }, ref) => /
|
|
|
445
895
|
className
|
|
446
896
|
),
|
|
447
897
|
...props,
|
|
448
|
-
children: /* @__PURE__ */
|
|
898
|
+
children: /* @__PURE__ */ jsx19(ChevronUp, { className: "h-4 w-4" })
|
|
449
899
|
}
|
|
450
900
|
));
|
|
451
901
|
SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
|
|
452
|
-
var SelectScrollDownButton =
|
|
902
|
+
var SelectScrollDownButton = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
|
|
453
903
|
SelectPrimitive.ScrollDownButton,
|
|
454
904
|
{
|
|
455
905
|
ref,
|
|
@@ -458,11 +908,11 @@ var SelectScrollDownButton = React7.forwardRef(({ className, ...props }, ref) =>
|
|
|
458
908
|
className
|
|
459
909
|
),
|
|
460
910
|
...props,
|
|
461
|
-
children: /* @__PURE__ */
|
|
911
|
+
children: /* @__PURE__ */ jsx19(ChevronDown, { className: "h-4 w-4" })
|
|
462
912
|
}
|
|
463
913
|
));
|
|
464
914
|
SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
|
|
465
|
-
var SelectContent =
|
|
915
|
+
var SelectContent = React9.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx19(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs10(
|
|
466
916
|
SelectPrimitive.Content,
|
|
467
917
|
{
|
|
468
918
|
ref,
|
|
@@ -474,8 +924,8 @@ var SelectContent = React7.forwardRef(({ className, children, position = "popper
|
|
|
474
924
|
position,
|
|
475
925
|
...props,
|
|
476
926
|
children: [
|
|
477
|
-
/* @__PURE__ */
|
|
478
|
-
/* @__PURE__ */
|
|
927
|
+
/* @__PURE__ */ jsx19(SelectScrollUpButton, {}),
|
|
928
|
+
/* @__PURE__ */ jsx19(
|
|
479
929
|
SelectPrimitive.Viewport,
|
|
480
930
|
{
|
|
481
931
|
className: cn(
|
|
@@ -485,12 +935,12 @@ var SelectContent = React7.forwardRef(({ className, children, position = "popper
|
|
|
485
935
|
children
|
|
486
936
|
}
|
|
487
937
|
),
|
|
488
|
-
/* @__PURE__ */
|
|
938
|
+
/* @__PURE__ */ jsx19(SelectScrollDownButton, {})
|
|
489
939
|
]
|
|
490
940
|
}
|
|
491
941
|
) }));
|
|
492
942
|
SelectContent.displayName = SelectPrimitive.Content.displayName;
|
|
493
|
-
var SelectLabel =
|
|
943
|
+
var SelectLabel = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
|
|
494
944
|
SelectPrimitive.Label,
|
|
495
945
|
{
|
|
496
946
|
ref,
|
|
@@ -499,7 +949,7 @@ var SelectLabel = React7.forwardRef(({ className, ...props }, ref) => /* @__PURE
|
|
|
499
949
|
}
|
|
500
950
|
));
|
|
501
951
|
SelectLabel.displayName = SelectPrimitive.Label.displayName;
|
|
502
|
-
var SelectItem =
|
|
952
|
+
var SelectItem = React9.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs10(
|
|
503
953
|
SelectPrimitive.Item,
|
|
504
954
|
{
|
|
505
955
|
ref,
|
|
@@ -509,13 +959,13 @@ var SelectItem = React7.forwardRef(({ className, children, ...props }, ref) => /
|
|
|
509
959
|
),
|
|
510
960
|
...props,
|
|
511
961
|
children: [
|
|
512
|
-
/* @__PURE__ */
|
|
513
|
-
/* @__PURE__ */
|
|
962
|
+
/* @__PURE__ */ jsx19("span", { className: "absolute right-2 flex h-3.5 w-3.5 items-center justify-center", children: /* @__PURE__ */ jsx19(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx19(Check, { className: "h-4 w-4" }) }) }),
|
|
963
|
+
/* @__PURE__ */ jsx19(SelectPrimitive.ItemText, { children })
|
|
514
964
|
]
|
|
515
965
|
}
|
|
516
966
|
));
|
|
517
967
|
SelectItem.displayName = SelectPrimitive.Item.displayName;
|
|
518
|
-
var SelectSeparator =
|
|
968
|
+
var SelectSeparator = React9.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx19(
|
|
519
969
|
SelectPrimitive.Separator,
|
|
520
970
|
{
|
|
521
971
|
ref,
|
|
@@ -526,7 +976,7 @@ var SelectSeparator = React7.forwardRef(({ className, ...props }, ref) => /* @__
|
|
|
526
976
|
SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
|
|
527
977
|
|
|
528
978
|
// src/tenant-switcher/index.tsx
|
|
529
|
-
import { jsx as
|
|
979
|
+
import { jsx as jsx20, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
530
980
|
function SwitchActiveTenant({
|
|
531
981
|
tenants,
|
|
532
982
|
currentTenantId,
|
|
@@ -535,7 +985,7 @@ function SwitchActiveTenant({
|
|
|
535
985
|
className,
|
|
536
986
|
onTenantChange
|
|
537
987
|
}) {
|
|
538
|
-
const [isLoading, setIsLoading] =
|
|
988
|
+
const [isLoading, setIsLoading] = React10.useState(false);
|
|
539
989
|
const handleTenantChange = async (tenantId) => {
|
|
540
990
|
if (tenantId === currentTenantId) return;
|
|
541
991
|
setIsLoading(true);
|
|
@@ -553,24 +1003,24 @@ function SwitchActiveTenant({
|
|
|
553
1003
|
}
|
|
554
1004
|
};
|
|
555
1005
|
const currentTenant = tenants.find((tenant) => tenant.id === currentTenantId);
|
|
556
|
-
return /* @__PURE__ */
|
|
1006
|
+
return /* @__PURE__ */ jsxs11(
|
|
557
1007
|
Select,
|
|
558
1008
|
{
|
|
559
1009
|
value: currentTenantId,
|
|
560
1010
|
onValueChange: handleTenantChange,
|
|
561
1011
|
disabled: isLoading,
|
|
562
1012
|
children: [
|
|
563
|
-
/* @__PURE__ */
|
|
564
|
-
/* @__PURE__ */
|
|
1013
|
+
/* @__PURE__ */ jsx20(SelectTrigger, { className: cn("max-w-64", className), children: /* @__PURE__ */ jsx20(SelectValue, { placeholder, children: currentTenant ? currentTenant.name : placeholder }) }),
|
|
1014
|
+
/* @__PURE__ */ jsx20(SelectContent, { children: tenants.map((tenant) => /* @__PURE__ */ jsx20(SelectItem, { value: tenant.id, children: tenant.name }, tenant.id)) })
|
|
565
1015
|
]
|
|
566
1016
|
}
|
|
567
1017
|
);
|
|
568
1018
|
}
|
|
569
1019
|
|
|
570
1020
|
// src/pricing-table/index.tsx
|
|
571
|
-
import * as
|
|
1021
|
+
import * as React11 from "react";
|
|
572
1022
|
import { Check as Check2, Star, ChevronLeft, ChevronRight } from "lucide-react";
|
|
573
|
-
import { Fragment, jsx as
|
|
1023
|
+
import { Fragment, jsx as jsx21, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
574
1024
|
var getCurrencySymbol = (currency) => {
|
|
575
1025
|
const symbols = {
|
|
576
1026
|
USD: "$",
|
|
@@ -611,7 +1061,7 @@ function PricingCard({
|
|
|
611
1061
|
}) {
|
|
612
1062
|
const ui = product.ui || {};
|
|
613
1063
|
const isHighlighted = ui.highlighted;
|
|
614
|
-
return /* @__PURE__ */
|
|
1064
|
+
return /* @__PURE__ */ jsxs12(
|
|
615
1065
|
"div",
|
|
616
1066
|
{
|
|
617
1067
|
className: cn(
|
|
@@ -619,11 +1069,11 @@ function PricingCard({
|
|
|
619
1069
|
isHighlighted ? "relative" : ""
|
|
620
1070
|
),
|
|
621
1071
|
children: [
|
|
622
|
-
/* @__PURE__ */
|
|
623
|
-
ui.badge === "Most Popular" && /* @__PURE__ */
|
|
1072
|
+
/* @__PURE__ */ jsx21("div", { className: "h-4 flex-shrink-0 relative", children: ui.badge && /* @__PURE__ */ jsx21("div", { className: "absolute top-0 left-1/2 transform -translate-x-1/2 z-10", children: /* @__PURE__ */ jsxs12("div", { className: "bg-primary text-primary-foreground px-3 py-1 rounded-full text-sm font-medium flex items-center gap-1 whitespace-nowrap shadow-md", children: [
|
|
1073
|
+
ui.badge === "Most Popular" && /* @__PURE__ */ jsx21(Star, { className: "w-3 h-3" }),
|
|
624
1074
|
ui.badge
|
|
625
1075
|
] }) }) }),
|
|
626
|
-
/* @__PURE__ */
|
|
1076
|
+
/* @__PURE__ */ jsxs12(
|
|
627
1077
|
Card,
|
|
628
1078
|
{
|
|
629
1079
|
className: cn(
|
|
@@ -632,36 +1082,36 @@ function PricingCard({
|
|
|
632
1082
|
isSelected && "ring-2 ring-primary"
|
|
633
1083
|
),
|
|
634
1084
|
children: [
|
|
635
|
-
/* @__PURE__ */
|
|
636
|
-
/* @__PURE__ */
|
|
637
|
-
ui.tagline && /* @__PURE__ */
|
|
1085
|
+
/* @__PURE__ */ jsxs12(CardHeader, { className: "text-center", children: [
|
|
1086
|
+
/* @__PURE__ */ jsx21(CardTitle, { className: "text-xl font-bold", children: ui.display_name || product.name }),
|
|
1087
|
+
ui.tagline && /* @__PURE__ */ jsx21(CardDescription, { className: "text-base", children: ui.tagline })
|
|
638
1088
|
] }),
|
|
639
|
-
/* @__PURE__ */
|
|
640
|
-
/* @__PURE__ */
|
|
641
|
-
/* @__PURE__ */
|
|
642
|
-
/* @__PURE__ */
|
|
1089
|
+
/* @__PURE__ */ jsxs12(CardContent, { className: "flex-1 space-y-6", children: [
|
|
1090
|
+
/* @__PURE__ */ jsxs12("div", { className: "text-center", children: [
|
|
1091
|
+
/* @__PURE__ */ jsx21("div", { className: "text-3xl font-bold", children: formatPrice(displayedPrice) }),
|
|
1092
|
+
/* @__PURE__ */ jsx21("div", { className: "text-sm text-muted-foreground", children: formatBillingPeriod(displayedPrice) })
|
|
643
1093
|
] }),
|
|
644
|
-
(ui.features && ui.features.length > 0 || displayedPrice.ui?.features?.length > 0 || displayedPrice.ui?.limits?.length > 0) && /* @__PURE__ */
|
|
645
|
-
ui.features && ui.features.length > 0 && /* @__PURE__ */
|
|
646
|
-
/* @__PURE__ */
|
|
647
|
-
/* @__PURE__ */
|
|
648
|
-
/* @__PURE__ */
|
|
649
|
-
/* @__PURE__ */
|
|
1094
|
+
(ui.features && ui.features.length > 0 || displayedPrice.ui?.features?.length > 0 || displayedPrice.ui?.limits?.length > 0) && /* @__PURE__ */ jsxs12("div", { className: "space-y-4", children: [
|
|
1095
|
+
ui.features && ui.features.length > 0 && /* @__PURE__ */ jsxs12("div", { className: "space-y-2", children: [
|
|
1096
|
+
/* @__PURE__ */ jsx21("h4", { className: "font-medium text-sm text-muted-foreground uppercase tracking-wide", children: "Features" }),
|
|
1097
|
+
/* @__PURE__ */ jsx21("ul", { className: "space-y-2", children: ui.features.map((feature, index) => /* @__PURE__ */ jsxs12("li", { className: "flex items-start gap-2", children: [
|
|
1098
|
+
/* @__PURE__ */ jsx21(Check2, { className: "w-4 h-4 text-green-500 mt-0.5 flex-shrink-0" }),
|
|
1099
|
+
/* @__PURE__ */ jsx21("span", { className: "text-sm", children: feature })
|
|
650
1100
|
] }, index)) })
|
|
651
1101
|
] }),
|
|
652
|
-
displayedPrice.ui?.features && displayedPrice.ui.features.length > 0 && /* @__PURE__ */
|
|
653
|
-
/* @__PURE__ */
|
|
654
|
-
/* @__PURE__ */
|
|
655
|
-
(feature, index) => /* @__PURE__ */
|
|
656
|
-
/* @__PURE__ */
|
|
657
|
-
/* @__PURE__ */
|
|
1102
|
+
displayedPrice.ui?.features && displayedPrice.ui.features.length > 0 && /* @__PURE__ */ jsxs12("div", { className: "space-y-2", children: [
|
|
1103
|
+
/* @__PURE__ */ jsx21("h4", { className: "font-medium text-sm text-muted-foreground uppercase tracking-wide", children: "This Plan" }),
|
|
1104
|
+
/* @__PURE__ */ jsx21("ul", { className: "space-y-2", children: displayedPrice.ui.features.map(
|
|
1105
|
+
(feature, index) => /* @__PURE__ */ jsxs12("li", { className: "flex items-start gap-2", children: [
|
|
1106
|
+
/* @__PURE__ */ jsx21(Check2, { className: "w-4 h-4 text-blue-500 mt-0.5 flex-shrink-0" }),
|
|
1107
|
+
/* @__PURE__ */ jsx21("span", { className: "text-sm", children: feature })
|
|
658
1108
|
] }, index)
|
|
659
1109
|
) })
|
|
660
1110
|
] }),
|
|
661
|
-
displayedPrice.ui?.limits && displayedPrice.ui.limits.length > 0 && /* @__PURE__ */
|
|
662
|
-
/* @__PURE__ */
|
|
663
|
-
/* @__PURE__ */
|
|
664
|
-
(limit, index) => /* @__PURE__ */
|
|
1111
|
+
displayedPrice.ui?.limits && displayedPrice.ui.limits.length > 0 && /* @__PURE__ */ jsxs12("div", { className: "space-y-2", children: [
|
|
1112
|
+
/* @__PURE__ */ jsx21("h4", { className: "font-medium text-sm text-muted-foreground uppercase tracking-wide", children: "Usage Limits" }),
|
|
1113
|
+
/* @__PURE__ */ jsx21("ul", { className: "space-y-1", children: displayedPrice.ui.limits.map(
|
|
1114
|
+
(limit, index) => /* @__PURE__ */ jsx21(
|
|
665
1115
|
"li",
|
|
666
1116
|
{
|
|
667
1117
|
className: "text-sm text-muted-foreground",
|
|
@@ -673,7 +1123,7 @@ function PricingCard({
|
|
|
673
1123
|
] })
|
|
674
1124
|
] })
|
|
675
1125
|
] }),
|
|
676
|
-
/* @__PURE__ */
|
|
1126
|
+
/* @__PURE__ */ jsx21(CardFooter, { children: /* @__PURE__ */ jsx21(
|
|
677
1127
|
Button,
|
|
678
1128
|
{
|
|
679
1129
|
className: "w-full",
|
|
@@ -700,24 +1150,24 @@ function PricingTable({
|
|
|
700
1150
|
showPricingToggle = false,
|
|
701
1151
|
defaultInterval = "month"
|
|
702
1152
|
}) {
|
|
703
|
-
const [selectedInterval, setSelectedInterval] =
|
|
704
|
-
const [carouselIndex, setCarouselIndex] =
|
|
705
|
-
const sortedProducts =
|
|
1153
|
+
const [selectedInterval, setSelectedInterval] = React11.useState(defaultInterval);
|
|
1154
|
+
const [carouselIndex, setCarouselIndex] = React11.useState(0);
|
|
1155
|
+
const sortedProducts = React11.useMemo(
|
|
706
1156
|
() => [...products].sort(
|
|
707
1157
|
(a, b) => (a.ui?.sort_order ?? 999) - (b.ui?.sort_order ?? 999)
|
|
708
1158
|
),
|
|
709
1159
|
[products]
|
|
710
1160
|
);
|
|
711
|
-
const hasMultipleIntervals =
|
|
1161
|
+
const hasMultipleIntervals = React11.useMemo(
|
|
712
1162
|
() => products.some(
|
|
713
1163
|
(p) => new Set(p.prices.map((price) => price.interval)).size > 1
|
|
714
1164
|
),
|
|
715
1165
|
[products]
|
|
716
1166
|
);
|
|
717
|
-
const getDisplayedPrice = (product) => product.prices.find((
|
|
1167
|
+
const getDisplayedPrice = (product) => product.prices.find((price) => price.interval === selectedInterval) || product.prices[0];
|
|
718
1168
|
const renderCard = (product) => {
|
|
719
1169
|
const displayedPrice = getDisplayedPrice(product);
|
|
720
|
-
return /* @__PURE__ */
|
|
1170
|
+
return /* @__PURE__ */ jsx21(
|
|
721
1171
|
PricingCard,
|
|
722
1172
|
{
|
|
723
1173
|
product,
|
|
@@ -727,8 +1177,8 @@ function PricingTable({
|
|
|
727
1177
|
}
|
|
728
1178
|
);
|
|
729
1179
|
};
|
|
730
|
-
const desktopCarousel = /* @__PURE__ */
|
|
731
|
-
/* @__PURE__ */
|
|
1180
|
+
const desktopCarousel = /* @__PURE__ */ jsxs12("div", { className: "relative max-w-7xl mx-auto", children: [
|
|
1181
|
+
/* @__PURE__ */ jsx21(
|
|
732
1182
|
Button,
|
|
733
1183
|
{
|
|
734
1184
|
variant: "ghost",
|
|
@@ -736,15 +1186,15 @@ function PricingTable({
|
|
|
736
1186
|
className: "absolute left-0 top-1/2 transform -translate-y-1/2 -translate-x-4 z-10 bg-white shadow-lg border hover:bg-gray-50 disabled:opacity-50",
|
|
737
1187
|
onClick: () => setCarouselIndex(Math.max(0, carouselIndex - 1)),
|
|
738
1188
|
disabled: carouselIndex === 0,
|
|
739
|
-
children: /* @__PURE__ */
|
|
1189
|
+
children: /* @__PURE__ */ jsx21(ChevronLeft, { className: "w-4 h-4" })
|
|
740
1190
|
}
|
|
741
1191
|
),
|
|
742
|
-
/* @__PURE__ */
|
|
1192
|
+
/* @__PURE__ */ jsx21(
|
|
743
1193
|
"div",
|
|
744
1194
|
{
|
|
745
1195
|
className: "overflow-hidden mx-auto",
|
|
746
1196
|
style: { width: `${3 * CARD_WIDTH + 2 * GAP}px` },
|
|
747
|
-
children: /* @__PURE__ */
|
|
1197
|
+
children: /* @__PURE__ */ jsx21(
|
|
748
1198
|
"div",
|
|
749
1199
|
{
|
|
750
1200
|
className: "flex items-stretch transition-transform duration-300 ease-in-out",
|
|
@@ -752,7 +1202,7 @@ function PricingTable({
|
|
|
752
1202
|
transform: `translateX(-${carouselIndex * (CARD_WIDTH + GAP)}px)`,
|
|
753
1203
|
gap: `${GAP}px`
|
|
754
1204
|
},
|
|
755
|
-
children: sortedProducts.map((p) => /* @__PURE__ */
|
|
1205
|
+
children: sortedProducts.map((p) => /* @__PURE__ */ jsx21(
|
|
756
1206
|
"div",
|
|
757
1207
|
{
|
|
758
1208
|
style: { width: `${CARD_WIDTH}px` },
|
|
@@ -765,7 +1215,7 @@ function PricingTable({
|
|
|
765
1215
|
)
|
|
766
1216
|
}
|
|
767
1217
|
),
|
|
768
|
-
/* @__PURE__ */
|
|
1218
|
+
/* @__PURE__ */ jsx21(
|
|
769
1219
|
Button,
|
|
770
1220
|
{
|
|
771
1221
|
variant: "ghost",
|
|
@@ -775,12 +1225,12 @@ function PricingTable({
|
|
|
775
1225
|
Math.min(sortedProducts.length - 3, carouselIndex + 1)
|
|
776
1226
|
),
|
|
777
1227
|
disabled: carouselIndex >= sortedProducts.length - 3,
|
|
778
|
-
children: /* @__PURE__ */
|
|
1228
|
+
children: /* @__PURE__ */ jsx21(ChevronRight, { className: "w-4 h-4" })
|
|
779
1229
|
}
|
|
780
1230
|
),
|
|
781
|
-
/* @__PURE__ */
|
|
1231
|
+
/* @__PURE__ */ jsx21("div", { className: "flex justify-center mt-6 space-x-2", children: Array.from(
|
|
782
1232
|
{ length: Math.max(1, sortedProducts.length - 2) },
|
|
783
|
-
(_, i) => /* @__PURE__ */
|
|
1233
|
+
(_, i) => /* @__PURE__ */ jsx21(
|
|
784
1234
|
"button",
|
|
785
1235
|
{
|
|
786
1236
|
onClick: () => setCarouselIndex(i),
|
|
@@ -794,12 +1244,12 @@ function PricingTable({
|
|
|
794
1244
|
)
|
|
795
1245
|
) })
|
|
796
1246
|
] });
|
|
797
|
-
const staticLayout = /* @__PURE__ */
|
|
1247
|
+
const staticLayout = /* @__PURE__ */ jsx21(
|
|
798
1248
|
"div",
|
|
799
1249
|
{
|
|
800
1250
|
className: "flex flex-row items-stretch justify-center",
|
|
801
1251
|
style: { gap: `${GAP}px` },
|
|
802
|
-
children: sortedProducts.map((p) => /* @__PURE__ */
|
|
1252
|
+
children: sortedProducts.map((p) => /* @__PURE__ */ jsx21(
|
|
803
1253
|
"div",
|
|
804
1254
|
{
|
|
805
1255
|
style: { width: `${CARD_WIDTH}px` },
|
|
@@ -810,9 +1260,9 @@ function PricingTable({
|
|
|
810
1260
|
))
|
|
811
1261
|
}
|
|
812
1262
|
);
|
|
813
|
-
return /* @__PURE__ */
|
|
814
|
-
showPricingToggle && hasMultipleIntervals && /* @__PURE__ */
|
|
815
|
-
/* @__PURE__ */
|
|
1263
|
+
return /* @__PURE__ */ jsxs12("div", { className: cn("w-full", className), children: [
|
|
1264
|
+
showPricingToggle && hasMultipleIntervals && /* @__PURE__ */ jsx21("div", { className: "flex justify-center mb-4", children: /* @__PURE__ */ jsxs12("div", { className: "flex bg-gray-100 p-1 rounded-lg", children: [
|
|
1265
|
+
/* @__PURE__ */ jsx21(
|
|
816
1266
|
Button,
|
|
817
1267
|
{
|
|
818
1268
|
variant: selectedInterval === "month" ? "default" : "ghost",
|
|
@@ -822,7 +1272,7 @@ function PricingTable({
|
|
|
822
1272
|
children: "Monthly"
|
|
823
1273
|
}
|
|
824
1274
|
),
|
|
825
|
-
/* @__PURE__ */
|
|
1275
|
+
/* @__PURE__ */ jsx21(
|
|
826
1276
|
Button,
|
|
827
1277
|
{
|
|
828
1278
|
variant: selectedInterval === "year" ? "default" : "ghost",
|
|
@@ -833,20 +1283,20 @@ function PricingTable({
|
|
|
833
1283
|
}
|
|
834
1284
|
)
|
|
835
1285
|
] }) }),
|
|
836
|
-
/* @__PURE__ */
|
|
837
|
-
/* @__PURE__ */
|
|
1286
|
+
/* @__PURE__ */ jsxs12("div", { className: "lg:hidden relative", children: [
|
|
1287
|
+
/* @__PURE__ */ jsx21(
|
|
838
1288
|
"div",
|
|
839
1289
|
{
|
|
840
1290
|
className: "overflow-hidden mx-auto",
|
|
841
1291
|
style: { width: `${CARD_WIDTH}px` },
|
|
842
|
-
children: /* @__PURE__ */
|
|
1292
|
+
children: /* @__PURE__ */ jsx21(
|
|
843
1293
|
"div",
|
|
844
1294
|
{
|
|
845
1295
|
className: "flex transition-transform duration-300 ease-in-out items-stretch",
|
|
846
1296
|
style: {
|
|
847
1297
|
transform: `translateX(-${carouselIndex * CARD_WIDTH}px)`
|
|
848
1298
|
},
|
|
849
|
-
children: sortedProducts.map((product) => /* @__PURE__ */
|
|
1299
|
+
children: sortedProducts.map((product) => /* @__PURE__ */ jsx21(
|
|
850
1300
|
"div",
|
|
851
1301
|
{
|
|
852
1302
|
className: "flex-shrink-0",
|
|
@@ -859,8 +1309,8 @@ function PricingTable({
|
|
|
859
1309
|
)
|
|
860
1310
|
}
|
|
861
1311
|
),
|
|
862
|
-
sortedProducts.length > 1 && /* @__PURE__ */
|
|
863
|
-
/* @__PURE__ */
|
|
1312
|
+
sortedProducts.length > 1 && /* @__PURE__ */ jsxs12(Fragment, { children: [
|
|
1313
|
+
/* @__PURE__ */ jsx21(
|
|
864
1314
|
Button,
|
|
865
1315
|
{
|
|
866
1316
|
variant: "ghost",
|
|
@@ -868,10 +1318,10 @@ function PricingTable({
|
|
|
868
1318
|
className: "absolute left-0 top-1/2 -translate-y-1/2 -translate-x-2 z-10 bg-white shadow-lg border hover:bg-gray-50 disabled:opacity-50",
|
|
869
1319
|
onClick: () => setCarouselIndex((prev) => Math.max(0, prev - 1)),
|
|
870
1320
|
disabled: carouselIndex === 0,
|
|
871
|
-
children: /* @__PURE__ */
|
|
1321
|
+
children: /* @__PURE__ */ jsx21(ChevronLeft, { className: "w-5 h-5" })
|
|
872
1322
|
}
|
|
873
1323
|
),
|
|
874
|
-
/* @__PURE__ */
|
|
1324
|
+
/* @__PURE__ */ jsx21(
|
|
875
1325
|
Button,
|
|
876
1326
|
{
|
|
877
1327
|
variant: "ghost",
|
|
@@ -881,10 +1331,10 @@ function PricingTable({
|
|
|
881
1331
|
(prev) => Math.min(sortedProducts.length - 1, prev + 1)
|
|
882
1332
|
),
|
|
883
1333
|
disabled: carouselIndex >= sortedProducts.length - 1,
|
|
884
|
-
children: /* @__PURE__ */
|
|
1334
|
+
children: /* @__PURE__ */ jsx21(ChevronRight, { className: "w-5 h-5" })
|
|
885
1335
|
}
|
|
886
1336
|
),
|
|
887
|
-
/* @__PURE__ */
|
|
1337
|
+
/* @__PURE__ */ jsx21("div", { className: "flex justify-center mt-6 space-x-2", children: Array.from({ length: sortedProducts.length }, (_, i) => /* @__PURE__ */ jsx21(
|
|
888
1338
|
"button",
|
|
889
1339
|
{
|
|
890
1340
|
onClick: () => setCarouselIndex(i),
|
|
@@ -898,30 +1348,32 @@ function PricingTable({
|
|
|
898
1348
|
)) })
|
|
899
1349
|
] })
|
|
900
1350
|
] }),
|
|
901
|
-
/* @__PURE__ */
|
|
1351
|
+
/* @__PURE__ */ jsx21("div", { className: "hidden lg:block", children: sortedProducts.length <= 3 ? staticLayout : desktopCarousel })
|
|
902
1352
|
] });
|
|
903
1353
|
}
|
|
904
1354
|
|
|
905
1355
|
// src/tenant-creator/index.tsx
|
|
906
|
-
import { useState as
|
|
907
|
-
import { jsx as
|
|
1356
|
+
import { useState as useState4, useEffect as useEffect2 } from "react";
|
|
1357
|
+
import { jsx as jsx22, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
908
1358
|
function TenantCreator({
|
|
909
1359
|
config = {},
|
|
910
1360
|
formActions = {},
|
|
911
1361
|
className
|
|
912
1362
|
}) {
|
|
913
|
-
const [mode, setMode] =
|
|
914
|
-
config.defaultMode || "create"
|
|
1363
|
+
const [mode, setMode] = useState4(
|
|
1364
|
+
!!config.joinForm?.token?.defaultValue === true ? "join" : config.defaultMode || "create"
|
|
915
1365
|
);
|
|
916
|
-
const [isLoading, setIsLoading] =
|
|
917
|
-
const [organizationName, setOrganizationName] =
|
|
1366
|
+
const [isLoading, setIsLoading] = useState4(false);
|
|
1367
|
+
const [organizationName, setOrganizationName] = useState4(
|
|
918
1368
|
config.createForm?.organizationName?.defaultValue || ""
|
|
919
1369
|
);
|
|
920
|
-
const [billingEmail, setBillingEmail] =
|
|
1370
|
+
const [billingEmail, setBillingEmail] = useState4(
|
|
921
1371
|
config.createForm?.billingEmail?.defaultValue || ""
|
|
922
1372
|
);
|
|
923
|
-
const [token, setToken] =
|
|
924
|
-
|
|
1373
|
+
const [token, setToken] = useState4(
|
|
1374
|
+
config.joinForm?.token?.defaultValue || ""
|
|
1375
|
+
);
|
|
1376
|
+
useEffect2(() => {
|
|
925
1377
|
const urlParams = new URLSearchParams(window.location.search);
|
|
926
1378
|
const inviteToken = urlParams.get("invite_token");
|
|
927
1379
|
if (inviteToken) {
|
|
@@ -951,14 +1403,14 @@ function TenantCreator({
|
|
|
951
1403
|
setIsLoading(false);
|
|
952
1404
|
}
|
|
953
1405
|
};
|
|
954
|
-
return /* @__PURE__ */
|
|
955
|
-
/* @__PURE__ */
|
|
956
|
-
/* @__PURE__ */
|
|
957
|
-
/* @__PURE__ */
|
|
1406
|
+
return /* @__PURE__ */ jsxs13(Card, { className: cn("w-full max-w-md mx-auto", className), children: [
|
|
1407
|
+
/* @__PURE__ */ jsxs13(CardHeader, { children: [
|
|
1408
|
+
/* @__PURE__ */ jsx22(CardTitle, { children: "Organization Setup" }),
|
|
1409
|
+
/* @__PURE__ */ jsx22(CardDescription, { children: "Choose how you want to get started with your organization." })
|
|
958
1410
|
] }),
|
|
959
|
-
/* @__PURE__ */
|
|
960
|
-
/* @__PURE__ */
|
|
961
|
-
/* @__PURE__ */
|
|
1411
|
+
/* @__PURE__ */ jsxs13(CardContent, { className: "space-y-6", children: [
|
|
1412
|
+
/* @__PURE__ */ jsxs13("div", { className: "grid grid-cols-2 rounded-lg bg-muted p-1", children: [
|
|
1413
|
+
/* @__PURE__ */ jsxs13(
|
|
962
1414
|
"label",
|
|
963
1415
|
{
|
|
964
1416
|
className: cn(
|
|
@@ -967,7 +1419,7 @@ function TenantCreator({
|
|
|
967
1419
|
isLoading && "pointer-events-none opacity-50"
|
|
968
1420
|
),
|
|
969
1421
|
children: [
|
|
970
|
-
/* @__PURE__ */
|
|
1422
|
+
/* @__PURE__ */ jsx22(
|
|
971
1423
|
"input",
|
|
972
1424
|
{
|
|
973
1425
|
type: "radio",
|
|
@@ -983,7 +1435,7 @@ function TenantCreator({
|
|
|
983
1435
|
]
|
|
984
1436
|
}
|
|
985
1437
|
),
|
|
986
|
-
/* @__PURE__ */
|
|
1438
|
+
/* @__PURE__ */ jsxs13(
|
|
987
1439
|
"label",
|
|
988
1440
|
{
|
|
989
1441
|
className: cn(
|
|
@@ -992,7 +1444,7 @@ function TenantCreator({
|
|
|
992
1444
|
isLoading && "pointer-events-none opacity-50"
|
|
993
1445
|
),
|
|
994
1446
|
children: [
|
|
995
|
-
/* @__PURE__ */
|
|
1447
|
+
/* @__PURE__ */ jsx22(
|
|
996
1448
|
"input",
|
|
997
1449
|
{
|
|
998
1450
|
type: "radio",
|
|
@@ -1009,10 +1461,10 @@ function TenantCreator({
|
|
|
1009
1461
|
}
|
|
1010
1462
|
)
|
|
1011
1463
|
] }),
|
|
1012
|
-
mode === "create" && /* @__PURE__ */
|
|
1013
|
-
/* @__PURE__ */
|
|
1014
|
-
/* @__PURE__ */
|
|
1015
|
-
/* @__PURE__ */
|
|
1464
|
+
mode === "create" && /* @__PURE__ */ jsxs13("form", { onSubmit: handleCreateSubmit, className: "space-y-4", children: [
|
|
1465
|
+
/* @__PURE__ */ jsxs13("div", { className: "space-y-2", children: [
|
|
1466
|
+
/* @__PURE__ */ jsx22(Label, { htmlFor: "organizationName", children: config.createForm?.organizationName?.label || "Organization Name" }),
|
|
1467
|
+
/* @__PURE__ */ jsx22(
|
|
1016
1468
|
Input,
|
|
1017
1469
|
{
|
|
1018
1470
|
id: "organizationName",
|
|
@@ -1026,9 +1478,9 @@ function TenantCreator({
|
|
|
1026
1478
|
}
|
|
1027
1479
|
)
|
|
1028
1480
|
] }),
|
|
1029
|
-
/* @__PURE__ */
|
|
1030
|
-
/* @__PURE__ */
|
|
1031
|
-
/* @__PURE__ */
|
|
1481
|
+
/* @__PURE__ */ jsxs13("div", { className: "space-y-2", children: [
|
|
1482
|
+
/* @__PURE__ */ jsx22(Label, { htmlFor: "billingEmail", children: config.createForm?.billingEmail?.label || "Billing Email" }),
|
|
1483
|
+
/* @__PURE__ */ jsx22(
|
|
1032
1484
|
Input,
|
|
1033
1485
|
{
|
|
1034
1486
|
id: "billingEmail",
|
|
@@ -1042,12 +1494,12 @@ function TenantCreator({
|
|
|
1042
1494
|
}
|
|
1043
1495
|
)
|
|
1044
1496
|
] }),
|
|
1045
|
-
/* @__PURE__ */
|
|
1497
|
+
/* @__PURE__ */ jsx22(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? "Creating..." : "Create Organization" })
|
|
1046
1498
|
] }),
|
|
1047
|
-
mode === "join" && /* @__PURE__ */
|
|
1048
|
-
/* @__PURE__ */
|
|
1049
|
-
/* @__PURE__ */
|
|
1050
|
-
/* @__PURE__ */
|
|
1499
|
+
mode === "join" && /* @__PURE__ */ jsxs13("form", { onSubmit: handleJoinSubmit, className: "space-y-4", children: [
|
|
1500
|
+
/* @__PURE__ */ jsxs13("div", { className: "space-y-2", children: [
|
|
1501
|
+
/* @__PURE__ */ jsx22(Label, { htmlFor: "token", children: config.joinForm?.token?.label || "Invitation Token" }),
|
|
1502
|
+
/* @__PURE__ */ jsx22(
|
|
1051
1503
|
Input,
|
|
1052
1504
|
{
|
|
1053
1505
|
id: "token",
|
|
@@ -1061,14 +1513,476 @@ function TenantCreator({
|
|
|
1061
1513
|
}
|
|
1062
1514
|
)
|
|
1063
1515
|
] }),
|
|
1064
|
-
/* @__PURE__ */
|
|
1516
|
+
/* @__PURE__ */ jsx22(Button, { type: "submit", className: "w-full", disabled: isLoading, children: isLoading ? "Joining..." : "Join Organization" })
|
|
1517
|
+
] })
|
|
1518
|
+
] })
|
|
1519
|
+
] });
|
|
1520
|
+
}
|
|
1521
|
+
|
|
1522
|
+
// src/user-invite/index.tsx
|
|
1523
|
+
import { useState as useState5 } from "react";
|
|
1524
|
+
import { jsx as jsx23, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
1525
|
+
function UserInvite({ roles, onInvite }) {
|
|
1526
|
+
const [email, setEmail] = useState5("");
|
|
1527
|
+
const [selectedRole, setSelectedRole] = useState5("");
|
|
1528
|
+
const [isSubmitting, setIsSubmitting] = useState5(false);
|
|
1529
|
+
const [error, setError] = useState5(null);
|
|
1530
|
+
const isValidEmail = (email2) => {
|
|
1531
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
1532
|
+
return emailRegex.test(email2);
|
|
1533
|
+
};
|
|
1534
|
+
const isFormValid = () => {
|
|
1535
|
+
return email.trim() !== "" && isValidEmail(email) && selectedRole !== "";
|
|
1536
|
+
};
|
|
1537
|
+
const handleSubmit = async (e) => {
|
|
1538
|
+
e.preventDefault();
|
|
1539
|
+
setError(null);
|
|
1540
|
+
if (!isFormValid()) {
|
|
1541
|
+
setError("Please fill in all fields with valid data");
|
|
1542
|
+
return;
|
|
1543
|
+
}
|
|
1544
|
+
setIsSubmitting(true);
|
|
1545
|
+
try {
|
|
1546
|
+
const inviteData = {
|
|
1547
|
+
email: email.trim(),
|
|
1548
|
+
role: selectedRole
|
|
1549
|
+
};
|
|
1550
|
+
await onInvite?.(inviteData);
|
|
1551
|
+
setEmail("");
|
|
1552
|
+
setSelectedRole("");
|
|
1553
|
+
} catch (err) {
|
|
1554
|
+
setError(
|
|
1555
|
+
err instanceof Error ? err.message : "Failed to send invitation"
|
|
1556
|
+
);
|
|
1557
|
+
} finally {
|
|
1558
|
+
setIsSubmitting(false);
|
|
1559
|
+
}
|
|
1560
|
+
};
|
|
1561
|
+
const handleReset = () => {
|
|
1562
|
+
setEmail("");
|
|
1563
|
+
setSelectedRole("");
|
|
1564
|
+
setError(null);
|
|
1565
|
+
};
|
|
1566
|
+
return /* @__PURE__ */ jsxs14(Card, { className: "w-full max-w-2xl", children: [
|
|
1567
|
+
/* @__PURE__ */ jsxs14(CardHeader, { children: [
|
|
1568
|
+
/* @__PURE__ */ jsx23(CardTitle, { children: "Invite User" }),
|
|
1569
|
+
/* @__PURE__ */ jsx23(CardDescription, { children: "Send an invitation to a new user to join your organization" })
|
|
1570
|
+
] }),
|
|
1571
|
+
/* @__PURE__ */ jsx23(CardContent, { children: /* @__PURE__ */ jsxs14("form", { onSubmit: handleSubmit, className: "space-y-6", children: [
|
|
1572
|
+
/* @__PURE__ */ jsxs14("div", { className: "space-y-2", children: [
|
|
1573
|
+
/* @__PURE__ */ jsx23(Label, { htmlFor: "email", children: "Email Address" }),
|
|
1574
|
+
/* @__PURE__ */ jsx23(
|
|
1575
|
+
Input,
|
|
1576
|
+
{
|
|
1577
|
+
id: "email",
|
|
1578
|
+
type: "email",
|
|
1579
|
+
placeholder: "colleague@company.com",
|
|
1580
|
+
value: email,
|
|
1581
|
+
onChange: (e) => setEmail(e.target.value),
|
|
1582
|
+
"aria-invalid": email !== "" && !isValidEmail(email)
|
|
1583
|
+
}
|
|
1584
|
+
),
|
|
1585
|
+
email !== "" && !isValidEmail(email) && /* @__PURE__ */ jsx23("p", { className: "text-xs text-destructive", children: "Please enter a valid email address" })
|
|
1586
|
+
] }),
|
|
1587
|
+
/* @__PURE__ */ jsxs14("div", { className: "space-y-2", children: [
|
|
1588
|
+
/* @__PURE__ */ jsx23(Label, { htmlFor: "role", children: "Role" }),
|
|
1589
|
+
/* @__PURE__ */ jsxs14(Select, { value: selectedRole, onValueChange: setSelectedRole, children: [
|
|
1590
|
+
/* @__PURE__ */ jsx23(SelectTrigger, { id: "role", children: /* @__PURE__ */ jsx23(SelectValue, { placeholder: "Select a role" }) }),
|
|
1591
|
+
/* @__PURE__ */ jsx23(SelectContent, { children: roles.length > 0 ? roles.map((role) => /* @__PURE__ */ jsx23(SelectItem, { value: role, children: role }, role)) : /* @__PURE__ */ jsx23(SelectItem, { value: "no-roles", disabled: true, children: "No roles available" }) })
|
|
1592
|
+
] }),
|
|
1593
|
+
/* @__PURE__ */ jsx23("p", { className: "text-xs text-muted-foreground", children: "The role determines what permissions the user will have" })
|
|
1594
|
+
] }),
|
|
1595
|
+
error && /* @__PURE__ */ jsx23("div", { className: "p-3 rounded-md bg-destructive/10 border border-destructive/20", children: /* @__PURE__ */ jsx23("p", { className: "text-sm text-destructive", children: error }) }),
|
|
1596
|
+
/* @__PURE__ */ jsxs14("div", { className: "flex justify-end space-x-3", children: [
|
|
1597
|
+
/* @__PURE__ */ jsx23(
|
|
1598
|
+
Button,
|
|
1599
|
+
{
|
|
1600
|
+
type: "button",
|
|
1601
|
+
variant: "outline",
|
|
1602
|
+
onClick: handleReset,
|
|
1603
|
+
disabled: isSubmitting,
|
|
1604
|
+
children: "Reset"
|
|
1605
|
+
}
|
|
1606
|
+
),
|
|
1607
|
+
/* @__PURE__ */ jsx23(Button, { type: "submit", disabled: !isFormValid() || isSubmitting, children: isSubmitting ? "Sending..." : "Send Invitation" })
|
|
1608
|
+
] })
|
|
1609
|
+
] }) })
|
|
1610
|
+
] });
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
// src/role-creator/index.tsx
|
|
1614
|
+
import { useState as useState6, useMemo as useMemo2 } from "react";
|
|
1615
|
+
|
|
1616
|
+
// src/components/ui/checkbox.tsx
|
|
1617
|
+
import "react";
|
|
1618
|
+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
|
|
1619
|
+
import { CheckIcon } from "lucide-react";
|
|
1620
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1621
|
+
function Checkbox({
|
|
1622
|
+
className,
|
|
1623
|
+
...props
|
|
1624
|
+
}) {
|
|
1625
|
+
return /* @__PURE__ */ jsx24(
|
|
1626
|
+
CheckboxPrimitive.Root,
|
|
1627
|
+
{
|
|
1628
|
+
"data-slot": "checkbox",
|
|
1629
|
+
className: cn(
|
|
1630
|
+
"peer border-input dark:bg-input/30 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:data-[state=checked]:bg-primary data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
|
|
1631
|
+
className
|
|
1632
|
+
),
|
|
1633
|
+
...props,
|
|
1634
|
+
children: /* @__PURE__ */ jsx24(
|
|
1635
|
+
CheckboxPrimitive.Indicator,
|
|
1636
|
+
{
|
|
1637
|
+
"data-slot": "checkbox-indicator",
|
|
1638
|
+
className: "grid place-content-center text-current transition-none",
|
|
1639
|
+
children: /* @__PURE__ */ jsx24(CheckIcon, { className: "size-3.5" })
|
|
1640
|
+
}
|
|
1641
|
+
)
|
|
1642
|
+
}
|
|
1643
|
+
);
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
// src/components/ui/separator.tsx
|
|
1647
|
+
import "react";
|
|
1648
|
+
import * as SeparatorPrimitive from "@radix-ui/react-separator";
|
|
1649
|
+
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
1650
|
+
function Separator2({
|
|
1651
|
+
className,
|
|
1652
|
+
orientation = "horizontal",
|
|
1653
|
+
decorative = true,
|
|
1654
|
+
...props
|
|
1655
|
+
}) {
|
|
1656
|
+
return /* @__PURE__ */ jsx25(
|
|
1657
|
+
SeparatorPrimitive.Root,
|
|
1658
|
+
{
|
|
1659
|
+
"data-slot": "separator",
|
|
1660
|
+
decorative,
|
|
1661
|
+
orientation,
|
|
1662
|
+
className: cn(
|
|
1663
|
+
"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
|
|
1664
|
+
className
|
|
1665
|
+
),
|
|
1666
|
+
...props
|
|
1667
|
+
}
|
|
1668
|
+
);
|
|
1669
|
+
}
|
|
1670
|
+
|
|
1671
|
+
// src/role-creator/index.tsx
|
|
1672
|
+
import { Fragment as Fragment2, jsx as jsx26, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
1673
|
+
function RoleCreator({
|
|
1674
|
+
definitions,
|
|
1675
|
+
roles,
|
|
1676
|
+
namespaceMap = {},
|
|
1677
|
+
onRoleCreate,
|
|
1678
|
+
onRoleUpdate
|
|
1679
|
+
}) {
|
|
1680
|
+
const [roleName, setRoleName] = useState6("");
|
|
1681
|
+
const [selectedPermissions, setSelectedPermissions] = useState6(
|
|
1682
|
+
/* @__PURE__ */ new Set()
|
|
1683
|
+
);
|
|
1684
|
+
const [showSuggestions, setShowSuggestions] = useState6(false);
|
|
1685
|
+
const [isEditMode, setIsEditMode] = useState6(false);
|
|
1686
|
+
const [editingRoleId, setEditingRoleId] = useState6(null);
|
|
1687
|
+
const { tenantNamespace, fineGrainedNamespaces } = useMemo2(() => {
|
|
1688
|
+
const tenant = definitions.find(
|
|
1689
|
+
(def) => def.namespace.toLowerCase() === "tenant"
|
|
1690
|
+
);
|
|
1691
|
+
const fineGrained = definitions.filter(
|
|
1692
|
+
(def) => def.namespace.toLowerCase() !== "tenant"
|
|
1693
|
+
);
|
|
1694
|
+
return {
|
|
1695
|
+
tenantNamespace: tenant,
|
|
1696
|
+
fineGrainedNamespaces: fineGrained
|
|
1697
|
+
};
|
|
1698
|
+
}, [definitions]);
|
|
1699
|
+
const roleSuggestions = useMemo2(() => {
|
|
1700
|
+
return roles.map((role) => role.role_name);
|
|
1701
|
+
}, [roles]);
|
|
1702
|
+
const handleRoleNameChange = (value) => {
|
|
1703
|
+
setRoleName(value);
|
|
1704
|
+
const existingRole = roles.find(
|
|
1705
|
+
(role) => role.role_name.toLowerCase() === value.toLowerCase()
|
|
1706
|
+
);
|
|
1707
|
+
if (existingRole) {
|
|
1708
|
+
setIsEditMode(true);
|
|
1709
|
+
setEditingRoleId(existingRole.id);
|
|
1710
|
+
const permissions = /* @__PURE__ */ new Set();
|
|
1711
|
+
existingRole.permissions.forEach((perm) => {
|
|
1712
|
+
permissions.add(perm);
|
|
1713
|
+
});
|
|
1714
|
+
setSelectedPermissions(permissions);
|
|
1715
|
+
} else {
|
|
1716
|
+
setIsEditMode(false);
|
|
1717
|
+
setEditingRoleId(null);
|
|
1718
|
+
}
|
|
1719
|
+
};
|
|
1720
|
+
const buildPermissionString = (namespace, relation, resourceId) => {
|
|
1721
|
+
if (resourceId) {
|
|
1722
|
+
return `${namespace.toLowerCase()}:${resourceId}#${relation}`;
|
|
1723
|
+
}
|
|
1724
|
+
return `${namespace.toLowerCase()}#${relation}`;
|
|
1725
|
+
};
|
|
1726
|
+
const togglePermission = (permissionString) => {
|
|
1727
|
+
const newPermissions = new Set(selectedPermissions);
|
|
1728
|
+
if (newPermissions.has(permissionString)) {
|
|
1729
|
+
newPermissions.delete(permissionString);
|
|
1730
|
+
} else {
|
|
1731
|
+
newPermissions.add(permissionString);
|
|
1732
|
+
}
|
|
1733
|
+
setSelectedPermissions(newPermissions);
|
|
1734
|
+
};
|
|
1735
|
+
const handleSubmit = () => {
|
|
1736
|
+
if (!roleName.trim()) return;
|
|
1737
|
+
const permissionsArray = Array.from(selectedPermissions);
|
|
1738
|
+
if (isEditMode && editingRoleId) {
|
|
1739
|
+
onRoleUpdate?.({
|
|
1740
|
+
role_id: editingRoleId,
|
|
1741
|
+
role_name: roleName,
|
|
1742
|
+
permissions: permissionsArray
|
|
1743
|
+
});
|
|
1744
|
+
} else {
|
|
1745
|
+
onRoleCreate?.({
|
|
1746
|
+
role_name: roleName,
|
|
1747
|
+
permissions: permissionsArray
|
|
1748
|
+
});
|
|
1749
|
+
}
|
|
1750
|
+
};
|
|
1751
|
+
const handleReset = () => {
|
|
1752
|
+
setRoleName("");
|
|
1753
|
+
setSelectedPermissions(/* @__PURE__ */ new Set());
|
|
1754
|
+
setIsEditMode(false);
|
|
1755
|
+
setEditingRoleId(null);
|
|
1756
|
+
};
|
|
1757
|
+
return /* @__PURE__ */ jsxs15(Card, { className: "w-full max-w-4xl", children: [
|
|
1758
|
+
/* @__PURE__ */ jsxs15(CardHeader, { children: [
|
|
1759
|
+
/* @__PURE__ */ jsx26(CardTitle, { children: isEditMode ? `Edit Role: ${roleName}` : "Create New Role" }),
|
|
1760
|
+
/* @__PURE__ */ jsx26(CardDescription, { children: isEditMode ? "Update permissions for this existing role" : "Define a new role with specific permissions" })
|
|
1761
|
+
] }),
|
|
1762
|
+
/* @__PURE__ */ jsxs15(CardContent, { className: "space-y-6", children: [
|
|
1763
|
+
/* @__PURE__ */ jsxs15("div", { className: "space-y-2 relative", children: [
|
|
1764
|
+
/* @__PURE__ */ jsx26(Label, { htmlFor: "role-name", children: "Role Name" }),
|
|
1765
|
+
/* @__PURE__ */ jsx26(
|
|
1766
|
+
Input,
|
|
1767
|
+
{
|
|
1768
|
+
id: "role-name",
|
|
1769
|
+
placeholder: "Enter role name (e.g., admin, developer, viewer)",
|
|
1770
|
+
value: roleName,
|
|
1771
|
+
onChange: (e) => handleRoleNameChange(e.target.value),
|
|
1772
|
+
onFocus: () => setShowSuggestions(true),
|
|
1773
|
+
onBlur: () => setTimeout(() => setShowSuggestions(false), 200)
|
|
1774
|
+
}
|
|
1775
|
+
),
|
|
1776
|
+
showSuggestions && roleSuggestions.length > 0 && /* @__PURE__ */ jsx26("div", { className: "absolute z-10 w-full mt-1 bg-background border rounded-md shadow-lg max-h-48 overflow-y-auto", children: roleSuggestions.filter(
|
|
1777
|
+
(suggestion) => suggestion.toLowerCase().includes(roleName.toLowerCase())
|
|
1778
|
+
).map((suggestion) => /* @__PURE__ */ jsx26(
|
|
1779
|
+
"button",
|
|
1780
|
+
{
|
|
1781
|
+
className: "w-full px-4 py-2 text-left hover:bg-accent hover:text-accent-foreground text-sm",
|
|
1782
|
+
onMouseDown: () => {
|
|
1783
|
+
handleRoleNameChange(suggestion);
|
|
1784
|
+
setShowSuggestions(false);
|
|
1785
|
+
},
|
|
1786
|
+
children: suggestion
|
|
1787
|
+
},
|
|
1788
|
+
suggestion
|
|
1789
|
+
)) }),
|
|
1790
|
+
isEditMode && /* @__PURE__ */ jsx26("p", { className: "text-xs text-amber-600 dark:text-amber-400", children: "\u26A0 Editing existing role - changes will update all users with this role" })
|
|
1791
|
+
] }),
|
|
1792
|
+
/* @__PURE__ */ jsx26(Separator2, {}),
|
|
1793
|
+
tenantNamespace && /* @__PURE__ */ jsxs15("div", { className: "space-y-4", children: [
|
|
1794
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1795
|
+
/* @__PURE__ */ jsx26("h3", { className: "text-lg font-semibold", children: "Organization Permissions" }),
|
|
1796
|
+
/* @__PURE__ */ jsx26("p", { className: "text-sm text-muted-foreground", children: "Tenant-wide permissions that apply across the entire organization" })
|
|
1797
|
+
] }),
|
|
1798
|
+
/* @__PURE__ */ jsx26("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-4 pl-4", children: tenantNamespace.relations.map((relation) => {
|
|
1799
|
+
const permissionString = buildPermissionString(
|
|
1800
|
+
tenantNamespace.namespace,
|
|
1801
|
+
relation
|
|
1802
|
+
);
|
|
1803
|
+
const isChecked = selectedPermissions.has(permissionString);
|
|
1804
|
+
return /* @__PURE__ */ jsxs15(
|
|
1805
|
+
"div",
|
|
1806
|
+
{
|
|
1807
|
+
className: "flex items-center space-x-2",
|
|
1808
|
+
children: [
|
|
1809
|
+
/* @__PURE__ */ jsx26(
|
|
1810
|
+
Checkbox,
|
|
1811
|
+
{
|
|
1812
|
+
id: permissionString,
|
|
1813
|
+
checked: isChecked,
|
|
1814
|
+
onCheckedChange: () => togglePermission(permissionString)
|
|
1815
|
+
}
|
|
1816
|
+
),
|
|
1817
|
+
/* @__PURE__ */ jsx26(
|
|
1818
|
+
Label,
|
|
1819
|
+
{
|
|
1820
|
+
htmlFor: permissionString,
|
|
1821
|
+
className: "text-sm font-normal cursor-pointer",
|
|
1822
|
+
children: relation.replace(/_/g, " ")
|
|
1823
|
+
}
|
|
1824
|
+
)
|
|
1825
|
+
]
|
|
1826
|
+
},
|
|
1827
|
+
permissionString
|
|
1828
|
+
);
|
|
1829
|
+
}) })
|
|
1830
|
+
] }),
|
|
1831
|
+
fineGrainedNamespaces.length > 0 && /* @__PURE__ */ jsxs15(Fragment2, { children: [
|
|
1832
|
+
/* @__PURE__ */ jsx26(Separator2, {}),
|
|
1833
|
+
/* @__PURE__ */ jsxs15("div", { className: "space-y-6", children: [
|
|
1834
|
+
/* @__PURE__ */ jsxs15("div", { children: [
|
|
1835
|
+
/* @__PURE__ */ jsx26("h3", { className: "text-lg font-semibold", children: "Fine-Grained Permissions" }),
|
|
1836
|
+
/* @__PURE__ */ jsx26("p", { className: "text-sm text-muted-foreground", children: "Resource-specific permissions that require an object ID" })
|
|
1837
|
+
] }),
|
|
1838
|
+
fineGrainedNamespaces.map((namespace) => {
|
|
1839
|
+
const namespaceLower = namespace.namespace.toLowerCase();
|
|
1840
|
+
const resourceMap = namespaceMap[namespaceLower] || [];
|
|
1841
|
+
return /* @__PURE__ */ jsx26("div", { className: "space-y-4", children: /* @__PURE__ */ jsxs15("div", { className: "pl-4", children: [
|
|
1842
|
+
/* @__PURE__ */ jsx26("h4", { className: "text-md font-medium capitalize", children: namespace.namespace }),
|
|
1843
|
+
resourceMap.length > 0 ? /* @__PURE__ */ jsx26("div", { className: "mt-4 space-y-6", children: resourceMap.map((resource) => /* @__PURE__ */ jsxs15(
|
|
1844
|
+
"div",
|
|
1845
|
+
{
|
|
1846
|
+
className: "border rounded-lg p-4 space-y-3 bg-muted/30",
|
|
1847
|
+
children: [
|
|
1848
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex items-center justify-between", children: [
|
|
1849
|
+
/* @__PURE__ */ jsx26("span", { className: "font-medium text-sm", children: resource.label }),
|
|
1850
|
+
/* @__PURE__ */ jsx26("span", { className: "text-xs text-muted-foreground font-mono", children: resource.id })
|
|
1851
|
+
] }),
|
|
1852
|
+
/* @__PURE__ */ jsx26("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: namespace.relations.map((relation) => {
|
|
1853
|
+
const permissionString = buildPermissionString(
|
|
1854
|
+
namespace.namespace,
|
|
1855
|
+
relation,
|
|
1856
|
+
resource.id
|
|
1857
|
+
);
|
|
1858
|
+
const isChecked = selectedPermissions.has(permissionString);
|
|
1859
|
+
return /* @__PURE__ */ jsxs15(
|
|
1860
|
+
"div",
|
|
1861
|
+
{
|
|
1862
|
+
className: "flex items-center space-x-2",
|
|
1863
|
+
children: [
|
|
1864
|
+
/* @__PURE__ */ jsx26(
|
|
1865
|
+
Checkbox,
|
|
1866
|
+
{
|
|
1867
|
+
id: permissionString,
|
|
1868
|
+
checked: isChecked,
|
|
1869
|
+
onCheckedChange: () => togglePermission(permissionString)
|
|
1870
|
+
}
|
|
1871
|
+
),
|
|
1872
|
+
/* @__PURE__ */ jsx26(
|
|
1873
|
+
Label,
|
|
1874
|
+
{
|
|
1875
|
+
htmlFor: permissionString,
|
|
1876
|
+
className: "text-sm font-normal cursor-pointer",
|
|
1877
|
+
children: relation.replace(/_/g, " ")
|
|
1878
|
+
}
|
|
1879
|
+
)
|
|
1880
|
+
]
|
|
1881
|
+
},
|
|
1882
|
+
permissionString
|
|
1883
|
+
);
|
|
1884
|
+
}) })
|
|
1885
|
+
]
|
|
1886
|
+
},
|
|
1887
|
+
resource.id
|
|
1888
|
+
)) }) : /* @__PURE__ */ jsxs15("div", { className: "mt-3 p-4 border-2 border-dashed rounded-lg text-center", children: [
|
|
1889
|
+
/* @__PURE__ */ jsxs15("p", { className: "text-sm text-muted-foreground", children: [
|
|
1890
|
+
"No ",
|
|
1891
|
+
namespace.namespace.toLowerCase(),
|
|
1892
|
+
" resources available"
|
|
1893
|
+
] }),
|
|
1894
|
+
/* @__PURE__ */ jsxs15("p", { className: "text-xs text-muted-foreground mt-1", children: [
|
|
1895
|
+
"Use wildcard permissions (e.g., ",
|
|
1896
|
+
namespaceLower,
|
|
1897
|
+
":*#permission) for all resources"
|
|
1898
|
+
] })
|
|
1899
|
+
] }),
|
|
1900
|
+
/* @__PURE__ */ jsxs15("div", { className: "mt-4 space-y-2", children: [
|
|
1901
|
+
/* @__PURE__ */ jsxs15(Label, { className: "text-sm font-medium", children: [
|
|
1902
|
+
"Wildcard Permissions (All ",
|
|
1903
|
+
namespace.namespace,
|
|
1904
|
+
"s)"
|
|
1905
|
+
] }),
|
|
1906
|
+
/* @__PURE__ */ jsx26("div", { className: "grid grid-cols-1 md:grid-cols-2 gap-3", children: namespace.relations.map((relation) => {
|
|
1907
|
+
const permissionString = buildPermissionString(
|
|
1908
|
+
namespace.namespace,
|
|
1909
|
+
relation,
|
|
1910
|
+
"*"
|
|
1911
|
+
);
|
|
1912
|
+
const isChecked = selectedPermissions.has(permissionString);
|
|
1913
|
+
return /* @__PURE__ */ jsxs15(
|
|
1914
|
+
"div",
|
|
1915
|
+
{
|
|
1916
|
+
className: "flex items-center space-x-2",
|
|
1917
|
+
children: [
|
|
1918
|
+
/* @__PURE__ */ jsx26(
|
|
1919
|
+
Checkbox,
|
|
1920
|
+
{
|
|
1921
|
+
id: permissionString,
|
|
1922
|
+
checked: isChecked,
|
|
1923
|
+
onCheckedChange: () => togglePermission(permissionString)
|
|
1924
|
+
}
|
|
1925
|
+
),
|
|
1926
|
+
/* @__PURE__ */ jsxs15(
|
|
1927
|
+
Label,
|
|
1928
|
+
{
|
|
1929
|
+
htmlFor: permissionString,
|
|
1930
|
+
className: "text-sm font-normal cursor-pointer",
|
|
1931
|
+
children: [
|
|
1932
|
+
relation.replace(/_/g, " "),
|
|
1933
|
+
" (all)"
|
|
1934
|
+
]
|
|
1935
|
+
}
|
|
1936
|
+
)
|
|
1937
|
+
]
|
|
1938
|
+
},
|
|
1939
|
+
permissionString
|
|
1940
|
+
);
|
|
1941
|
+
}) })
|
|
1942
|
+
] })
|
|
1943
|
+
] }) }, namespace.id);
|
|
1944
|
+
})
|
|
1945
|
+
] })
|
|
1946
|
+
] }),
|
|
1947
|
+
/* @__PURE__ */ jsx26(Separator2, {}),
|
|
1948
|
+
/* @__PURE__ */ jsxs15("div", { className: "space-y-2", children: [
|
|
1949
|
+
/* @__PURE__ */ jsxs15(Label, { className: "text-sm font-medium", children: [
|
|
1950
|
+
"Selected Permissions (",
|
|
1951
|
+
selectedPermissions.size,
|
|
1952
|
+
")"
|
|
1953
|
+
] }),
|
|
1954
|
+
selectedPermissions.size > 0 ? /* @__PURE__ */ jsx26("div", { className: "p-4 bg-muted rounded-md max-h-40 overflow-y-auto", children: /* @__PURE__ */ jsx26("ul", { className: "space-y-1 text-xs font-mono", children: Array.from(selectedPermissions).map((perm) => /* @__PURE__ */ jsx26("li", { className: "text-muted-foreground", children: perm }, perm)) }) }) : /* @__PURE__ */ jsx26("p", { className: "text-sm text-muted-foreground italic", children: "No permissions selected" })
|
|
1955
|
+
] }),
|
|
1956
|
+
/* @__PURE__ */ jsxs15("div", { className: "flex justify-end space-x-3", children: [
|
|
1957
|
+
/* @__PURE__ */ jsx26(Button, { variant: "outline", onClick: handleReset, children: "Reset" }),
|
|
1958
|
+
/* @__PURE__ */ jsx26(
|
|
1959
|
+
Button,
|
|
1960
|
+
{
|
|
1961
|
+
onClick: handleSubmit,
|
|
1962
|
+
disabled: !roleName.trim() || selectedPermissions.size === 0,
|
|
1963
|
+
children: isEditMode ? "Update Role" : "Create Role"
|
|
1964
|
+
}
|
|
1965
|
+
)
|
|
1065
1966
|
] })
|
|
1066
1967
|
] })
|
|
1067
1968
|
] });
|
|
1068
1969
|
}
|
|
1069
1970
|
export {
|
|
1070
|
-
|
|
1971
|
+
LoginForm,
|
|
1071
1972
|
PricingTable,
|
|
1973
|
+
RecoveryForm,
|
|
1974
|
+
RegistrationForm,
|
|
1975
|
+
RoleCreator,
|
|
1976
|
+
SettingsForm,
|
|
1072
1977
|
SwitchActiveTenant,
|
|
1073
|
-
TenantCreator
|
|
1978
|
+
TenantCreator,
|
|
1979
|
+
UserInvite,
|
|
1980
|
+
VerificationForm,
|
|
1981
|
+
filterInputNodes,
|
|
1982
|
+
findAnchorNode,
|
|
1983
|
+
findCsrfToken,
|
|
1984
|
+
findSubmitButton,
|
|
1985
|
+
groupNodesByGroup,
|
|
1986
|
+
isUiNodeInputAttributes,
|
|
1987
|
+
sortNodes
|
|
1074
1988
|
};
|