@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.esm.js
CHANGED
|
@@ -7597,13 +7597,32 @@ const createLucideIcon = (iconName, iconNode) => {
|
|
|
7597
7597
|
*/
|
|
7598
7598
|
|
|
7599
7599
|
|
|
7600
|
-
const __iconNode$
|
|
7600
|
+
const __iconNode$o = [
|
|
7601
|
+
[
|
|
7602
|
+
"path",
|
|
7603
|
+
{
|
|
7604
|
+
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",
|
|
7605
|
+
key: "169zse"
|
|
7606
|
+
}
|
|
7607
|
+
]
|
|
7608
|
+
];
|
|
7609
|
+
const Activity = createLucideIcon("activity", __iconNode$o);
|
|
7610
|
+
|
|
7611
|
+
/**
|
|
7612
|
+
* @license lucide-react v0.563.0 - ISC
|
|
7613
|
+
*
|
|
7614
|
+
* This source code is licensed under the ISC license.
|
|
7615
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7616
|
+
*/
|
|
7617
|
+
|
|
7618
|
+
|
|
7619
|
+
const __iconNode$n = [
|
|
7601
7620
|
["path", { d: "M8 2v4", key: "1cmpym" }],
|
|
7602
7621
|
["path", { d: "M16 2v4", key: "4m81vk" }],
|
|
7603
7622
|
["rect", { width: "18", height: "18", x: "3", y: "4", rx: "2", key: "1hopcy" }],
|
|
7604
7623
|
["path", { d: "M3 10h18", key: "8toen8" }]
|
|
7605
7624
|
];
|
|
7606
|
-
const Calendar = createLucideIcon("calendar", __iconNode$
|
|
7625
|
+
const Calendar = createLucideIcon("calendar", __iconNode$n);
|
|
7607
7626
|
|
|
7608
7627
|
/**
|
|
7609
7628
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7613,8 +7632,8 @@ const Calendar = createLucideIcon("calendar", __iconNode$m);
|
|
|
7613
7632
|
*/
|
|
7614
7633
|
|
|
7615
7634
|
|
|
7616
|
-
const __iconNode$
|
|
7617
|
-
const Check = createLucideIcon("check", __iconNode$
|
|
7635
|
+
const __iconNode$m = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
7636
|
+
const Check = createLucideIcon("check", __iconNode$m);
|
|
7618
7637
|
|
|
7619
7638
|
/**
|
|
7620
7639
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7624,8 +7643,8 @@ const Check = createLucideIcon("check", __iconNode$l);
|
|
|
7624
7643
|
*/
|
|
7625
7644
|
|
|
7626
7645
|
|
|
7627
|
-
const __iconNode$
|
|
7628
|
-
const ChevronDown = createLucideIcon("chevron-down", __iconNode$
|
|
7646
|
+
const __iconNode$l = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
7647
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
|
|
7629
7648
|
|
|
7630
7649
|
/**
|
|
7631
7650
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7635,8 +7654,8 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$k);
|
|
|
7635
7654
|
*/
|
|
7636
7655
|
|
|
7637
7656
|
|
|
7638
|
-
const __iconNode$
|
|
7639
|
-
const ChevronRight = createLucideIcon("chevron-right", __iconNode$
|
|
7657
|
+
const __iconNode$k = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
|
|
7658
|
+
const ChevronRight = createLucideIcon("chevron-right", __iconNode$k);
|
|
7640
7659
|
|
|
7641
7660
|
/**
|
|
7642
7661
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7646,8 +7665,8 @@ const ChevronRight = createLucideIcon("chevron-right", __iconNode$j);
|
|
|
7646
7665
|
*/
|
|
7647
7666
|
|
|
7648
7667
|
|
|
7649
|
-
const __iconNode$
|
|
7650
|
-
const ChevronUp = createLucideIcon("chevron-up", __iconNode$
|
|
7668
|
+
const __iconNode$j = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
|
|
7669
|
+
const ChevronUp = createLucideIcon("chevron-up", __iconNode$j);
|
|
7651
7670
|
|
|
7652
7671
|
/**
|
|
7653
7672
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7657,11 +7676,11 @@ const ChevronUp = createLucideIcon("chevron-up", __iconNode$i);
|
|
|
7657
7676
|
*/
|
|
7658
7677
|
|
|
7659
7678
|
|
|
7660
|
-
const __iconNode$
|
|
7679
|
+
const __iconNode$i = [
|
|
7661
7680
|
["path", { d: "m7 15 5 5 5-5", key: "1hf1tw" }],
|
|
7662
7681
|
["path", { d: "m7 9 5-5 5 5", key: "sgt6xg" }]
|
|
7663
7682
|
];
|
|
7664
|
-
const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$
|
|
7683
|
+
const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$i);
|
|
7665
7684
|
|
|
7666
7685
|
/**
|
|
7667
7686
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7671,12 +7690,12 @@ const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$h);
|
|
|
7671
7690
|
*/
|
|
7672
7691
|
|
|
7673
7692
|
|
|
7674
|
-
const __iconNode$
|
|
7693
|
+
const __iconNode$h = [
|
|
7675
7694
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
7676
7695
|
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
7677
7696
|
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
7678
7697
|
];
|
|
7679
|
-
const CircleAlert = createLucideIcon("circle-alert", __iconNode$
|
|
7698
|
+
const CircleAlert = createLucideIcon("circle-alert", __iconNode$h);
|
|
7680
7699
|
|
|
7681
7700
|
/**
|
|
7682
7701
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7686,11 +7705,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$g);
|
|
|
7686
7705
|
*/
|
|
7687
7706
|
|
|
7688
7707
|
|
|
7689
|
-
const __iconNode$
|
|
7708
|
+
const __iconNode$g = [
|
|
7690
7709
|
["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
|
|
7691
7710
|
["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
|
|
7692
7711
|
];
|
|
7693
|
-
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$
|
|
7712
|
+
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$g);
|
|
7694
7713
|
|
|
7695
7714
|
/**
|
|
7696
7715
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7700,11 +7719,11 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$f);
|
|
|
7700
7719
|
*/
|
|
7701
7720
|
|
|
7702
7721
|
|
|
7703
|
-
const __iconNode$
|
|
7722
|
+
const __iconNode$f = [
|
|
7704
7723
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
7705
7724
|
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
7706
7725
|
];
|
|
7707
|
-
const CircleCheck = createLucideIcon("circle-check", __iconNode$
|
|
7726
|
+
const CircleCheck = createLucideIcon("circle-check", __iconNode$f);
|
|
7708
7727
|
|
|
7709
7728
|
/**
|
|
7710
7729
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7714,12 +7733,12 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$e);
|
|
|
7714
7733
|
*/
|
|
7715
7734
|
|
|
7716
7735
|
|
|
7717
|
-
const __iconNode$
|
|
7736
|
+
const __iconNode$e = [
|
|
7718
7737
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
7719
7738
|
["path", { d: "m15 9-6 6", key: "1uzhvr" }],
|
|
7720
7739
|
["path", { d: "m9 9 6 6", key: "z0biqf" }]
|
|
7721
7740
|
];
|
|
7722
|
-
const CircleX = createLucideIcon("circle-x", __iconNode$
|
|
7741
|
+
const CircleX = createLucideIcon("circle-x", __iconNode$e);
|
|
7723
7742
|
|
|
7724
7743
|
/**
|
|
7725
7744
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7729,11 +7748,11 @@ const CircleX = createLucideIcon("circle-x", __iconNode$d);
|
|
|
7729
7748
|
*/
|
|
7730
7749
|
|
|
7731
7750
|
|
|
7732
|
-
const __iconNode$
|
|
7751
|
+
const __iconNode$d = [
|
|
7733
7752
|
["path", { d: "M12 6v6l4 2", key: "mmk7yg" }],
|
|
7734
7753
|
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }]
|
|
7735
7754
|
];
|
|
7736
|
-
const Clock = createLucideIcon("clock", __iconNode$
|
|
7755
|
+
const Clock = createLucideIcon("clock", __iconNode$d);
|
|
7737
7756
|
|
|
7738
7757
|
/**
|
|
7739
7758
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7743,11 +7762,11 @@ const Clock = createLucideIcon("clock", __iconNode$c);
|
|
|
7743
7762
|
*/
|
|
7744
7763
|
|
|
7745
7764
|
|
|
7746
|
-
const __iconNode$
|
|
7765
|
+
const __iconNode$c = [
|
|
7747
7766
|
["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
|
|
7748
7767
|
["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" }]
|
|
7749
7768
|
];
|
|
7750
|
-
const Copy = createLucideIcon("copy", __iconNode$
|
|
7769
|
+
const Copy = createLucideIcon("copy", __iconNode$c);
|
|
7751
7770
|
|
|
7752
7771
|
/**
|
|
7753
7772
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7757,7 +7776,7 @@ const Copy = createLucideIcon("copy", __iconNode$b);
|
|
|
7757
7776
|
*/
|
|
7758
7777
|
|
|
7759
7778
|
|
|
7760
|
-
const __iconNode$
|
|
7779
|
+
const __iconNode$b = [
|
|
7761
7780
|
[
|
|
7762
7781
|
"path",
|
|
7763
7782
|
{
|
|
@@ -7767,7 +7786,18 @@ const __iconNode$a = [
|
|
|
7767
7786
|
],
|
|
7768
7787
|
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
7769
7788
|
];
|
|
7770
|
-
const Eye = createLucideIcon("eye", __iconNode$
|
|
7789
|
+
const Eye = createLucideIcon("eye", __iconNode$b);
|
|
7790
|
+
|
|
7791
|
+
/**
|
|
7792
|
+
* @license lucide-react v0.563.0 - ISC
|
|
7793
|
+
*
|
|
7794
|
+
* This source code is licensed under the ISC license.
|
|
7795
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7796
|
+
*/
|
|
7797
|
+
|
|
7798
|
+
|
|
7799
|
+
const __iconNode$a = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
7800
|
+
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$a);
|
|
7771
7801
|
|
|
7772
7802
|
/**
|
|
7773
7803
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -7777,8 +7807,17 @@ const Eye = createLucideIcon("eye", __iconNode$a);
|
|
|
7777
7807
|
*/
|
|
7778
7808
|
|
|
7779
7809
|
|
|
7780
|
-
const __iconNode$9 = [
|
|
7781
|
-
|
|
7810
|
+
const __iconNode$9 = [
|
|
7811
|
+
[
|
|
7812
|
+
"path",
|
|
7813
|
+
{
|
|
7814
|
+
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",
|
|
7815
|
+
key: "1a8usu"
|
|
7816
|
+
}
|
|
7817
|
+
],
|
|
7818
|
+
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
7819
|
+
];
|
|
7820
|
+
const Pencil = createLucideIcon("pencil", __iconNode$9);
|
|
7782
7821
|
|
|
7783
7822
|
/**
|
|
7784
7823
|
* @license lucide-react v0.563.0 - ISC
|
|
@@ -8517,7 +8556,7 @@ function FilterChip({ label, values, options = [], onValuesChange, onClear, inpu
|
|
|
8517
8556
|
}, [options]);
|
|
8518
8557
|
// Find selected options for chips display
|
|
8519
8558
|
const selectedOptions = options.filter((opt) => values.includes(opt.value));
|
|
8520
|
-
return (jsxs("div", { className: cn('inline-flex items-center', className), children: [jsxs(Popover.Root, { open: open, onOpenChange: handleOpenChange, children: [jsx(Popover.Trigger, { asChild: true, children: 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-
|
|
8559
|
+
return (jsxs("div", { className: cn('inline-flex items-center', className), children: [jsxs(Popover.Root, { open: open, onOpenChange: handleOpenChange, children: [jsx(Popover.Trigger, { asChild: true, children: 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: [jsxs("span", { className: "font-medium text-foreground", children: [label, ":"] }), jsx("span", { className: "text-foreground truncate max-w-[120px]", children: displayValue }), jsx(ChevronDown, { className: "h-3 w-3 text-muted-foreground ml-1" })] }) }), jsx(Popover.Portal, { children: jsx(Popover.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' ? (jsxs(Command, { filter: filterOptions, className: "w-full", children: [jsx("div", { className: "flex items-center border-b px-3", children: jsx(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 && (jsx("div", { className: "flex flex-wrap gap-1 p-2 border-b", children: selectedOptions.map((option) => (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, jsx("button", { type: "button", onClick: (e) => handleRemoveValue(e, option.value), className: "rounded-sm hover:bg-accent-foreground/20", children: jsx(X, { className: "h-3 w-3" }) })] }, option.value))) })), jsxs(CommandList, { className: "max-h-[300px] overflow-y-auto p-1", children: [jsx(CommandEmpty, { className: "py-6 text-center text-sm text-muted-foreground", children: "No results found." }), jsx(CommandGroup, { children: options.map((option) => (jsxs(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: [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) && (jsx("svg", { viewBox: "0 0 12 12", fill: "none", className: "h-full w-full p-0.5 text-primary-foreground", children: jsx("path", { d: "M2 6l3 3 5-5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) })) }), jsx("span", { className: "flex-1 truncate", children: option.label }), option.count !== undefined && (jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: ["(", option.count, ")"] }))] }, option.value))) })] })] })) : (jsx("div", { className: "p-3", children: jsx(Input, { type: "text", value: textValue, onChange: handleTextChange, placeholder: placeholder, className: "w-full", autoFocus: true }) })) }) })] }), 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: jsx(X, { className: "h-3 w-3 text-muted-foreground" }) })] }));
|
|
8521
8560
|
}
|
|
8522
8561
|
|
|
8523
8562
|
/**
|
|
@@ -10209,13 +10248,14 @@ const TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }
|
|
|
10209
10248
|
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
10210
10249
|
|
|
10211
10250
|
/**
|
|
10212
|
-
* Format timestamp for display (
|
|
10251
|
+
* Format timestamp for display (in UTC)
|
|
10213
10252
|
*/
|
|
10214
10253
|
function formatTimestampFull$3(timestamp) {
|
|
10215
10254
|
if (!timestamp)
|
|
10216
10255
|
return 'Unknown time';
|
|
10217
10256
|
try {
|
|
10218
|
-
|
|
10257
|
+
const date = new Date(timestamp);
|
|
10258
|
+
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`;
|
|
10219
10259
|
}
|
|
10220
10260
|
catch {
|
|
10221
10261
|
return timestamp;
|
|
@@ -10251,11 +10291,11 @@ function CopyButton({ value, label }) {
|
|
|
10251
10291
|
* 5. Resource - what resource was affected
|
|
10252
10292
|
* 6. Origin - correlation to audit logs
|
|
10253
10293
|
*/
|
|
10254
|
-
function ActivityExpandedDetails({ activity, tenantLinkResolver }) {
|
|
10294
|
+
function ActivityExpandedDetails({ activity, tenantLinkResolver, compact = false }) {
|
|
10255
10295
|
const { spec, metadata } = activity;
|
|
10256
10296
|
const { actor, resource, origin, changes, tenant } = spec;
|
|
10257
10297
|
const timestamp = metadata?.creationTimestamp;
|
|
10258
|
-
return (jsx(TooltipProvider, { children: jsxs("div", { className:
|
|
10298
|
+
return (jsx(TooltipProvider, { children: jsxs("div", { className: compact ? 'p-4 bg-muted/30' : 'mt-4 pt-4 border-t border-border', children: [changes && changes.length > 0 && (jsxs("div", { className: "mb-3", children: [jsx("h4", { className: "m-0 mb-2 text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Changes" }), jsx("div", { className: "flex flex-col gap-2", children: changes.map((change, index) => (jsxs("div", { className: "p-2 bg-muted rounded text-sm", children: [jsx("span", { className: "block font-semibold text-foreground mb-1 font-mono text-xs", children: change.field }), change.old && (jsxs("span", { className: "block ml-2 text-red-600 dark:text-red-400 text-xs", children: [jsx("span", { className: "font-medium mr-1", children: "\u2212" }), jsx("span", { className: "line-through", children: change.old })] })), change.new && (jsxs("span", { className: "block ml-2 text-green-600 dark:text-green-400 text-xs", children: [jsx("span", { className: "font-medium mr-1", children: "+" }), change.new] }))] }, index))) })] })), jsxs("dl", { className: "grid grid-cols-[repeat(auto-fit,minmax(250px,1fr))] gap-x-6 gap-y-2 m-0 text-xs", children: [jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Timestamp:" }), jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: formatTimestampFull$3(timestamp) }), jsx(CopyButton, { value: formatTimestampFull$3(timestamp), label: "timestamp" })] })] }), jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Actor Type:" }), jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: actor.type }), jsx(CopyButton, { value: actor.type, label: "actor type" })] })] }), jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Actor:" }), jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: actor.name }), jsx(CopyButton, { value: actor.name, label: "actor name" })] })] }), resource.apiGroup && (jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "API Group:" }), jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: resource.apiGroup }), jsx(CopyButton, { value: resource.apiGroup, label: "API group" })] })] })), jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Resource:" }), jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: resource.kind }), jsx(CopyButton, { value: resource.kind, label: "resource kind" })] })] }), jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Resource Name:" }), jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: resource.name }), jsx(CopyButton, { value: resource.name, label: "resource name" })] })] }), resource.namespace && (jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Namespace:" }), jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: resource.namespace }), jsx(CopyButton, { value: resource.namespace, label: "namespace" })] })] })), resource.uid && (jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Resource UID:" }), jsxs("dd", { className: "m-0 font-mono text-muted-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: resource.uid }), jsx(CopyButton, { value: resource.uid, label: "resource UID" })] })] })), jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Origin:" }), jsxs("dd", { className: "m-0 text-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: origin.type }), jsx(CopyButton, { value: origin.type, label: "origin type" })] })] }), jsxs("div", { className: "flex gap-1 items-baseline", children: [jsx("dt", { className: "text-muted-foreground shrink-0", children: "Origin ID:" }), jsxs("dd", { className: "m-0 font-mono text-muted-foreground flex items-center min-w-0", children: [jsx("span", { className: "truncate", children: origin.id }), jsx(CopyButton, { value: origin.id, label: "origin ID" })] })] })] })] }) }));
|
|
10259
10299
|
}
|
|
10260
10300
|
|
|
10261
10301
|
/**
|
|
@@ -10273,13 +10313,14 @@ function formatTimestamp$1(timestamp) {
|
|
|
10273
10313
|
}
|
|
10274
10314
|
}
|
|
10275
10315
|
/**
|
|
10276
|
-
* Format timestamp for tooltip (
|
|
10316
|
+
* Format timestamp for tooltip (in UTC)
|
|
10277
10317
|
*/
|
|
10278
10318
|
function formatTimestampFull$2(timestamp) {
|
|
10279
10319
|
if (!timestamp)
|
|
10280
10320
|
return 'Unknown time';
|
|
10281
10321
|
try {
|
|
10282
|
-
|
|
10322
|
+
const date = new Date(timestamp);
|
|
10323
|
+
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`;
|
|
10283
10324
|
}
|
|
10284
10325
|
catch {
|
|
10285
10326
|
return timestamp;
|
|
@@ -10336,25 +10377,41 @@ function normalizeVerb(verb) {
|
|
|
10336
10377
|
return 'other';
|
|
10337
10378
|
}
|
|
10338
10379
|
/**
|
|
10339
|
-
* Get
|
|
10380
|
+
* Get icon container + icon color classes based on verb
|
|
10381
|
+
*/
|
|
10382
|
+
function getActionIconClasses(verb) {
|
|
10383
|
+
const normalizedVerb = normalizeVerb(verb);
|
|
10384
|
+
switch (normalizedVerb) {
|
|
10385
|
+
case 'create':
|
|
10386
|
+
return { container: 'bg-blue-50 dark:bg-blue-950', icon: 'text-blue-500 dark:text-blue-400' };
|
|
10387
|
+
case 'update':
|
|
10388
|
+
return { container: 'bg-green-50 dark:bg-green-950', icon: 'text-green-600 dark:text-green-400' };
|
|
10389
|
+
case 'delete':
|
|
10390
|
+
return { container: 'bg-red-50 dark:bg-red-950', icon: 'text-red-500 dark:text-red-400' };
|
|
10391
|
+
default:
|
|
10392
|
+
return { container: 'bg-slate-100 dark:bg-slate-800', icon: 'text-slate-500 dark:text-slate-400' };
|
|
10393
|
+
}
|
|
10394
|
+
}
|
|
10395
|
+
/**
|
|
10396
|
+
* Get the Lucide icon component for the timeline node based on verb
|
|
10340
10397
|
*/
|
|
10341
|
-
function
|
|
10398
|
+
function getTimelineIcon(verb) {
|
|
10342
10399
|
const normalizedVerb = normalizeVerb(verb);
|
|
10343
10400
|
switch (normalizedVerb) {
|
|
10344
10401
|
case 'create':
|
|
10345
|
-
return
|
|
10402
|
+
return Plus;
|
|
10346
10403
|
case 'update':
|
|
10347
|
-
return
|
|
10404
|
+
return Pencil;
|
|
10348
10405
|
case 'delete':
|
|
10349
|
-
return
|
|
10406
|
+
return Trash2;
|
|
10350
10407
|
default:
|
|
10351
|
-
return
|
|
10408
|
+
return Activity;
|
|
10352
10409
|
}
|
|
10353
10410
|
}
|
|
10354
10411
|
/**
|
|
10355
10412
|
* ActivityFeedItem renders a single activity in the feed or timeline
|
|
10356
10413
|
*/
|
|
10357
|
-
function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isSelected = false, className = '', compact = false, isNew = false, variant = 'feed',
|
|
10414
|
+
function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isSelected = false, className = '', compact = false, isNew = false, variant = 'feed', isLast = false, defaultExpanded = false, }) {
|
|
10358
10415
|
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
10359
10416
|
const { spec, metadata } = activity;
|
|
10360
10417
|
const { actor, summary, links, tenant } = spec;
|
|
@@ -10374,9 +10431,11 @@ function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, ten
|
|
|
10374
10431
|
const timestamp = metadata?.creationTimestamp;
|
|
10375
10432
|
const verb = extractVerb(summary);
|
|
10376
10433
|
const isTimeline = variant === 'timeline';
|
|
10377
|
-
// Timeline variant
|
|
10434
|
+
// Timeline variant — flat list row with bottom border
|
|
10378
10435
|
if (isTimeline) {
|
|
10379
|
-
|
|
10436
|
+
const { container: iconBg, icon: iconColor } = getActionIconClasses(verb);
|
|
10437
|
+
const Icon = getTimelineIcon(verb);
|
|
10438
|
+
return (jsxs("div", { className: cn(!isLast && !isExpanded && 'border-b border-border', className), children: [jsxs("div", { className: cn('flex items-center gap-3 py-3 pl-4 cursor-pointer group', isSelected && 'bg-muted/40'), onClick: toggleExpand, children: [jsx("div", { className: cn('w-8 h-8 rounded-md shrink-0 flex items-center justify-center', iconBg, iconColor), children: jsx(Icon, { size: 16, strokeWidth: 2 }) }), jsx("div", { className: "flex-1 min-w-0 text-sm text-foreground leading-snug", children: jsx(ActivityFeedSummary, { summary: summary, links: links, onResourceClick: onResourceClick, resourceLinkResolver: resourceLinkResolver, resourceLinkContext: { tenant } }) }), tenant && (jsx("div", { className: "shrink-0", children: tenantRenderer ? tenantRenderer(tenant) : jsx(TenantBadge, { tenant: tenant, tenantLinkResolver: tenantLinkResolver, size: "compact" }) })), jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0", title: formatTimestampFull$2(timestamp), children: formatTimestamp$1(timestamp) }), 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 && (jsx(ActivityExpandedDetails, { activity: activity, tenantLinkResolver: tenantLinkResolver, compact: true }))] }));
|
|
10380
10439
|
}
|
|
10381
10440
|
// Feed variant (single-row layout)
|
|
10382
10441
|
return (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: [jsxs("div", { className: "flex items-center gap-2", children: [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' ? (jsx("span", { className: "text-xs", children: "\u2699" })) : actor.type === 'machine account' ? (jsx("span", { className: "text-xs", children: "\uD83E\uDD16" })) : (jsx("span", { className: "uppercase", children: getActorInitials(actor.name) })) }), jsx("div", { className: "flex-1 min-w-0 text-xs leading-snug", children: jsx(ActivityFeedSummary, { summary: summary, links: links, onResourceClick: onResourceClick, resourceLinkResolver: resourceLinkResolver, resourceLinkContext: { tenant } }) }), tenant && (jsx("div", { className: "shrink-0", children: tenantRenderer ? tenantRenderer(tenant) : jsx(TenantBadge, { tenant: tenant, tenantLinkResolver: tenantLinkResolver, size: "compact" }) })), jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0", title: formatTimestampFull$2(timestamp), children: formatTimestamp$1(timestamp) }), 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 && jsx(ActivityExpandedDetails, { activity: activity, tenantLinkResolver: tenantLinkResolver })] }));
|
|
@@ -10696,19 +10755,22 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10696
10755
|
return 'Select time range';
|
|
10697
10756
|
};
|
|
10698
10757
|
// Determine which filters are currently active (have values) and not hidden
|
|
10699
|
-
const filtersWithValues =
|
|
10700
|
-
|
|
10701
|
-
|
|
10702
|
-
|
|
10703
|
-
|
|
10704
|
-
|
|
10705
|
-
|
|
10706
|
-
|
|
10707
|
-
|
|
10708
|
-
|
|
10709
|
-
|
|
10710
|
-
|
|
10711
|
-
|
|
10758
|
+
const filtersWithValues = useMemo(() => {
|
|
10759
|
+
const result = [];
|
|
10760
|
+
if (filters.resourceKinds && filters.resourceKinds.length > 0 && !hiddenFilters.includes('resourceKinds'))
|
|
10761
|
+
result.push('resourceKinds');
|
|
10762
|
+
if (filters.actorNames && filters.actorNames.length > 0 && !hiddenFilters.includes('actorNames'))
|
|
10763
|
+
result.push('actorNames');
|
|
10764
|
+
if (filters.apiGroups && filters.apiGroups.length > 0 && !hiddenFilters.includes('apiGroups'))
|
|
10765
|
+
result.push('apiGroups');
|
|
10766
|
+
if (filters.resourceNamespaces && filters.resourceNamespaces.length > 0 && !hiddenFilters.includes('resourceNamespaces'))
|
|
10767
|
+
result.push('resourceNamespaces');
|
|
10768
|
+
if (filters.resourceName && !hiddenFilters.includes('resourceName'))
|
|
10769
|
+
result.push('resourceName');
|
|
10770
|
+
if (filters.actions && filters.actions.length > 0)
|
|
10771
|
+
result.push('actions');
|
|
10772
|
+
return result;
|
|
10773
|
+
}, [filters, hiddenFilters]);
|
|
10712
10774
|
// Include pendingFilter (newly added filter awaiting value selection) in the displayed filters
|
|
10713
10775
|
const activeFilterIds = pendingFilter && !filtersWithValues.includes(pendingFilter)
|
|
10714
10776
|
? [...filtersWithValues, pendingFilter]
|
|
@@ -10727,7 +10789,7 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10727
10789
|
{ id: 'apiGroups', label: 'API Group' },
|
|
10728
10790
|
{ id: 'resourceNamespaces', label: 'Namespace' },
|
|
10729
10791
|
{ id: 'resourceName', label: 'Resource Name' },
|
|
10730
|
-
|
|
10792
|
+
// 'actions' hidden until backend facet support is available
|
|
10731
10793
|
].filter((filter) => !hiddenFilters.includes(filter.id));
|
|
10732
10794
|
// Handle adding a filter
|
|
10733
10795
|
const handleAddFilter = useCallback((filterId) => {
|
|
@@ -10814,15 +10876,37 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10814
10876
|
}
|
|
10815
10877
|
return value || [];
|
|
10816
10878
|
};
|
|
10817
|
-
//
|
|
10879
|
+
// Local search value for debouncing — keeps input responsive while query runs
|
|
10880
|
+
const [searchInputValue, setSearchInputValue] = useState(filters.search || '');
|
|
10881
|
+
const searchDebounceRef = useRef(null);
|
|
10882
|
+
// Use refs so the debounced callback never closes over stale values
|
|
10883
|
+
const filtersRef = useRef(filters);
|
|
10884
|
+
filtersRef.current = filters;
|
|
10885
|
+
const onFiltersChangeRef = useRef(onFiltersChange);
|
|
10886
|
+
onFiltersChangeRef.current = onFiltersChange;
|
|
10887
|
+
// Cancel any pending debounce on unmount
|
|
10888
|
+
useEffect(() => {
|
|
10889
|
+
return () => {
|
|
10890
|
+
if (searchDebounceRef.current)
|
|
10891
|
+
clearTimeout(searchDebounceRef.current);
|
|
10892
|
+
};
|
|
10893
|
+
}, []);
|
|
10818
10894
|
const handleSearchChange = useCallback((event) => {
|
|
10819
10895
|
const value = event.target.value;
|
|
10820
|
-
|
|
10821
|
-
|
|
10822
|
-
|
|
10823
|
-
|
|
10824
|
-
|
|
10825
|
-
|
|
10896
|
+
setSearchInputValue(value);
|
|
10897
|
+
if (searchDebounceRef.current)
|
|
10898
|
+
clearTimeout(searchDebounceRef.current);
|
|
10899
|
+
searchDebounceRef.current = setTimeout(() => {
|
|
10900
|
+
onFiltersChangeRef.current({ ...filtersRef.current, search: value || undefined });
|
|
10901
|
+
}, 400);
|
|
10902
|
+
}, []);
|
|
10903
|
+
const handleSearchClear = useCallback(() => {
|
|
10904
|
+
setSearchInputValue('');
|
|
10905
|
+
if (searchDebounceRef.current)
|
|
10906
|
+
clearTimeout(searchDebounceRef.current);
|
|
10907
|
+
onFiltersChangeRef.current({ ...filtersRef.current, search: undefined });
|
|
10908
|
+
}, []);
|
|
10909
|
+
return (jsx("div", { className: `mb-3 pb-3 border-b border-border p-4 ${className}`, children: jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [!hiddenFilters.includes('changeSource') && (jsx(ChangeSourceToggle, { value: filters.changeSource || 'all', onChange: handleChangeSourceChange, disabled: disabled })), jsxs("div", { className: "relative min-w-[200px] flex-1 max-w-xs", children: [jsx(Search, { className: "absolute left-2 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), jsx(Input, { type: "text", placeholder: "Search activities...", value: searchInputValue, onChange: handleSearchChange, className: "pl-8 h-7 text-xs pr-6" }), searchInputValue && (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: jsx(X, { className: "h-3.5 w-3.5" }) }))] }), activeFilterIds.map((filterId) => {
|
|
10826
10910
|
const config = FILTER_CONFIGS$1[filterId];
|
|
10827
10911
|
return (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));
|
|
10828
10912
|
}), jsx(AddFilterDropdown, { availableFilters: availableFilters, activeFilterIds: activeFilterIds, onAddFilter: handleAddFilter, hasActiveFilters: activeFilterIds.length > 0, disabled: disabled }), jsx("div", { className: "flex-1 min-w-[20px]" }), jsx(TimeRangeDropdown, { presets: TIME_PRESETS$1, selectedPreset: selectedPreset, onPresetSelect: handleTimePresetSelect, onCustomRangeApply: handleCustomRangeApply, customStart: customStart, customEnd: customEnd, disabled: disabled, displayLabel: getTimeRangeLabel() })] }) }));
|
|
@@ -10832,7 +10916,7 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10832
10916
|
* ActivityFeed displays a chronological list of activities with filtering and pagination.
|
|
10833
10917
|
* Supports optional real-time streaming of new activities.
|
|
10834
10918
|
*/
|
|
10835
|
-
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, }) {
|
|
10919
|
+
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, }) {
|
|
10836
10920
|
// Merge resourceUid into initial filters if provided
|
|
10837
10921
|
const mergedInitialFilters = {
|
|
10838
10922
|
...initialFilters,
|
|
@@ -10932,13 +11016,13 @@ function ActivityFeed({ client, initialFilters = { changeSource: 'human' }, init
|
|
|
10932
11016
|
// Build container classes - use flex layout to properly fill available space
|
|
10933
11017
|
// flex-1 min-h-0 allows the Card to fill parent flex container and enable child scrolling
|
|
10934
11018
|
const containerClasses = compact
|
|
10935
|
-
? `flex-1 min-h-0 flex flex-col p-
|
|
11019
|
+
? `flex-1 min-h-0 flex flex-col p-0 shadow-none border-none ${className}`
|
|
10936
11020
|
: `flex-1 min-h-0 flex flex-col p-3 ${className}`;
|
|
10937
11021
|
// Build list classes - use flex-1 min-h-0 for flex-based scrolling
|
|
10938
11022
|
// Parent containers must have proper height constraints (h-screen/h-full + overflow-hidden)
|
|
10939
11023
|
const effectiveMaxHeight = maxHeight === 'none' ? undefined : maxHeight;
|
|
10940
|
-
const listClasses = 'flex-1 min-h-0 overflow-y-auto
|
|
10941
|
-
return (jsxs(Card, { className: containerClasses, children: [enableStreaming && (jsxs("div", { className: "flex items-center justify-between mb-1 pb-0.5 border-b border-border", children: [jsxs("div", { className: "flex items-center gap-2", children: [isStreaming && !watchError && (jsx(TooltipProvider, { delayDuration: 300, children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsxs("div", { className: "flex items-center gap-2", children: [jsxs("span", { className: "relative flex h-2 w-2", children: [jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 dark:bg-green-500 opacity-75" }), jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500 dark:bg-green-400" })] }), jsx("span", { className: "text-xs text-muted-foreground", children: "Streaming activity..." })] }) }), jsx(TooltipContent, { className: "text-xs", children: jsx("p", { children: "New activities will appear automatically" }) })] }) })), watchError && (jsx(TooltipProvider, { delayDuration: 300, children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "relative flex h-2 w-2", children: jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-red-500 dark:bg-red-400" }) }), jsx("span", { className: "text-xs text-destructive", children: "Connection error" })] }) }), jsx(TooltipContent, { className: "text-xs", children: jsx("p", { children: "Stream connection lost" }) })] }) })), newActivitiesCount > 0 && !watchError && (jsxs(Badge, { variant: "secondary", className: "text-xs", children: ["+", newActivitiesCount, " new"] }))] }), jsx(Button, { variant: "ghost", size: "sm", onClick: handleStreamingToggle, className: "text-xs", children: watchError ? (jsxs(Fragment, { children: [jsxs("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: "2", children: [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" }), jsx("circle", { cx: "12", cy: "12", r: "3" })] }), "Retry"] })) : isStreaming ? (jsxs(Fragment, { children: [jsxs("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [jsx("rect", { x: "6", y: "4", width: "4", height: "16" }), jsx("rect", { x: "14", y: "4", width: "4", height: "16" })] }), "Pause"] })) : (jsxs(Fragment, { children: [jsx("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("polygon", { points: "5,3 19,12 5,21", fill: "currentColor" }) }), "Resume"] })) })] })), showFilters && (jsx(ActivityFeedFilters, { client: client, filters: filters, timeRange: timeRange, onFiltersChange: handleFiltersChange, onTimeRangeChange: handleTimeRangeChange, disabled: isLoading, hiddenFilters: hiddenFilters })), jsx(ApiErrorAlert, { error: error, onRetry: refresh, className: "mb-4", errorFormatter: errorFormatter }), jsx(ApiErrorAlert, { error: watchError, onRetry: startStreaming, className: "mb-4", errorFormatter: errorFormatter }), !policiesLoading && hasPolicies === false && (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: [jsx("div", { className: "flex justify-center mb-4 text-muted-foreground", children: jsxs("svg", { width: "56", height: "56", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2" }), jsx("rect", { x: "9", y: "3", width: "6", height: "4", rx: "1" }), jsx("path", { d: "M9 12h6" }), jsx("path", { d: "M9 16h6" })] }) }), jsx("h3", { className: "m-0 mb-2 text-lg font-semibold text-foreground leading-snug", children: "Get started with activity logging" }), 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 && (jsx(Button, { onClick: onCreatePolicy, children: "Create Policy" }))] })), jsxs("div", { className: listClasses, ref: scrollContainerRef, style: { gap: compact ? '0.25rem' : '0.5rem', ...(effectiveMaxHeight ? { maxHeight: effectiveMaxHeight } : {}) }, children: [isLoading && activities.length === 0 && (jsx(Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsx(ActivityFeedItemSkeleton, { compact: compact }, index))) })), !isLoading && activities.length === 0 && hasPolicies !== false && (jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [jsx("p", { className: "m-0", children: "No activities found" }), jsx("p", { className: "text-sm text-muted-foreground mt-2 m-0", children: "Try adjusting your filters or time range" })] })), activities.map((activity, index) => (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 && (jsx("div", { ref: loadMoreTriggerRef, className: "h-px mt-4" })), !infiniteScroll && hasMore && !isLoading && (jsx("div", { className: "flex justify-center p-4 mt-4", children: jsx(Button, { onClick: handleLoadMoreClick, children: "Load more" }) })), !hasMore && activities.length > 0 && !isLoading && (jsx("div", { className: "text-center py-6 text-muted-foreground text-sm border-t border-border mt-4", children: "No more activities to load" }))] })] }));
|
|
11024
|
+
const listClasses = 'flex-1 min-h-0 overflow-y-auto flex flex-col';
|
|
11025
|
+
return (jsxs(Card, { className: containerClasses, children: [enableStreaming && (jsxs("div", { className: "flex items-center justify-between mb-1 pb-0.5 border-b border-border", children: [jsxs("div", { className: "flex items-center gap-2", children: [isStreaming && !watchError && (jsx(TooltipProvider, { delayDuration: 300, children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsxs("div", { className: "flex items-center gap-2", children: [jsxs("span", { className: "relative flex h-2 w-2", children: [jsx("span", { className: "animate-ping absolute inline-flex h-full w-full rounded-full bg-green-400 dark:bg-green-500 opacity-75" }), jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-green-500 dark:bg-green-400" })] }), jsx("span", { className: "text-xs text-muted-foreground", children: "Streaming activity..." })] }) }), jsx(TooltipContent, { className: "text-xs", children: jsx("p", { children: "New activities will appear automatically" }) })] }) })), watchError && (jsx(TooltipProvider, { delayDuration: 300, children: jsxs(Tooltip, { children: [jsx(TooltipTrigger, { asChild: true, children: jsxs("div", { className: "flex items-center gap-2", children: [jsx("span", { className: "relative flex h-2 w-2", children: jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-red-500 dark:bg-red-400" }) }), jsx("span", { className: "text-xs text-destructive", children: "Connection error" })] }) }), jsx(TooltipContent, { className: "text-xs", children: jsx("p", { children: "Stream connection lost" }) })] }) })), newActivitiesCount > 0 && !watchError && (jsxs(Badge, { variant: "secondary", className: "text-xs", children: ["+", newActivitiesCount, " new"] }))] }), jsx(Button, { variant: "ghost", size: "sm", onClick: handleStreamingToggle, className: "text-xs", children: watchError ? (jsxs(Fragment, { children: [jsxs("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", strokeWidth: "2", children: [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" }), jsx("circle", { cx: "12", cy: "12", r: "3" })] }), "Retry"] })) : isStreaming ? (jsxs(Fragment, { children: [jsxs("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: [jsx("rect", { x: "6", y: "4", width: "4", height: "16" }), jsx("rect", { x: "14", y: "4", width: "4", height: "16" })] }), "Pause"] })) : (jsxs(Fragment, { children: [jsx("svg", { className: "w-4 h-4 mr-1.5", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("polygon", { points: "5,3 19,12 5,21", fill: "currentColor" }) }), "Resume"] })) })] })), showFilters && (jsx(ActivityFeedFilters, { client: client, filters: filters, timeRange: timeRange, onFiltersChange: handleFiltersChange, onTimeRangeChange: handleTimeRangeChange, disabled: isLoading, hiddenFilters: hiddenFilters })), jsx(ApiErrorAlert, { error: error, onRetry: refresh, className: "mb-4", errorFormatter: errorFormatter }), jsx(ApiErrorAlert, { error: watchError, onRetry: startStreaming, className: "mb-4", errorFormatter: errorFormatter }), !policiesLoading && hasPolicies === false && (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: [jsx("div", { className: "flex justify-center mb-4 text-muted-foreground", children: jsxs("svg", { width: "56", height: "56", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round", children: [jsx("path", { d: "M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2" }), jsx("rect", { x: "9", y: "3", width: "6", height: "4", rx: "1" }), jsx("path", { d: "M9 12h6" }), jsx("path", { d: "M9 16h6" })] }) }), jsx("h3", { className: "m-0 mb-2 text-lg font-semibold text-foreground leading-snug", children: "Get started with activity logging" }), 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 && (jsx(Button, { onClick: onCreatePolicy, children: "Create Policy" }))] })), jsxs("div", { className: listClasses, ref: scrollContainerRef, style: { gap: compact ? '0.25rem' : '0.5rem', ...(effectiveMaxHeight ? { maxHeight: effectiveMaxHeight } : {}) }, children: [isLoading && activities.length === 0 && (jsx(Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsx(ActivityFeedItemSkeleton, { compact: compact }, index))) })), !isLoading && activities.length === 0 && hasPolicies !== false && (jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [jsx("p", { className: "m-0", children: "No activities found" }), jsx("p", { className: "text-sm text-muted-foreground mt-2 m-0", children: "Try adjusting your filters or time range" })] })), activities.map((activity, index) => (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 && (jsx("div", { ref: loadMoreTriggerRef, className: "h-px mt-4" })), !infiniteScroll && hasMore && !isLoading && (jsx("div", { className: "flex justify-center p-4 mt-4", children: jsx(Button, { onClick: handleLoadMoreClick, children: "Load more" }) })), !hasMore && activities.length > 0 && !isLoading && (jsx("div", { className: "text-center py-6 text-muted-foreground text-sm border-t border-border mt-4", children: "No more activities to load" }))] })] }));
|
|
10942
11026
|
}
|
|
10943
11027
|
|
|
10944
11028
|
/**
|
|
@@ -11025,7 +11109,7 @@ function ResourceHistoryView({ client, resourceFilter, startTime = 'now-30d', li
|
|
|
11025
11109
|
resourceFilter.name;
|
|
11026
11110
|
return (jsxs(Card, { className: cn(compact ? 'p-0 shadow-none border-0' : '', className), children: [showHeader && (jsx(CardHeader, { className: cn(compact ? 'px-0 pt-0 pb-3' : 'pb-4'), children: jsxs(CardTitle, { className: "text-base font-semibold text-foreground flex items-center gap-2", children: [jsx("svg", { className: "w-4 h-4 text-muted-foreground", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", children: jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z" }) }), headerTitle] }) })), jsxs(CardContent, { className: cn(compact ? 'p-0' : ''), children: [!hasValidFilter && (jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [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: 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" }) }), jsx("p", { className: "m-0 text-sm", children: "No resource filter specified" }), jsx("p", { className: "text-xs text-muted-foreground mt-1 m-0", children: "Provide at least one filter criterion to view resource history" })] })), hasValidFilter && jsx(ApiErrorAlert, { error: error, onRetry: refresh, className: "mb-4", errorFormatter: errorFormatter }), hasValidFilter && isLoading && activities.length === 0 && (jsxs("div", { className: "flex items-center justify-center gap-3 py-12 text-muted-foreground text-sm", children: [jsx("div", { className: "w-5 h-5 border-[3px] border-muted border-t-primary rounded-full animate-spin" }), jsx("span", { children: "Loading history..." })] })), hasValidFilter && !isLoading && activities.length === 0 && !error && (jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [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: 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" }) }), jsx("p", { className: "m-0 text-sm", children: "No history found for this resource" }), 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 && (jsxs("div", { className: "relative", children: [activities.map((activity, index) => {
|
|
11027
11111
|
const activityId = activity.metadata?.uid || activity.metadata?.name || String(index);
|
|
11028
|
-
return (jsx(ActivityFeedItem, { activity: activity, variant: "timeline", compact: compact,
|
|
11112
|
+
return (jsx(ActivityFeedItem, { activity: activity, variant: "timeline", compact: compact, isLast: index === activities.length - 1 && !hasMore, onActivityClick: onActivityClick, onResourceClick: onResourceClick, resourceLinkResolver: resourceLinkResolver, onActorClick: onActorClick }, activityId));
|
|
11029
11113
|
}), isLoading && activities.length > 0 && (jsx("div", { className: cn('relative', compact ? 'pl-8' : 'pl-10'), children: jsxs("div", { className: "flex items-center gap-3 py-4 text-muted-foreground text-sm", children: [jsx("div", { className: "w-4 h-4 border-2 border-muted border-t-primary rounded-full animate-spin" }), jsx("span", { children: "Loading more..." })] }) })), hasMore && !isLoading && (jsxs("div", { className: cn('relative', compact ? 'pl-8' : 'pl-10'), children: [jsx("div", { className: cn('absolute w-0.5 bg-border', compact ? 'left-[11px] top-0 h-4' : 'left-[15px] top-0 h-5') }), 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 && (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)'] }))] })] }));
|
|
11030
11114
|
}
|
|
11031
11115
|
|
|
@@ -14429,6 +14513,20 @@ function RulePreviewPanel({ rule, ruleType, policyResource, apiClient, className
|
|
|
14429
14513
|
}) }) }) }), stats.matched === 0 && stats.errors === 0 && (jsxs(Alert, { children: [jsx(CircleAlert, { className: "h-4 w-4" }), jsxs(AlertDescription, { children: ["This rule did not match any of the ", stats.total, " sample", stats.total !== 1 ? 's' : '', ". Check your match expression."] })] }))] }))] }));
|
|
14430
14514
|
}
|
|
14431
14515
|
|
|
14516
|
+
const defaultTabs = (basePath) => [
|
|
14517
|
+
{ label: 'Activity Feed', value: 'feed', href: basePath },
|
|
14518
|
+
{ label: 'Events', value: 'events', href: `${basePath}/events` },
|
|
14519
|
+
{ label: 'Audit Logs', value: 'audit-logs', href: `${basePath}/audit-logs` },
|
|
14520
|
+
];
|
|
14521
|
+
/**
|
|
14522
|
+
* Shared activity layout with tab navigation for Activity Feed, Events, and Audit Logs.
|
|
14523
|
+
* Framework-agnostic — pass a linkComponent (e.g., react-router's Link) for navigation.
|
|
14524
|
+
*/
|
|
14525
|
+
function ActivityLayout({ basePath, activeTab, tabs, linkComponent: LinkComp, children, className, }) {
|
|
14526
|
+
const resolvedTabs = tabs ?? defaultTabs(basePath);
|
|
14527
|
+
return (jsxs("div", { className: cn('flex h-full flex-col overflow-hidden', className), children: [jsx("div", { className: "shrink-0 border-b px-4 pt-3", children: jsx(Tabs, { value: activeTab, children: jsx(TabsList, { children: resolvedTabs.map((tab) => (jsx(TabsTrigger, { value: tab.value, asChild: !!LinkComp, children: LinkComp ? (jsx(LinkComp, { to: tab.href, children: tab.label })) : (jsx("span", { children: tab.label })) }, tab.value))) }) }) }), jsx("div", { className: "min-h-0 flex-1 overflow-hidden p-4", children: jsx("div", { className: "flex h-full flex-col", children: children }) })] }));
|
|
14528
|
+
}
|
|
14529
|
+
|
|
14432
14530
|
/**
|
|
14433
14531
|
* React hook for managing ReindexJobs with optional real-time watching
|
|
14434
14532
|
*/
|
|
@@ -14960,6 +15058,205 @@ function MultiCombobox({ options, values, onValuesChange, placeholder = 'Select.
|
|
|
14960
15058
|
}, className: "rounded-sm opacity-50 hover:opacity-100 cursor-pointer", children: jsx(X, { className: "h-3 w-3" }) })), jsx(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })] })] }) }), jsx(Popover.Portal, { children: jsx(Popover.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: jsxs(Command, { filter: filterOptions, className: "w-full", children: [jsx("div", { className: "flex items-center border-b px-3", children: jsx(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 && (jsx("div", { className: "flex flex-wrap gap-1 p-2 border-b", children: selectedOptions.map((option) => (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, jsx("button", { type: "button", onClick: (e) => handleRemove(e, option.value), className: "rounded-sm hover:bg-secondary-foreground/20", children: jsx(X, { className: "h-3 w-3" }) })] }, option.value))) })), jsxs(CommandList, { className: "max-h-[300px] overflow-y-auto p-1", children: [jsx(CommandEmpty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }), jsx(CommandGroup, { children: options.map((option) => (jsxs(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: [jsx(Check, { className: cn('mr-2 h-4 w-4', values.includes(option.value) ? 'opacity-100' : 'opacity-0') }), jsx("span", { className: "flex-1 truncate", children: option.label }), option.count !== undefined && (jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: ["(", option.count, ")"] }))] }, option.value))) })] })] }) }) })] }));
|
|
14961
15059
|
}
|
|
14962
15060
|
|
|
15061
|
+
/**
|
|
15062
|
+
* Serialize Activity Feed filters to URL search params.
|
|
15063
|
+
* Used to sync filter changes back to the URL for deep linking.
|
|
15064
|
+
*/
|
|
15065
|
+
function serializeActivityFilters(filters, timeRange, streamingEnabled = true) {
|
|
15066
|
+
const params = new URLSearchParams();
|
|
15067
|
+
if (timeRange.start) {
|
|
15068
|
+
params.set('start', timeRange.start);
|
|
15069
|
+
}
|
|
15070
|
+
if (timeRange.end) {
|
|
15071
|
+
params.set('end', timeRange.end);
|
|
15072
|
+
}
|
|
15073
|
+
if (!streamingEnabled) {
|
|
15074
|
+
params.set('streaming', 'false');
|
|
15075
|
+
}
|
|
15076
|
+
if (filters.changeSource && filters.changeSource !== 'human') {
|
|
15077
|
+
params.set('changeSource', filters.changeSource);
|
|
15078
|
+
}
|
|
15079
|
+
if (filters.actorNames && filters.actorNames.length > 0) {
|
|
15080
|
+
params.set('actorNames', filters.actorNames.join(','));
|
|
15081
|
+
}
|
|
15082
|
+
if (filters.resourceKinds && filters.resourceKinds.length > 0) {
|
|
15083
|
+
params.set('resourceKinds', filters.resourceKinds.join(','));
|
|
15084
|
+
}
|
|
15085
|
+
if (filters.apiGroups && filters.apiGroups.length > 0) {
|
|
15086
|
+
params.set('apiGroups', filters.apiGroups.join(','));
|
|
15087
|
+
}
|
|
15088
|
+
if (filters.resourceNamespaces && filters.resourceNamespaces.length > 0) {
|
|
15089
|
+
params.set('resourceNamespaces', filters.resourceNamespaces.join(','));
|
|
15090
|
+
}
|
|
15091
|
+
if (filters.resourceUid) {
|
|
15092
|
+
params.set('resourceUid', filters.resourceUid);
|
|
15093
|
+
}
|
|
15094
|
+
if (filters.resourceName) {
|
|
15095
|
+
params.set('resourceName', filters.resourceName);
|
|
15096
|
+
}
|
|
15097
|
+
if (filters.search) {
|
|
15098
|
+
params.set('search', filters.search);
|
|
15099
|
+
}
|
|
15100
|
+
return params;
|
|
15101
|
+
}
|
|
15102
|
+
/**
|
|
15103
|
+
* Serialize Events Feed filters to URL search params.
|
|
15104
|
+
* Used to sync filter changes back to the URL for deep linking.
|
|
15105
|
+
*/
|
|
15106
|
+
function serializeEventFilters(filters, timeRange, streamingEnabled = true) {
|
|
15107
|
+
const params = new URLSearchParams();
|
|
15108
|
+
if (timeRange.start) {
|
|
15109
|
+
params.set('start', timeRange.start);
|
|
15110
|
+
}
|
|
15111
|
+
if (timeRange.end) {
|
|
15112
|
+
params.set('end', timeRange.end);
|
|
15113
|
+
}
|
|
15114
|
+
if (!streamingEnabled) {
|
|
15115
|
+
params.set('streaming', 'false');
|
|
15116
|
+
}
|
|
15117
|
+
if (filters.eventType && filters.eventType !== 'all') {
|
|
15118
|
+
params.set('eventType', filters.eventType);
|
|
15119
|
+
}
|
|
15120
|
+
if (filters.reasons && filters.reasons.length > 0) {
|
|
15121
|
+
params.set('reasons', filters.reasons.join(','));
|
|
15122
|
+
}
|
|
15123
|
+
if (filters.namespaces && filters.namespaces.length > 0) {
|
|
15124
|
+
params.set('namespaces', filters.namespaces.join(','));
|
|
15125
|
+
}
|
|
15126
|
+
if (filters.involvedKinds && filters.involvedKinds.length > 0) {
|
|
15127
|
+
params.set('involvedKinds', filters.involvedKinds.join(','));
|
|
15128
|
+
}
|
|
15129
|
+
if (filters.search) {
|
|
15130
|
+
params.set('search', filters.search);
|
|
15131
|
+
}
|
|
15132
|
+
return params;
|
|
15133
|
+
}
|
|
15134
|
+
/**
|
|
15135
|
+
* Parse Activity Feed filters from URL query params
|
|
15136
|
+
*/
|
|
15137
|
+
function parseActivityFilters(searchParams) {
|
|
15138
|
+
const filters = {};
|
|
15139
|
+
const changeSource = searchParams.get('changeSource');
|
|
15140
|
+
if (changeSource === 'human' || changeSource === 'system' || changeSource === 'all') {
|
|
15141
|
+
filters.changeSource = changeSource;
|
|
15142
|
+
}
|
|
15143
|
+
else {
|
|
15144
|
+
filters.changeSource = 'human';
|
|
15145
|
+
}
|
|
15146
|
+
const actorNames = searchParams.get('actorNames');
|
|
15147
|
+
if (actorNames) {
|
|
15148
|
+
filters.actorNames = actorNames.split(',').filter(Boolean);
|
|
15149
|
+
}
|
|
15150
|
+
const resourceKinds = searchParams.get('resourceKinds');
|
|
15151
|
+
if (resourceKinds) {
|
|
15152
|
+
filters.resourceKinds = resourceKinds.split(',').filter(Boolean);
|
|
15153
|
+
}
|
|
15154
|
+
const apiGroups = searchParams.get('apiGroups');
|
|
15155
|
+
if (apiGroups) {
|
|
15156
|
+
filters.apiGroups = apiGroups.split(',').filter(Boolean);
|
|
15157
|
+
}
|
|
15158
|
+
const resourceNamespaces = searchParams.get('resourceNamespaces');
|
|
15159
|
+
if (resourceNamespaces) {
|
|
15160
|
+
filters.resourceNamespaces = resourceNamespaces.split(',').filter(Boolean);
|
|
15161
|
+
}
|
|
15162
|
+
const resourceUid = searchParams.get('resourceUid');
|
|
15163
|
+
if (resourceUid) {
|
|
15164
|
+
filters.resourceUid = resourceUid;
|
|
15165
|
+
}
|
|
15166
|
+
const resourceName = searchParams.get('resourceName');
|
|
15167
|
+
if (resourceName) {
|
|
15168
|
+
filters.resourceName = resourceName;
|
|
15169
|
+
}
|
|
15170
|
+
const search = searchParams.get('search');
|
|
15171
|
+
if (search) {
|
|
15172
|
+
filters.search = search;
|
|
15173
|
+
}
|
|
15174
|
+
return filters;
|
|
15175
|
+
}
|
|
15176
|
+
/**
|
|
15177
|
+
* Parse Events Feed filters from URL query params
|
|
15178
|
+
*/
|
|
15179
|
+
function parseEventFilters(searchParams) {
|
|
15180
|
+
const filters = {};
|
|
15181
|
+
const eventType = searchParams.get('eventType');
|
|
15182
|
+
if (eventType === 'Normal' || eventType === 'Warning' || eventType === 'all') {
|
|
15183
|
+
filters.eventType = eventType;
|
|
15184
|
+
}
|
|
15185
|
+
const reasons = searchParams.get('reasons');
|
|
15186
|
+
if (reasons) {
|
|
15187
|
+
filters.reasons = reasons.split(',').filter(Boolean);
|
|
15188
|
+
}
|
|
15189
|
+
const namespaces = searchParams.get('namespaces');
|
|
15190
|
+
if (namespaces) {
|
|
15191
|
+
filters.namespaces = namespaces.split(',').filter(Boolean);
|
|
15192
|
+
}
|
|
15193
|
+
const involvedKinds = searchParams.get('involvedKinds');
|
|
15194
|
+
if (involvedKinds) {
|
|
15195
|
+
filters.involvedKinds = involvedKinds.split(',').filter(Boolean);
|
|
15196
|
+
}
|
|
15197
|
+
const search = searchParams.get('search');
|
|
15198
|
+
if (search) {
|
|
15199
|
+
filters.search = search;
|
|
15200
|
+
}
|
|
15201
|
+
return filters;
|
|
15202
|
+
}
|
|
15203
|
+
/**
|
|
15204
|
+
* Parse time range from URL query params
|
|
15205
|
+
*/
|
|
15206
|
+
function parseTimeRange(searchParams) {
|
|
15207
|
+
const start = searchParams.get('start');
|
|
15208
|
+
const end = searchParams.get('end');
|
|
15209
|
+
if (!start) {
|
|
15210
|
+
return undefined;
|
|
15211
|
+
}
|
|
15212
|
+
return { start, end: end || undefined };
|
|
15213
|
+
}
|
|
15214
|
+
|
|
15215
|
+
/**
|
|
15216
|
+
* Generate a shareable URL for the current activity view.
|
|
15217
|
+
*
|
|
15218
|
+
* The shareable URL:
|
|
15219
|
+
* - Uses absolute timestamps (not relative like "now-1h")
|
|
15220
|
+
* - Disables streaming so the view is static
|
|
15221
|
+
* - Preserves all current filters
|
|
15222
|
+
*
|
|
15223
|
+
* This ensures the shared link shows the exact same data regardless of
|
|
15224
|
+
* when someone opens it.
|
|
15225
|
+
*
|
|
15226
|
+
* @param basePath - Current route path (e.g., "/activity/feed")
|
|
15227
|
+
* @param effectiveTimeRange - Server-calculated effective time range
|
|
15228
|
+
* @param filters - Current filter state
|
|
15229
|
+
* @param origin - Window origin for absolute URL (e.g., "https://staff.datum.cloud")
|
|
15230
|
+
*/
|
|
15231
|
+
function generateShareableUrl(basePath, effectiveTimeRange, filters, origin = typeof window !== 'undefined' ? window.location.origin : '') {
|
|
15232
|
+
const params = new URLSearchParams();
|
|
15233
|
+
// Use absolute timestamps from server-calculated range
|
|
15234
|
+
params.set('start', effectiveTimeRange.startTime);
|
|
15235
|
+
params.set('end', effectiveTimeRange.endTime);
|
|
15236
|
+
// Disable streaming for shared links (static view)
|
|
15237
|
+
params.set('streaming', 'false');
|
|
15238
|
+
// Preserve all current filters
|
|
15239
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
15240
|
+
if (value && key !== 'start' && key !== 'end' && key !== 'streaming') {
|
|
15241
|
+
params.set(key, value);
|
|
15242
|
+
}
|
|
15243
|
+
}
|
|
15244
|
+
return `${origin}${basePath}?${params.toString()}`;
|
|
15245
|
+
}
|
|
15246
|
+
/**
|
|
15247
|
+
* Copy text to clipboard and return success status
|
|
15248
|
+
*/
|
|
15249
|
+
async function copyToClipboard(text) {
|
|
15250
|
+
try {
|
|
15251
|
+
await navigator.clipboard.writeText(text);
|
|
15252
|
+
return true;
|
|
15253
|
+
}
|
|
15254
|
+
catch (err) {
|
|
15255
|
+
console.error('Failed to copy to clipboard:', err);
|
|
15256
|
+
return false;
|
|
15257
|
+
}
|
|
15258
|
+
}
|
|
15259
|
+
|
|
14963
15260
|
/**
|
|
14964
15261
|
* Create an empty audit event for preview
|
|
14965
15262
|
*/
|
|
@@ -16220,5 +16517,5 @@ const POLICY_FILTER_FIELDS = [
|
|
|
16220
16517
|
},
|
|
16221
16518
|
];
|
|
16222
16519
|
|
|
16223
|
-
export { ACTIVITY_FILTER_FIELDS, AUDIT_TEMPLATES, ActionMultiSelect, ActionToggle, ActivityApiClient, ActivityExpandedDetails, ActivityFeed, ActivityFeedItem, ActivityFeedItemSkeleton, ActivityFeedSummary, Alert, AlertDescription, AlertTitle, ApiError, ApiErrorAlert, AuditEventViewer, AuditLogExpandedDetails, AuditLogFeedItem, AuditLogFilters, AuditLogQueryComponent, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CelEditor, ChangeSourceToggle, Checkbox, Combobox, DateTimeRangePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, EVENT_FACET_FIELDS, EVENT_FILTER_FIELDS, EVENT_TEMPLATES, EventExpandedDetails, EventFeedItem, EventFeedItemSkeleton, EventTypeToggle, EventsFeed, FILTER_FIELDS, FilterBuilder, FilterBuilderWithAutocomplete, Input, Label, MultiCombobox, NetworkError, POLICY_FILTER_FIELDS, PolicyActivityView, PolicyActivityViewSkeleton, PolicyDetailView, PolicyEditView, PolicyEditor, PolicyList, PolicyPreviewPanel, PolicyPreviewResult, PolicyResourceForm, PolicyRuleEditor, PolicyRuleEditorDialog, PolicyRuleList, PolicyRuleListItem, ReindexJobCreate, ReindexJobDetailView, ReindexJobDialog, ReindexJobList, ResourceHistoryView, RulePreviewPanel, SampleInputTemplates, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, SimpleQueryBuilder, Skeleton, Tabs, TabsContent, TabsList, TabsTrigger, TenantBadge, Textarea, TimeRangeDropdown, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserSelect, badgeVariants, buildAuditLogCEL, buttonVariants, cn, defaultErrorFormatter, defaultResourceLinkResolver, extractEvent, extractFieldPaths, extractFieldPathsFromMany, getReindexJobDuration, getReindexJobStatusMessage, isEventRecord, isReindexJobRunning, isReindexJobTerminal, parseApiError, useActivityFeed, useAuditLogFacets, useAuditLogQuery, useEventFacets, useEventsFeed, useFacets, usePolicyEditor, usePolicyList, usePolicyPreview, useReindexJobs };
|
|
16520
|
+
export { ACTIVITY_FILTER_FIELDS, AUDIT_TEMPLATES, ActionMultiSelect, ActionToggle, ActivityApiClient, ActivityExpandedDetails, ActivityFeed, ActivityFeedItem, ActivityFeedItemSkeleton, ActivityFeedSummary, ActivityLayout, Alert, AlertDescription, AlertTitle, ApiError, ApiErrorAlert, AuditEventViewer, AuditLogExpandedDetails, AuditLogFeedItem, AuditLogFilters, AuditLogQueryComponent, Badge, Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle, CelEditor, ChangeSourceToggle, Checkbox, Combobox, DateTimeRangePicker, Dialog, DialogClose, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogOverlay, DialogPortal, DialogTitle, DialogTrigger, EVENT_FACET_FIELDS, EVENT_FILTER_FIELDS, EVENT_TEMPLATES, EventExpandedDetails, EventFeedItem, EventFeedItemSkeleton, EventTypeToggle, EventsFeed, FILTER_FIELDS, FilterBuilder, FilterBuilderWithAutocomplete, Input, Label, MultiCombobox, NetworkError, POLICY_FILTER_FIELDS, PolicyActivityView, PolicyActivityViewSkeleton, PolicyDetailView, PolicyEditView, PolicyEditor, PolicyList, PolicyPreviewPanel, PolicyPreviewResult, PolicyResourceForm, PolicyRuleEditor, PolicyRuleEditorDialog, PolicyRuleList, PolicyRuleListItem, ReindexJobCreate, ReindexJobDetailView, ReindexJobDialog, ReindexJobList, ResourceHistoryView, RulePreviewPanel, SampleInputTemplates, Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue, Separator, SimpleQueryBuilder, Skeleton, Tabs, TabsContent, TabsList, TabsTrigger, TenantBadge, Textarea, TimeRangeDropdown, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger, UserSelect, badgeVariants, buildAuditLogCEL, buttonVariants, cn, copyToClipboard, defaultErrorFormatter, defaultResourceLinkResolver, extractEvent, extractFieldPaths, extractFieldPathsFromMany, generateShareableUrl, getReindexJobDuration, getReindexJobStatusMessage, isEventRecord, isReindexJobRunning, isReindexJobTerminal, parseActivityFilters, parseApiError, parseEventFilters, parseTimeRange, serializeActivityFilters, serializeEventFilters, useActivityFeed, useAuditLogFacets, useAuditLogQuery, useEventFacets, useEventsFeed, useFacets, usePolicyEditor, usePolicyList, usePolicyPreview, useReindexJobs };
|
|
16224
16521
|
//# sourceMappingURL=index.esm.js.map
|