acai-ui-library 0.1.13 → 0.1.15
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/components/alert.cjs +3 -2
- package/dist/components/alert.cjs.map +1 -1
- package/dist/components/alert.js +3 -2
- package/dist/components/alert.js.map +1 -1
- package/dist/components/card.cjs +1 -1
- package/dist/components/card.cjs.map +1 -1
- package/dist/components/card.js +1 -1
- package/dist/components/card.js.map +1 -1
- package/dist/components/checkbox.cjs +2 -1
- package/dist/components/checkbox.cjs.map +1 -1
- package/dist/components/checkbox.js +2 -1
- package/dist/components/checkbox.js.map +1 -1
- package/dist/components/data-table.cjs +2 -1
- package/dist/components/data-table.cjs.map +1 -1
- package/dist/components/data-table.js +2 -1
- package/dist/components/data-table.js.map +1 -1
- package/dist/components/date-picker.cjs.map +1 -1
- package/dist/components/date-picker.js.map +1 -1
- package/dist/components/dropdown-menu.cjs +2 -2
- package/dist/components/dropdown-menu.cjs.map +1 -1
- package/dist/components/dropdown-menu.js +2 -2
- package/dist/components/dropdown-menu.js.map +1 -1
- package/dist/components/impersonation-banner.cjs +137 -0
- package/dist/components/impersonation-banner.cjs.map +1 -0
- package/dist/components/impersonation-banner.d.cts +36 -0
- package/dist/components/impersonation-banner.d.ts +36 -0
- package/dist/components/impersonation-banner.js +101 -0
- package/dist/components/impersonation-banner.js.map +1 -0
- package/dist/components/input.cjs +2 -1
- package/dist/components/input.cjs.map +1 -1
- package/dist/components/input.js +2 -1
- package/dist/components/input.js.map +1 -1
- package/dist/components/item.cjs +1 -2
- package/dist/components/item.cjs.map +1 -1
- package/dist/components/item.js +1 -2
- package/dist/components/item.js.map +1 -1
- package/dist/components/pagination.cjs +3 -1
- package/dist/components/pagination.cjs.map +1 -1
- package/dist/components/pagination.d.cts +1 -1
- package/dist/components/pagination.d.ts +1 -1
- package/dist/components/pagination.js +3 -1
- package/dist/components/pagination.js.map +1 -1
- package/dist/components/read-only-guard.cjs +103 -0
- package/dist/components/read-only-guard.cjs.map +1 -0
- package/dist/components/read-only-guard.d.cts +40 -0
- package/dist/components/read-only-guard.d.ts +40 -0
- package/dist/components/read-only-guard.js +64 -0
- package/dist/components/read-only-guard.js.map +1 -0
- package/dist/components/stepper.cjs.map +1 -1
- package/dist/components/stepper.js.map +1 -1
- package/dist/components/switch.cjs +2 -2
- package/dist/components/switch.cjs.map +1 -1
- package/dist/components/switch.js +2 -2
- package/dist/components/switch.js.map +1 -1
- package/dist/components/typography.cjs +4 -4
- package/dist/components/typography.cjs.map +1 -1
- package/dist/components/typography.js +4 -4
- package/dist/components/typography.js.map +1 -1
- package/dist/index.cjs +240 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +228 -16
- package/dist/index.js.map +1 -1
- package/dist/lib/impersonation.cjs +127 -0
- package/dist/lib/impersonation.cjs.map +1 -0
- package/dist/lib/impersonation.d.cts +45 -0
- package/dist/lib/impersonation.d.ts +45 -0
- package/dist/lib/impersonation.js +86 -0
- package/dist/lib/impersonation.js.map +1 -0
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -173,7 +173,9 @@ __export(src_exports, {
|
|
|
173
173
|
HoverCard: () => HoverCard,
|
|
174
174
|
HoverCardContent: () => HoverCardContent,
|
|
175
175
|
HoverCardTrigger: () => HoverCardTrigger,
|
|
176
|
+
INACTIVE_IMPERSONATION: () => INACTIVE_IMPERSONATION,
|
|
176
177
|
IconInfoLineIcon: () => IconInfoLineIcon,
|
|
178
|
+
ImpersonationBanner: () => ImpersonationBanner,
|
|
177
179
|
Input: () => Input,
|
|
178
180
|
InputAddon: () => InputAddon,
|
|
179
181
|
InputGroup: () => InputGroup,
|
|
@@ -215,6 +217,7 @@ __export(src_exports, {
|
|
|
215
217
|
NavigationMenuList: () => NavigationMenuList,
|
|
216
218
|
NavigationMenuTrigger: () => NavigationMenuTrigger,
|
|
217
219
|
NavigationMenuViewport: () => NavigationMenuViewport,
|
|
220
|
+
OPERATION_CLASSES: () => OPERATION_CLASSES,
|
|
218
221
|
Pagination: () => Pagination,
|
|
219
222
|
PaginationContent: () => PaginationContent,
|
|
220
223
|
PaginationEllipsis: () => PaginationEllipsis,
|
|
@@ -227,8 +230,10 @@ __export(src_exports, {
|
|
|
227
230
|
PopoverContent: () => PopoverContent,
|
|
228
231
|
PopoverTrigger: () => PopoverTrigger,
|
|
229
232
|
Progress: () => Progress,
|
|
233
|
+
READ_ONLY_REASON: () => READ_ONLY_REASON,
|
|
230
234
|
RadioGroup: () => RadioGroup,
|
|
231
235
|
RadioGroupItem: () => RadioGroupItem,
|
|
236
|
+
ReadOnlyGuard: () => ReadOnlyGuard,
|
|
232
237
|
ResizableHandle: () => ResizableHandle,
|
|
233
238
|
ResizablePanel: () => ResizablePanel,
|
|
234
239
|
ResizablePanelGroup: () => ResizablePanelGroup,
|
|
@@ -299,17 +304,24 @@ __export(src_exports, {
|
|
|
299
304
|
TooltipProvider: () => TooltipProvider,
|
|
300
305
|
TooltipTrigger: () => TooltipTrigger,
|
|
301
306
|
alertVariants: () => alertVariants,
|
|
307
|
+
approvedOpsOf: () => approvedOpsOf,
|
|
302
308
|
buttonVariants: () => buttonVariants,
|
|
303
309
|
checkboxVariants: () => checkboxVariants,
|
|
304
310
|
cn: () => cn,
|
|
311
|
+
decodeJwtPayload: () => decodeJwtPayload,
|
|
305
312
|
emptyStateVariants: () => emptyStateVariants,
|
|
313
|
+
formatRemaining: () => formatRemaining,
|
|
306
314
|
inputVariants: () => inputVariants,
|
|
315
|
+
isGuarded: () => isGuarded,
|
|
316
|
+
modeOfOps: () => modeOfOps,
|
|
307
317
|
navigationMenuTriggerStyle: () => navigationMenuTriggerStyle,
|
|
318
|
+
readImpersonation: () => readImpersonation,
|
|
308
319
|
spinnerVariants: () => spinnerVariants,
|
|
309
320
|
switchVariants: () => switchVariants,
|
|
310
321
|
toast: () => import_sonner.toast,
|
|
311
322
|
toggleVariants: () => toggleVariants,
|
|
312
323
|
useFormField: () => useFormField,
|
|
324
|
+
useImpersonation: () => useImpersonation,
|
|
313
325
|
useSidebar: () => useSidebar,
|
|
314
326
|
useTheme: () => import_next_themes3.useTheme
|
|
315
327
|
});
|
|
@@ -443,7 +455,8 @@ var Input = React2.forwardRef(
|
|
|
443
455
|
onChange,
|
|
444
456
|
...props
|
|
445
457
|
}, ref) => {
|
|
446
|
-
const
|
|
458
|
+
const generatedId = React2.useId();
|
|
459
|
+
const inputId = id || generatedId;
|
|
447
460
|
const isControlled = value !== void 0;
|
|
448
461
|
const [internalValue, setInternalValue] = React2.useState(defaultValue);
|
|
449
462
|
const innerRef = React2.useRef(null);
|
|
@@ -816,7 +829,8 @@ var checkboxIconSize = {
|
|
|
816
829
|
lg: "size-4"
|
|
817
830
|
};
|
|
818
831
|
var Checkbox = React7.forwardRef(({ className, label, id, variant, size = "default", ...props }, ref) => {
|
|
819
|
-
const
|
|
832
|
+
const generatedId = React7.useId();
|
|
833
|
+
const checkboxId = id || generatedId;
|
|
820
834
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "inline-flex items-center gap-2", children: [
|
|
821
835
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
822
836
|
CheckboxPrimitive.Root,
|
|
@@ -878,7 +892,7 @@ var SwitchPrimitives = __toESM(require("@radix-ui/react-switch"), 1);
|
|
|
878
892
|
var import_class_variance_authority5 = require("class-variance-authority");
|
|
879
893
|
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
880
894
|
var switchVariants = (0, import_class_variance_authority5.cva)(
|
|
881
|
-
"peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=unchecked]:bg-[var(--hc-grey-
|
|
895
|
+
"peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=unchecked]:bg-[var(--hc-grey-400,#7C7C83)] aria-[invalid=true]:ring-2 aria-[invalid=true]:ring-destructive aria-[invalid=true]:ring-offset-2",
|
|
882
896
|
{
|
|
883
897
|
variants: {
|
|
884
898
|
variant: {
|
|
@@ -913,7 +927,7 @@ var Switch = React9.forwardRef(({ className, variant, size = "default", ...props
|
|
|
913
927
|
SwitchPrimitives.Thumb,
|
|
914
928
|
{
|
|
915
929
|
className: cn(
|
|
916
|
-
"pointer-events-none block rounded-full bg-white shadow-lg ring-0 transition-transform duration-200 [[disabled]_&]:bg-[var(--hc-grey-300)]",
|
|
930
|
+
"pointer-events-none block rounded-full bg-white shadow-lg ring-0 transition-transform duration-200 [[disabled]_&]:bg-[var(--hc-grey-300,#A2A2A6)]",
|
|
917
931
|
thumbStyles[size ?? "default"]
|
|
918
932
|
)
|
|
919
933
|
}
|
|
@@ -1562,12 +1576,13 @@ var Alert = React17.forwardRef(({ className, variant, ...props }, ref) => /* @__
|
|
|
1562
1576
|
}
|
|
1563
1577
|
));
|
|
1564
1578
|
Alert.displayName = "Alert";
|
|
1565
|
-
var AlertTitle = React17.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1579
|
+
var AlertTitle = React17.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
1566
1580
|
"h5",
|
|
1567
1581
|
{
|
|
1568
1582
|
ref,
|
|
1569
1583
|
className: cn("mb-1 font-medium leading-none tracking-tight", className),
|
|
1570
|
-
...props
|
|
1584
|
+
...props,
|
|
1585
|
+
children
|
|
1571
1586
|
}
|
|
1572
1587
|
));
|
|
1573
1588
|
AlertTitle.displayName = "AlertTitle";
|
|
@@ -1939,7 +1954,7 @@ var Item4 = React24.forwardRef(
|
|
|
1939
1954
|
({ className, clickable, onClick, children, ...props }, ref) => {
|
|
1940
1955
|
const baseClasses = "flex items-center gap-3 px-4 py-3 rounded-md";
|
|
1941
1956
|
const interactiveClasses = "cursor-pointer transition-colors hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--hc-primary-500)] w-full text-start";
|
|
1942
|
-
if (clickable) {
|
|
1957
|
+
if (clickable || onClick) {
|
|
1943
1958
|
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
1944
1959
|
"button",
|
|
1945
1960
|
{
|
|
@@ -1956,7 +1971,6 @@ var Item4 = React24.forwardRef(
|
|
|
1956
1971
|
"div",
|
|
1957
1972
|
{
|
|
1958
1973
|
ref,
|
|
1959
|
-
onClick,
|
|
1960
1974
|
className: cn(baseClasses, className),
|
|
1961
1975
|
...props,
|
|
1962
1976
|
children
|
|
@@ -2677,7 +2691,7 @@ var DropdownMenuSubContent = React32.forwardRef(({ className, ...props }, ref) =
|
|
|
2677
2691
|
{
|
|
2678
2692
|
ref,
|
|
2679
2693
|
className: cn(
|
|
2680
|
-
"z-50 min-w-[8rem] overflow-hidden rounded-[6px] border border-[var(--hc-color-border-subtle)] bg-popover p-1 text-popover-foreground shadow-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
2694
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-[6px] border border-[var(--hc-color-border-subtle)] bg-popover p-1 text-popover-foreground shadow-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:pointer-events-none data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
2681
2695
|
className
|
|
2682
2696
|
),
|
|
2683
2697
|
...props
|
|
@@ -2690,7 +2704,7 @@ var DropdownMenuContent = React32.forwardRef(({ className, sideOffset = 4, ...pr
|
|
|
2690
2704
|
ref,
|
|
2691
2705
|
sideOffset,
|
|
2692
2706
|
className: cn(
|
|
2693
|
-
"z-50 min-w-[8rem] overflow-hidden rounded-[6px] border border-[var(--hc-color-border-subtle)] bg-popover p-1 text-popover-foreground shadow-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
2707
|
+
"z-50 min-w-[8rem] overflow-hidden rounded-[6px] border border-[var(--hc-color-border-subtle)] bg-popover p-1 text-popover-foreground shadow-sm data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:pointer-events-none data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
2694
2708
|
className
|
|
2695
2709
|
),
|
|
2696
2710
|
...props
|
|
@@ -3522,7 +3536,7 @@ var CardHeader = React39.forwardRef(
|
|
|
3522
3536
|
);
|
|
3523
3537
|
CardHeader.displayName = "CardHeader";
|
|
3524
3538
|
var CardTitle = React39.forwardRef(
|
|
3525
|
-
({ className, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props })
|
|
3539
|
+
({ className, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime42.jsx)("h3", { ref, className: cn("text-2xl font-semibold leading-none tracking-tight", className), ...props, children })
|
|
3526
3540
|
);
|
|
3527
3541
|
CardTitle.displayName = "CardTitle";
|
|
3528
3542
|
var CardDescription = React39.forwardRef(
|
|
@@ -3890,6 +3904,7 @@ var PaginationLink = ({
|
|
|
3890
3904
|
className,
|
|
3891
3905
|
isActive,
|
|
3892
3906
|
size = "icon",
|
|
3907
|
+
children,
|
|
3893
3908
|
...props
|
|
3894
3909
|
}) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
3895
3910
|
"a",
|
|
@@ -3902,7 +3917,8 @@ var PaginationLink = ({
|
|
|
3902
3917
|
}),
|
|
3903
3918
|
className
|
|
3904
3919
|
),
|
|
3905
|
-
...props
|
|
3920
|
+
...props,
|
|
3921
|
+
children
|
|
3906
3922
|
}
|
|
3907
3923
|
);
|
|
3908
3924
|
PaginationLink.displayName = "PaginationLink";
|
|
@@ -4660,19 +4676,19 @@ function resolveColor(color, defaultColorClass) {
|
|
|
4660
4676
|
return colorMap[color];
|
|
4661
4677
|
}
|
|
4662
4678
|
var H1 = React50.forwardRef(
|
|
4663
|
-
({ className, weight = "semibold", color, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h1", { ref, className: cn("scroll-m-20 text-3xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props })
|
|
4679
|
+
({ className, weight = "semibold", color, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h1", { ref, className: cn("scroll-m-20 text-3xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props, children })
|
|
4664
4680
|
);
|
|
4665
4681
|
H1.displayName = "H1";
|
|
4666
4682
|
var H2 = React50.forwardRef(
|
|
4667
|
-
({ className, weight = "semibold", color, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h2", { ref, className: cn("scroll-m-20 text-2xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props })
|
|
4683
|
+
({ className, weight = "semibold", color, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h2", { ref, className: cn("scroll-m-20 text-2xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props, children })
|
|
4668
4684
|
);
|
|
4669
4685
|
H2.displayName = "H2";
|
|
4670
4686
|
var H3 = React50.forwardRef(
|
|
4671
|
-
({ className, weight = "semibold", color, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h3", { ref, className: cn("scroll-m-20 text-xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props })
|
|
4687
|
+
({ className, weight = "semibold", color, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h3", { ref, className: cn("scroll-m-20 text-xl tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props, children })
|
|
4672
4688
|
);
|
|
4673
4689
|
H3.displayName = "H3";
|
|
4674
4690
|
var H4 = React50.forwardRef(
|
|
4675
|
-
({ className, weight = "semibold", color, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h4", { ref, className: cn("scroll-m-20 text-lg tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props })
|
|
4691
|
+
({ className, weight = "semibold", color, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("h4", { ref, className: cn("scroll-m-20 text-lg tracking-tight", resolveColor(color, "text-foreground"), weightMap[weight], className), ...props, children })
|
|
4676
4692
|
);
|
|
4677
4693
|
H4.displayName = "H4";
|
|
4678
4694
|
var Body = React50.forwardRef(
|
|
@@ -4757,6 +4773,202 @@ var Banner = React51.forwardRef(
|
|
|
4757
4773
|
)
|
|
4758
4774
|
);
|
|
4759
4775
|
Banner.displayName = "Banner";
|
|
4776
|
+
|
|
4777
|
+
// src/components/impersonation-banner.tsx
|
|
4778
|
+
var React52 = __toESM(require("react"), 1);
|
|
4779
|
+
var import_jsx_runtime61 = require("react/jsx-runtime");
|
|
4780
|
+
function toMs(value) {
|
|
4781
|
+
if (value instanceof Date) return value.getTime();
|
|
4782
|
+
if (typeof value === "number") return value;
|
|
4783
|
+
const parsed = Date.parse(value);
|
|
4784
|
+
return Number.isNaN(parsed) ? 0 : parsed;
|
|
4785
|
+
}
|
|
4786
|
+
function formatRemaining(ms) {
|
|
4787
|
+
const total = Math.max(0, Math.floor(ms / 1e3));
|
|
4788
|
+
const h = Math.floor(total / 3600);
|
|
4789
|
+
const m = Math.floor(total % 3600 / 60);
|
|
4790
|
+
const s = total % 60;
|
|
4791
|
+
const pad = (n) => String(n).padStart(2, "0");
|
|
4792
|
+
return h > 0 ? `${h}:${pad(m)}:${pad(s)}` : `${m}:${pad(s)}`;
|
|
4793
|
+
}
|
|
4794
|
+
var ImpersonationBanner = React52.forwardRef(
|
|
4795
|
+
({ actorLabel, mode, expiresAt, onExit, targetLabel, ops, inline = false, onExpire, className }, ref) => {
|
|
4796
|
+
const endMs = toMs(expiresAt);
|
|
4797
|
+
const [now, setNow] = React52.useState(() => Date.now());
|
|
4798
|
+
const remaining = endMs - now;
|
|
4799
|
+
const expired = remaining <= 0;
|
|
4800
|
+
const onExpireRef = React52.useRef(onExpire);
|
|
4801
|
+
onExpireRef.current = onExpire;
|
|
4802
|
+
React52.useEffect(() => {
|
|
4803
|
+
if (expired) return void 0;
|
|
4804
|
+
const timer = setInterval(() => setNow(Date.now()), 1e3);
|
|
4805
|
+
return () => clearInterval(timer);
|
|
4806
|
+
}, [expired]);
|
|
4807
|
+
const firedFor = React52.useRef(null);
|
|
4808
|
+
React52.useEffect(() => {
|
|
4809
|
+
if (expired && firedFor.current !== endMs) {
|
|
4810
|
+
firedFor.current = endMs;
|
|
4811
|
+
onExpireRef.current?.();
|
|
4812
|
+
}
|
|
4813
|
+
}, [expired, endMs]);
|
|
4814
|
+
const isRead = mode === "READ";
|
|
4815
|
+
const modeText = isRead ? "Read-only" : "Changes allowed";
|
|
4816
|
+
const opsText = ops && ops.length > 0 ? ops.join(", ") : null;
|
|
4817
|
+
return /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
|
|
4818
|
+
inline ? null : /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("div", { "aria-hidden": "true", className: "h-12", "data-impersonation-spacer": "" }),
|
|
4819
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(
|
|
4820
|
+
"div",
|
|
4821
|
+
{
|
|
4822
|
+
ref,
|
|
4823
|
+
role: "alert",
|
|
4824
|
+
"data-impersonation-banner": "",
|
|
4825
|
+
"data-mode": mode,
|
|
4826
|
+
className: cn(
|
|
4827
|
+
inline ? "relative" : "fixed inset-x-0 top-0 z-[2147483000]",
|
|
4828
|
+
"flex h-12 items-center gap-3 border-b-2 px-4 text-sm font-medium shadow-md",
|
|
4829
|
+
isRead ? "border-black bg-[#FDE047] text-black" : "border-white bg-[#991B1B] text-white",
|
|
4830
|
+
className
|
|
4831
|
+
),
|
|
4832
|
+
children: [
|
|
4833
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "shrink-0 rounded px-2 py-0.5 text-xs font-bold uppercase tracking-wide ring-1 ring-current", children: "Support session" }),
|
|
4834
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsxs)("p", { className: "min-w-0 flex-1 truncate", children: [
|
|
4835
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "font-semibold", children: actorLabel }),
|
|
4836
|
+
targetLabel ? /* @__PURE__ */ (0, import_jsx_runtime61.jsxs)(import_jsx_runtime61.Fragment, { children: [
|
|
4837
|
+
" is acting as ",
|
|
4838
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "font-semibold", children: targetLabel })
|
|
4839
|
+
] }) : " is acting as this user",
|
|
4840
|
+
" \xB7 ",
|
|
4841
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { "data-testid": "impersonation-mode", children: modeText }),
|
|
4842
|
+
opsText ? /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "hidden sm:inline", children: ` (${opsText})` }) : null
|
|
4843
|
+
] }),
|
|
4844
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)("span", { className: "shrink-0 tabular-nums", "aria-live": "off", title: "Time left in this support session", children: /* @__PURE__ */ (0, import_jsx_runtime61.jsx)("time", { "data-testid": "impersonation-countdown", dateTime: new Date(endMs).toISOString(), children: expired ? "Expired" : formatRemaining(remaining) }) }),
|
|
4845
|
+
/* @__PURE__ */ (0, import_jsx_runtime61.jsx)(
|
|
4846
|
+
"button",
|
|
4847
|
+
{
|
|
4848
|
+
type: "button",
|
|
4849
|
+
onClick: onExit,
|
|
4850
|
+
className: cn(
|
|
4851
|
+
"shrink-0 rounded-md px-3 py-1 text-sm font-semibold focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2",
|
|
4852
|
+
isRead ? "bg-black text-[#FDE047] hover:bg-black/85 focus-visible:ring-black focus-visible:ring-offset-[#FDE047]" : "bg-white text-[#991B1B] hover:bg-white/90 focus-visible:ring-white focus-visible:ring-offset-[#991B1B]"
|
|
4853
|
+
),
|
|
4854
|
+
children: "Exit"
|
|
4855
|
+
}
|
|
4856
|
+
)
|
|
4857
|
+
]
|
|
4858
|
+
}
|
|
4859
|
+
)
|
|
4860
|
+
] });
|
|
4861
|
+
}
|
|
4862
|
+
);
|
|
4863
|
+
ImpersonationBanner.displayName = "ImpersonationBanner";
|
|
4864
|
+
|
|
4865
|
+
// src/components/read-only-guard.tsx
|
|
4866
|
+
var import_jsx_runtime62 = require("react/jsx-runtime");
|
|
4867
|
+
var READ_ONLY_REASON = "Read-only support session: this action is turned off.";
|
|
4868
|
+
function isGuarded({ mode, ops, op = "WRITE" }) {
|
|
4869
|
+
if (ops) return !ops.includes(op);
|
|
4870
|
+
return mode === "READ";
|
|
4871
|
+
}
|
|
4872
|
+
function ReadOnlyGuard({ mode, ops, op = "WRITE", reason = READ_ONLY_REASON, className, children }) {
|
|
4873
|
+
if (!isGuarded({ mode, ops, op })) return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(import_jsx_runtime62.Fragment, { children });
|
|
4874
|
+
const swallow = (e) => {
|
|
4875
|
+
e.preventDefault();
|
|
4876
|
+
e.stopPropagation();
|
|
4877
|
+
};
|
|
4878
|
+
return /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TooltipProvider, { delayDuration: 150, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsxs)(Tooltip, { children: [
|
|
4879
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)(
|
|
4880
|
+
"span",
|
|
4881
|
+
{
|
|
4882
|
+
tabIndex: 0,
|
|
4883
|
+
"data-read-only": "",
|
|
4884
|
+
"aria-disabled": "true",
|
|
4885
|
+
className: cn("inline-flex cursor-not-allowed", className),
|
|
4886
|
+
onClickCapture: swallow,
|
|
4887
|
+
onSubmitCapture: swallow,
|
|
4888
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime62.jsx)("fieldset", { disabled: true, className: "contents", children })
|
|
4889
|
+
}
|
|
4890
|
+
) }),
|
|
4891
|
+
/* @__PURE__ */ (0, import_jsx_runtime62.jsx)(TooltipContent, { children: reason })
|
|
4892
|
+
] }) });
|
|
4893
|
+
}
|
|
4894
|
+
ReadOnlyGuard.displayName = "ReadOnlyGuard";
|
|
4895
|
+
|
|
4896
|
+
// src/lib/impersonation.ts
|
|
4897
|
+
var React53 = __toESM(require("react"), 1);
|
|
4898
|
+
var OPERATION_CLASSES = ["READ", "WRITE", "DESTRUCTIVE", "FINANCIAL", "SECURITY"];
|
|
4899
|
+
var PLATFORM_BLOCKED = /* @__PURE__ */ new Set(["FINANCIAL", "SECURITY"]);
|
|
4900
|
+
var INACTIVE_IMPERSONATION = Object.freeze({
|
|
4901
|
+
active: false,
|
|
4902
|
+
mode: null,
|
|
4903
|
+
ops: [],
|
|
4904
|
+
actorSub: null,
|
|
4905
|
+
actorUserType: null,
|
|
4906
|
+
sessionId: null,
|
|
4907
|
+
expiresAt: null
|
|
4908
|
+
});
|
|
4909
|
+
function base64UrlDecode(segment) {
|
|
4910
|
+
const b64 = segment.replace(/-/g, "+").replace(/_/g, "/");
|
|
4911
|
+
const padded = b64 + "=".repeat((4 - b64.length % 4) % 4);
|
|
4912
|
+
const binary = atob(padded);
|
|
4913
|
+
const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0));
|
|
4914
|
+
return new TextDecoder().decode(bytes);
|
|
4915
|
+
}
|
|
4916
|
+
function decodeJwtPayload(token) {
|
|
4917
|
+
if (typeof token !== "string") return null;
|
|
4918
|
+
const parts = token.split(".");
|
|
4919
|
+
if (parts.length !== 3 || !parts[1]) return null;
|
|
4920
|
+
try {
|
|
4921
|
+
const payload = JSON.parse(base64UrlDecode(parts[1]));
|
|
4922
|
+
return payload !== null && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
|
|
4923
|
+
} catch {
|
|
4924
|
+
return null;
|
|
4925
|
+
}
|
|
4926
|
+
}
|
|
4927
|
+
var nonEmpty = (v) => typeof v === "string" && v.trim() !== "" ? v : null;
|
|
4928
|
+
function approvedOpsOf(claims) {
|
|
4929
|
+
let ops;
|
|
4930
|
+
if (Array.isArray(claims.imp_ops)) ops = claims.imp_ops.filter((v) => typeof v === "string");
|
|
4931
|
+
else if (claims.imp_mode === "WRITE") ops = ["READ", "WRITE"];
|
|
4932
|
+
else ops = ["READ"];
|
|
4933
|
+
const set = new Set(ops.filter((op) => !PLATFORM_BLOCKED.has(op)));
|
|
4934
|
+
return OPERATION_CLASSES.filter((c) => set.has(c));
|
|
4935
|
+
}
|
|
4936
|
+
function modeOfOps(ops) {
|
|
4937
|
+
return ops.every((op) => op === "READ") ? "READ" : "WRITE";
|
|
4938
|
+
}
|
|
4939
|
+
function readImpersonation(token, now = Date.now()) {
|
|
4940
|
+
const claims = decodeJwtPayload(token);
|
|
4941
|
+
if (!claims) return INACTIVE_IMPERSONATION;
|
|
4942
|
+
const amr = Array.isArray(claims.amr) ? claims.amr : [];
|
|
4943
|
+
if (!amr.includes("impersonation")) return INACTIVE_IMPERSONATION;
|
|
4944
|
+
const act = claims.act !== null && typeof claims.act === "object" ? claims.act : {};
|
|
4945
|
+
const actorSub = nonEmpty(act.sub);
|
|
4946
|
+
const sessionId = nonEmpty(claims.imp_sid);
|
|
4947
|
+
const expiresAt = typeof claims.exp === "number" ? new Date(claims.exp * 1e3) : null;
|
|
4948
|
+
if (!actorSub || !sessionId || !expiresAt || expiresAt.getTime() <= now) return INACTIVE_IMPERSONATION;
|
|
4949
|
+
const ops = approvedOpsOf(claims);
|
|
4950
|
+
return {
|
|
4951
|
+
active: true,
|
|
4952
|
+
mode: modeOfOps(ops),
|
|
4953
|
+
ops,
|
|
4954
|
+
actorSub,
|
|
4955
|
+
actorUserType: nonEmpty(act.userType),
|
|
4956
|
+
sessionId,
|
|
4957
|
+
expiresAt
|
|
4958
|
+
};
|
|
4959
|
+
}
|
|
4960
|
+
function useImpersonation(token) {
|
|
4961
|
+
const [tick, setTick] = React53.useState(0);
|
|
4962
|
+
const state = React53.useMemo(() => readImpersonation(token), [token, tick]);
|
|
4963
|
+
const expiresAtMs = state.expiresAt?.getTime() ?? null;
|
|
4964
|
+
React53.useEffect(() => {
|
|
4965
|
+
if (expiresAtMs === null) return void 0;
|
|
4966
|
+
const delay = Math.max(0, expiresAtMs - Date.now());
|
|
4967
|
+
const timer = setTimeout(() => setTick((t) => t + 1), Math.min(delay + 50, 2147e6));
|
|
4968
|
+
return () => clearTimeout(timer);
|
|
4969
|
+
}, [expiresAtMs]);
|
|
4970
|
+
return state;
|
|
4971
|
+
}
|
|
4760
4972
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4761
4973
|
0 && (module.exports = {
|
|
4762
4974
|
Accordion,
|
|
@@ -4902,7 +5114,9 @@ Banner.displayName = "Banner";
|
|
|
4902
5114
|
HoverCard,
|
|
4903
5115
|
HoverCardContent,
|
|
4904
5116
|
HoverCardTrigger,
|
|
5117
|
+
INACTIVE_IMPERSONATION,
|
|
4905
5118
|
IconInfoLineIcon,
|
|
5119
|
+
ImpersonationBanner,
|
|
4906
5120
|
Input,
|
|
4907
5121
|
InputAddon,
|
|
4908
5122
|
InputGroup,
|
|
@@ -4944,6 +5158,7 @@ Banner.displayName = "Banner";
|
|
|
4944
5158
|
NavigationMenuList,
|
|
4945
5159
|
NavigationMenuTrigger,
|
|
4946
5160
|
NavigationMenuViewport,
|
|
5161
|
+
OPERATION_CLASSES,
|
|
4947
5162
|
Pagination,
|
|
4948
5163
|
PaginationContent,
|
|
4949
5164
|
PaginationEllipsis,
|
|
@@ -4956,8 +5171,10 @@ Banner.displayName = "Banner";
|
|
|
4956
5171
|
PopoverContent,
|
|
4957
5172
|
PopoverTrigger,
|
|
4958
5173
|
Progress,
|
|
5174
|
+
READ_ONLY_REASON,
|
|
4959
5175
|
RadioGroup,
|
|
4960
5176
|
RadioGroupItem,
|
|
5177
|
+
ReadOnlyGuard,
|
|
4961
5178
|
ResizableHandle,
|
|
4962
5179
|
ResizablePanel,
|
|
4963
5180
|
ResizablePanelGroup,
|
|
@@ -5028,17 +5245,24 @@ Banner.displayName = "Banner";
|
|
|
5028
5245
|
TooltipProvider,
|
|
5029
5246
|
TooltipTrigger,
|
|
5030
5247
|
alertVariants,
|
|
5248
|
+
approvedOpsOf,
|
|
5031
5249
|
buttonVariants,
|
|
5032
5250
|
checkboxVariants,
|
|
5033
5251
|
cn,
|
|
5252
|
+
decodeJwtPayload,
|
|
5034
5253
|
emptyStateVariants,
|
|
5254
|
+
formatRemaining,
|
|
5035
5255
|
inputVariants,
|
|
5256
|
+
isGuarded,
|
|
5257
|
+
modeOfOps,
|
|
5036
5258
|
navigationMenuTriggerStyle,
|
|
5259
|
+
readImpersonation,
|
|
5037
5260
|
spinnerVariants,
|
|
5038
5261
|
switchVariants,
|
|
5039
5262
|
toast,
|
|
5040
5263
|
toggleVariants,
|
|
5041
5264
|
useFormField,
|
|
5265
|
+
useImpersonation,
|
|
5042
5266
|
useSidebar,
|
|
5043
5267
|
useTheme
|
|
5044
5268
|
});
|