@datum-cloud/activity-ui 0.1.0 → 0.3.0-dev.0838a36
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/ActivityExpandedDetails.d.ts +3 -1
- package/dist/components/ActivityExpandedDetails.d.ts.map +1 -1
- package/dist/components/ActivityFeed.d.ts +3 -1
- package/dist/components/ActivityFeed.d.ts.map +1 -1
- package/dist/components/ActivityFeedFilters.d.ts.map +1 -1
- package/dist/components/ActivityFeedItem.d.ts +2 -4
- package/dist/components/ActivityFeedItem.d.ts.map +1 -1
- package/dist/components/ActivityLayout.d.ts +26 -0
- package/dist/components/ActivityLayout.d.ts.map +1 -0
- package/dist/components/ResourceHistoryView.d.ts.map +1 -1
- package/dist/components/ui/filter-chip.d.ts.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +368 -71
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +375 -70
- package/dist/index.js.map +1 -1
- package/dist/lib/activity-filters.d.ts +25 -0
- package/dist/lib/activity-filters.d.ts.map +1 -0
- package/dist/lib/activity-share.d.ts +23 -0
- package/dist/lib/activity-share.d.ts.map +1 -0
- package/package.json +18 -14
package/dist/index.js
CHANGED
|
@@ -7624,13 +7624,32 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
7624
7624
|
*/
|
|
7625
7625
|
|
|
7626
7626
|
|
|
7627
|
-
const __iconNode$
|
|
7627
|
+
const __iconNode$o = [
|
|
7628
|
+
[
|
|
7629
|
+
"path",
|
|
7630
|
+
{
|
|
7631
|
+
d: "M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2",
|
|
7632
|
+
key: "169zse"
|
|
7633
|
+
}
|
|
7634
|
+
]
|
|
7635
|
+
];
|
|
7636
|
+
const Activity = createLucideIcon("activity", __iconNode$o);
|
|
7637
|
+
|
|
7638
|
+
/**
|
|
7639
|
+
* @license lucide-react v0.563.0 - ISC
|
|
7640
|
+
*
|
|
7641
|
+
* This source code is licensed under the ISC license.
|
|
7642
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7643
|
+
*/
|
|
7644
|
+
|
|
7645
|
+
|
|
7646
|
+
const __iconNode$n = [
|
|
7628
7647
|
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
7629
7648
|
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
7630
7649
|
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
7631
7650
|
["path", { d: "M3 10h18", key: "8toen8" }]
|
|
7632
7651
|
];
|
|
7633
|
-
const Calendar = createLucideIcon("calendar", __iconNode$
|
|
7652
|
+
const Calendar = createLucideIcon("calendar", __iconNode$n);
|
|
7634
7653
|
|
|
7635
7654
|
/**
|
|
7636
7655
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7640,8 +7659,8 @@ const Calendar = createLucideIcon("calendar", __iconNode$m);
|
|
|
7640
7659
|
*/
|
|
7641
7660
|
|
|
7642
7661
|
|
|
7643
|
-
const __iconNode$
|
|
7644
|
-
const Check = createLucideIcon("check", __iconNode$
|
|
7662
|
+
const __iconNode$m = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
7663
|
+
const Check = createLucideIcon("check", __iconNode$m);
|
|
7645
7664
|
|
|
7646
7665
|
/**
|
|
7647
7666
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7651,8 +7670,8 @@ const Check = createLucideIcon("check", __iconNode$l);
|
|
|
7651
7670
|
*/
|
|
7652
7671
|
|
|
7653
7672
|
|
|
7654
|
-
const __iconNode$
|
|
7655
|
-
const ChevronDown = createLucideIcon("chevron-down", __iconNode$
|
|
7673
|
+
const __iconNode$l = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
7674
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
|
|
7656
7675
|
|
|
7657
7676
|
/**
|
|
7658
7677
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7662,8 +7681,8 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$k);
|
|
|
7662
7681
|
*/
|
|
7663
7682
|
|
|
7664
7683
|
|
|
7665
|
-
const __iconNode$
|
|
7666
|
-
const ChevronRight = createLucideIcon("chevron-right", __iconNode$
|
|
7684
|
+
const __iconNode$k = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
|
|
7685
|
+
const ChevronRight = createLucideIcon("chevron-right", __iconNode$k);
|
|
7667
7686
|
|
|
7668
7687
|
/**
|
|
7669
7688
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7673,8 +7692,8 @@ const ChevronRight = createLucideIcon("chevron-right", __iconNode$j);
|
|
|
7673
7692
|
*/
|
|
7674
7693
|
|
|
7675
7694
|
|
|
7676
|
-
const __iconNode$
|
|
7677
|
-
const ChevronUp = createLucideIcon("chevron-up", __iconNode$
|
|
7695
|
+
const __iconNode$j = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
|
|
7696
|
+
const ChevronUp = createLucideIcon("chevron-up", __iconNode$j);
|
|
7678
7697
|
|
|
7679
7698
|
/**
|
|
7680
7699
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7684,11 +7703,11 @@ const ChevronUp = createLucideIcon("chevron-up", __iconNode$i);
|
|
|
7684
7703
|
*/
|
|
7685
7704
|
|
|
7686
7705
|
|
|
7687
|
-
const __iconNode$
|
|
7706
|
+
const __iconNode$i = [
|
|
7688
7707
|
["path", { d: "m7 15 5 5 5-5", key: "1hf1tw" }],
|
|
7689
7708
|
["path", { d: "m7 9 5-5 5 5", key: "sgt6xg" }]
|
|
7690
7709
|
];
|
|
7691
|
-
const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$
|
|
7710
|
+
const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$i);
|
|
7692
7711
|
|
|
7693
7712
|
/**
|
|
7694
7713
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7698,12 +7717,12 @@ const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$h);
|
|
|
7698
7717
|
*/
|
|
7699
7718
|
|
|
7700
7719
|
|
|
7701
|
-
const __iconNode$
|
|
7720
|
+
const __iconNode$h = [
|
|
7702
7721
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
7703
7722
|
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
7704
7723
|
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
7705
7724
|
];
|
|
7706
|
-
const CircleAlert = createLucideIcon("circle-alert", __iconNode$
|
|
7725
|
+
const CircleAlert = createLucideIcon("circle-alert", __iconNode$h);
|
|
7707
7726
|
|
|
7708
7727
|
/**
|
|
7709
7728
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7713,11 +7732,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$g);
|
|
|
7713
7732
|
*/
|
|
7714
7733
|
|
|
7715
7734
|
|
|
7716
|
-
const __iconNode$
|
|
7735
|
+
const __iconNode$g = [
|
|
7717
7736
|
["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
|
|
7718
7737
|
["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
|
|
7719
7738
|
];
|
|
7720
|
-
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$
|
|
7739
|
+
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$g);
|
|
7721
7740
|
|
|
7722
7741
|
/**
|
|
7723
7742
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7727,11 +7746,11 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$f);
|
|
|
7727
7746
|
*/
|
|
7728
7747
|
|
|
7729
7748
|
|
|
7730
|
-
const __iconNode$
|
|
7749
|
+
const __iconNode$f = [
|
|
7731
7750
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
7732
7751
|
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
7733
7752
|
];
|
|
7734
|
-
const CircleCheck = createLucideIcon("circle-check", __iconNode$
|
|
7753
|
+
const CircleCheck = createLucideIcon("circle-check", __iconNode$f);
|
|
7735
7754
|
|
|
7736
7755
|
/**
|
|
7737
7756
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7741,12 +7760,12 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$e);
|
|
|
7741
7760
|
*/
|
|
7742
7761
|
|
|
7743
7762
|
|
|
7744
|
-
const __iconNode$
|
|
7763
|
+
const __iconNode$e = [
|
|
7745
7764
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
7746
7765
|
["path", { d: "m15 9-6 6", key: "1uzhvr" }],
|
|
7747
7766
|
["path", { d: "m9 9 6 6", key: "z0biqf" }]
|
|
7748
7767
|
];
|
|
7749
|
-
const CircleX = createLucideIcon("circle-x", __iconNode$
|
|
7768
|
+
const CircleX = createLucideIcon("circle-x", __iconNode$e);
|
|
7750
7769
|
|
|
7751
7770
|
/**
|
|
7752
7771
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7756,11 +7775,11 @@ const CircleX = createLucideIcon("circle-x", __iconNode$d);
|
|
|
7756
7775
|
*/
|
|
7757
7776
|
|
|
7758
7777
|
|
|
7759
|
-
const __iconNode$
|
|
7778
|
+
const __iconNode$d = [
|
|
7760
7779
|
["path", { d: "M12 6v6l4 2", key: "mmk7yg" }],
|
|
7761
7780
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
|
|
7762
7781
|
];
|
|
7763
|
-
const Clock = createLucideIcon("clock", __iconNode$
|
|
7782
|
+
const Clock = createLucideIcon("clock", __iconNode$d);
|
|
7764
7783
|
|
|
7765
7784
|
/**
|
|
7766
7785
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7770,11 +7789,11 @@ const Clock = createLucideIcon("clock", __iconNode$c);
|
|
|
7770
7789
|
*/
|
|
7771
7790
|
|
|
7772
7791
|
|
|
7773
|
-
const __iconNode$
|
|
7792
|
+
const __iconNode$c = [
|
|
7774
7793
|
["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
|
|
7775
7794
|
["path", { d: "M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2", key: "zix9uf" }]
|
|
7776
7795
|
];
|
|
7777
|
-
const Copy = createLucideIcon("copy", __iconNode$
|
|
7796
|
+
const Copy = createLucideIcon("copy", __iconNode$c);
|
|
7778
7797
|
|
|
7779
7798
|
/**
|
|
7780
7799
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7784,7 +7803,7 @@ const Copy = createLucideIcon("copy", __iconNode$b);
|
|
|
7784
7803
|
*/
|
|
7785
7804
|
|
|
7786
7805
|
|
|
7787
|
-
const __iconNode$
|
|
7806
|
+
const __iconNode$b = [
|
|
7788
7807
|
[
|
|
7789
7808
|
"path",
|
|
7790
7809
|
{
|
|
@@ -7794,7 +7813,18 @@ const __iconNode$a = [
|
|
|
7794
7813
|
],
|
|
7795
7814
|
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
7796
7815
|
];
|
|
7797
|
-
const Eye = createLucideIcon("eye", __iconNode$
|
|
7816
|
+
const Eye = createLucideIcon("eye", __iconNode$b);
|
|
7817
|
+
|
|
7818
|
+
/**
|
|
7819
|
+
* @license lucide-react v0.563.0 - ISC
|
|
7820
|
+
*
|
|
7821
|
+
* This source code is licensed under the ISC license.
|
|
7822
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7823
|
+
*/
|
|
7824
|
+
|
|
7825
|
+
|
|
7826
|
+
const __iconNode$a = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
7827
|
+
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$a);
|
|
7798
7828
|
|
|
7799
7829
|
/**
|
|
7800
7830
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7804,8 +7834,17 @@ const Eye = createLucideIcon("eye", __iconNode$a);
|
|
|
7804
7834
|
*/
|
|
7805
7835
|
|
|
7806
7836
|
|
|
7807
|
-
const __iconNode$9 = [
|
|
7808
|
-
|
|
7837
|
+
const __iconNode$9 = [
|
|
7838
|
+
[
|
|
7839
|
+
"path",
|
|
7840
|
+
{
|
|
7841
|
+
d: "M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z",
|
|
7842
|
+
key: "1a8usu"
|
|
7843
|
+
}
|
|
7844
|
+
],
|
|
7845
|
+
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
7846
|
+
];
|
|
7847
|
+
const Pencil = createLucideIcon("pencil", __iconNode$9);
|
|
7809
7848
|
|
|
7810
7849
|
/**
|
|
7811
7850
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -8544,7 +8583,7 @@ function FilterChip({ label, values, options = [], onValuesChange, onClear, inpu
|
|
|
8544
8583
|
}, [options]);
|
|
8545
8584
|
// Find selected options for chips display
|
|
8546
8585
|
const selectedOptions = options.filter((opt) => values.includes(opt.value));
|
|
8547
|
-
return (jsxRuntime.jsxs("div", { className: cn('inline-flex items-center', className), children: [jsxRuntime.jsxs(Popover__namespace.Root, { open: open, onOpenChange: handleOpenChange, children: [jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: jsxRuntime.jsxs("button", { type: "button", disabled: disabled, className: cn('flex h-7 items-center gap-2 rounded-l-md border border-r-0 border-border bg-
|
|
8586
|
+
return (jsxRuntime.jsxs("div", { className: cn('inline-flex items-center', className), children: [jsxRuntime.jsxs(Popover__namespace.Root, { open: open, onOpenChange: handleOpenChange, children: [jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: jsxRuntime.jsxs("button", { type: "button", disabled: disabled, className: cn('flex h-7 items-center gap-2 rounded-l-md border border-r-0 border-border bg-card px-2 text-xs outline-none', 'hover:bg-accent/40 data-[state=open]:bg-accent/40 transition-colors', 'disabled:cursor-not-allowed disabled:opacity-50'), children: [jsxRuntime.jsxs("span", { className: "font-medium text-foreground", children: [label, ":"] }), jsxRuntime.jsx("span", { className: "text-foreground truncate max-w-[120px]", children: displayValue }), jsxRuntime.jsx(ChevronDown, { className: "h-3 w-3 text-muted-foreground ml-1" })] }) }), jsxRuntime.jsx(Popover__namespace.Portal, { children: jsxRuntime.jsx(Popover__namespace.Content, { className: cn('z-50 min-w-[var(--radix-popover-trigger-width)] max-w-[320px] overflow-hidden rounded-md border bg-popover text-popover-foreground shadow-md', '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=top]:slide-in-from-bottom-2'), sideOffset: 4, align: "start", children: inputMode === 'typeahead' ? (jsxRuntime.jsxs(cmdk.Command, { filter: filterOptions, className: "w-full", children: [jsxRuntime.jsx("div", { className: "flex items-center border-b px-3", children: jsxRuntime.jsx(cmdk.CommandInput, { placeholder: searchPlaceholder, value: search, onValueChange: setSearch, className: "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50" }) }), values.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 p-2 border-b", children: selectedOptions.map((option) => (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-accent text-accent-foreground text-xs", children: [option.label, jsxRuntime.jsx("button", { type: "button", onClick: (e) => handleRemoveValue(e, option.value), className: "rounded-sm hover:bg-accent-foreground/20", children: jsxRuntime.jsx(X, { className: "h-3 w-3" }) })] }, option.value))) })), jsxRuntime.jsxs(cmdk.CommandList, { className: "max-h-[300px] overflow-y-auto p-1", children: [jsxRuntime.jsx(cmdk.CommandEmpty, { className: "py-6 text-center text-sm text-muted-foreground", children: "No results found." }), jsxRuntime.jsx(cmdk.CommandGroup, { children: options.map((option) => (jsxRuntime.jsxs(cmdk.CommandItem, { value: option.value, onSelect: () => handleSelect(option.value), className: cn('relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none', 'data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground', 'hover:bg-accent hover:text-accent-foreground'), children: [jsxRuntime.jsx("div", { className: cn('mr-2 h-4 w-4 shrink-0 rounded-sm border border-border', values.includes(option.value) && 'bg-primary border-primary'), children: values.includes(option.value) && (jsxRuntime.jsx("svg", { viewBox: "0 0 12 12", fill: "none", className: "h-full w-full p-0.5 text-primary-foreground", children: jsxRuntime.jsx("path", { d: "M2 6l3 3 5-5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })) }), jsxRuntime.jsx("span", { className: "flex-1 truncate", children: option.label }), option.count !== undefined && (jsxRuntime.jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: ["(", option.count, ")"] }))] }, option.value))) })] })] })) : (jsxRuntime.jsx("div", { className: "p-3", children: jsxRuntime.jsx(Input, { type: "text", value: textValue, onChange: handleTextChange, placeholder: placeholder, className: "w-full", autoFocus: true }) })) }) })] }), jsxRuntime.jsx("button", { type: "button", onClick: handleClearAll, disabled: disabled, className: cn('flex h-7 items-center rounded-r-md border border-border bg-card px-2 outline-none', 'hover:bg-accent/40 transition-colors', 'disabled:cursor-not-allowed disabled:opacity-50'), "aria-label": `Clear ${label} filter`, children: jsxRuntime.jsx(X, { className: "h-3 w-3 text-muted-foreground" }) })] }));
|
|
8548
8587
|
}
|
|
8549
8588
|
|
|
8550
8589
|
/**
|
|
@@ -10236,13 +10275,14 @@ const TooltipContent = React__namespace.forwardRef(({ className, sideOffset = 4,
|
|
|
10236
10275
|
TooltipContent.displayName = TooltipPrimitive__namespace.Content.displayName;
|
|
10237
10276
|
|
|
10238
10277
|
/**
|
|
10239
|
-
* Format timestamp for display (
|
|
10278
|
+
* Format timestamp for display (in UTC)
|
|
10240
10279
|
*/
|
|
10241
10280
|
function formatTimestampFull$3(timestamp) {
|
|
10242
10281
|
if (!timestamp)
|
|
10243
10282
|
return 'Unknown time';
|
|
10244
10283
|
try {
|
|
10245
|
-
|
|
10284
|
+
const date = new Date(timestamp);
|
|
10285
|
+
return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(date.getUTCDate()).padStart(2, '0')} ${String(date.getUTCHours()).padStart(2, '0')}:${String(date.getUTCMinutes()).padStart(2, '0')}:${String(date.getUTCSeconds()).padStart(2, '0')} UTC`;
|
|
10246
10286
|
}
|
|
10247
10287
|
catch {
|
|
10248
10288
|
return timestamp;
|
|
@@ -10278,11 +10318,11 @@ function CopyButton({ value, label }) {
|
|
|
10278
10318
|
* 5. Resource - what resource was affected
|
|
10279
10319
|
* 6. Origin - correlation to audit logs
|
|
10280
10320
|
*/
|
|
10281
|
-
function ActivityExpandedDetails({ activity, tenantLinkResolver }) {
|
|
10321
|
+
function ActivityExpandedDetails({ activity, tenantLinkResolver, compact = false }) {
|
|
10282
10322
|
const { spec, metadata } = activity;
|
|
10283
10323
|
const { actor, resource, origin, changes, tenant } = spec;
|
|
10284
10324
|
const timestamp = metadata?.creationTimestamp;
|
|
10285
|
-
return (jsxRuntime.jsx(TooltipProvider, { children: jsxRuntime.jsxs("div", { className:
|
|
10325
|
+
return (jsxRuntime.jsx(TooltipProvider, { children: jsxRuntime.jsxs("div", { className: compact ? 'p-4 bg-muted/30' : 'mt-4 pt-4 border-t border-border', children: [changes && changes.length > 0 && (jsxRuntime.jsxs("div", { className: "mb-3", children: [jsxRuntime.jsx("h4", { className: "m-0 mb-2 text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Changes" }), jsxRuntime.jsx("div", { className: "flex flex-col gap-2", children: changes.map((change, index) => (jsxRuntime.jsxs("div", { className: "p-2 bg-muted rounded text-sm", children: [jsxRuntime.jsx("span", { className: "block font-semibold text-foreground mb-1 font-mono text-xs", children: change.field }), change.old && (jsxRuntime.jsxs("span", { className: "block ml-2 text-red-600 dark:text-red-400 text-xs", children: [jsxRuntime.jsx("span", { className: "font-medium mr-1", children: "\u2212" }), jsxRuntime.jsx("span", { className: "line-through", children: change.old })] })), change.new && (jsxRuntime.jsxs("span", { className: "block ml-2 text-green-600 dark:text-green-400 text-xs", children: [jsxRuntime.jsx("span", { className: "font-medium mr-1", children: "+" }), change.new] }))] }, index))) })] })), jsxRuntime.jsxs("dl", { className: "grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-x-6 gap-y-2 m-0 text-xs", children: [jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Timestamp:" }), jsxRuntime.jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: formatTimestampFull$3(timestamp) }), jsxRuntime.jsx(CopyButton, { value: formatTimestampFull$3(timestamp), label: "timestamp" })] })] }), jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Actor Type:" }), jsxRuntime.jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: actor.type }), jsxRuntime.jsx(CopyButton, { value: actor.type, label: "actor type" })] })] }), jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Actor:" }), jsxRuntime.jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: actor.name }), jsxRuntime.jsx(CopyButton, { value: actor.name, label: "actor name" })] })] }), resource.apiGroup && (jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "API Group:" }), jsxRuntime.jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: resource.apiGroup }), jsxRuntime.jsx(CopyButton, { value: resource.apiGroup, label: "API group" })] })] })), jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Resource:" }), jsxRuntime.jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: resource.kind }), jsxRuntime.jsx(CopyButton, { value: resource.kind, label: "resource kind" })] })] }), jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Resource Name:" }), jsxRuntime.jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: resource.name }), jsxRuntime.jsx(CopyButton, { value: resource.name, label: "resource name" })] })] }), resource.namespace && (jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Namespace:" }), jsxRuntime.jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: resource.namespace }), jsxRuntime.jsx(CopyButton, { value: resource.namespace, label: "namespace" })] })] })), resource.uid && (jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Resource UID:" }), jsxRuntime.jsxs("dd", { className: "m-0 font-mono text-muted-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: resource.uid }), jsxRuntime.jsx(CopyButton, { value: resource.uid, label: "resource UID" })] })] })), jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Origin:" }), jsxRuntime.jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: origin.type }), jsxRuntime.jsx(CopyButton, { value: origin.type, label: "origin type" })] })] }), jsxRuntime.jsxs("div", { className: "flex gap-1 items-baseline", children: [jsxRuntime.jsx("dt", { className: "text-muted-foreground shrink-0", children: "Origin ID:" }), jsxRuntime.jsxs("dd", { className: "m-0 font-mono text-muted-foreground flex items-center min-w-0", children: [jsxRuntime.jsx("span", { className: "truncate", children: origin.id }), jsxRuntime.jsx(CopyButton, { value: origin.id, label: "origin ID" })] })] })] })] }) }));
|
|
10286
10326
|
}
|
|
10287
10327
|
|
|
10288
10328
|
/**
|
|
@@ -10300,13 +10340,14 @@ function formatTimestamp$1(timestamp) {
|
|
|
10300
10340
|
}
|
|
10301
10341
|
}
|
|
10302
10342
|
/**
|
|
10303
|
-
* Format timestamp for tooltip (
|
|
10343
|
+
* Format timestamp for tooltip (in UTC)
|
|
10304
10344
|
*/
|
|
10305
10345
|
function formatTimestampFull$2(timestamp) {
|
|
10306
10346
|
if (!timestamp)
|
|
10307
10347
|
return 'Unknown time';
|
|
10308
10348
|
try {
|
|
10309
|
-
|
|
10349
|
+
const date = new Date(timestamp);
|
|
10350
|
+
return `${date.getUTCFullYear()}-${String(date.getUTCMonth() + 1).padStart(2, '0')}-${String(date.getUTCDate()).padStart(2, '0')} ${String(date.getUTCHours()).padStart(2, '0')}:${String(date.getUTCMinutes()).padStart(2, '0')}:${String(date.getUTCSeconds()).padStart(2, '0')} UTC`;
|
|
10310
10351
|
}
|
|
10311
10352
|
catch {
|
|
10312
10353
|
return timestamp;
|
|
@@ -10363,25 +10404,41 @@ function normalizeVerb(verb) {
|
|
|
10363
10404
|
return 'other';
|
|
10364
10405
|
}
|
|
10365
10406
|
/**
|
|
10366
|
-
* Get
|
|
10407
|
+
* Get icon container + icon color classes based on verb
|
|
10408
|
+
*/
|
|
10409
|
+
function getActionIconClasses(verb) {
|
|
10410
|
+
const normalizedVerb = normalizeVerb(verb);
|
|
10411
|
+
switch (normalizedVerb) {
|
|
10412
|
+
case 'create':
|
|
10413
|
+
return { container: 'bg-blue-50 dark:bg-blue-950', icon: 'text-blue-500 dark:text-blue-400' };
|
|
10414
|
+
case 'update':
|
|
10415
|
+
return { container: 'bg-green-50 dark:bg-green-950', icon: 'text-green-600 dark:text-green-400' };
|
|
10416
|
+
case 'delete':
|
|
10417
|
+
return { container: 'bg-red-50 dark:bg-red-950', icon: 'text-red-500 dark:text-red-400' };
|
|
10418
|
+
default:
|
|
10419
|
+
return { container: 'bg-slate-100 dark:bg-slate-800', icon: 'text-slate-500 dark:text-slate-400' };
|
|
10420
|
+
}
|
|
10421
|
+
}
|
|
10422
|
+
/**
|
|
10423
|
+
* Get the Lucide icon component for the timeline node based on verb
|
|
10367
10424
|
*/
|
|
10368
|
-
function
|
|
10425
|
+
function getTimelineIcon(verb) {
|
|
10369
10426
|
const normalizedVerb = normalizeVerb(verb);
|
|
10370
10427
|
switch (normalizedVerb) {
|
|
10371
10428
|
case 'create':
|
|
10372
|
-
return
|
|
10429
|
+
return Plus;
|
|
10373
10430
|
case 'update':
|
|
10374
|
-
return
|
|
10431
|
+
return Pencil;
|
|
10375
10432
|
case 'delete':
|
|
10376
|
-
return
|
|
10433
|
+
return Trash2;
|
|
10377
10434
|
default:
|
|
10378
|
-
return
|
|
10435
|
+
return Activity;
|
|
10379
10436
|
}
|
|
10380
10437
|
}
|
|
10381
10438
|
/**
|
|
10382
10439
|
* ActivityFeedItem renders a single activity in the feed or timeline
|
|
10383
10440
|
*/
|
|
10384
|
-
function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isSelected = false, className = '', compact = false, isNew = false, variant = 'feed',
|
|
10441
|
+
function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isSelected = false, className = '', compact = false, isNew = false, variant = 'feed', isLast = false, defaultExpanded = false, }) {
|
|
10385
10442
|
const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);
|
|
10386
10443
|
const { spec, metadata } = activity;
|
|
10387
10444
|
const { actor, summary, links, tenant } = spec;
|
|
@@ -10401,9 +10458,11 @@ function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, ten
|
|
|
10401
10458
|
const timestamp = metadata?.creationTimestamp;
|
|
10402
10459
|
const verb = extractVerb(summary);
|
|
10403
10460
|
const isTimeline = variant === 'timeline';
|
|
10404
|
-
// Timeline variant
|
|
10461
|
+
// Timeline variant — flat list row with bottom border
|
|
10405
10462
|
if (isTimeline) {
|
|
10406
|
-
|
|
10463
|
+
const { container: iconBg, icon: iconColor } = getActionIconClasses(verb);
|
|
10464
|
+
const Icon = getTimelineIcon(verb);
|
|
10465
|
+
return (jsxRuntime.jsxs("div", { className: cn(!isLast && !isExpanded && 'border-b border-border', className), children: [jsxRuntime.jsxs("div", { className: cn('flex items-center gap-3 py-3 pl-4 cursor-pointer group', isSelected && 'bg-muted/40'), onClick: toggleExpand, children: [jsxRuntime.jsx("div", { className: cn('w-8 h-8 rounded-md shrink-0 flex items-center justify-center', iconBg, iconColor), children: jsxRuntime.jsx(Icon, { size: 16, strokeWidth: 2 }) }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0 text-sm text-foreground leading-snug", children: jsxRuntime.jsx(ActivityFeedSummary, { summary: summary, links: links, onResourceClick: onResourceClick, resourceLinkResolver: resourceLinkResolver, resourceLinkContext: { tenant } }) }), tenant && (jsxRuntime.jsx("div", { className: "shrink-0", children: tenantRenderer ? tenantRenderer(tenant) : jsxRuntime.jsx(TenantBadge, { tenant: tenant, tenantLinkResolver: tenantLinkResolver, size: "compact" }) })), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0", title: formatTimestampFull$2(timestamp), children: formatTimestamp$1(timestamp) }), jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", className: "h-5 py-0 px-1 text-base text-muted-foreground opacity-0 group-hover:opacity-100 transition-opacity shrink-0", onClick: toggleExpand, "aria-expanded": isExpanded, children: isExpanded ? '−' : '+' })] }), isExpanded && (jsxRuntime.jsx(ActivityExpandedDetails, { activity: activity, tenantLinkResolver: tenantLinkResolver, compact: true }))] }));
|
|
10407
10466
|
}
|
|
10408
10467
|
// Feed variant (single-row layout)
|
|
10409
10468
|
return (jsxRuntime.jsxs(Card, { className: cn('cursor-pointer transition-all duration-200', 'shadow-sm hover:shadow-md hover:-translate-y-0.5', 'hover:border-primary/30 dark:hover:border-primary/40', compact ? 'p-1.5 mb-1' : 'p-4 mb-3', isSelected && 'border-primary bg-primary/5 shadow-md ring-1 ring-primary/20 dark:bg-primary/10', isNew && 'border-l-4 border-l-green-500 bg-green-50/50 dark:border-l-green-400 dark:bg-green-950/30', className), onClick: handleClick, children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("div", { className: cn(getActorAvatarClasses(actor.type, compact), onActorClick && 'cursor-pointer hover:opacity-80 transition-opacity'), title: actor.name, onClick: onActorClick ? handleActorClick : undefined, children: actor.type === 'controller' ? (jsxRuntime.jsx("span", { className: "text-xs", children: "\u2699" })) : actor.type === 'machine account' ? (jsxRuntime.jsx("span", { className: "text-xs", children: "\uD83E\uDD16" })) : (jsxRuntime.jsx("span", { className: "uppercase", children: getActorInitials(actor.name) })) }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0 text-xs leading-snug", children: jsxRuntime.jsx(ActivityFeedSummary, { summary: summary, links: links, onResourceClick: onResourceClick, resourceLinkResolver: resourceLinkResolver, resourceLinkContext: { tenant } }) }), tenant && (jsxRuntime.jsx("div", { className: "shrink-0", children: tenantRenderer ? tenantRenderer(tenant) : jsxRuntime.jsx(TenantBadge, { tenant: tenant, tenantLinkResolver: tenantLinkResolver, size: "compact" }) })), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0", title: formatTimestampFull$2(timestamp), children: formatTimestamp$1(timestamp) }), jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", className: "h-5 py-0 px-1 text-base text-muted-foreground hover:text-foreground shrink-0", onClick: toggleExpand, "aria-expanded": isExpanded, children: isExpanded ? '−' : '+' })] }), isExpanded && jsxRuntime.jsx(ActivityExpandedDetails, { activity: activity, tenantLinkResolver: tenantLinkResolver })] }));
|
|
@@ -10723,19 +10782,22 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10723
10782
|
return 'Select time range';
|
|
10724
10783
|
};
|
|
10725
10784
|
// Determine which filters are currently active (have values) and not hidden
|
|
10726
|
-
const filtersWithValues =
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10731
|
-
|
|
10732
|
-
|
|
10733
|
-
|
|
10734
|
-
|
|
10735
|
-
|
|
10736
|
-
|
|
10737
|
-
|
|
10738
|
-
|
|
10785
|
+
const filtersWithValues = React.useMemo(() => {
|
|
10786
|
+
const result = [];
|
|
10787
|
+
if (filters.resourceKinds && filters.resourceKinds.length > 0 && !hiddenFilters.includes('resourceKinds'))
|
|
10788
|
+
result.push('resourceKinds');
|
|
10789
|
+
if (filters.actorNames && filters.actorNames.length > 0 && !hiddenFilters.includes('actorNames'))
|
|
10790
|
+
result.push('actorNames');
|
|
10791
|
+
if (filters.apiGroups && filters.apiGroups.length > 0 && !hiddenFilters.includes('apiGroups'))
|
|
10792
|
+
result.push('apiGroups');
|
|
10793
|
+
if (filters.resourceNamespaces && filters.resourceNamespaces.length > 0 && !hiddenFilters.includes('resourceNamespaces'))
|
|
10794
|
+
result.push('resourceNamespaces');
|
|
10795
|
+
if (filters.resourceName && !hiddenFilters.includes('resourceName'))
|
|
10796
|
+
result.push('resourceName');
|
|
10797
|
+
if (filters.actions && filters.actions.length > 0)
|
|
10798
|
+
result.push('actions');
|
|
10799
|
+
return result;
|
|
10800
|
+
}, [filters, hiddenFilters]);
|
|
10739
10801
|
// Include pendingFilter (newly added filter awaiting value selection) in the displayed filters
|
|
10740
10802
|
const activeFilterIds = pendingFilter && !filtersWithValues.includes(pendingFilter)
|
|
10741
10803
|
? [...filtersWithValues, pendingFilter]
|
|
@@ -10754,7 +10816,7 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10754
10816
|
{ id: 'apiGroups', label: 'API Group' },
|
|
10755
10817
|
{ id: 'resourceNamespaces', label: 'Namespace' },
|
|
10756
10818
|
{ id: 'resourceName', label: 'Resource Name' },
|
|
10757
|
-
|
|
10819
|
+
// 'actions' hidden until backend facet support is available
|
|
10758
10820
|
].filter((filter) => !hiddenFilters.includes(filter.id));
|
|
10759
10821
|
// Handle adding a filter
|
|
10760
10822
|
const handleAddFilter = React.useCallback((filterId) => {
|
|
@@ -10841,15 +10903,37 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10841
10903
|
}
|
|
10842
10904
|
return value || [];
|
|
10843
10905
|
};
|
|
10844
|
-
//
|
|
10906
|
+
// Local search value for debouncing — keeps input responsive while query runs
|
|
10907
|
+
const [searchInputValue, setSearchInputValue] = React.useState(filters.search || '');
|
|
10908
|
+
const searchDebounceRef = React.useRef(null);
|
|
10909
|
+
// Use refs so the debounced callback never closes over stale values
|
|
10910
|
+
const filtersRef = React.useRef(filters);
|
|
10911
|
+
filtersRef.current = filters;
|
|
10912
|
+
const onFiltersChangeRef = React.useRef(onFiltersChange);
|
|
10913
|
+
onFiltersChangeRef.current = onFiltersChange;
|
|
10914
|
+
// Cancel any pending debounce on unmount
|
|
10915
|
+
React.useEffect(() => {
|
|
10916
|
+
return () => {
|
|
10917
|
+
if (searchDebounceRef.current)
|
|
10918
|
+
clearTimeout(searchDebounceRef.current);
|
|
10919
|
+
};
|
|
10920
|
+
}, []);
|
|
10845
10921
|
const handleSearchChange = React.useCallback((event) => {
|
|
10846
10922
|
const value = event.target.value;
|
|
10847
|
-
|
|
10848
|
-
|
|
10849
|
-
|
|
10850
|
-
|
|
10851
|
-
|
|
10852
|
-
|
|
10923
|
+
setSearchInputValue(value);
|
|
10924
|
+
if (searchDebounceRef.current)
|
|
10925
|
+
clearTimeout(searchDebounceRef.current);
|
|
10926
|
+
searchDebounceRef.current = setTimeout(() => {
|
|
10927
|
+
onFiltersChangeRef.current({ ...filtersRef.current, search: value || undefined });
|
|
10928
|
+
}, 400);
|
|
10929
|
+
}, []);
|
|
10930
|
+
const handleSearchClear = React.useCallback(() => {
|
|
10931
|
+
setSearchInputValue('');
|
|
10932
|
+
if (searchDebounceRef.current)
|
|
10933
|
+
clearTimeout(searchDebounceRef.current);
|
|
10934
|
+
onFiltersChangeRef.current({ ...filtersRef.current, search: undefined });
|
|
10935
|
+
}, []);
|
|
10936
|
+
return (jsxRuntime.jsx("div", { className: `mb-3 pb-3 border-b border-border p-4 ${className}`, children: jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [!hiddenFilters.includes('changeSource') && (jsxRuntime.jsx(ChangeSourceToggle, { value: filters.changeSource || 'all', onChange: handleChangeSourceChange, disabled: disabled })), jsxRuntime.jsxs("div", { className: "relative min-w-[200px] flex-1 max-w-xs", children: [jsxRuntime.jsx(Search, { className: "absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), jsxRuntime.jsx(Input, { type: "text", placeholder: "Search activities...", value: searchInputValue, onChange: handleSearchChange, className: "pl-8 h-7 text-xs pr-6" }), searchInputValue && (jsxRuntime.jsx("button", { onClick: handleSearchClear, className: "absolute right-1.5 top-1/2 -translate-y-1/2 text-muted-foreground hover:text-foreground transition-colors", "aria-label": "Clear search", children: jsxRuntime.jsx(X, { className: "h-3.5 w-3.5" }) }))] }), activeFilterIds.map((filterId) => {
|
|
10853
10937
|
const config = FILTER_CONFIGS$1[filterId];
|
|
10854
10938
|
return (jsxRuntime.jsx(FilterChip, { label: config.label, values: getFilterValues(filterId), options: config.inputMode === 'typeahead' ? getFilterOptions(filterId) : undefined, onValuesChange: (values) => handleFilterChange(filterId, values), onClear: () => handleFilterClear(filterId), onPopoverClose: () => handlePopoverClose(filterId), inputMode: config.inputMode, placeholder: config.placeholder, searchPlaceholder: config.searchPlaceholder, autoOpen: pendingFilter === filterId, disabled: disabled }, filterId));
|
|
10855
10939
|
}), jsxRuntime.jsx(AddFilterDropdown, { availableFilters: availableFilters, activeFilterIds: activeFilterIds, onAddFilter: handleAddFilter, hasActiveFilters: activeFilterIds.length > 0, disabled: disabled }), jsxRuntime.jsx("div", { className: "flex-1 min-w-[20px]" }), jsxRuntime.jsx(TimeRangeDropdown, { presets: TIME_PRESETS$1, selectedPreset: selectedPreset, onPresetSelect: handleTimePresetSelect, onCustomRangeApply: handleCustomRangeApply, customStart: customStart, customEnd: customEnd, disabled: disabled, displayLabel: getTimeRangeLabel() })] }) }));
|
|
@@ -10859,7 +10943,7 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10859
10943
|
* ActivityFeed displays a chronological list of activities with filtering and pagination.
|
|
10860
10944
|
* Supports optional real-time streaming of new activities.
|
|
10861
10945
|
*/
|
|
10862
|
-
function ActivityFeed({ client, initialFilters = { changeSource: 'human' }, initialTimeRange = { start: 'now-7d' }, pageSize = 30, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActivityClick, compact = false, resourceUid, showFilters = true, hiddenFilters = [], className = '', infiniteScroll = true, loadMoreThreshold = 200, onCreatePolicy, enableStreaming = false, onEffectiveTimeRangeChange, errorFormatter, maxHeight, onFiltersChange: onFiltersChangeProp, }) {
|
|
10946
|
+
function ActivityFeed({ client, initialFilters = { changeSource: 'human' }, initialTimeRange = { start: 'now-7d' }, pageSize = 30, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActivityClick, compact = false, variant = 'feed', resourceUid, showFilters = true, hiddenFilters = [], className = '', infiniteScroll = true, loadMoreThreshold = 200, onCreatePolicy, enableStreaming = false, onEffectiveTimeRangeChange, errorFormatter, maxHeight, onFiltersChange: onFiltersChangeProp, }) {
|
|
10863
10947
|
// Merge resourceUid into initial filters if provided
|
|
10864
10948
|
const mergedInitialFilters = {
|
|
10865
10949
|
...initialFilters,
|
|
@@ -10959,13 +11043,13 @@ function ActivityFeed({ client, initialFilters = { changeSource: 'human' }, init
|
|
|
10959
11043
|
// Build container classes - use flex layout to properly fill available space
|
|
10960
11044
|
// flex-1 min-h-0 allows the Card to fill parent flex container and enable child scrolling
|
|
10961
11045
|
const containerClasses = compact
|
|
10962
|
-
? `flex-1 min-h-0 flex flex-col p-
|
|
11046
|
+
? `flex-1 min-h-0 flex flex-col p-0 shadow-none border-none ${className}`
|
|
10963
11047
|
: `flex-1 min-h-0 flex flex-col p-3 ${className}`;
|
|
10964
11048
|
// Build list classes - use flex-1 min-h-0 for flex-based scrolling
|
|
10965
11049
|
// Parent containers must have proper height constraints (h-screen/h-full + overflow-hidden)
|
|
10966
11050
|
const effectiveMaxHeight = maxHeight === 'none' ? undefined : maxHeight;
|
|
10967
|
-
const listClasses = 'flex-1 min-h-0 overflow-y-auto
|
|
10968
|
-
return (jsxRuntime.jsxs(Card, { className: containerClasses, children: [enableStreaming && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-1 pb-0.5 border-b border-border", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [isStreaming && !watchError && (jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2", children: [jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 dark:bg-green-500 opacity-75" }), jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500 dark:bg-green-400" })] }), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Streaming activity..." })] }) }), jsxRuntime.jsx(TooltipContent, { className: "text-xs", children: jsxRuntime.jsx("p", { children: "New activities will appear automatically" }) })] }) })), watchError && (jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("span", { className: "relative flex h-2 w-2", children: jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-red-500 dark:bg-red-400" }) }), jsxRuntime.jsx("span", { className: "text-xs text-destructive", children: "Connection error" })] }) }), jsxRuntime.jsx(TooltipContent, { className: "text-xs", children: jsxRuntime.jsx("p", { children: "Stream connection lost" }) })] }) })), newActivitiesCount > 0 && !watchError && (jsxRuntime.jsxs(Badge, { variant: "secondary", className: "text-xs", children: ["+", newActivitiesCount, " new"] }))] }), jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: handleStreamingToggle, className: "text-xs", children: watchError ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: "2", children: [jsxRuntime.jsx("path", { d: "M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "3" })] }), "Retry"] })) : isStreaming ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [jsxRuntime.jsx("rect", { x: "6", y: "4", width: "4", height: "16" }), jsxRuntime.jsx("rect", { x: "14", y: "4", width: "4", height: "16" })] }), "Pause"] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("polygon", { points: "5,3 19,12 5,21", fill: "currentColor" }) }), "Resume"] })) })] })), showFilters && (jsxRuntime.jsx(ActivityFeedFilters, { client: client, filters: filters, timeRange: timeRange, onFiltersChange: handleFiltersChange, onTimeRangeChange: handleTimeRangeChange, disabled: isLoading, hiddenFilters: hiddenFilters })), jsxRuntime.jsx(ApiErrorAlert, { error: error, onRetry: refresh, className: "mb-4", errorFormatter: errorFormatter }), jsxRuntime.jsx(ApiErrorAlert, { error: watchError, onRetry: startStreaming, className: "mb-4", errorFormatter: errorFormatter }), !policiesLoading && hasPolicies === false && (jsxRuntime.jsxs("div", { className: "flex flex-col items-center py-12 px-8 text-center bg-muted border border-dashed border-border rounded-xl mb-4", children: [jsxRuntime.jsx("div", { className: "flex justify-center mb-4 text-muted-foreground", children: jsxRuntime.jsxs("svg", { width: "56", height: "56", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2" }), jsxRuntime.jsx("rect", { x: "9", y: "3", width: "6", height: "4", rx: "1" }), jsxRuntime.jsx("path", { d: "M9 12h6" }), jsxRuntime.jsx("path", { d: "M9 16h6" })] }) }), jsxRuntime.jsx("h3", { className: "m-0 mb-2 text-lg font-semibold text-foreground leading-snug", children: "Get started with activity logging" }), jsxRuntime.jsx("p", { className: "m-0 mb-6 text-sm leading-relaxed text-muted-foreground max-w-[400px]", children: "Activity policies define which resources to track and how to summarize changes. Create your first policy to start seeing activity logs here." }), onCreatePolicy && (jsxRuntime.jsx(Button, { onClick: onCreatePolicy, children: "Create Policy" }))] })), jsxRuntime.jsxs("div", { className: listClasses, ref: scrollContainerRef, style: { gap: compact ? '0.25rem' : '0.5rem', ...(effectiveMaxHeight ? { maxHeight: effectiveMaxHeight } : {}) }, children: [isLoading && activities.length === 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsx(ActivityFeedItemSkeleton, { compact: compact }, index))) })), !isLoading && activities.length === 0 && hasPolicies !== false && (jsxRuntime.jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [jsxRuntime.jsx("p", { className: "m-0", children: "No activities found" }), jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-2 m-0", children: "Try adjusting your filters or time range" })] })), activities.map((activity, index) => (jsxRuntime.jsx(ActivityFeedItem, { activity: activity, onResourceClick: onResourceClick, resourceLinkResolver: resourceLinkResolver, tenantLinkResolver: tenantLinkResolver, tenantRenderer: tenantRenderer, onActorClick: handleActorClick, onActivityClick: onActivityClick, compact: compact, isNew: enableStreaming && index < newActivitiesCount }, activity.metadata?.uid || activity.metadata?.name))), infiniteScroll && hasMore && (jsxRuntime.jsx("div", { ref: loadMoreTriggerRef, className: "h-px mt-4" })), !infiniteScroll && hasMore && !isLoading && (jsxRuntime.jsx("div", { className: "flex justify-center p-4 mt-4", children: jsxRuntime.jsx(Button, { onClick: handleLoadMoreClick, children: "Load more" }) })), !hasMore && activities.length > 0 && !isLoading && (jsxRuntime.jsx("div", { className: "text-center py-6 text-muted-foreground text-sm border-t border-border mt-4", children: "No more activities to load" }))] })] }));
|
|
11051
|
+
const listClasses = 'flex-1 min-h-0 overflow-y-auto flex flex-col';
|
|
11052
|
+
return (jsxRuntime.jsxs(Card, { className: containerClasses, children: [enableStreaming && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between mb-1 pb-0.5 border-b border-border", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [isStreaming && !watchError && (jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsxs("span", { className: "relative flex h-2 w-2", children: [jsxRuntime.jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 dark:bg-green-500 opacity-75" }), jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500 dark:bg-green-400" })] }), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Streaming activity..." })] }) }), jsxRuntime.jsx(TooltipContent, { className: "text-xs", children: jsxRuntime.jsx("p", { children: "New activities will appear automatically" }) })] }) })), watchError && (jsxRuntime.jsx(TooltipProvider, { delayDuration: 300, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("span", { className: "relative flex h-2 w-2", children: jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-red-500 dark:bg-red-400" }) }), jsxRuntime.jsx("span", { className: "text-xs text-destructive", children: "Connection error" })] }) }), jsxRuntime.jsx(TooltipContent, { className: "text-xs", children: jsxRuntime.jsx("p", { children: "Stream connection lost" }) })] }) })), newActivitiesCount > 0 && !watchError && (jsxRuntime.jsxs(Badge, { variant: "secondary", className: "text-xs", children: ["+", newActivitiesCount, " new"] }))] }), jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: handleStreamingToggle, className: "text-xs", children: watchError ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: "2", children: [jsxRuntime.jsx("path", { d: "M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4" }), jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "3" })] }), "Retry"] })) : isStreaming ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [jsxRuntime.jsx("rect", { x: "6", y: "4", width: "4", height: "16" }), jsxRuntime.jsx("rect", { x: "14", y: "4", width: "4", height: "16" })] }), "Pause"] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("polygon", { points: "5,3 19,12 5,21", fill: "currentColor" }) }), "Resume"] })) })] })), showFilters && (jsxRuntime.jsx(ActivityFeedFilters, { client: client, filters: filters, timeRange: timeRange, onFiltersChange: handleFiltersChange, onTimeRangeChange: handleTimeRangeChange, disabled: isLoading, hiddenFilters: hiddenFilters })), jsxRuntime.jsx(ApiErrorAlert, { error: error, onRetry: refresh, className: "mb-4", errorFormatter: errorFormatter }), jsxRuntime.jsx(ApiErrorAlert, { error: watchError, onRetry: startStreaming, className: "mb-4", errorFormatter: errorFormatter }), !policiesLoading && hasPolicies === false && (jsxRuntime.jsxs("div", { className: "flex flex-col items-center py-12 px-8 text-center bg-muted border border-dashed border-border rounded-xl mb-4", children: [jsxRuntime.jsx("div", { className: "flex justify-center mb-4 text-muted-foreground", children: jsxRuntime.jsxs("svg", { width: "56", height: "56", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsxRuntime.jsx("path", { d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2" }), jsxRuntime.jsx("rect", { x: "9", y: "3", width: "6", height: "4", rx: "1" }), jsxRuntime.jsx("path", { d: "M9 12h6" }), jsxRuntime.jsx("path", { d: "M9 16h6" })] }) }), jsxRuntime.jsx("h3", { className: "m-0 mb-2 text-lg font-semibold text-foreground leading-snug", children: "Get started with activity logging" }), jsxRuntime.jsx("p", { className: "m-0 mb-6 text-sm leading-relaxed text-muted-foreground max-w-[400px]", children: "Activity policies define which resources to track and how to summarize changes. Create your first policy to start seeing activity logs here." }), onCreatePolicy && (jsxRuntime.jsx(Button, { onClick: onCreatePolicy, children: "Create Policy" }))] })), jsxRuntime.jsxs("div", { className: listClasses, ref: scrollContainerRef, style: { gap: compact ? '0.25rem' : '0.5rem', ...(effectiveMaxHeight ? { maxHeight: effectiveMaxHeight } : {}) }, children: [isLoading && activities.length === 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsx(ActivityFeedItemSkeleton, { compact: compact }, index))) })), !isLoading && activities.length === 0 && hasPolicies !== false && (jsxRuntime.jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [jsxRuntime.jsx("p", { className: "m-0", children: "No activities found" }), jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground mt-2 m-0", children: "Try adjusting your filters or time range" })] })), activities.map((activity, index) => (jsxRuntime.jsx(ActivityFeedItem, { activity: activity, onResourceClick: onResourceClick, resourceLinkResolver: resourceLinkResolver, tenantLinkResolver: tenantLinkResolver, tenantRenderer: tenantRenderer, onActorClick: handleActorClick, onActivityClick: onActivityClick, compact: compact, isNew: enableStreaming && index < newActivitiesCount, variant: variant, isLast: index === activities.length - 1 }, activity.metadata?.uid || activity.metadata?.name))), infiniteScroll && hasMore && (jsxRuntime.jsx("div", { ref: loadMoreTriggerRef, className: "h-px mt-4" })), !infiniteScroll && hasMore && !isLoading && (jsxRuntime.jsx("div", { className: "flex justify-center p-4 mt-4", children: jsxRuntime.jsx(Button, { onClick: handleLoadMoreClick, children: "Load more" }) })), !hasMore && activities.length > 0 && !isLoading && (jsxRuntime.jsx("div", { className: "text-center py-6 text-muted-foreground text-sm border-t border-border mt-4", children: "No more activities to load" }))] })] }));
|
|
10969
11053
|
}
|
|
10970
11054
|
|
|
10971
11055
|
/**
|
|
@@ -11052,7 +11136,7 @@ function ResourceHistoryView({ client, resourceFilter, startTime = 'now-30d', li
|
|
|
11052
11136
|
resourceFilter.name;
|
|
11053
11137
|
return (jsxRuntime.jsxs(Card, { className: cn(compact ? 'p-0 shadow-none border-0' : '', className), children: [showHeader && (jsxRuntime.jsx(CardHeader, { className: cn(compact ? 'px-0 pt-0 pb-3' : 'pb-4'), children: jsxRuntime.jsxs(CardTitle, { className: "text-base font-semibold text-foreground flex items-center gap-2", children: [jsxRuntime.jsx("svg", { className: "w-4 h-4 text-muted-foreground", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) }), headerTitle] }) })), jsxRuntime.jsxs(CardContent, { className: cn(compact ? 'p-0' : ''), children: [!hasValidFilter && (jsxRuntime.jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [jsxRuntime.jsx("svg", { className: "w-12 h-12 mx-auto mb-3 text-muted-foreground/50", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" }) }), jsxRuntime.jsx("p", { className: "m-0 text-sm", children: "No resource filter specified" }), jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-1 m-0", children: "Provide at least one filter criterion to view resource history" })] })), hasValidFilter && jsxRuntime.jsx(ApiErrorAlert, { error: error, onRetry: refresh, className: "mb-4", errorFormatter: errorFormatter }), hasValidFilter && isLoading && activities.length === 0 && (jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-3 py-12 text-muted-foreground text-sm", children: [jsxRuntime.jsx("div", { className: "w-5 h-5 border-[3px] border-muted border-t-primary rounded-full animate-spin" }), jsxRuntime.jsx("span", { children: "Loading history..." })] })), hasValidFilter && !isLoading && activities.length === 0 && !error && (jsxRuntime.jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [jsxRuntime.jsx("svg", { className: "w-12 h-12 mx-auto mb-3 text-muted-foreground/50", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 1.5, d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" }) }), jsxRuntime.jsx("p", { className: "m-0 text-sm", children: "No history found for this resource" }), jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground mt-1 m-0", children: "Changes will appear here once activity policies are configured" })] })), hasValidFilter && activities.length > 0 && (jsxRuntime.jsxs("div", { className: "relative", children: [activities.map((activity, index) => {
|
|
11054
11138
|
const activityId = activity.metadata?.uid || activity.metadata?.name || String(index);
|
|
11055
|
-
return (jsxRuntime.jsx(ActivityFeedItem, { activity: activity, variant: "timeline", compact: compact,
|
|
11139
|
+
return (jsxRuntime.jsx(ActivityFeedItem, { activity: activity, variant: "timeline", compact: compact, isLast: index === activities.length - 1 && !hasMore, onActivityClick: onActivityClick, onResourceClick: onResourceClick, resourceLinkResolver: resourceLinkResolver, onActorClick: onActorClick }, activityId));
|
|
11056
11140
|
}), isLoading && activities.length > 0 && (jsxRuntime.jsx("div", { className: cn('relative', compact ? 'pl-8' : 'pl-10'), children: jsxRuntime.jsxs("div", { className: "flex items-center gap-3 py-4 text-muted-foreground text-sm", children: [jsxRuntime.jsx("div", { className: "w-4 h-4 border-2 border-muted border-t-primary rounded-full animate-spin" }), jsxRuntime.jsx("span", { children: "Loading more..." })] }) })), hasMore && !isLoading && (jsxRuntime.jsxs("div", { className: cn('relative', compact ? 'pl-8' : 'pl-10'), children: [jsxRuntime.jsx("div", { className: cn('absolute w-0.5 bg-border', compact ? 'left-[11px] top-0 h-4' : 'left-[15px] top-0 h-5') }), jsxRuntime.jsx(Button, { variant: "ghost", size: "sm", onClick: handleLoadMore, className: "text-muted-foreground hover:text-foreground mt-2", children: "Load more history" })] }))] })), hasValidFilter && activities.length > 0 && (jsxRuntime.jsxs("div", { className: cn('text-xs text-muted-foreground mt-4 pt-3 border-t border-border', compact ? '' : ''), children: ["Showing ", activities.length, " event", activities.length !== 1 ? 's' : '', hasMore && ' (more available)'] }))] })] }));
|
|
11057
11141
|
}
|
|
11058
11142
|
|
|
@@ -14456,6 +14540,20 @@ function RulePreviewPanel({ rule, ruleType, policyResource, apiClient, className
|
|
|
14456
14540
|
}) }) }) }), stats.matched === 0 && stats.errors === 0 && (jsxRuntime.jsxs(Alert, { children: [jsxRuntime.jsx(CircleAlert, { className: "h-4 w-4" }), jsxRuntime.jsxs(AlertDescription, { children: ["This rule did not match any of the ", stats.total, " sample", stats.total !== 1 ? 's' : '', ". Check your match expression."] })] }))] }))] }));
|
|
14457
14541
|
}
|
|
14458
14542
|
|
|
14543
|
+
const defaultTabs = (basePath) => [
|
|
14544
|
+
{ label: 'Activity Feed', value: 'feed', href: basePath },
|
|
14545
|
+
{ label: 'Events', value: 'events', href: `${basePath}/events` },
|
|
14546
|
+
{ label: 'Audit Logs', value: 'audit-logs', href: `${basePath}/audit-logs` },
|
|
14547
|
+
];
|
|
14548
|
+
/**
|
|
14549
|
+
* Shared activity layout with tab navigation for Activity Feed, Events, and Audit Logs.
|
|
14550
|
+
* Framework-agnostic — pass a linkComponent (e.g., react-router's Link) for navigation.
|
|
14551
|
+
*/
|
|
14552
|
+
function ActivityLayout({ basePath, activeTab, tabs, linkComponent: LinkComp, children, className, }) {
|
|
14553
|
+
const resolvedTabs = tabs ?? defaultTabs(basePath);
|
|
14554
|
+
return (jsxRuntime.jsxs("div", { className: cn('flex h-full flex-col overflow-hidden', className), children: [jsxRuntime.jsx("div", { className: "shrink-0 border-b px-4 pt-3", children: jsxRuntime.jsx(Tabs, { value: activeTab, children: jsxRuntime.jsx(TabsList, { children: resolvedTabs.map((tab) => (jsxRuntime.jsx(TabsTrigger, { value: tab.value, asChild: !!LinkComp, children: LinkComp ? (jsxRuntime.jsx(LinkComp, { to: tab.href, children: tab.label })) : (jsxRuntime.jsx("span", { children: tab.label })) }, tab.value))) }) }) }), jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-hidden p-4", children: jsxRuntime.jsx("div", { className: "flex h-full flex-col", children: children }) })] }));
|
|
14555
|
+
}
|
|
14556
|
+
|
|
14459
14557
|
/**
|
|
14460
14558
|
* React hook for managing ReindexJobs with optional real-time watching
|
|
14461
14559
|
*/
|
|
@@ -14987,6 +15085,205 @@ function MultiCombobox({ options, values, onValuesChange, placeholder = 'Select.
|
|
|
14987
15085
|
}, className: "rounded-sm opacity-50 hover:opacity-100 cursor-pointer", children: jsxRuntime.jsx(X, { className: "h-3 w-3" }) })), jsxRuntime.jsx(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })] })] }) }), jsxRuntime.jsx(Popover__namespace.Portal, { children: jsxRuntime.jsx(Popover__namespace.Content, { className: cn('z-50 min-w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-md border shadow-md', 'bg-white dark:bg-slate-900 text-foreground', '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=top]:slide-in-from-bottom-2'), sideOffset: 4, align: "start", children: jsxRuntime.jsxs(cmdk.Command, { filter: filterOptions, className: "w-full", children: [jsxRuntime.jsx("div", { className: "flex items-center border-b px-3", children: jsxRuntime.jsx(cmdk.CommandInput, { placeholder: searchPlaceholder, value: search, onValueChange: setSearch, className: "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50" }) }), values.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 p-2 border-b", children: selectedOptions.map((option) => (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-secondary text-secondary-foreground text-xs", children: [option.label, jsxRuntime.jsx("button", { type: "button", onClick: (e) => handleRemove(e, option.value), className: "rounded-sm hover:bg-secondary-foreground/20", children: jsxRuntime.jsx(X, { className: "h-3 w-3" }) })] }, option.value))) })), jsxRuntime.jsxs(cmdk.CommandList, { className: "max-h-[300px] overflow-y-auto p-1", children: [jsxRuntime.jsx(cmdk.CommandEmpty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }), jsxRuntime.jsx(cmdk.CommandGroup, { children: options.map((option) => (jsxRuntime.jsxs(cmdk.CommandItem, { value: option.value, onSelect: () => handleSelect(option.value), className: cn('relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none', 'data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground', 'hover:bg-accent hover:text-accent-foreground'), children: [jsxRuntime.jsx(Check, { className: cn('mr-2 h-4 w-4', values.includes(option.value) ? 'opacity-100' : 'opacity-0') }), jsxRuntime.jsx("span", { className: "flex-1 truncate", children: option.label }), option.count !== undefined && (jsxRuntime.jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: ["(", option.count, ")"] }))] }, option.value))) })] })] }) }) })] }));
|
|
14988
15086
|
}
|
|
14989
15087
|
|
|
15088
|
+
/**
|
|
15089
|
+
* Serialize Activity Feed filters to URL search params.
|
|
15090
|
+
* Used to sync filter changes back to the URL for deep linking.
|
|
15091
|
+
*/
|
|
15092
|
+
function serializeActivityFilters(filters, timeRange, streamingEnabled = true) {
|
|
15093
|
+
const params = new URLSearchParams();
|
|
15094
|
+
if (timeRange.start) {
|
|
15095
|
+
params.set('start', timeRange.start);
|
|
15096
|
+
}
|
|
15097
|
+
if (timeRange.end) {
|
|
15098
|
+
params.set('end', timeRange.end);
|
|
15099
|
+
}
|
|
15100
|
+
if (!streamingEnabled) {
|
|
15101
|
+
params.set('streaming', 'false');
|
|
15102
|
+
}
|
|
15103
|
+
if (filters.changeSource && filters.changeSource !== 'human') {
|
|
15104
|
+
params.set('changeSource', filters.changeSource);
|
|
15105
|
+
}
|
|
15106
|
+
if (filters.actorNames && filters.actorNames.length > 0) {
|
|
15107
|
+
params.set('actorNames', filters.actorNames.join(','));
|
|
15108
|
+
}
|
|
15109
|
+
if (filters.resourceKinds && filters.resourceKinds.length > 0) {
|
|
15110
|
+
params.set('resourceKinds', filters.resourceKinds.join(','));
|
|
15111
|
+
}
|
|
15112
|
+
if (filters.apiGroups && filters.apiGroups.length > 0) {
|
|
15113
|
+
params.set('apiGroups', filters.apiGroups.join(','));
|
|
15114
|
+
}
|
|
15115
|
+
if (filters.resourceNamespaces && filters.resourceNamespaces.length > 0) {
|
|
15116
|
+
params.set('resourceNamespaces', filters.resourceNamespaces.join(','));
|
|
15117
|
+
}
|
|
15118
|
+
if (filters.resourceUid) {
|
|
15119
|
+
params.set('resourceUid', filters.resourceUid);
|
|
15120
|
+
}
|
|
15121
|
+
if (filters.resourceName) {
|
|
15122
|
+
params.set('resourceName', filters.resourceName);
|
|
15123
|
+
}
|
|
15124
|
+
if (filters.search) {
|
|
15125
|
+
params.set('search', filters.search);
|
|
15126
|
+
}
|
|
15127
|
+
return params;
|
|
15128
|
+
}
|
|
15129
|
+
/**
|
|
15130
|
+
* Serialize Events Feed filters to URL search params.
|
|
15131
|
+
* Used to sync filter changes back to the URL for deep linking.
|
|
15132
|
+
*/
|
|
15133
|
+
function serializeEventFilters(filters, timeRange, streamingEnabled = true) {
|
|
15134
|
+
const params = new URLSearchParams();
|
|
15135
|
+
if (timeRange.start) {
|
|
15136
|
+
params.set('start', timeRange.start);
|
|
15137
|
+
}
|
|
15138
|
+
if (timeRange.end) {
|
|
15139
|
+
params.set('end', timeRange.end);
|
|
15140
|
+
}
|
|
15141
|
+
if (!streamingEnabled) {
|
|
15142
|
+
params.set('streaming', 'false');
|
|
15143
|
+
}
|
|
15144
|
+
if (filters.eventType && filters.eventType !== 'all') {
|
|
15145
|
+
params.set('eventType', filters.eventType);
|
|
15146
|
+
}
|
|
15147
|
+
if (filters.reasons && filters.reasons.length > 0) {
|
|
15148
|
+
params.set('reasons', filters.reasons.join(','));
|
|
15149
|
+
}
|
|
15150
|
+
if (filters.namespaces && filters.namespaces.length > 0) {
|
|
15151
|
+
params.set('namespaces', filters.namespaces.join(','));
|
|
15152
|
+
}
|
|
15153
|
+
if (filters.involvedKinds && filters.involvedKinds.length > 0) {
|
|
15154
|
+
params.set('involvedKinds', filters.involvedKinds.join(','));
|
|
15155
|
+
}
|
|
15156
|
+
if (filters.search) {
|
|
15157
|
+
params.set('search', filters.search);
|
|
15158
|
+
}
|
|
15159
|
+
return params;
|
|
15160
|
+
}
|
|
15161
|
+
/**
|
|
15162
|
+
* Parse Activity Feed filters from URL query params
|
|
15163
|
+
*/
|
|
15164
|
+
function parseActivityFilters(searchParams) {
|
|
15165
|
+
const filters = {};
|
|
15166
|
+
const changeSource = searchParams.get('changeSource');
|
|
15167
|
+
if (changeSource === 'human' || changeSource === 'system' || changeSource === 'all') {
|
|
15168
|
+
filters.changeSource = changeSource;
|
|
15169
|
+
}
|
|
15170
|
+
else {
|
|
15171
|
+
filters.changeSource = 'human';
|
|
15172
|
+
}
|
|
15173
|
+
const actorNames = searchParams.get('actorNames');
|
|
15174
|
+
if (actorNames) {
|
|
15175
|
+
filters.actorNames = actorNames.split(',').filter(Boolean);
|
|
15176
|
+
}
|
|
15177
|
+
const resourceKinds = searchParams.get('resourceKinds');
|
|
15178
|
+
if (resourceKinds) {
|
|
15179
|
+
filters.resourceKinds = resourceKinds.split(',').filter(Boolean);
|
|
15180
|
+
}
|
|
15181
|
+
const apiGroups = searchParams.get('apiGroups');
|
|
15182
|
+
if (apiGroups) {
|
|
15183
|
+
filters.apiGroups = apiGroups.split(',').filter(Boolean);
|
|
15184
|
+
}
|
|
15185
|
+
const resourceNamespaces = searchParams.get('resourceNamespaces');
|
|
15186
|
+
if (resourceNamespaces) {
|
|
15187
|
+
filters.resourceNamespaces = resourceNamespaces.split(',').filter(Boolean);
|
|
15188
|
+
}
|
|
15189
|
+
const resourceUid = searchParams.get('resourceUid');
|
|
15190
|
+
if (resourceUid) {
|
|
15191
|
+
filters.resourceUid = resourceUid;
|
|
15192
|
+
}
|
|
15193
|
+
const resourceName = searchParams.get('resourceName');
|
|
15194
|
+
if (resourceName) {
|
|
15195
|
+
filters.resourceName = resourceName;
|
|
15196
|
+
}
|
|
15197
|
+
const search = searchParams.get('search');
|
|
15198
|
+
if (search) {
|
|
15199
|
+
filters.search = search;
|
|
15200
|
+
}
|
|
15201
|
+
return filters;
|
|
15202
|
+
}
|
|
15203
|
+
/**
|
|
15204
|
+
* Parse Events Feed filters from URL query params
|
|
15205
|
+
*/
|
|
15206
|
+
function parseEventFilters(searchParams) {
|
|
15207
|
+
const filters = {};
|
|
15208
|
+
const eventType = searchParams.get('eventType');
|
|
15209
|
+
if (eventType === 'Normal' || eventType === 'Warning' || eventType === 'all') {
|
|
15210
|
+
filters.eventType = eventType;
|
|
15211
|
+
}
|
|
15212
|
+
const reasons = searchParams.get('reasons');
|
|
15213
|
+
if (reasons) {
|
|
15214
|
+
filters.reasons = reasons.split(',').filter(Boolean);
|
|
15215
|
+
}
|
|
15216
|
+
const namespaces = searchParams.get('namespaces');
|
|
15217
|
+
if (namespaces) {
|
|
15218
|
+
filters.namespaces = namespaces.split(',').filter(Boolean);
|
|
15219
|
+
}
|
|
15220
|
+
const involvedKinds = searchParams.get('involvedKinds');
|
|
15221
|
+
if (involvedKinds) {
|
|
15222
|
+
filters.involvedKinds = involvedKinds.split(',').filter(Boolean);
|
|
15223
|
+
}
|
|
15224
|
+
const search = searchParams.get('search');
|
|
15225
|
+
if (search) {
|
|
15226
|
+
filters.search = search;
|
|
15227
|
+
}
|
|
15228
|
+
return filters;
|
|
15229
|
+
}
|
|
15230
|
+
/**
|
|
15231
|
+
* Parse time range from URL query params
|
|
15232
|
+
*/
|
|
15233
|
+
function parseTimeRange(searchParams) {
|
|
15234
|
+
const start = searchParams.get('start');
|
|
15235
|
+
const end = searchParams.get('end');
|
|
15236
|
+
if (!start) {
|
|
15237
|
+
return undefined;
|
|
15238
|
+
}
|
|
15239
|
+
return { start, end: end || undefined };
|
|
15240
|
+
}
|
|
15241
|
+
|
|
15242
|
+
/**
|
|
15243
|
+
* Generate a shareable URL for the current activity view.
|
|
15244
|
+
*
|
|
15245
|
+
* The shareable URL:
|
|
15246
|
+
* - Uses absolute timestamps (not relative like "now-1h")
|
|
15247
|
+
* - Disables streaming so the view is static
|
|
15248
|
+
* - Preserves all current filters
|
|
15249
|
+
*
|
|
15250
|
+
* This ensures the shared link shows the exact same data regardless of
|
|
15251
|
+
* when someone opens it.
|
|
15252
|
+
*
|
|
15253
|
+
* @param basePath - Current route path (e.g., "/activity/feed")
|
|
15254
|
+
* @param effectiveTimeRange - Server-calculated effective time range
|
|
15255
|
+
* @param filters - Current filter state
|
|
15256
|
+
* @param origin - Window origin for absolute URL (e.g., "https://staff.datum.cloud")
|
|
15257
|
+
*/
|
|
15258
|
+
function generateShareableUrl(basePath, effectiveTimeRange, filters, origin = typeof window !== 'undefined' ? window.location.origin : '') {
|
|
15259
|
+
const params = new URLSearchParams();
|
|
15260
|
+
// Use absolute timestamps from server-calculated range
|
|
15261
|
+
params.set('start', effectiveTimeRange.startTime);
|
|
15262
|
+
params.set('end', effectiveTimeRange.endTime);
|
|
15263
|
+
// Disable streaming for shared links (static view)
|
|
15264
|
+
params.set('streaming', 'false');
|
|
15265
|
+
// Preserve all current filters
|
|
15266
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
15267
|
+
if (value && key !== 'start' && key !== 'end' && key !== 'streaming') {
|
|
15268
|
+
params.set(key, value);
|
|
15269
|
+
}
|
|
15270
|
+
}
|
|
15271
|
+
return `${origin}${basePath}?${params.toString()}`;
|
|
15272
|
+
}
|
|
15273
|
+
/**
|
|
15274
|
+
* Copy text to clipboard and return success status
|
|
15275
|
+
*/
|
|
15276
|
+
async function copyToClipboard(text) {
|
|
15277
|
+
try {
|
|
15278
|
+
await navigator.clipboard.writeText(text);
|
|
15279
|
+
return true;
|
|
15280
|
+
}
|
|
15281
|
+
catch (err) {
|
|
15282
|
+
console.error('Failed to copy to clipboard:', err);
|
|
15283
|
+
return false;
|
|
15284
|
+
}
|
|
15285
|
+
}
|
|
15286
|
+
|
|
14990
15287
|
/**
|
|
14991
15288
|
* Create an empty audit event for preview
|
|
14992
15289
|
*/
|
|
@@ -16257,6 +16554,7 @@ exports.ActivityFeed = ActivityFeed;
|
|
|
16257
16554
|
exports.ActivityFeedItem = ActivityFeedItem;
|
|
16258
16555
|
exports.ActivityFeedItemSkeleton = ActivityFeedItemSkeleton;
|
|
16259
16556
|
exports.ActivityFeedSummary = ActivityFeedSummary;
|
|
16557
|
+
exports.ActivityLayout = ActivityLayout;
|
|
16260
16558
|
exports.Alert = Alert;
|
|
16261
16559
|
exports.AlertDescription = AlertDescription;
|
|
16262
16560
|
exports.AlertTitle = AlertTitle;
|
|
@@ -16353,17 +16651,24 @@ exports.badgeVariants = badgeVariants;
|
|
|
16353
16651
|
exports.buildAuditLogCEL = buildAuditLogCEL;
|
|
16354
16652
|
exports.buttonVariants = buttonVariants;
|
|
16355
16653
|
exports.cn = cn;
|
|
16654
|
+
exports.copyToClipboard = copyToClipboard;
|
|
16356
16655
|
exports.defaultErrorFormatter = defaultErrorFormatter;
|
|
16357
16656
|
exports.defaultResourceLinkResolver = defaultResourceLinkResolver;
|
|
16358
16657
|
exports.extractEvent = extractEvent;
|
|
16359
16658
|
exports.extractFieldPaths = extractFieldPaths;
|
|
16360
16659
|
exports.extractFieldPathsFromMany = extractFieldPathsFromMany;
|
|
16660
|
+
exports.generateShareableUrl = generateShareableUrl;
|
|
16361
16661
|
exports.getReindexJobDuration = getReindexJobDuration;
|
|
16362
16662
|
exports.getReindexJobStatusMessage = getReindexJobStatusMessage;
|
|
16363
16663
|
exports.isEventRecord = isEventRecord;
|
|
16364
16664
|
exports.isReindexJobRunning = isReindexJobRunning;
|
|
16365
16665
|
exports.isReindexJobTerminal = isReindexJobTerminal;
|
|
16666
|
+
exports.parseActivityFilters = parseActivityFilters;
|
|
16366
16667
|
exports.parseApiError = parseApiError;
|
|
16668
|
+
exports.parseEventFilters = parseEventFilters;
|
|
16669
|
+
exports.parseTimeRange = parseTimeRange;
|
|
16670
|
+
exports.serializeActivityFilters = serializeActivityFilters;
|
|
16671
|
+
exports.serializeEventFilters = serializeEventFilters;
|
|
16367
16672
|
exports.useActivityFeed = useActivityFeed;
|
|
16368
16673
|
exports.useAuditLogFacets = useAuditLogFacets;
|
|
16369
16674
|
exports.useAuditLogQuery = useAuditLogQuery;
|