@datum-cloud/activity-ui 0.5.1 → 0.6.0-dev.5b51180
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/README.md +14 -0
- package/dist/components/ActionMultiSelect.d.ts.map +1 -1
- package/dist/components/ActivityDigestSummary.d.ts +15 -0
- package/dist/components/ActivityDigestSummary.d.ts.map +1 -0
- package/dist/components/ActivityFeed.d.ts +11 -2
- package/dist/components/ActivityFeed.d.ts.map +1 -1
- package/dist/components/ActivityFeedFilters.d.ts +9 -1
- package/dist/components/ActivityFeedFilters.d.ts.map +1 -1
- package/dist/components/ActivityFeedGroupItem.d.ts +23 -0
- package/dist/components/ActivityFeedGroupItem.d.ts.map +1 -0
- package/dist/components/ActivityFeedItem.d.ts +8 -1
- package/dist/components/ActivityFeedItem.d.ts.map +1 -1
- package/dist/components/AuditLogFeedItem.d.ts.map +1 -1
- package/dist/components/CelEditor.d.ts +1 -1
- package/dist/components/CelEditor.d.ts.map +1 -1
- package/dist/components/ChangeSourceToggle.d.ts.map +1 -1
- package/dist/components/DateTimeRangePicker.d.ts.map +1 -1
- package/dist/components/EventFeedItem.d.ts.map +1 -1
- package/dist/components/EventTypeToggle.d.ts.map +1 -1
- package/dist/components/FilterBuilder.d.ts.map +1 -1
- package/dist/components/FilterBuilderWithAutocomplete.d.ts.map +1 -1
- package/dist/components/PolicyDetailView.d.ts.map +1 -1
- package/dist/components/PolicyEditView.d.ts.map +1 -1
- package/dist/components/PolicyEditor.d.ts.map +1 -1
- package/dist/components/UserSelect.d.ts.map +1 -1
- package/dist/components/VerbToggle.d.ts.map +1 -1
- package/dist/components/ui/add-filter-dropdown.d.ts.map +1 -1
- package/dist/components/ui/combobox.d.ts +0 -4
- package/dist/components/ui/combobox.d.ts.map +1 -1
- package/dist/components/ui/filter-chip.d.ts.map +1 -1
- package/dist/components/ui/multi-combobox.d.ts +2 -5
- package/dist/components/ui/multi-combobox.d.ts.map +1 -1
- package/dist/components/ui/segmented-toggle.d.ts +26 -0
- package/dist/components/ui/segmented-toggle.d.ts.map +1 -0
- package/dist/components/ui/time-range-dropdown.d.ts +13 -4
- package/dist/components/ui/time-range-dropdown.d.ts.map +1 -1
- package/dist/hooks/useAuditLogQuery.d.ts +1 -1
- package/dist/hooks/useAuditLogQuery.d.ts.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +1524 -1271
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +1527 -1271
- package/dist/index.js.map +1 -1
- package/dist/lib/groupActivities.d.ts +40 -0
- package/dist/lib/groupActivities.d.ts.map +1 -0
- package/dist/lib/verb.d.ts +22 -0
- package/dist/lib/verb.d.ts.map +1 -0
- package/package.json +7 -12
- package/dist/components/ui/alert.d.ts +0 -9
- package/dist/components/ui/alert.d.ts.map +0 -1
- package/dist/components/ui/button.d.ts +0 -12
- package/dist/components/ui/button.d.ts.map +0 -1
- package/dist/components/ui/card.d.ts +0 -9
- package/dist/components/ui/card.d.ts.map +0 -1
- package/dist/components/ui/checkbox.d.ts +0 -5
- package/dist/components/ui/checkbox.d.ts.map +0 -1
- package/dist/components/ui/input.d.ts +0 -6
- package/dist/components/ui/input.d.ts.map +0 -1
- package/dist/components/ui/label.d.ts +0 -8
- package/dist/components/ui/label.d.ts.map +0 -1
- package/dist/components/ui/select.d.ts +0 -14
- package/dist/components/ui/select.d.ts.map +0 -1
- package/dist/components/ui/separator.d.ts +0 -5
- package/dist/components/ui/separator.d.ts.map +0 -1
- package/dist/components/ui/sheet.d.ts +0 -23
- package/dist/components/ui/sheet.d.ts.map +0 -1
- package/dist/components/ui/skeleton.d.ts +0 -3
- package/dist/components/ui/skeleton.d.ts.map +0 -1
- package/dist/components/ui/tabs.d.ts +0 -8
- package/dist/components/ui/tabs.d.ts.map +0 -1
- package/dist/components/ui/textarea.d.ts +0 -6
- package/dist/components/ui/textarea.d.ts.map +0 -1
package/dist/index.js
CHANGED
|
@@ -9,9 +9,12 @@ var label = require('@datum-cloud/datum-ui/label');
|
|
|
9
9
|
var separator = require('@datum-cloud/datum-ui/separator');
|
|
10
10
|
var textarea = require('@datum-cloud/datum-ui/textarea');
|
|
11
11
|
var badge = require('@datum-cloud/datum-ui/badge');
|
|
12
|
-
var
|
|
13
|
-
var Popover = require('@radix-ui/react-popover');
|
|
12
|
+
var autocomplete = require('@datum-cloud/datum-ui/autocomplete');
|
|
14
13
|
var checkbox = require('@datum-cloud/datum-ui/checkbox');
|
|
14
|
+
var picker = require('@datum-cloud/datum-ui/picker');
|
|
15
|
+
var command = require('@datum-cloud/datum-ui/command');
|
|
16
|
+
var popover = require('@datum-cloud/datum-ui/popover');
|
|
17
|
+
var buttonGroup = require('@datum-cloud/datum-ui/button-group');
|
|
15
18
|
var TooltipPrimitive = require('@radix-ui/react-tooltip');
|
|
16
19
|
var table = require('@datum-cloud/datum-ui/table');
|
|
17
20
|
var skeleton = require('@datum-cloud/datum-ui/skeleton');
|
|
@@ -20,6 +23,7 @@ var select = require('@datum-cloud/datum-ui/select');
|
|
|
20
23
|
var sheet = require('@datum-cloud/datum-ui/sheet');
|
|
21
24
|
var tabs = require('@datum-cloud/datum-ui/tabs');
|
|
22
25
|
var dialog = require('@datum-cloud/datum-ui/dialog');
|
|
26
|
+
var multiSelect = require('@datum-cloud/datum-ui/multi-select');
|
|
23
27
|
|
|
24
28
|
function _interopNamespaceDefault(e) {
|
|
25
29
|
var n = Object.create(null);
|
|
@@ -39,7 +43,6 @@ function _interopNamespaceDefault(e) {
|
|
|
39
43
|
}
|
|
40
44
|
|
|
41
45
|
var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
|
|
42
|
-
var Popover__namespace = /*#__PURE__*/_interopNamespaceDefault(Popover);
|
|
43
46
|
var TooltipPrimitive__namespace = /*#__PURE__*/_interopNamespaceDefault(TooltipPrimitive);
|
|
44
47
|
|
|
45
48
|
/**
|
|
@@ -213,7 +216,7 @@ function FilterBuilder({ onFilterChange, initialFilter = '', initialLimit = 100,
|
|
|
213
216
|
const newFilter = filter ? `${filter} && ${example}` : example;
|
|
214
217
|
handleFilterChange(newFilter);
|
|
215
218
|
};
|
|
216
|
-
return (jsxRuntime.jsxs(card.Card, { className: `mb-6 ${className}`, children: [jsxRuntime.jsx(card.CardHeader, { className: "pb-4", children: jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [jsxRuntime.jsx("h3", { className: "m-0 text-2xl font-semibold text-foreground", children: "Build Your Query" }), jsxRuntime.jsxs(button.Button, { onClick: () => setShowHelp(!showHelp), type: "tertiary", theme: "outline", htmlType: "button", children: [showHelp ? 'Hide' : 'Show', " Help"] })] }) }), jsxRuntime.jsx(separator.Separator, {}), jsxRuntime.jsxs(card.CardContent, { className: "pt-6", children: [showHelp && (jsxRuntime.jsxs("div", { className: "bg-muted p-6 rounded-lg mb-6 max-h-[400px] overflow-y-auto border border-border", children: [jsxRuntime.jsx("h4", { className: "text-base font-semibold text-foreground", children: "Available Filter Fields" }), jsxRuntime.jsx("div", { className: "mt-4", children: FILTER_FIELDS.map((field) => (jsxRuntime.jsxs("div", { className: "mb-6 pb-4 border-b border-border last:border-b-0", children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-2", children: [jsxRuntime.jsx("strong", { className: "text-foreground", children: field.name }), jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground italic", children: field.type })] }), jsxRuntime.jsx("p", { className: "my-2 text-muted-foreground", children: field.description }), field.examples && field.examples.length > 0 && (jsxRuntime.jsxs("div", { className: "mt-2", children: [jsxRuntime.jsx("strong", { className: "text-foreground", children: "Examples:" }), field.examples.map((example, idx) => (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 my-2", children: [jsxRuntime.jsx("code", { className: "flex-1 px-2 py-1 bg-background rounded text-sm font-mono", children: example }), jsxRuntime.jsx(button.Button, { onClick: () => insertExample(example), type: "
|
|
219
|
+
return (jsxRuntime.jsxs(card.Card, { className: `mb-6 ${className}`, children: [jsxRuntime.jsx(card.CardHeader, { className: "pb-4", children: jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [jsxRuntime.jsx("h3", { className: "m-0 text-2xl font-semibold text-foreground", children: "Build Your Query" }), jsxRuntime.jsxs(button.Button, { onClick: () => setShowHelp(!showHelp), type: "tertiary", theme: "outline", htmlType: "button", children: [showHelp ? 'Hide' : 'Show', " Help"] })] }) }), jsxRuntime.jsx(separator.Separator, {}), jsxRuntime.jsxs(card.CardContent, { className: "pt-6", children: [showHelp && (jsxRuntime.jsxs("div", { className: "bg-muted p-6 rounded-lg mb-6 max-h-[400px] overflow-y-auto border border-border", children: [jsxRuntime.jsx("h4", { className: "text-base font-semibold text-foreground", children: "Available Filter Fields" }), jsxRuntime.jsx("div", { className: "mt-4", children: FILTER_FIELDS.map((field) => (jsxRuntime.jsxs("div", { className: "mb-6 pb-4 border-b border-border last:border-b-0", children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-2", children: [jsxRuntime.jsx("strong", { className: "text-foreground", children: field.name }), jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground italic", children: field.type })] }), jsxRuntime.jsx("p", { className: "my-2 text-muted-foreground", children: field.description }), field.examples && field.examples.length > 0 && (jsxRuntime.jsxs("div", { className: "mt-2", children: [jsxRuntime.jsx("strong", { className: "text-foreground", children: "Examples:" }), field.examples.map((example, idx) => (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 my-2", children: [jsxRuntime.jsx("code", { className: "flex-1 px-2 py-1 bg-background rounded text-sm font-mono", children: example }), jsxRuntime.jsx(button.Button, { onClick: () => insertExample(example), type: "success", theme: "solid", size: "small", htmlType: "button", children: "Insert" })] }, idx)))] }))] }, field.name))) }), jsxRuntime.jsxs("div", { className: "mt-4", children: [jsxRuntime.jsx("h4", { className: "mb-2 text-base font-semibold text-foreground", children: "Common Operators" }), jsxRuntime.jsxs("ul", { className: "m-0 pl-6 text-muted-foreground", children: [jsxRuntime.jsxs("li", { className: "my-1", children: [jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: "==" }), " - Equals"] }), jsxRuntime.jsxs("li", { className: "my-1", children: [jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: "!=" }), " - Not equals"] }), jsxRuntime.jsxs("li", { className: "my-1", children: [jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: "&&" }), " - And"] }), jsxRuntime.jsxs("li", { className: "my-1", children: [jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: "||" }), " - Or"] }), jsxRuntime.jsxs("li", { className: "my-1", children: [jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: "in" }), " - In list (e.g., ", jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: "verb in [\"create\", \"delete\"]" }), ")"] }), jsxRuntime.jsxs("li", { className: "my-1", children: [jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: ".startsWith()" }), " - String starts with"] }), jsxRuntime.jsxs("li", { className: "my-1", children: [jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: ".contains()" }), " - String contains"] }), jsxRuntime.jsxs("li", { className: "my-1", children: [jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: "timestamp()" }), " - Parse timestamp (e.g., ", jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-background rounded text-sm font-mono", children: "timestamp(\"2024-01-01T00:00:00Z\")" }), ")"] })] })] })] })), jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx(label.Label, { htmlFor: "filter-input", className: "block mb-2", children: "CEL Filter Expression" }), jsxRuntime.jsx(textarea.Textarea, { id: "filter-input", value: filter, onChange: (e) => handleFilterChange(e.target.value), placeholder: 'e.g., verb == "delete" && ns == "production"', rows: 4, className: "font-mono text-sm resize-y" })] }), jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx(label.Label, { htmlFor: "limit-input", className: "block mb-2", children: "Result Limit (max 1,000)" }), jsxRuntime.jsx(input.Input, { id: "limit-input", type: "number", value: limit, onChange: (e) => handleLimitChange(parseInt(e.target.value) || 100), min: 1, max: 1000, className: "w-44" })] }), jsxRuntime.jsx(separator.Separator, { className: "my-6" }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("h4", { className: "mb-3 text-base font-semibold text-foreground", children: "Quick Filters" }), jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [jsxRuntime.jsx(button.Button, { onClick: () => insertExample('verb == "delete"'), htmlType: "button", type: "tertiary", theme: "outline", children: "Delete Operations" }), jsxRuntime.jsx(button.Button, { onClick: () => insertExample('resource == "secrets"'), htmlType: "button", type: "tertiary", theme: "outline", children: "Secret Access" }), jsxRuntime.jsx(button.Button, { onClick: () => insertExample('user.startsWith("system:")'), htmlType: "button", type: "tertiary", theme: "outline", children: "System Users" }), jsxRuntime.jsx(button.Button, { onClick: () => insertExample('stage == "ResponseComplete"'), htmlType: "button", type: "tertiary", theme: "outline", children: "Completed Requests" })] })] })] })] }));
|
|
217
220
|
}
|
|
218
221
|
|
|
219
222
|
function mapVariant(variant) {
|
|
@@ -322,7 +325,7 @@ function FilterBuilderWithAutocomplete({ onFilterChange, initialFilter = '', ini
|
|
|
322
325
|
// Suggest logical operators to continue
|
|
323
326
|
const completedValuePattern = /["'][^"']*["']\s*$/;
|
|
324
327
|
const completedNumberPattern = /\d+\s*$/;
|
|
325
|
-
const afterLogicalOp = /(
|
|
328
|
+
const afterLogicalOp = /(&&|\|\|)\s*$/;
|
|
326
329
|
if ((completedValuePattern.test(textBeforeCursor) || completedNumberPattern.test(textBeforeCursor)) && !afterLogicalOp.test(textBeforeCursor)) {
|
|
327
330
|
// After a complete value, suggest logical operators
|
|
328
331
|
newSuggestions.push({ text: ' && ', description: 'Logical AND - add another condition', type: 'operator' }, { text: ' || ', description: 'Logical OR - add alternative condition', type: 'operator' });
|
|
@@ -447,7 +450,7 @@ function FilterBuilderWithAutocomplete({ onFilterChange, initialFilter = '', ini
|
|
|
447
450
|
return 'outline';
|
|
448
451
|
}
|
|
449
452
|
};
|
|
450
|
-
return (jsxRuntime.jsxs(card.Card, { className: `p-8 rounded-xl mb-6 ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-center p-0 mb-6 pb-4 border-b border-border", children: [jsxRuntime.jsx("h3", { className: "m-0 text-2xl font-semibold text-foreground", children: "Search Audit Logs" }), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx(button.Button, { onClick: () => setShowShortcuts(!showShortcuts), type: "tertiary", theme: "outline", size: "small", htmlType: "button", title: "View keyboard shortcuts", children: "Shortcuts" }), jsxRuntime.jsx(button.Button, { onClick: () => setShowHelp(!showHelp), type: "tertiary", theme: "outline", size: "small", htmlType: "button", title: "View available filter fields and examples", children: "Field Guide" })] })] }), jsxRuntime.jsxs(card.CardContent, { className: "p-0", children: [showShortcuts && (jsxRuntime.jsxs("div", { className: "bg-
|
|
453
|
+
return (jsxRuntime.jsxs(card.Card, { className: `p-8 rounded-xl mb-6 ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-center p-0 mb-6 pb-4 border-b border-border", children: [jsxRuntime.jsx("h3", { className: "m-0 text-2xl font-semibold text-foreground", children: "Search Audit Logs" }), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [jsxRuntime.jsx(button.Button, { onClick: () => setShowShortcuts(!showShortcuts), type: "tertiary", theme: "outline", size: "small", htmlType: "button", title: "View keyboard shortcuts", children: "Shortcuts" }), jsxRuntime.jsx(button.Button, { onClick: () => setShowHelp(!showHelp), type: "tertiary", theme: "outline", size: "small", htmlType: "button", title: "View available filter fields and examples", children: "Field Guide" })] })] }), jsxRuntime.jsxs(card.CardContent, { className: "p-0", children: [showShortcuts && (jsxRuntime.jsxs("div", { className: "bg-[var(--info-100)] border border-[var(--info-300)] p-6 rounded-lg mb-6 max-h-96 overflow-y-auto", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-4 text-lg font-semibold text-foreground", children: "Keyboard Shortcuts" }), jsxRuntime.jsxs("div", { className: "grid grid-cols-[auto_1fr] gap-x-6 gap-y-3 items-start", children: [jsxRuntime.jsx("kbd", { className: "px-2 py-1 bg-background border border-input rounded font-mono text-sm", children: "Ctrl+Space" }), jsxRuntime.jsx("span", { children: "Trigger autocomplete suggestions at cursor position" }), jsxRuntime.jsx("kbd", { className: "px-2 py-1 bg-background border border-input rounded font-mono text-sm", children: "\u2191 / \u2193" }), jsxRuntime.jsx("span", { children: "Navigate through autocomplete suggestions" }), jsxRuntime.jsx("kbd", { className: "px-2 py-1 bg-background border border-input rounded font-mono text-sm", children: "Tab" }), jsxRuntime.jsx("span", { children: "Accept the selected suggestion" }), jsxRuntime.jsx("kbd", { className: "px-2 py-1 bg-background border border-input rounded font-mono text-sm", children: "Enter" }), jsxRuntime.jsx("span", { children: "Accept the selected suggestion" }), jsxRuntime.jsx("kbd", { className: "px-2 py-1 bg-background border border-input rounded font-mono text-sm", children: "Esc" }), jsxRuntime.jsx("span", { children: "Close autocomplete suggestions" })] }), jsxRuntime.jsxs("div", { className: "mt-4 p-3 bg-background rounded text-sm", children: [jsxRuntime.jsx("strong", { children: "Pro Tips:" }), jsxRuntime.jsxs("ul", { className: "mt-2 mb-0 pl-6", children: [jsxRuntime.jsx("li", { children: "Autocomplete appears automatically as you type" }), jsxRuntime.jsxs("li", { children: ["After completing a value (e.g., ", jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-muted rounded text-sm", children: "\"get\"" }), "), suggestions show logical operators (", jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-muted rounded text-sm", children: "&&" }), ", ", jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-muted rounded text-sm", children: "||" }), ")"] }), jsxRuntime.jsxs("li", { children: ["After typing ", jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-muted rounded text-sm", children: "&&" }), " or ", jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-muted rounded text-sm", children: "||" }), ", all field names are suggested"] }), jsxRuntime.jsxs("li", { children: ["Type ", jsxRuntime.jsx("code", { className: "px-1 py-0.5 bg-muted rounded text-sm", children: "." }), " after a field name to see available string functions"] })] })] })] })), showHelp && (jsxRuntime.jsxs("div", { className: "bg-muted p-6 rounded-lg mb-6 max-h-96 overflow-y-auto", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-4 text-lg font-semibold text-foreground", children: "Available Fields & Examples" }), jsxRuntime.jsx("p", { className: "mb-4 text-muted-foreground text-sm", children: "Click \"Insert\" to add an example to your query" }), jsxRuntime.jsx("div", { className: "mt-4", children: FILTER_FIELDS.map((field) => (jsxRuntime.jsxs("div", { className: "mb-6 pb-4 border-b border-border last:border-b-0", children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-2", children: [jsxRuntime.jsx("strong", { className: "text-foreground", children: field.name }), jsxRuntime.jsx("span", { className: "text-sm text-muted-foreground italic", children: field.type })] }), jsxRuntime.jsx("p", { className: "my-2 text-muted-foreground", children: field.description }), field.examples && field.examples.length > 0 && (jsxRuntime.jsxs("div", { className: "mt-2", children: [jsxRuntime.jsx("strong", { className: "text-sm text-foreground", children: "Examples:" }), field.examples.map((example, idx) => (jsxRuntime.jsxs("div", { className: "flex items-center gap-2 my-2", children: [jsxRuntime.jsx("code", { className: "flex-1 px-2 py-1 bg-background rounded text-sm font-mono", children: example }), jsxRuntime.jsx(button.Button, { onClick: () => insertExample(example), type: "success", theme: "solid", size: "small", htmlType: "button", children: "Insert" })] }, idx)))] }))] }, field.name))) })] })), jsxRuntime.jsxs("div", { className: "relative mb-4", children: [jsxRuntime.jsxs(label.Label, { htmlFor: "filter-input", className: "block mb-2", children: [jsxRuntime.jsx("strong", { className: "text-foreground", children: "Filter Expression" }), jsxRuntime.jsx("span", { className: "ml-2 text-sm text-muted-foreground font-normal", children: "Press Ctrl+Space for suggestions" })] }), jsxRuntime.jsx("p", { className: "m-0 mb-3 text-sm text-muted-foreground", children: "Use autocomplete to build your query, or type field names directly (e.g., verb, objectRef.resource)" }), jsxRuntime.jsx(textarea.Textarea, { ref: textareaRef, id: "filter-input", value: filter, onChange: (e) => handleFilterChange(e.target.value), onKeyDown: handleKeyDown, onFocus: () => updateSuggestions(filter), placeholder: 'Example: verb == "delete" && objectRef.namespace == "production"', rows: 4, className: "font-mono text-sm bg-muted resize-y focus:bg-background" }), showSuggestions && suggestions.length > 0 && (jsxRuntime.jsx("div", { className: "absolute top-full left-0 right-0 max-h-72 overflow-y-auto bg-background border border-input border-t-0 rounded-b shadow-md z-50 -mt-1", children: suggestions.map((suggestion, idx) => (jsxRuntime.jsxs("div", { className: `px-4 py-3 cursor-pointer flex items-center gap-3 border-b border-border transition-colors ${idx === selectedSuggestion ? 'bg-accent' : 'hover:bg-muted'}`, onClick: () => insertSuggestion(suggestion), onMouseEnter: () => setSelectedSuggestion(idx), children: [jsxRuntime.jsx("span", { className: "font-mono font-semibold text-foreground min-w-[120px]", children: suggestion.text }), jsxRuntime.jsx("span", { className: "flex-1 text-muted-foreground text-sm", children: suggestion.description }), jsxRuntime.jsx(Badge, { variant: getBadgeVariant(suggestion.type), className: "uppercase", children: suggestion.type })] }, idx))) }))] }), jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsxs(label.Label, { htmlFor: "limit-input", className: "block mb-2", children: [jsxRuntime.jsx("strong", { className: "text-foreground", children: "Number of results" }), jsxRuntime.jsx("span", { className: "ml-2 text-sm text-muted-foreground font-normal", children: "(1 to 1,000 events)" })] }), jsxRuntime.jsx(input.Input, { id: "limit-input", type: "number", value: limit, onChange: (e) => handleLimitChange(parseInt(e.target.value) || 100), min: 1, max: 1000, className: "w-44 bg-muted focus:bg-background" })] })] })] }));
|
|
451
454
|
}
|
|
452
455
|
|
|
453
456
|
/**
|
|
@@ -1195,6 +1198,48 @@ function constructNow(date) {
|
|
|
1195
1198
|
return constructFrom(date, Date.now());
|
|
1196
1199
|
}
|
|
1197
1200
|
|
|
1201
|
+
/**
|
|
1202
|
+
* The {@link isSameDay} function options.
|
|
1203
|
+
*/
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* @name isSameDay
|
|
1207
|
+
* @category Day Helpers
|
|
1208
|
+
* @summary Are the given dates in the same day (and year and month)?
|
|
1209
|
+
*
|
|
1210
|
+
* @description
|
|
1211
|
+
* Are the given dates in the same day (and year and month)?
|
|
1212
|
+
*
|
|
1213
|
+
* @param laterDate - The first date to check
|
|
1214
|
+
* @param earlierDate - The second date to check
|
|
1215
|
+
* @param options - An object with options
|
|
1216
|
+
*
|
|
1217
|
+
* @returns The dates are in the same day (and year and month)
|
|
1218
|
+
*
|
|
1219
|
+
* @example
|
|
1220
|
+
* // Are 4 September 06:00:00 and 4 September 18:00:00 in the same day?
|
|
1221
|
+
* const result = isSameDay(new Date(2014, 8, 4, 6, 0), new Date(2014, 8, 4, 18, 0))
|
|
1222
|
+
* //=> true
|
|
1223
|
+
*
|
|
1224
|
+
* @example
|
|
1225
|
+
* // Are 4 September and 4 October in the same day?
|
|
1226
|
+
* const result = isSameDay(new Date(2014, 8, 4), new Date(2014, 9, 4))
|
|
1227
|
+
* //=> false
|
|
1228
|
+
*
|
|
1229
|
+
* @example
|
|
1230
|
+
* // Are 4 September, 2014 and 4 September, 2015 in the same day?
|
|
1231
|
+
* const result = isSameDay(new Date(2014, 8, 4), new Date(2015, 8, 4))
|
|
1232
|
+
* //=> false
|
|
1233
|
+
*/
|
|
1234
|
+
function isSameDay(laterDate, earlierDate, options) {
|
|
1235
|
+
const [dateLeft_, dateRight_] = normalizeDates(
|
|
1236
|
+
options?.in,
|
|
1237
|
+
laterDate,
|
|
1238
|
+
earlierDate,
|
|
1239
|
+
);
|
|
1240
|
+
return +startOfDay(dateLeft_) === +startOfDay(dateRight_);
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1198
1243
|
/**
|
|
1199
1244
|
* @name isDate
|
|
1200
1245
|
* @category Common Helpers
|
|
@@ -3931,6 +3976,36 @@ function formatISO(date, options) {
|
|
|
3931
3976
|
return result;
|
|
3932
3977
|
}
|
|
3933
3978
|
|
|
3979
|
+
/**
|
|
3980
|
+
* The {@link isToday} function options.
|
|
3981
|
+
*/
|
|
3982
|
+
|
|
3983
|
+
/**
|
|
3984
|
+
* @name isToday
|
|
3985
|
+
* @category Day Helpers
|
|
3986
|
+
* @summary Is the given date today?
|
|
3987
|
+
* @pure false
|
|
3988
|
+
*
|
|
3989
|
+
* @description
|
|
3990
|
+
* Is the given date today?
|
|
3991
|
+
*
|
|
3992
|
+
* @param date - The date to check
|
|
3993
|
+
* @param options - An object with options
|
|
3994
|
+
*
|
|
3995
|
+
* @returns The date is today
|
|
3996
|
+
*
|
|
3997
|
+
* @example
|
|
3998
|
+
* // If today is 6 October 2014, is 6 October 14:00:00 today?
|
|
3999
|
+
* const result = isToday(new Date(2014, 9, 6, 14, 0))
|
|
4000
|
+
* //=> true
|
|
4001
|
+
*/
|
|
4002
|
+
function isToday(date, options) {
|
|
4003
|
+
return isSameDay(
|
|
4004
|
+
constructFrom(date, date),
|
|
4005
|
+
constructNow(date),
|
|
4006
|
+
);
|
|
4007
|
+
}
|
|
4008
|
+
|
|
3934
4009
|
/**
|
|
3935
4010
|
* The {@link subDays} function options.
|
|
3936
4011
|
*/
|
|
@@ -3958,6 +4033,36 @@ function subDays(date, amount, options) {
|
|
|
3958
4033
|
return addDays(date, -amount, options);
|
|
3959
4034
|
}
|
|
3960
4035
|
|
|
4036
|
+
/**
|
|
4037
|
+
* The {@link isYesterday} function options.
|
|
4038
|
+
*/
|
|
4039
|
+
|
|
4040
|
+
/**
|
|
4041
|
+
* @name isYesterday
|
|
4042
|
+
* @category Day Helpers
|
|
4043
|
+
* @summary Is the given date yesterday?
|
|
4044
|
+
* @pure false
|
|
4045
|
+
*
|
|
4046
|
+
* @description
|
|
4047
|
+
* Is the given date yesterday?
|
|
4048
|
+
*
|
|
4049
|
+
* @param date - The date to check
|
|
4050
|
+
* @param options - An object with options
|
|
4051
|
+
*
|
|
4052
|
+
* @returns The date is yesterday
|
|
4053
|
+
*
|
|
4054
|
+
* @example
|
|
4055
|
+
* // If today is 6 October 2014, is 5 October 14:00:00 yesterday?
|
|
4056
|
+
* const result = isYesterday(new Date(2014, 9, 5, 14, 0))
|
|
4057
|
+
* //=> true
|
|
4058
|
+
*/
|
|
4059
|
+
function isYesterday(date, options) {
|
|
4060
|
+
return isSameDay(
|
|
4061
|
+
constructFrom(date, date),
|
|
4062
|
+
subDays(constructNow(date), 1),
|
|
4063
|
+
);
|
|
4064
|
+
}
|
|
4065
|
+
|
|
3961
4066
|
/**
|
|
3962
4067
|
* The {@link subHours} function options.
|
|
3963
4068
|
*/
|
|
@@ -4018,559 +4123,323 @@ function subMinutes(date, amount, options) {
|
|
|
4018
4123
|
return addMinutes(date, -15, options);
|
|
4019
4124
|
}
|
|
4020
4125
|
|
|
4021
|
-
/**
|
|
4022
|
-
|
|
4023
|
-
|
|
4024
|
-
|
|
4025
|
-
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
}).
|
|
4031
|
-
|
|
4032
|
-
/**
|
|
4033
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4034
|
-
*
|
|
4035
|
-
* This source code is licensed under the ISC license.
|
|
4036
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4037
|
-
*/
|
|
4038
|
-
|
|
4039
|
-
const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
4040
|
-
|
|
4041
|
-
/**
|
|
4042
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4043
|
-
*
|
|
4044
|
-
* This source code is licensed under the ISC license.
|
|
4045
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4046
|
-
*/
|
|
4047
|
-
|
|
4048
|
-
const toCamelCase = (string) => string.replace(
|
|
4049
|
-
/^([A-Z])|[\s-_]+(\w)/g,
|
|
4050
|
-
(match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
|
|
4051
|
-
);
|
|
4052
|
-
|
|
4053
|
-
/**
|
|
4054
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4055
|
-
*
|
|
4056
|
-
* This source code is licensed under the ISC license.
|
|
4057
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4058
|
-
*/
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
const toPascalCase = (string) => {
|
|
4062
|
-
const camelCase = toCamelCase(string);
|
|
4063
|
-
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
|
4064
|
-
};
|
|
4065
|
-
|
|
4066
|
-
/**
|
|
4067
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4068
|
-
*
|
|
4069
|
-
* This source code is licensed under the ISC license.
|
|
4070
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4071
|
-
*/
|
|
4072
|
-
|
|
4073
|
-
var defaultAttributes = {
|
|
4074
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
4075
|
-
width: 24,
|
|
4076
|
-
height: 24,
|
|
4077
|
-
viewBox: "0 0 24 24",
|
|
4078
|
-
fill: "none",
|
|
4079
|
-
stroke: "currentColor",
|
|
4080
|
-
strokeWidth: 2,
|
|
4081
|
-
strokeLinecap: "round",
|
|
4082
|
-
strokeLinejoin: "round"
|
|
4083
|
-
};
|
|
4084
|
-
|
|
4085
|
-
/**
|
|
4086
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4087
|
-
*
|
|
4088
|
-
* This source code is licensed under the ISC license.
|
|
4089
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4090
|
-
*/
|
|
4091
|
-
|
|
4092
|
-
const hasA11yProp = (props) => {
|
|
4093
|
-
for (const prop in props) {
|
|
4094
|
-
if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
|
|
4095
|
-
return true;
|
|
4096
|
-
}
|
|
4097
|
-
}
|
|
4098
|
-
return false;
|
|
4099
|
-
};
|
|
4126
|
+
/** Sentinel for the "All" item; the public value stays '' for "no filter". */
|
|
4127
|
+
const ALL_VALUE = '__all__';
|
|
4128
|
+
function Combobox({ options, value, onValueChange, placeholder = 'Select…', searchPlaceholder = 'Search…', emptyMessage = 'No results', disabled, loading, className, clearable = false, showAllOption = true, allOptionLabel = 'All', }) {
|
|
4129
|
+
const items = React__namespace.useMemo(() => {
|
|
4130
|
+
const base = options.map((o) => ({ value: o.value, label: o.label, count: o.count }));
|
|
4131
|
+
return showAllOption ? [{ value: ALL_VALUE, label: allOptionLabel }, ...base] : base;
|
|
4132
|
+
}, [options, showAllOption, allOptionLabel]);
|
|
4133
|
+
// An empty value selects the "All" item so the trigger reads its label.
|
|
4134
|
+
const selectedValue = value === '' && showAllOption ? ALL_VALUE : value;
|
|
4135
|
+
return (jsxRuntime.jsx(autocomplete.Autocomplete, { className: className, options: items, value: selectedValue, onValueChange: (next) => onValueChange(next === ALL_VALUE ? '' : next), placeholder: placeholder, searchPlaceholder: searchPlaceholder, emptyContent: emptyMessage, disabled: disabled, loading: loading, footer: clearable && value ? (jsxRuntime.jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground w-full px-2 py-1.5 text-left text-xs", onClick: () => onValueChange(''), children: "Clear selection" })) : undefined, renderValue: (option) => (jsxRuntime.jsx("span", { className: "truncate", children: option.count !== undefined ? `${option.label} (${option.count})` : option.label })), renderOption: (option) => (jsxRuntime.jsxs("span", { className: "flex w-full items-center justify-between gap-2", children: [jsxRuntime.jsx("span", { className: "truncate", children: option.label }), 'count' in option && option.count !== undefined && (jsxRuntime.jsx("span", { className: "text-muted-foreground text-xs", children: option.count }))] })) }));
|
|
4136
|
+
}
|
|
4100
4137
|
|
|
4138
|
+
const RELATIVE_KEY = /^now-(\d+)([mhd])$/;
|
|
4139
|
+
/** Resolve a relative key such as `now-7d` to a `{ from, to }` window ending now. */
|
|
4140
|
+
function relativeKeyToRange(key, now = new Date()) {
|
|
4141
|
+
const match = RELATIVE_KEY.exec(key);
|
|
4142
|
+
if (!match)
|
|
4143
|
+
return null;
|
|
4144
|
+
const amount = Number(match[1]);
|
|
4145
|
+
const unitMs = { m: 60000, h: 3600000, d: 86400000 }[match[2]];
|
|
4146
|
+
return { from: new Date(now.getTime() - amount * unitMs), to: now };
|
|
4147
|
+
}
|
|
4148
|
+
/** `YYYY-MM-DDTHH:mm` in local time, the format the filter components store. */
|
|
4149
|
+
function toDatetimeLocal(iso) {
|
|
4150
|
+
const d = new Date(iso);
|
|
4151
|
+
const pad = (n) => String(n).padStart(2, '0');
|
|
4152
|
+
return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
|
|
4153
|
+
}
|
|
4154
|
+
function toPickerPresets(presets) {
|
|
4155
|
+
return presets
|
|
4156
|
+
.filter((p) => RELATIVE_KEY.test(p.key))
|
|
4157
|
+
.map((p) => ({
|
|
4158
|
+
key: p.key,
|
|
4159
|
+
label: p.label,
|
|
4160
|
+
getRange: () => relativeKeyToRange(p.key),
|
|
4161
|
+
}));
|
|
4162
|
+
}
|
|
4101
4163
|
/**
|
|
4102
|
-
*
|
|
4103
|
-
*
|
|
4104
|
-
*
|
|
4105
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4164
|
+
* TimeRangeDropdown - relative presets plus an absolute range, on datum-ui's
|
|
4165
|
+
* DateTimeRangePicker. The emitted value carries `preset` when a preset was
|
|
4166
|
+
* clicked, which keeps `start=now-7d` style URL state intact.
|
|
4106
4167
|
*/
|
|
4168
|
+
function TimeRangeDropdown({ presets, selectedPreset, onPresetSelect, onCustomRangeApply, customStart, customEnd, disabled = false, className, displayLabel, }) {
|
|
4169
|
+
const pickerPresets = React__namespace.useMemo(() => toPickerPresets(presets), [presets]);
|
|
4170
|
+
const value = React__namespace.useMemo(() => {
|
|
4171
|
+
if (selectedPreset !== 'custom') {
|
|
4172
|
+
const range = relativeKeyToRange(selectedPreset);
|
|
4173
|
+
return range
|
|
4174
|
+
? { from: range.from.toISOString(), to: range.to.toISOString(), preset: selectedPreset }
|
|
4175
|
+
: null;
|
|
4176
|
+
}
|
|
4177
|
+
if (customStart && customEnd) {
|
|
4178
|
+
return { from: new Date(customStart).toISOString(), to: new Date(customEnd).toISOString() };
|
|
4179
|
+
}
|
|
4180
|
+
return null;
|
|
4181
|
+
}, [selectedPreset, customStart, customEnd]);
|
|
4182
|
+
const handleChange = (next) => {
|
|
4183
|
+
if (!next)
|
|
4184
|
+
return;
|
|
4185
|
+
const preset = next.preset;
|
|
4186
|
+
if (preset) {
|
|
4187
|
+
onPresetSelect(preset);
|
|
4188
|
+
return;
|
|
4189
|
+
}
|
|
4190
|
+
onCustomRangeApply(toDatetimeLocal(next.from), toDatetimeLocal(next.to));
|
|
4191
|
+
};
|
|
4192
|
+
return (jsxRuntime.jsx(picker.DateTimeRangePicker, { className: className, triggerClassName: "h-9 rounded-lg px-3 text-xs", value: value, onChange: handleChange, presets: pickerPresets, disableFuture: true, clearable: false, disabled: disabled, placeholder: displayLabel ?? 'Select time range', triggerLabel: displayLabel ? () => displayLabel : undefined }));
|
|
4193
|
+
}
|
|
4107
4194
|
|
|
4108
|
-
|
|
4109
|
-
const Icon = React.forwardRef(
|
|
4110
|
-
({
|
|
4111
|
-
color = "currentColor",
|
|
4112
|
-
size = 24,
|
|
4113
|
-
strokeWidth = 2,
|
|
4114
|
-
absoluteStrokeWidth,
|
|
4115
|
-
className = "",
|
|
4116
|
-
children,
|
|
4117
|
-
iconNode,
|
|
4118
|
-
...rest
|
|
4119
|
-
}, ref) => React.createElement(
|
|
4120
|
-
"svg",
|
|
4195
|
+
const TIME_PRESETS$3 = [
|
|
4121
4196
|
{
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
className: mergeClasses("lucide", className),
|
|
4129
|
-
...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
|
|
4130
|
-
...rest
|
|
4197
|
+
key: 'last15min',
|
|
4198
|
+
label: 'Last 15 min',
|
|
4199
|
+
getValue: () => ({
|
|
4200
|
+
start: formatISO(subMinutes(new Date())),
|
|
4201
|
+
end: formatISO(new Date()),
|
|
4202
|
+
}),
|
|
4131
4203
|
},
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
)
|
|
4138
|
-
|
|
4204
|
+
{
|
|
4205
|
+
key: 'last1hour',
|
|
4206
|
+
label: 'Last hour',
|
|
4207
|
+
getValue: () => ({
|
|
4208
|
+
start: formatISO(subHours(new Date(), 1)),
|
|
4209
|
+
end: formatISO(new Date()),
|
|
4210
|
+
}),
|
|
4211
|
+
},
|
|
4212
|
+
{
|
|
4213
|
+
key: 'last6hours',
|
|
4214
|
+
label: 'Last 6 hours',
|
|
4215
|
+
getValue: () => ({
|
|
4216
|
+
start: formatISO(subHours(new Date(), 6)),
|
|
4217
|
+
end: formatISO(new Date()),
|
|
4218
|
+
}),
|
|
4219
|
+
},
|
|
4220
|
+
{
|
|
4221
|
+
key: 'last24hours',
|
|
4222
|
+
label: 'Last 24 hours',
|
|
4223
|
+
getValue: () => ({
|
|
4224
|
+
start: formatISO(subHours(new Date(), 24)),
|
|
4225
|
+
end: formatISO(new Date()),
|
|
4226
|
+
}),
|
|
4227
|
+
},
|
|
4228
|
+
{
|
|
4229
|
+
key: 'last7days',
|
|
4230
|
+
label: 'Last 7 days',
|
|
4231
|
+
getValue: () => ({
|
|
4232
|
+
start: formatISO(subDays(new Date(), 7)),
|
|
4233
|
+
end: formatISO(new Date()),
|
|
4234
|
+
}),
|
|
4235
|
+
},
|
|
4236
|
+
{
|
|
4237
|
+
key: 'last30days',
|
|
4238
|
+
label: 'Last 30 days',
|
|
4239
|
+
getValue: () => ({
|
|
4240
|
+
start: formatISO(subDays(new Date(), 30)),
|
|
4241
|
+
end: formatISO(new Date()),
|
|
4242
|
+
}),
|
|
4243
|
+
},
|
|
4244
|
+
];
|
|
4245
|
+
/** Debounce delay for text inputs (ms) */
|
|
4246
|
+
const DEBOUNCE_DELAY = 300;
|
|
4139
4247
|
/**
|
|
4140
|
-
*
|
|
4141
|
-
*
|
|
4142
|
-
* This source code is licensed under the ISC license.
|
|
4143
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4248
|
+
* Helper function to convert ISO string to datetime-local format
|
|
4144
4249
|
*/
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
const
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
`lucide-${toKebabCase(toPascalCase(iconName))}`,
|
|
4154
|
-
`lucide-${iconName}`,
|
|
4155
|
-
className
|
|
4156
|
-
),
|
|
4157
|
-
...props
|
|
4158
|
-
})
|
|
4159
|
-
);
|
|
4160
|
-
Component.displayName = toPascalCase(iconName);
|
|
4161
|
-
return Component;
|
|
4250
|
+
const formatDatetimeLocal$4 = (isoString) => {
|
|
4251
|
+
const date = new Date(isoString);
|
|
4252
|
+
const year = date.getFullYear();
|
|
4253
|
+
const month = String(date.getMonth() + 1).padStart(2, '0');
|
|
4254
|
+
const day = String(date.getDate()).padStart(2, '0');
|
|
4255
|
+
const hours = String(date.getHours()).padStart(2, '0');
|
|
4256
|
+
const minutes = String(date.getMinutes()).padStart(2, '0');
|
|
4257
|
+
return `${year}-${month}-${day}T${hours}:${minutes}`;
|
|
4162
4258
|
};
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
|
|
4171
|
-
|
|
4172
|
-
const
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4176
|
-
|
|
4177
|
-
|
|
4178
|
-
|
|
4179
|
-
|
|
4180
|
-
|
|
4181
|
-
const
|
|
4182
|
-
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
*
|
|
4186
|
-
* This source code is licensed under the ISC license.
|
|
4187
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4188
|
-
*/
|
|
4189
|
-
|
|
4190
|
-
|
|
4191
|
-
const __iconNode$o = [
|
|
4192
|
-
["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
|
|
4193
|
-
[
|
|
4194
|
-
"path",
|
|
4195
|
-
{
|
|
4196
|
-
d: "M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326",
|
|
4197
|
-
key: "11g9vi"
|
|
4259
|
+
function SimpleQueryBuilder({ client, onFilterChange, initialLimit = 100, className = '', disabled = false, }) {
|
|
4260
|
+
const [isAdvancedExpanded, setIsAdvancedExpanded] = React.useState(false);
|
|
4261
|
+
const [filters, setFilters] = React.useState({
|
|
4262
|
+
verb: '',
|
|
4263
|
+
resourceType: '',
|
|
4264
|
+
namespace: '',
|
|
4265
|
+
resourceName: '',
|
|
4266
|
+
username: '',
|
|
4267
|
+
});
|
|
4268
|
+
const [limit, setLimit] = React.useState(initialLimit);
|
|
4269
|
+
const [advancedFilter, setAdvancedFilter] = React.useState('');
|
|
4270
|
+
const [useAdvancedFilter, setUseAdvancedFilter] = React.useState(false);
|
|
4271
|
+
// Time range state
|
|
4272
|
+
const [selectedPreset, setSelectedPreset] = React.useState('last24hours');
|
|
4273
|
+
const [timeRange, setTimeRange] = React.useState(null);
|
|
4274
|
+
const [customStart, setCustomStart] = React.useState(() => formatDatetimeLocal$4(formatISO(subDays(new Date(), 1))));
|
|
4275
|
+
const [customEnd, setCustomEnd] = React.useState(() => formatDatetimeLocal$4(formatISO(new Date())));
|
|
4276
|
+
// Fetch facets for dynamic filter options
|
|
4277
|
+
const { verbs, resources, namespaces, usernames, isLoading: facetsLoading, error: facetsError } = useAuditLogFacets(client, timeRange);
|
|
4278
|
+
// Log facets error for debugging
|
|
4279
|
+
if (facetsError) {
|
|
4280
|
+
console.error('Failed to load audit log facets:', facetsError);
|
|
4198
4281
|
}
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
const
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4282
|
+
// Refs for debouncing
|
|
4283
|
+
const debounceTimerRef = React.useRef(null);
|
|
4284
|
+
const isInitialMount = React.useRef(true);
|
|
4285
|
+
// Initialize with default time range and trigger initial query
|
|
4286
|
+
React.useEffect(() => {
|
|
4287
|
+
const defaultRange = TIME_PRESETS$3.find(p => p.key === 'last24hours')?.getValue();
|
|
4288
|
+
if (defaultRange) {
|
|
4289
|
+
setTimeRange(defaultRange);
|
|
4290
|
+
}
|
|
4291
|
+
}, []);
|
|
4292
|
+
const generateCEL = React.useCallback(() => {
|
|
4293
|
+
const parts = [];
|
|
4294
|
+
if (filters.verb) {
|
|
4295
|
+
parts.push(`verb == "${filters.verb}"`);
|
|
4296
|
+
}
|
|
4297
|
+
if (filters.resourceType) {
|
|
4298
|
+
parts.push(`objectRef.resource == "${filters.resourceType}"`);
|
|
4299
|
+
}
|
|
4300
|
+
if (filters.namespace) {
|
|
4301
|
+
parts.push(`objectRef.namespace == "${filters.namespace}"`);
|
|
4302
|
+
}
|
|
4303
|
+
if (filters.resourceName) {
|
|
4304
|
+
parts.push(`objectRef.name.contains("${filters.resourceName}")`);
|
|
4305
|
+
}
|
|
4306
|
+
if (filters.username) {
|
|
4307
|
+
parts.push(`user.username.contains("${filters.username}")`);
|
|
4308
|
+
}
|
|
4309
|
+
return parts.join(' && ');
|
|
4310
|
+
}, [filters]);
|
|
4311
|
+
// Execute query when filters change (with debouncing for text inputs)
|
|
4312
|
+
const executeQuery = React.useCallback(() => {
|
|
4313
|
+
if (!timeRange || disabled)
|
|
4314
|
+
return;
|
|
4315
|
+
const filter = useAdvancedFilter ? advancedFilter : generateCEL();
|
|
4316
|
+
onFilterChange({
|
|
4317
|
+
filter,
|
|
4318
|
+
limit,
|
|
4319
|
+
startTime: timeRange.start,
|
|
4320
|
+
endTime: timeRange.end
|
|
4321
|
+
});
|
|
4322
|
+
}, [useAdvancedFilter, advancedFilter, generateCEL, onFilterChange, limit, timeRange, disabled]);
|
|
4323
|
+
// Auto-execute query when dropdown filters or time range change (immediate)
|
|
4324
|
+
React.useEffect(() => {
|
|
4325
|
+
// Skip the initial mount - we want to wait for timeRange to be set
|
|
4326
|
+
if (isInitialMount.current) {
|
|
4327
|
+
isInitialMount.current = false;
|
|
4328
|
+
return;
|
|
4329
|
+
}
|
|
4330
|
+
// Clear any pending debounced query
|
|
4331
|
+
if (debounceTimerRef.current) {
|
|
4332
|
+
clearTimeout(debounceTimerRef.current);
|
|
4333
|
+
}
|
|
4334
|
+
executeQuery();
|
|
4335
|
+
}, [filters.verb, filters.resourceType, timeRange, limit, useAdvancedFilter]);
|
|
4336
|
+
// Auto-execute query when text filters change (debounced)
|
|
4337
|
+
React.useEffect(() => {
|
|
4338
|
+
if (isInitialMount.current || !timeRange)
|
|
4339
|
+
return;
|
|
4340
|
+
// Clear previous timer
|
|
4341
|
+
if (debounceTimerRef.current) {
|
|
4342
|
+
clearTimeout(debounceTimerRef.current);
|
|
4343
|
+
}
|
|
4344
|
+
// Set new debounced timer
|
|
4345
|
+
debounceTimerRef.current = setTimeout(() => {
|
|
4346
|
+
executeQuery();
|
|
4347
|
+
}, DEBOUNCE_DELAY);
|
|
4348
|
+
return () => {
|
|
4349
|
+
if (debounceTimerRef.current) {
|
|
4350
|
+
clearTimeout(debounceTimerRef.current);
|
|
4351
|
+
}
|
|
4352
|
+
};
|
|
4353
|
+
}, [filters.namespace, filters.resourceName, filters.username, advancedFilter]);
|
|
4354
|
+
const handleFilterChange = React.useCallback((field, value) => {
|
|
4355
|
+
setFilters(prev => ({ ...prev, [field]: value }));
|
|
4356
|
+
}, []);
|
|
4357
|
+
const handleTimePresetSelect = React.useCallback((presetKey) => {
|
|
4358
|
+
const preset = TIME_PRESETS$3.find(p => p.key === presetKey);
|
|
4359
|
+
if (preset) {
|
|
4360
|
+
setSelectedPreset(presetKey);
|
|
4361
|
+
setTimeRange(preset.getValue());
|
|
4362
|
+
}
|
|
4363
|
+
}, []);
|
|
4364
|
+
const handleCustomRangeApply = React.useCallback((start, end) => {
|
|
4365
|
+
setSelectedPreset('custom');
|
|
4366
|
+
setCustomStart(start);
|
|
4367
|
+
setCustomEnd(end);
|
|
4368
|
+
setTimeRange({
|
|
4369
|
+
start: new Date(start).toISOString(),
|
|
4370
|
+
end: new Date(end).toISOString(),
|
|
4371
|
+
});
|
|
4372
|
+
}, []);
|
|
4373
|
+
const handleLimitChange = React.useCallback((newLimit) => {
|
|
4374
|
+
const validLimit = Math.min(Math.max(1, newLimit), 1000);
|
|
4375
|
+
setLimit(validLimit);
|
|
4376
|
+
}, []);
|
|
4377
|
+
const handleAdvancedToggle = React.useCallback(() => {
|
|
4378
|
+
if (!isAdvancedExpanded) {
|
|
4379
|
+
// When expanding, populate advanced filter with generated CEL
|
|
4380
|
+
setAdvancedFilter(generateCEL());
|
|
4381
|
+
}
|
|
4382
|
+
setIsAdvancedExpanded(!isAdvancedExpanded);
|
|
4383
|
+
}, [isAdvancedExpanded, generateCEL]);
|
|
4384
|
+
const handleUseAdvancedChange = React.useCallback((checked) => {
|
|
4385
|
+
setUseAdvancedFilter(checked === true);
|
|
4386
|
+
}, []);
|
|
4387
|
+
// Get display label for time range
|
|
4388
|
+
const getTimeRangeLabel = () => {
|
|
4389
|
+
if (selectedPreset === 'custom') {
|
|
4390
|
+
if (timeRange?.start && timeRange?.end) {
|
|
4391
|
+
const start = new Date(timeRange.start);
|
|
4392
|
+
const end = new Date(timeRange.end);
|
|
4393
|
+
return `${start.toLocaleDateString()} - ${end.toLocaleDateString()}`;
|
|
4394
|
+
}
|
|
4395
|
+
return 'Custom';
|
|
4396
|
+
}
|
|
4397
|
+
const preset = TIME_PRESETS$3.find(p => p.key === selectedPreset);
|
|
4398
|
+
return preset?.label || 'Select time range';
|
|
4399
|
+
};
|
|
4400
|
+
return (jsxRuntime.jsxs("div", { className: `mb-6 pb-6 border-b border-border ${className}`, children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-4 items-end", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Action" }), jsxRuntime.jsx(Combobox, { options: verbs
|
|
4401
|
+
.filter(facet => facet.value)
|
|
4402
|
+
.map(facet => ({
|
|
4403
|
+
value: facet.value,
|
|
4404
|
+
label: facet.value,
|
|
4405
|
+
count: facet.count,
|
|
4406
|
+
})), value: filters.verb, onValueChange: (value) => handleFilterChange('verb', value), placeholder: "All", searchPlaceholder: "Search actions...", allOptionLabel: "All", disabled: disabled || useAdvancedFilter, loading: facetsLoading, className: "min-w-[130px]" })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Resource" }), jsxRuntime.jsx(Combobox, { options: resources
|
|
4407
|
+
.filter(facet => facet.value)
|
|
4408
|
+
.map(facet => ({
|
|
4409
|
+
value: facet.value,
|
|
4410
|
+
label: facet.value,
|
|
4411
|
+
count: facet.count,
|
|
4412
|
+
})), value: filters.resourceType, onValueChange: (value) => handleFilterChange('resourceType', value), placeholder: "All", searchPlaceholder: "Search resources...", allOptionLabel: "All", disabled: disabled || useAdvancedFilter, loading: facetsLoading, className: "min-w-[130px]" })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Namespace" }), jsxRuntime.jsx(Combobox, { options: namespaces
|
|
4413
|
+
.filter(facet => facet.value)
|
|
4414
|
+
.map(facet => ({
|
|
4415
|
+
value: facet.value,
|
|
4416
|
+
label: facet.value,
|
|
4417
|
+
count: facet.count,
|
|
4418
|
+
})), value: filters.namespace, onValueChange: (value) => handleFilterChange('namespace', value), placeholder: "All", searchPlaceholder: "Search namespaces...", allOptionLabel: "All", disabled: disabled || useAdvancedFilter, loading: facetsLoading, className: "min-w-[130px]" })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "User" }), jsxRuntime.jsx(Combobox, { options: usernames
|
|
4419
|
+
.filter(facet => facet.value)
|
|
4420
|
+
.map(facet => ({
|
|
4421
|
+
value: facet.value,
|
|
4422
|
+
label: facet.value,
|
|
4423
|
+
count: facet.count,
|
|
4424
|
+
})), value: filters.username, onValueChange: (value) => handleFilterChange('username', value), placeholder: "All", searchPlaceholder: "Search users...", allOptionLabel: "All", disabled: disabled || useAdvancedFilter, loading: facetsLoading, className: "min-w-[130px]" })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Name" }), jsxRuntime.jsx(input.Input, { type: "text", value: filters.resourceName, onChange: (e) => handleFilterChange('resourceName', e.target.value), placeholder: "Filter by name...", className: "min-w-[140px]", disabled: disabled || useAdvancedFilter })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Limit" }), jsxRuntime.jsx(input.Input, { type: "number", value: limit, onChange: (e) => handleLimitChange(parseInt(e.target.value) || 100), min: 1, max: 1000, className: "w-[80px]", disabled: disabled })] }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "small", className: "whitespace-nowrap text-muted-foreground hover:text-foreground", onClick: handleAdvancedToggle, "aria-expanded": isAdvancedExpanded, children: isAdvancedExpanded ? '- CEL' : '+ CEL' }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 ml-auto", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Time Range" }), jsxRuntime.jsx(TimeRangeDropdown, { presets: TIME_PRESETS$3.map(p => ({ key: p.key, label: p.label })), selectedPreset: selectedPreset, onPresetSelect: handleTimePresetSelect, onCustomRangeApply: handleCustomRangeApply, customStart: customStart, customEnd: customEnd, disabled: disabled, displayLabel: getTimeRangeLabel() })] })] }), isAdvancedExpanded && (jsxRuntime.jsxs("div", { className: "mt-4 pt-4", children: [jsxRuntime.jsx(separator.Separator, { className: "mb-4" }), jsxRuntime.jsx("div", { className: "mb-3", children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(checkbox.Checkbox, { id: "use-cel-expression", checked: useAdvancedFilter, onCheckedChange: handleUseAdvancedChange, disabled: disabled }), jsxRuntime.jsx(label.Label, { htmlFor: "use-cel-expression", className: "text-sm font-medium text-foreground cursor-pointer", children: "Use CEL Expression" })] }) }), useAdvancedFilter && (jsxRuntime.jsxs("div", { className: "mt-3", children: [jsxRuntime.jsx("p", { className: "m-0 mb-2 text-sm text-muted-foreground", children: "Write your query using CEL syntax for complex filters" }), jsxRuntime.jsx(textarea.Textarea, { value: advancedFilter, onChange: (e) => setAdvancedFilter(e.target.value), placeholder: 'Example: verb == "delete" && objectRef.namespace == "production"', rows: 3, className: "w-full font-mono resize-y", disabled: disabled })] }))] }))] }));
|
|
4425
|
+
}
|
|
4226
4426
|
|
|
4227
|
-
|
|
4228
|
-
const Check = createLucideIcon("check", __iconNode$m);
|
|
4427
|
+
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
|
|
4229
4428
|
|
|
4230
4429
|
/**
|
|
4231
|
-
*
|
|
4232
|
-
*
|
|
4233
|
-
* This source code is licensed under the ISC license.
|
|
4234
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4430
|
+
* Concatenates two arrays faster than the array spread operator.
|
|
4235
4431
|
*/
|
|
4236
|
-
|
|
4237
|
-
|
|
4238
|
-
const
|
|
4239
|
-
|
|
4240
|
-
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
const __iconNode$k = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
|
|
4250
|
-
const ChevronRight = createLucideIcon("chevron-right", __iconNode$k);
|
|
4251
|
-
|
|
4252
|
-
/**
|
|
4253
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4254
|
-
*
|
|
4255
|
-
* This source code is licensed under the ISC license.
|
|
4256
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4257
|
-
*/
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
const __iconNode$j = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
|
|
4261
|
-
const ChevronUp = createLucideIcon("chevron-up", __iconNode$j);
|
|
4262
|
-
|
|
4263
|
-
/**
|
|
4264
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4265
|
-
*
|
|
4266
|
-
* This source code is licensed under the ISC license.
|
|
4267
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4268
|
-
*/
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
const __iconNode$i = [
|
|
4272
|
-
["path", { d: "m7 15 5 5 5-5", key: "1hf1tw" }],
|
|
4273
|
-
["path", { d: "m7 9 5-5 5 5", key: "sgt6xg" }]
|
|
4274
|
-
];
|
|
4275
|
-
const ChevronsUpDown = createLucideIcon("chevrons-up-down", __iconNode$i);
|
|
4276
|
-
|
|
4277
|
-
/**
|
|
4278
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4279
|
-
*
|
|
4280
|
-
* This source code is licensed under the ISC license.
|
|
4281
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4282
|
-
*/
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
const __iconNode$h = [
|
|
4286
|
-
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
4287
|
-
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
4288
|
-
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
4289
|
-
];
|
|
4290
|
-
const CircleAlert = createLucideIcon("circle-alert", __iconNode$h);
|
|
4291
|
-
|
|
4292
|
-
/**
|
|
4293
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4294
|
-
*
|
|
4295
|
-
* This source code is licensed under the ISC license.
|
|
4296
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4297
|
-
*/
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
const __iconNode$g = [
|
|
4301
|
-
["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
|
|
4302
|
-
["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
|
|
4303
|
-
];
|
|
4304
|
-
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$g);
|
|
4305
|
-
|
|
4306
|
-
/**
|
|
4307
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4308
|
-
*
|
|
4309
|
-
* This source code is licensed under the ISC license.
|
|
4310
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4311
|
-
*/
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
const __iconNode$f = [
|
|
4315
|
-
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
4316
|
-
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
4317
|
-
];
|
|
4318
|
-
const CircleCheck = createLucideIcon("circle-check", __iconNode$f);
|
|
4319
|
-
|
|
4320
|
-
/**
|
|
4321
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4322
|
-
*
|
|
4323
|
-
* This source code is licensed under the ISC license.
|
|
4324
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4325
|
-
*/
|
|
4326
|
-
|
|
4327
|
-
|
|
4328
|
-
const __iconNode$e = [
|
|
4329
|
-
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
4330
|
-
["path", { d: "m15 9-6 6", key: "1uzhvr" }],
|
|
4331
|
-
["path", { d: "m9 9 6 6", key: "z0biqf" }]
|
|
4332
|
-
];
|
|
4333
|
-
const CircleX = createLucideIcon("circle-x", __iconNode$e);
|
|
4334
|
-
|
|
4335
|
-
/**
|
|
4336
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4337
|
-
*
|
|
4338
|
-
* This source code is licensed under the ISC license.
|
|
4339
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4340
|
-
*/
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
const __iconNode$d = [
|
|
4344
|
-
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
4345
|
-
["path", { d: "M12 6v6l4 2", key: "mmk7yg" }]
|
|
4346
|
-
];
|
|
4347
|
-
const Clock = createLucideIcon("clock", __iconNode$d);
|
|
4348
|
-
|
|
4349
|
-
/**
|
|
4350
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4351
|
-
*
|
|
4352
|
-
* This source code is licensed under the ISC license.
|
|
4353
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4354
|
-
*/
|
|
4355
|
-
|
|
4356
|
-
|
|
4357
|
-
const __iconNode$c = [
|
|
4358
|
-
["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
|
|
4359
|
-
["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" }]
|
|
4360
|
-
];
|
|
4361
|
-
const Copy = createLucideIcon("copy", __iconNode$c);
|
|
4362
|
-
|
|
4363
|
-
/**
|
|
4364
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4365
|
-
*
|
|
4366
|
-
* This source code is licensed under the ISC license.
|
|
4367
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4368
|
-
*/
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
const __iconNode$b = [
|
|
4372
|
-
[
|
|
4373
|
-
"path",
|
|
4374
|
-
{
|
|
4375
|
-
d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",
|
|
4376
|
-
key: "1nclc0"
|
|
4377
|
-
}
|
|
4378
|
-
],
|
|
4379
|
-
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
4380
|
-
];
|
|
4381
|
-
const Eye = createLucideIcon("eye", __iconNode$b);
|
|
4382
|
-
|
|
4383
|
-
/**
|
|
4384
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4385
|
-
*
|
|
4386
|
-
* This source code is licensed under the ISC license.
|
|
4387
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4388
|
-
*/
|
|
4389
|
-
|
|
4390
|
-
|
|
4391
|
-
const __iconNode$a = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
4392
|
-
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$a);
|
|
4393
|
-
|
|
4394
|
-
/**
|
|
4395
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4396
|
-
*
|
|
4397
|
-
* This source code is licensed under the ISC license.
|
|
4398
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4399
|
-
*/
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
const __iconNode$9 = [
|
|
4403
|
-
[
|
|
4404
|
-
"path",
|
|
4405
|
-
{
|
|
4406
|
-
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",
|
|
4407
|
-
key: "1a8usu"
|
|
4408
|
-
}
|
|
4409
|
-
],
|
|
4410
|
-
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
4411
|
-
];
|
|
4412
|
-
const Pencil = createLucideIcon("pencil", __iconNode$9);
|
|
4413
|
-
|
|
4414
|
-
/**
|
|
4415
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4416
|
-
*
|
|
4417
|
-
* This source code is licensed under the ISC license.
|
|
4418
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4419
|
-
*/
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
const __iconNode$8 = [
|
|
4423
|
-
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
4424
|
-
["path", { d: "M12 5v14", key: "s699le" }]
|
|
4425
|
-
];
|
|
4426
|
-
const Plus = createLucideIcon("plus", __iconNode$8);
|
|
4427
|
-
|
|
4428
|
-
/**
|
|
4429
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4430
|
-
*
|
|
4431
|
-
* This source code is licensed under the ISC license.
|
|
4432
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4433
|
-
*/
|
|
4434
|
-
|
|
4435
|
-
|
|
4436
|
-
const __iconNode$7 = [
|
|
4437
|
-
["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
|
|
4438
|
-
["path", { d: "M21 3v5h-5", key: "1q7to0" }],
|
|
4439
|
-
["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
|
|
4440
|
-
["path", { d: "M8 16H3v5", key: "1cv678" }]
|
|
4441
|
-
];
|
|
4442
|
-
const RefreshCw = createLucideIcon("refresh-cw", __iconNode$7);
|
|
4443
|
-
|
|
4444
|
-
/**
|
|
4445
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4446
|
-
*
|
|
4447
|
-
* This source code is licensed under the ISC license.
|
|
4448
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4449
|
-
*/
|
|
4450
|
-
|
|
4451
|
-
|
|
4452
|
-
const __iconNode$6 = [
|
|
4453
|
-
["path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", key: "1p45f6" }],
|
|
4454
|
-
["path", { d: "M21 3v5h-5", key: "1q7to0" }]
|
|
4455
|
-
];
|
|
4456
|
-
const RotateCw = createLucideIcon("rotate-cw", __iconNode$6);
|
|
4457
|
-
|
|
4458
|
-
/**
|
|
4459
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4460
|
-
*
|
|
4461
|
-
* This source code is licensed under the ISC license.
|
|
4462
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4463
|
-
*/
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
const __iconNode$5 = [
|
|
4467
|
-
["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
|
|
4468
|
-
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
|
|
4469
|
-
];
|
|
4470
|
-
const Search = createLucideIcon("search", __iconNode$5);
|
|
4471
|
-
|
|
4472
|
-
/**
|
|
4473
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4474
|
-
*
|
|
4475
|
-
* This source code is licensed under the ISC license.
|
|
4476
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4477
|
-
*/
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
const __iconNode$4 = [
|
|
4481
|
-
["path", { d: "M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7", key: "1m0v6g" }],
|
|
4482
|
-
[
|
|
4483
|
-
"path",
|
|
4484
|
-
{
|
|
4485
|
-
d: "M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z",
|
|
4486
|
-
key: "ohrbg2"
|
|
4487
|
-
}
|
|
4488
|
-
]
|
|
4489
|
-
];
|
|
4490
|
-
const SquarePen = createLucideIcon("square-pen", __iconNode$4);
|
|
4491
|
-
|
|
4492
|
-
/**
|
|
4493
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4494
|
-
*
|
|
4495
|
-
* This source code is licensed under the ISC license.
|
|
4496
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4497
|
-
*/
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
const __iconNode$3 = [
|
|
4501
|
-
["path", { d: "M10 11v6", key: "nco0om" }],
|
|
4502
|
-
["path", { d: "M14 11v6", key: "outv1u" }],
|
|
4503
|
-
["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", key: "miytrc" }],
|
|
4504
|
-
["path", { d: "M3 6h18", key: "d0wm0j" }],
|
|
4505
|
-
["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2", key: "e791ji" }]
|
|
4506
|
-
];
|
|
4507
|
-
const Trash2 = createLucideIcon("trash-2", __iconNode$3);
|
|
4508
|
-
|
|
4509
|
-
/**
|
|
4510
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4511
|
-
*
|
|
4512
|
-
* This source code is licensed under the ISC license.
|
|
4513
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4514
|
-
*/
|
|
4515
|
-
|
|
4516
|
-
|
|
4517
|
-
const __iconNode$2 = [
|
|
4518
|
-
[
|
|
4519
|
-
"path",
|
|
4520
|
-
{
|
|
4521
|
-
d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",
|
|
4522
|
-
key: "wmoenq"
|
|
4523
|
-
}
|
|
4524
|
-
],
|
|
4525
|
-
["path", { d: "M12 9v4", key: "juzpu7" }],
|
|
4526
|
-
["path", { d: "M12 17h.01", key: "p32p05" }]
|
|
4527
|
-
];
|
|
4528
|
-
const TriangleAlert = createLucideIcon("triangle-alert", __iconNode$2);
|
|
4529
|
-
|
|
4530
|
-
/**
|
|
4531
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4532
|
-
*
|
|
4533
|
-
* This source code is licensed under the ISC license.
|
|
4534
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4535
|
-
*/
|
|
4536
|
-
|
|
4537
|
-
|
|
4538
|
-
const __iconNode$1 = [
|
|
4539
|
-
["path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2", key: "975kel" }],
|
|
4540
|
-
["circle", { cx: "12", cy: "7", r: "4", key: "17ys0d" }]
|
|
4541
|
-
];
|
|
4542
|
-
const User = createLucideIcon("user", __iconNode$1);
|
|
4543
|
-
|
|
4544
|
-
/**
|
|
4545
|
-
* @license lucide-react v0.577.0 - ISC
|
|
4546
|
-
*
|
|
4547
|
-
* This source code is licensed under the ISC license.
|
|
4548
|
-
* See the LICENSE file in the root directory of this source tree.
|
|
4549
|
-
*/
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
const __iconNode = [
|
|
4553
|
-
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
4554
|
-
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
4555
|
-
];
|
|
4556
|
-
const X = createLucideIcon("x", __iconNode);
|
|
4557
|
-
|
|
4558
|
-
function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
|
|
4559
|
-
|
|
4560
|
-
/**
|
|
4561
|
-
* Concatenates two arrays faster than the array spread operator.
|
|
4562
|
-
*/
|
|
4563
|
-
const concatArrays = (array1, array2) => {
|
|
4564
|
-
// Pre-allocate for better V8 optimization
|
|
4565
|
-
const combinedArray = new Array(array1.length + array2.length);
|
|
4566
|
-
for (let i = 0; i < array1.length; i++) {
|
|
4567
|
-
combinedArray[i] = array1[i];
|
|
4568
|
-
}
|
|
4569
|
-
for (let i = 0; i < array2.length; i++) {
|
|
4570
|
-
combinedArray[array1.length + i] = array2[i];
|
|
4571
|
-
}
|
|
4572
|
-
return combinedArray;
|
|
4573
|
-
};
|
|
4432
|
+
const concatArrays = (array1, array2) => {
|
|
4433
|
+
// Pre-allocate for better V8 optimization
|
|
4434
|
+
const combinedArray = new Array(array1.length + array2.length);
|
|
4435
|
+
for (let i = 0; i < array1.length; i++) {
|
|
4436
|
+
combinedArray[i] = array1[i];
|
|
4437
|
+
}
|
|
4438
|
+
for (let i = 0; i < array2.length; i++) {
|
|
4439
|
+
combinedArray[array1.length + i] = array2[i];
|
|
4440
|
+
}
|
|
4441
|
+
return combinedArray;
|
|
4442
|
+
};
|
|
4574
4443
|
|
|
4575
4444
|
// Factory function ensures consistent object shapes
|
|
4576
4445
|
const createClassValidatorObject = (classGroupId, validator) => ({
|
|
@@ -4904,15 +4773,27 @@ const createConfigUtils = config => ({
|
|
|
4904
4773
|
cache: createLruCache(config.cacheSize),
|
|
4905
4774
|
parseClassName: createParseClassName(config),
|
|
4906
4775
|
sortModifiers: createSortModifiers(config),
|
|
4776
|
+
postfixLookupClassGroupIds: createPostfixLookupClassGroupIds(config),
|
|
4907
4777
|
...createClassGroupUtils(config)
|
|
4908
4778
|
});
|
|
4779
|
+
const createPostfixLookupClassGroupIds = config => {
|
|
4780
|
+
const lookup = Object.create(null);
|
|
4781
|
+
const classGroupIds = config.postfixLookupClassGroups;
|
|
4782
|
+
if (classGroupIds) {
|
|
4783
|
+
for (let i = 0; i < classGroupIds.length; i++) {
|
|
4784
|
+
lookup[classGroupIds[i]] = true;
|
|
4785
|
+
}
|
|
4786
|
+
}
|
|
4787
|
+
return lookup;
|
|
4788
|
+
};
|
|
4909
4789
|
const SPLIT_CLASSES_REGEX = /\s+/;
|
|
4910
4790
|
const mergeClassList = (classList, configUtils) => {
|
|
4911
4791
|
const {
|
|
4912
4792
|
parseClassName,
|
|
4913
4793
|
getClassGroupId,
|
|
4914
4794
|
getConflictingClassGroupIds,
|
|
4915
|
-
sortModifiers
|
|
4795
|
+
sortModifiers,
|
|
4796
|
+
postfixLookupClassGroupIds
|
|
4916
4797
|
} = configUtils;
|
|
4917
4798
|
/**
|
|
4918
4799
|
* Set of classGroupIds in following format:
|
|
@@ -4938,7 +4819,18 @@ const mergeClassList = (classList, configUtils) => {
|
|
|
4938
4819
|
continue;
|
|
4939
4820
|
}
|
|
4940
4821
|
let hasPostfixModifier = !!maybePostfixModifierPosition;
|
|
4941
|
-
let classGroupId
|
|
4822
|
+
let classGroupId;
|
|
4823
|
+
if (hasPostfixModifier) {
|
|
4824
|
+
const baseClassNameWithoutPostfix = baseClassName.substring(0, maybePostfixModifierPosition);
|
|
4825
|
+
classGroupId = getClassGroupId(baseClassNameWithoutPostfix);
|
|
4826
|
+
const classGroupIdWithPostfix = classGroupId && postfixLookupClassGroupIds[classGroupId] ? getClassGroupId(baseClassName) : undefined;
|
|
4827
|
+
if (classGroupIdWithPostfix && classGroupIdWithPostfix !== classGroupId) {
|
|
4828
|
+
classGroupId = classGroupIdWithPostfix;
|
|
4829
|
+
hasPostfixModifier = false;
|
|
4830
|
+
}
|
|
4831
|
+
} else {
|
|
4832
|
+
classGroupId = getClassGroupId(baseClassName);
|
|
4833
|
+
}
|
|
4942
4834
|
if (!classGroupId) {
|
|
4943
4835
|
if (!hasPostfixModifier) {
|
|
4944
4836
|
// Not a Tailwind class
|
|
@@ -5043,6 +4935,7 @@ const fallbackThemeArr = [];
|
|
|
5043
4935
|
const fromTheme = key => {
|
|
5044
4936
|
const themeGetter = theme => theme[key] || fallbackThemeArr;
|
|
5045
4937
|
themeGetter.isThemeGetter = true;
|
|
4938
|
+
themeGetter.themeKey = key;
|
|
5046
4939
|
return themeGetter;
|
|
5047
4940
|
};
|
|
5048
4941
|
const arbitraryValueRegex = /^\[(?:(\w[\w-]*):)?(.+)\]$/i;
|
|
@@ -5050,7 +4943,7 @@ const arbitraryVariableRegex = /^\((?:(\w[\w-]*):)?(.+)\)$/i;
|
|
|
5050
4943
|
const fractionRegex = /^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/;
|
|
5051
4944
|
const tshirtUnitRegex = /^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/;
|
|
5052
4945
|
const lengthUnitRegex = /\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/;
|
|
5053
|
-
const colorFunctionRegex = /^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/;
|
|
4946
|
+
const colorFunctionRegex = /^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix|color|light-dark)\(.+\)$/;
|
|
5054
4947
|
// Shadow always begins with x and y offset separated by underscore optionally prepended by inset
|
|
5055
4948
|
const shadowRegex = /^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/;
|
|
5056
4949
|
const imageRegex = /^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/;
|
|
@@ -5069,6 +4962,7 @@ const isNever = () => false;
|
|
|
5069
4962
|
const isShadow = value => shadowRegex.test(value);
|
|
5070
4963
|
const isImage = value => imageRegex.test(value);
|
|
5071
4964
|
const isAnyNonArbitrary = value => !isArbitraryValue(value) && !isArbitraryVariable(value);
|
|
4965
|
+
const isNamedContainerQuery = value => value.startsWith('@container') && (value[10] === '/' && value[11] !== undefined || value[11] === 's' && value[16] !== undefined && value.startsWith('-size/', 10) || value[11] === 'n' && value[18] !== undefined && value.startsWith('-normal/', 10));
|
|
5072
4966
|
const isArbitrarySize = value => getIsArbitraryValue(value, isLabelSize, isNever);
|
|
5073
4967
|
const isArbitraryValue = value => arbitraryValueRegex.test(value);
|
|
5074
4968
|
const isArbitraryLength = value => getIsArbitraryValue(value, isLabelLength, isLengthOnly);
|
|
@@ -5173,7 +5067,7 @@ const getDefaultConfig = () => {
|
|
|
5173
5067
|
const scaleAlignSecondaryAxis = () => ['start', 'end', 'center', 'stretch', 'center-safe', 'end-safe'];
|
|
5174
5068
|
const scaleMargin = () => ['auto', ...scaleUnambiguousSpacing()];
|
|
5175
5069
|
const scaleSizing = () => [isFraction, 'auto', 'full', 'dvw', 'dvh', 'lvw', 'lvh', 'svw', 'svh', 'min', 'max', 'fit', ...scaleUnambiguousSpacing()];
|
|
5176
|
-
const scaleSizingInline = () => [isFraction, 'screen', 'full', 'dvw', 'lvw', 'svw', 'min', 'max', 'fit', ...scaleUnambiguousSpacing()];
|
|
5070
|
+
const scaleSizingInline = () => [themeContainer, isFraction, 'screen', 'full', 'dvw', 'lvw', 'svw', 'min', 'max', 'fit', ...scaleUnambiguousSpacing()];
|
|
5177
5071
|
const scaleSizingBlock = () => [isFraction, 'screen', 'full', 'lh', 'dvh', 'lvh', 'svh', 'min', 'max', 'fit', ...scaleUnambiguousSpacing()];
|
|
5178
5072
|
const scaleColor = () => [themeColor, isArbitraryVariable, isArbitraryValue];
|
|
5179
5073
|
const scaleBgPosition = () => [...scalePosition(), isArbitraryVariablePosition, isArbitraryPosition, {
|
|
@@ -5240,12 +5134,24 @@ const getDefaultConfig = () => {
|
|
|
5240
5134
|
* @deprecated since Tailwind CSS v4.0.0
|
|
5241
5135
|
*/
|
|
5242
5136
|
container: ['container'],
|
|
5137
|
+
/**
|
|
5138
|
+
* Container Type
|
|
5139
|
+
* @see https://tailwindcss.com/docs/responsive-design#container-queries
|
|
5140
|
+
*/
|
|
5141
|
+
'container-type': [{
|
|
5142
|
+
'@container': ['', 'normal', 'size', isArbitraryVariable, isArbitraryValue]
|
|
5143
|
+
}],
|
|
5144
|
+
/**
|
|
5145
|
+
* Container Name
|
|
5146
|
+
* @see https://tailwindcss.com/docs/responsive-design#named-containers
|
|
5147
|
+
*/
|
|
5148
|
+
'container-named': [isNamedContainerQuery],
|
|
5243
5149
|
/**
|
|
5244
5150
|
* Columns
|
|
5245
5151
|
* @see https://tailwindcss.com/docs/columns
|
|
5246
5152
|
*/
|
|
5247
5153
|
columns: [{
|
|
5248
|
-
columns: [isNumber, isArbitraryValue, isArbitraryVariable, themeContainer]
|
|
5154
|
+
columns: [isNumber, 'auto', isArbitraryValue, isArbitraryVariable, themeContainer]
|
|
5249
5155
|
}],
|
|
5250
5156
|
/**
|
|
5251
5157
|
* Break After
|
|
@@ -5881,42 +5787,42 @@ const getDefaultConfig = () => {
|
|
|
5881
5787
|
}],
|
|
5882
5788
|
/**
|
|
5883
5789
|
* Inline Size
|
|
5884
|
-
* @see https://tailwindcss.com/docs/
|
|
5790
|
+
* @see https://tailwindcss.com/docs/inline-size
|
|
5885
5791
|
*/
|
|
5886
5792
|
'inline-size': [{
|
|
5887
5793
|
inline: ['auto', ...scaleSizingInline()]
|
|
5888
5794
|
}],
|
|
5889
5795
|
/**
|
|
5890
5796
|
* Min-Inline Size
|
|
5891
|
-
* @see https://tailwindcss.com/docs/min-
|
|
5797
|
+
* @see https://tailwindcss.com/docs/min-inline-size
|
|
5892
5798
|
*/
|
|
5893
5799
|
'min-inline-size': [{
|
|
5894
5800
|
'min-inline': ['auto', ...scaleSizingInline()]
|
|
5895
5801
|
}],
|
|
5896
5802
|
/**
|
|
5897
5803
|
* Max-Inline Size
|
|
5898
|
-
* @see https://tailwindcss.com/docs/max-
|
|
5804
|
+
* @see https://tailwindcss.com/docs/max-inline-size
|
|
5899
5805
|
*/
|
|
5900
5806
|
'max-inline-size': [{
|
|
5901
5807
|
'max-inline': ['none', ...scaleSizingInline()]
|
|
5902
5808
|
}],
|
|
5903
5809
|
/**
|
|
5904
5810
|
* Block Size
|
|
5905
|
-
* @see https://tailwindcss.com/docs/
|
|
5811
|
+
* @see https://tailwindcss.com/docs/block-size
|
|
5906
5812
|
*/
|
|
5907
5813
|
'block-size': [{
|
|
5908
5814
|
block: ['auto', ...scaleSizingBlock()]
|
|
5909
5815
|
}],
|
|
5910
5816
|
/**
|
|
5911
5817
|
* Min-Block Size
|
|
5912
|
-
* @see https://tailwindcss.com/docs/min-
|
|
5818
|
+
* @see https://tailwindcss.com/docs/min-block-size
|
|
5913
5819
|
*/
|
|
5914
5820
|
'min-block-size': [{
|
|
5915
5821
|
'min-block': ['auto', ...scaleSizingBlock()]
|
|
5916
5822
|
}],
|
|
5917
5823
|
/**
|
|
5918
5824
|
* Max-Block Size
|
|
5919
|
-
* @see https://tailwindcss.com/docs/max-
|
|
5825
|
+
* @see https://tailwindcss.com/docs/max-block-size
|
|
5920
5826
|
*/
|
|
5921
5827
|
'max-block-size': [{
|
|
5922
5828
|
'max-block': ['none', ...scaleSizingBlock()]
|
|
@@ -5966,7 +5872,7 @@ const getDefaultConfig = () => {
|
|
|
5966
5872
|
* @see https://tailwindcss.com/docs/max-height
|
|
5967
5873
|
*/
|
|
5968
5874
|
'max-h': [{
|
|
5969
|
-
'max-h': ['screen', 'lh', ...scaleSizing()]
|
|
5875
|
+
'max-h': ['screen', 'lh', 'none', ...scaleSizing()]
|
|
5970
5876
|
}],
|
|
5971
5877
|
// ------------------
|
|
5972
5878
|
// --- Typography ---
|
|
@@ -6065,7 +5971,7 @@ const getDefaultConfig = () => {
|
|
|
6065
5971
|
* @see https://tailwindcss.com/docs/line-height
|
|
6066
5972
|
*/
|
|
6067
5973
|
leading: [{
|
|
6068
|
-
leading: [/** Deprecated since Tailwind CSS v4.0.0. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */
|
|
5974
|
+
leading: ['none', /** Deprecated since Tailwind CSS v4.0.0. @see https://github.com/tailwindlabs/tailwindcss.com/issues/2027#issuecomment-2620152757 */
|
|
6069
5975
|
themeLeading, ...scaleUnambiguousSpacing()]
|
|
6070
5976
|
}],
|
|
6071
5977
|
/**
|
|
@@ -6168,6 +6074,13 @@ const getDefaultConfig = () => {
|
|
|
6168
6074
|
indent: [{
|
|
6169
6075
|
indent: scaleUnambiguousSpacing()
|
|
6170
6076
|
}],
|
|
6077
|
+
/**
|
|
6078
|
+
* Tab Size
|
|
6079
|
+
* @see https://tailwindcss.com/docs/tab-size
|
|
6080
|
+
*/
|
|
6081
|
+
'tab-size': [{
|
|
6082
|
+
tab: [isInteger, isArbitraryVariable, isArbitraryValue]
|
|
6083
|
+
}],
|
|
6171
6084
|
/**
|
|
6172
6085
|
* Vertical Alignment
|
|
6173
6086
|
* @see https://tailwindcss.com/docs/vertical-align
|
|
@@ -6265,7 +6178,7 @@ const getDefaultConfig = () => {
|
|
|
6265
6178
|
to: ['t', 'tr', 'r', 'br', 'b', 'bl', 'l', 'tl']
|
|
6266
6179
|
}, isInteger, isArbitraryVariable, isArbitraryValue],
|
|
6267
6180
|
radial: ['', isArbitraryVariable, isArbitraryValue],
|
|
6268
|
-
conic: [isInteger, isArbitraryVariable, isArbitraryValue]
|
|
6181
|
+
conic: ['', isInteger, isArbitraryVariable, isArbitraryValue]
|
|
6269
6182
|
}, isArbitraryVariableImage, isArbitraryImage]
|
|
6270
6183
|
}],
|
|
6271
6184
|
/**
|
|
@@ -6662,7 +6575,9 @@ const getDefaultConfig = () => {
|
|
|
6662
6575
|
shadow: [{
|
|
6663
6576
|
shadow: [
|
|
6664
6577
|
// Deprecated since Tailwind CSS v4.0.0
|
|
6665
|
-
'',
|
|
6578
|
+
'',
|
|
6579
|
+
// Deprecated since Tailwind CSS v4.0.0
|
|
6580
|
+
'inner', 'none', themeShadow, isArbitraryVariableShadow, isArbitraryShadow]
|
|
6666
6581
|
}],
|
|
6667
6582
|
/**
|
|
6668
6583
|
* Box Shadow Color
|
|
@@ -7375,6 +7290,13 @@ const getDefaultConfig = () => {
|
|
|
7375
7290
|
* @see https://tailwindcss.com/docs/translate
|
|
7376
7291
|
*/
|
|
7377
7292
|
'translate-none': ['translate-none'],
|
|
7293
|
+
/**
|
|
7294
|
+
* Zoom
|
|
7295
|
+
* @see https://tailwindcss.com/docs/zoom
|
|
7296
|
+
*/
|
|
7297
|
+
zoom: [{
|
|
7298
|
+
zoom: [isInteger, isArbitraryVariable, isArbitraryValue]
|
|
7299
|
+
}],
|
|
7378
7300
|
// ---------------------
|
|
7379
7301
|
// --- Interactivity ---
|
|
7380
7302
|
// ---------------------
|
|
@@ -7441,6 +7363,34 @@ const getDefaultConfig = () => {
|
|
|
7441
7363
|
'scroll-behavior': [{
|
|
7442
7364
|
scroll: ['auto', 'smooth']
|
|
7443
7365
|
}],
|
|
7366
|
+
/**
|
|
7367
|
+
* Scrollbar Thumb Color
|
|
7368
|
+
* @see https://tailwindcss.com/docs/scrollbar-color
|
|
7369
|
+
*/
|
|
7370
|
+
'scrollbar-thumb-color': [{
|
|
7371
|
+
'scrollbar-thumb': scaleColor()
|
|
7372
|
+
}],
|
|
7373
|
+
/**
|
|
7374
|
+
* Scrollbar Track Color
|
|
7375
|
+
* @see https://tailwindcss.com/docs/scrollbar-color
|
|
7376
|
+
*/
|
|
7377
|
+
'scrollbar-track-color': [{
|
|
7378
|
+
'scrollbar-track': scaleColor()
|
|
7379
|
+
}],
|
|
7380
|
+
/**
|
|
7381
|
+
* Scrollbar Gutter
|
|
7382
|
+
* @see https://tailwindcss.com/docs/scrollbar-gutter
|
|
7383
|
+
*/
|
|
7384
|
+
'scrollbar-gutter': [{
|
|
7385
|
+
'scrollbar-gutter': ['auto', 'stable', 'both']
|
|
7386
|
+
}],
|
|
7387
|
+
/**
|
|
7388
|
+
* Scrollbar Width
|
|
7389
|
+
* @see https://tailwindcss.com/docs/scrollbar-width
|
|
7390
|
+
*/
|
|
7391
|
+
'scrollbar-w': [{
|
|
7392
|
+
scrollbar: ['auto', 'thin', 'none']
|
|
7393
|
+
}],
|
|
7444
7394
|
/**
|
|
7445
7395
|
* Scroll Margin
|
|
7446
7396
|
* @see https://tailwindcss.com/docs/scroll-margin
|
|
@@ -7699,19 +7649,20 @@ const getDefaultConfig = () => {
|
|
|
7699
7649
|
}]
|
|
7700
7650
|
},
|
|
7701
7651
|
conflictingClassGroups: {
|
|
7652
|
+
'container-named': ['container-type'],
|
|
7702
7653
|
overflow: ['overflow-x', 'overflow-y'],
|
|
7703
7654
|
overscroll: ['overscroll-x', 'overscroll-y'],
|
|
7704
7655
|
inset: ['inset-x', 'inset-y', 'inset-bs', 'inset-be', 'start', 'end', 'top', 'right', 'bottom', 'left'],
|
|
7705
|
-
'inset-x': ['right', 'left'],
|
|
7706
|
-
'inset-y': ['top', 'bottom'],
|
|
7656
|
+
'inset-x': ['start', 'end', 'right', 'left'],
|
|
7657
|
+
'inset-y': ['inset-bs', 'inset-be', 'top', 'bottom'],
|
|
7707
7658
|
flex: ['basis', 'grow', 'shrink'],
|
|
7708
7659
|
gap: ['gap-x', 'gap-y'],
|
|
7709
7660
|
p: ['px', 'py', 'ps', 'pe', 'pbs', 'pbe', 'pt', 'pr', 'pb', 'pl'],
|
|
7710
|
-
px: ['pr', 'pl'],
|
|
7711
|
-
py: ['pt', 'pb'],
|
|
7661
|
+
px: ['ps', 'pe', 'pr', 'pl'],
|
|
7662
|
+
py: ['pbs', 'pbe', 'pt', 'pb'],
|
|
7712
7663
|
m: ['mx', 'my', 'ms', 'me', 'mbs', 'mbe', 'mt', 'mr', 'mb', 'ml'],
|
|
7713
|
-
mx: ['mr', 'ml'],
|
|
7714
|
-
my: ['mt', 'mb'],
|
|
7664
|
+
mx: ['ms', 'me', 'mr', 'ml'],
|
|
7665
|
+
my: ['mbs', 'mbe', 'mt', 'mb'],
|
|
7715
7666
|
size: ['w', 'h'],
|
|
7716
7667
|
'font-size': ['leading'],
|
|
7717
7668
|
'fvn-normal': ['fvn-ordinal', 'fvn-slashed-zero', 'fvn-figure', 'fvn-spacing', 'fvn-fraction'],
|
|
@@ -7730,19 +7681,19 @@ const getDefaultConfig = () => {
|
|
|
7730
7681
|
'rounded-l': ['rounded-tl', 'rounded-bl'],
|
|
7731
7682
|
'border-spacing': ['border-spacing-x', 'border-spacing-y'],
|
|
7732
7683
|
'border-w': ['border-w-x', 'border-w-y', 'border-w-s', 'border-w-e', 'border-w-bs', 'border-w-be', 'border-w-t', 'border-w-r', 'border-w-b', 'border-w-l'],
|
|
7733
|
-
'border-w-x': ['border-w-r', 'border-w-l'],
|
|
7734
|
-
'border-w-y': ['border-w-t', 'border-w-b'],
|
|
7684
|
+
'border-w-x': ['border-w-s', 'border-w-e', 'border-w-r', 'border-w-l'],
|
|
7685
|
+
'border-w-y': ['border-w-bs', 'border-w-be', 'border-w-t', 'border-w-b'],
|
|
7735
7686
|
'border-color': ['border-color-x', 'border-color-y', 'border-color-s', 'border-color-e', 'border-color-bs', 'border-color-be', 'border-color-t', 'border-color-r', 'border-color-b', 'border-color-l'],
|
|
7736
|
-
'border-color-x': ['border-color-r', 'border-color-l'],
|
|
7737
|
-
'border-color-y': ['border-color-t', 'border-color-b'],
|
|
7687
|
+
'border-color-x': ['border-color-s', 'border-color-e', 'border-color-r', 'border-color-l'],
|
|
7688
|
+
'border-color-y': ['border-color-bs', 'border-color-be', 'border-color-t', 'border-color-b'],
|
|
7738
7689
|
translate: ['translate-x', 'translate-y', 'translate-none'],
|
|
7739
7690
|
'translate-none': ['translate', 'translate-x', 'translate-y', 'translate-z'],
|
|
7740
7691
|
'scroll-m': ['scroll-mx', 'scroll-my', 'scroll-ms', 'scroll-me', 'scroll-mbs', 'scroll-mbe', 'scroll-mt', 'scroll-mr', 'scroll-mb', 'scroll-ml'],
|
|
7741
|
-
'scroll-mx': ['scroll-mr', 'scroll-ml'],
|
|
7742
|
-
'scroll-my': ['scroll-mt', 'scroll-mb'],
|
|
7692
|
+
'scroll-mx': ['scroll-ms', 'scroll-me', 'scroll-mr', 'scroll-ml'],
|
|
7693
|
+
'scroll-my': ['scroll-mbs', 'scroll-mbe', 'scroll-mt', 'scroll-mb'],
|
|
7743
7694
|
'scroll-p': ['scroll-px', 'scroll-py', 'scroll-ps', 'scroll-pe', 'scroll-pbs', 'scroll-pbe', 'scroll-pt', 'scroll-pr', 'scroll-pb', 'scroll-pl'],
|
|
7744
|
-
'scroll-px': ['scroll-pr', 'scroll-pl'],
|
|
7745
|
-
'scroll-py': ['scroll-pt', 'scroll-pb'],
|
|
7695
|
+
'scroll-px': ['scroll-ps', 'scroll-pe', 'scroll-pr', 'scroll-pl'],
|
|
7696
|
+
'scroll-py': ['scroll-pbs', 'scroll-pbe', 'scroll-pt', 'scroll-pb'],
|
|
7746
7697
|
touch: ['touch-x', 'touch-y', 'touch-pz'],
|
|
7747
7698
|
'touch-x': ['touch'],
|
|
7748
7699
|
'touch-y': ['touch'],
|
|
@@ -7751,485 +7702,684 @@ const getDefaultConfig = () => {
|
|
|
7751
7702
|
conflictingClassGroupModifiers: {
|
|
7752
7703
|
'font-size': ['leading']
|
|
7753
7704
|
},
|
|
7754
|
-
|
|
7755
|
-
|
|
7705
|
+
postfixLookupClassGroups: ['container-type'],
|
|
7706
|
+
orderSensitiveModifiers: ['*', '**', 'after', 'backdrop', 'before', 'details-content', 'file', 'first-letter', 'first-line', 'marker', 'placeholder', 'selection']
|
|
7707
|
+
};
|
|
7708
|
+
};
|
|
7709
|
+
const twMerge = /*#__PURE__*/createTailwindMerge(getDefaultConfig);
|
|
7710
|
+
|
|
7711
|
+
function cn(...inputs) {
|
|
7712
|
+
return twMerge(clsx(inputs));
|
|
7713
|
+
}
|
|
7714
|
+
|
|
7715
|
+
/**
|
|
7716
|
+
* Get icon for tenant type
|
|
7717
|
+
*/
|
|
7718
|
+
function getTenantIcon(type) {
|
|
7719
|
+
switch (type) {
|
|
7720
|
+
case "organization":
|
|
7721
|
+
return (jsxRuntime.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 21V5a2 2 0 00-2-2H7a2 2 0 00-2 2v16m14 0h2m-2 0h-5m-9 0H3m2 0h5M9 7h1m-1 4h1m4-4h1m-1 4h1m-5 10v-5a1 1 0 011-1h2a1 1 0 011 1v5m-4 0h4" }) }));
|
|
7722
|
+
case "project":
|
|
7723
|
+
return (jsxRuntime.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3 7v10a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-6l-2-2H5a2 2 0 00-2 2z" }) }));
|
|
7724
|
+
case "user":
|
|
7725
|
+
return (jsxRuntime.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z" }) }));
|
|
7726
|
+
case "platform":
|
|
7727
|
+
return (jsxRuntime.jsx("svg", { className: "w-3 h-3", fill: "none", stroke: "currentColor", viewBox: "0 0 24 24", "aria-hidden": "true", children: jsxRuntime.jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M3.055 11H5a2 2 0 012 2v1a2 2 0 002 2 2 2 0 012 2v2.945M8 3.935V5.5A2.5 2.5 0 0010.5 8h.5a2 2 0 012 2 2 2 0 104 0 2 2 0 012-2h1.064M15 20.488V18a2 2 0 012-2h3.064M21 12a9 9 0 11-18 0 9 9 0 0118 0z" }) }));
|
|
7728
|
+
default:
|
|
7729
|
+
return null;
|
|
7730
|
+
}
|
|
7731
|
+
}
|
|
7732
|
+
/**
|
|
7733
|
+
* Get badge variant based on tenant type
|
|
7734
|
+
*/
|
|
7735
|
+
function getTenantBadgeVariant(type) {
|
|
7736
|
+
switch (type) {
|
|
7737
|
+
case "organization":
|
|
7738
|
+
return "default";
|
|
7739
|
+
case "project":
|
|
7740
|
+
return "secondary";
|
|
7741
|
+
case "user":
|
|
7742
|
+
return "default";
|
|
7743
|
+
case "platform":
|
|
7744
|
+
return "default";
|
|
7745
|
+
default:
|
|
7746
|
+
return "secondary";
|
|
7747
|
+
}
|
|
7748
|
+
}
|
|
7749
|
+
/**
|
|
7750
|
+
* TenantBadge displays tenant information in a compact badge format
|
|
7751
|
+
* Renders as a clickable link if tenantLinkResolver is provided and returns a URL
|
|
7752
|
+
*/
|
|
7753
|
+
function TenantBadge({ tenant, tenantLinkResolver, className = "", size = "default", }) {
|
|
7754
|
+
const icon = getTenantIcon(tenant.type);
|
|
7755
|
+
const variant = getTenantBadgeVariant(tenant.type);
|
|
7756
|
+
const url = tenantLinkResolver?.(tenant);
|
|
7757
|
+
const badgeContent = (jsxRuntime.jsxs(Badge, { variant: variant, className: cn("inline-flex items-center gap-1 whitespace-nowrap", size === "compact" ? "text-xs h-4 py-0 px-1.5" : "text-xs h-5 px-2", url && "cursor-pointer hover:opacity-80 transition-opacity", className), children: [icon, jsxRuntime.jsx("span", { className: "font-medium capitalize", children: tenant.type }), tenant.type !== "platform" && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "text-muted-foreground", children: "/" }), jsxRuntime.jsx("span", { children: tenant.name })] }))] }));
|
|
7758
|
+
if (url) {
|
|
7759
|
+
return (jsxRuntime.jsx("a", { href: url, className: "no-underline", onClick: (e) => e.stopPropagation(), title: `View ${tenant.type}: ${tenant.name}`, children: badgeContent }));
|
|
7760
|
+
}
|
|
7761
|
+
return badgeContent;
|
|
7762
|
+
}
|
|
7763
|
+
|
|
7764
|
+
/**
|
|
7765
|
+
* Extract tenant information from audit event annotations if present
|
|
7766
|
+
* Expected annotations: tenant.type and tenant.name
|
|
7767
|
+
*/
|
|
7768
|
+
function extractTenantFromAnnotations(event) {
|
|
7769
|
+
const annotations = event.annotations;
|
|
7770
|
+
if (!annotations)
|
|
7771
|
+
return undefined;
|
|
7772
|
+
const tenantType = annotations["tenant.type"];
|
|
7773
|
+
const tenantName = annotations["tenant.name"];
|
|
7774
|
+
if (tenantType && tenantName) {
|
|
7775
|
+
const validTypes = [
|
|
7776
|
+
"platform",
|
|
7777
|
+
"organization",
|
|
7778
|
+
"project",
|
|
7779
|
+
"user",
|
|
7780
|
+
];
|
|
7781
|
+
if (validTypes.includes(tenantType)) {
|
|
7782
|
+
return {
|
|
7783
|
+
type: tenantType,
|
|
7784
|
+
name: tenantName,
|
|
7785
|
+
};
|
|
7786
|
+
}
|
|
7787
|
+
}
|
|
7788
|
+
return undefined;
|
|
7789
|
+
}
|
|
7790
|
+
/**
|
|
7791
|
+
* AuditEventViewer displays a list of audit events with details
|
|
7792
|
+
*/
|
|
7793
|
+
function AuditEventViewer({ events, className = "", onEventSelect, tenantLinkResolver, }) {
|
|
7794
|
+
const [selectedEvent, setSelectedEvent] = React.useState(null);
|
|
7795
|
+
const [expandedEvents, setExpandedEvents] = React.useState(new Set());
|
|
7796
|
+
const toggleEventExpansion = (auditId) => {
|
|
7797
|
+
const newExpanded = new Set(expandedEvents);
|
|
7798
|
+
if (expandedEvents.has(auditId)) {
|
|
7799
|
+
newExpanded.delete(auditId);
|
|
7800
|
+
}
|
|
7801
|
+
else {
|
|
7802
|
+
newExpanded.add(auditId);
|
|
7803
|
+
}
|
|
7804
|
+
setExpandedEvents(newExpanded);
|
|
7805
|
+
};
|
|
7806
|
+
const handleEventClick = (event) => {
|
|
7807
|
+
setSelectedEvent(event);
|
|
7808
|
+
if (onEventSelect) {
|
|
7809
|
+
onEventSelect(event);
|
|
7810
|
+
}
|
|
7811
|
+
};
|
|
7812
|
+
const formatTimestamp = (timestamp) => {
|
|
7813
|
+
if (!timestamp)
|
|
7814
|
+
return "N/A";
|
|
7815
|
+
try {
|
|
7816
|
+
return format(new Date(timestamp), "yyyy-MM-dd HH:mm:ss");
|
|
7817
|
+
}
|
|
7818
|
+
catch {
|
|
7819
|
+
return timestamp;
|
|
7820
|
+
}
|
|
7821
|
+
};
|
|
7822
|
+
const getVerbBadgeVariant = (verb) => {
|
|
7823
|
+
switch (verb?.toLowerCase()) {
|
|
7824
|
+
case "create":
|
|
7825
|
+
return "success";
|
|
7826
|
+
case "update":
|
|
7827
|
+
case "patch":
|
|
7828
|
+
return "warning";
|
|
7829
|
+
case "delete":
|
|
7830
|
+
return "destructive";
|
|
7831
|
+
case "get":
|
|
7832
|
+
case "list":
|
|
7833
|
+
case "watch":
|
|
7834
|
+
return "default";
|
|
7835
|
+
default:
|
|
7836
|
+
return "secondary";
|
|
7837
|
+
}
|
|
7838
|
+
};
|
|
7839
|
+
if (events.length === 0) {
|
|
7840
|
+
return (jsxRuntime.jsx("div", { className: `bg-muted rounded-lg border border-border ${className}`, children: jsxRuntime.jsx("div", { className: "p-12 text-center text-muted-foreground text-sm", children: "No events found" }) }));
|
|
7841
|
+
}
|
|
7842
|
+
return (jsxRuntime.jsx("div", { className: `bg-muted rounded-lg border border-border ${className}`, children: jsxRuntime.jsx("div", { className: "p-4", children: events.map((event) => {
|
|
7843
|
+
const auditId = event.auditID || "";
|
|
7844
|
+
const isExpanded = expandedEvents.has(auditId);
|
|
7845
|
+
const tenant = extractTenantFromAnnotations(event);
|
|
7846
|
+
return (jsxRuntime.jsxs(card.Card, { className: `p-5 mb-3 cursor-pointer transition-all hover:border-primary/50 hover:shadow-sm hover:-translate-y-px ${selectedEvent?.auditID === auditId
|
|
7847
|
+
? "border-primary bg-primary/5 shadow-md"
|
|
7848
|
+
: ""}`, onClick: () => handleEventClick(event), children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [jsxRuntime.jsxs("div", { className: "flex gap-3 items-center flex-1", children: [jsxRuntime.jsx(Badge, { variant: getVerbBadgeVariant(event.verb), className: "px-3 py-1", children: event.verb?.toUpperCase() || "UNKNOWN" }), jsxRuntime.jsx("span", { className: "font-semibold", children: event.objectRef?.resource || "N/A" }), event.objectRef?.namespace && (jsxRuntime.jsxs("span", { className: "text-muted-foreground text-sm", children: ["ns: ", event.objectRef.namespace] })), event.objectRef?.name && (jsxRuntime.jsx("span", { className: "text-foreground/80 text-sm", children: event.objectRef.name })), tenant && (jsxRuntime.jsx(TenantBadge, { tenant: tenant, tenantLinkResolver: tenantLinkResolver, size: "compact" }))] }), jsxRuntime.jsxs("div", { className: "flex gap-4 items-center", children: [jsxRuntime.jsx("span", { className: "text-foreground/80 text-sm", children: event.user?.username || "N/A" }), jsxRuntime.jsx("span", { className: "text-muted-foreground text-sm font-mono", children: formatTimestamp(event.stageTimestamp) }), jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", onClick: (e) => {
|
|
7849
|
+
e.stopPropagation();
|
|
7850
|
+
toggleEventExpansion(auditId);
|
|
7851
|
+
}, className: "text-primary", children: isExpanded ? "▼" : "▶" })] })] }), isExpanded && (jsxRuntime.jsxs("div", { className: "mt-4 pt-4 border-t border-border", children: [jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Event Information" }), jsxRuntime.jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-2 m-0", children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Audit ID:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.auditID || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Stage:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.stage || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Level:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.level || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Request URI:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground font-mono text-sm break-all", children: event.requestURI || "N/A" }), event.userAgent && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "User Agent:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground font-mono text-sm break-all", children: event.userAgent })] })), event.sourceIPs && event.sourceIPs.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Source IPs:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.sourceIPs.join(", ") })] }))] })] }), tenant && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Tenant" }), jsxRuntime.jsx(TenantBadge, { tenant: tenant, tenantLinkResolver: tenantLinkResolver })] })), event.user && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "User Information" }), jsxRuntime.jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-2 m-0", children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Username:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.user.username || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "UID:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.user.uid || "N/A" }), event.user.groups && event.user.groups.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Groups:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.user.groups.join(", ") })] }))] })] })), event.responseStatus && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Response Status" }), jsxRuntime.jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-2 m-0", children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Code:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.responseStatus.code || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Status:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.responseStatus.status || "N/A" }), event.responseStatus.message && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Message:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.responseStatus.message })] }))] })] })), event.annotations &&
|
|
7852
|
+
Object.keys(event.annotations).length > 0 && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Annotations" }), jsxRuntime.jsx("dl", { className: "grid grid-cols-[auto_1fr] gap-2 m-0", children: Object.entries(event.annotations).map(([key, value]) => (jsxRuntime.jsxs("div", { className: "contents", children: [jsxRuntime.jsxs("dt", { className: "font-semibold text-foreground/80", children: [key, ":"] }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: value })] }, key))) })] })), event.requestObject || event.responseObject ? (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Request/Response Data" }), event.requestObject ? (jsxRuntime.jsxs("details", { className: "mt-2", children: [jsxRuntime.jsx("summary", { className: "cursor-pointer font-semibold p-2 bg-muted rounded", children: "Request Object" }), jsxRuntime.jsx("pre", { className: "mt-2 p-4 bg-muted rounded overflow-x-auto text-sm", children: JSON.stringify(event.requestObject, null, 2) })] })) : null, event.responseObject ? (jsxRuntime.jsxs("details", { className: "mt-2", children: [jsxRuntime.jsx("summary", { className: "cursor-pointer font-semibold p-2 bg-muted rounded", children: "Response Object" }), jsxRuntime.jsx("pre", { className: "mt-2 p-4 bg-muted rounded overflow-x-auto text-sm", children: JSON.stringify(event.responseObject, null, 2) })] })) : null] })) : null] }))] }, auditId));
|
|
7853
|
+
}) }) }));
|
|
7854
|
+
}
|
|
7855
|
+
|
|
7856
|
+
/**
|
|
7857
|
+
* @license lucide-react v0.577.0 - ISC
|
|
7858
|
+
*
|
|
7859
|
+
* This source code is licensed under the ISC license.
|
|
7860
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7861
|
+
*/
|
|
7862
|
+
|
|
7863
|
+
const mergeClasses = (...classes) => classes.filter((className, index, array) => {
|
|
7864
|
+
return Boolean(className) && className.trim() !== "" && array.indexOf(className) === index;
|
|
7865
|
+
}).join(" ").trim();
|
|
7866
|
+
|
|
7867
|
+
/**
|
|
7868
|
+
* @license lucide-react v0.577.0 - ISC
|
|
7869
|
+
*
|
|
7870
|
+
* This source code is licensed under the ISC license.
|
|
7871
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7872
|
+
*/
|
|
7873
|
+
|
|
7874
|
+
const toKebabCase = (string) => string.replace(/([a-z0-9])([A-Z])/g, "$1-$2").toLowerCase();
|
|
7875
|
+
|
|
7876
|
+
/**
|
|
7877
|
+
* @license lucide-react v0.577.0 - ISC
|
|
7878
|
+
*
|
|
7879
|
+
* This source code is licensed under the ISC license.
|
|
7880
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7881
|
+
*/
|
|
7882
|
+
|
|
7883
|
+
const toCamelCase = (string) => string.replace(
|
|
7884
|
+
/^([A-Z])|[\s-_]+(\w)/g,
|
|
7885
|
+
(match, p1, p2) => p2 ? p2.toUpperCase() : p1.toLowerCase()
|
|
7886
|
+
);
|
|
7887
|
+
|
|
7888
|
+
/**
|
|
7889
|
+
* @license lucide-react v0.577.0 - ISC
|
|
7890
|
+
*
|
|
7891
|
+
* This source code is licensed under the ISC license.
|
|
7892
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7893
|
+
*/
|
|
7894
|
+
|
|
7895
|
+
|
|
7896
|
+
const toPascalCase = (string) => {
|
|
7897
|
+
const camelCase = toCamelCase(string);
|
|
7898
|
+
return camelCase.charAt(0).toUpperCase() + camelCase.slice(1);
|
|
7899
|
+
};
|
|
7900
|
+
|
|
7901
|
+
/**
|
|
7902
|
+
* @license lucide-react v0.577.0 - ISC
|
|
7903
|
+
*
|
|
7904
|
+
* This source code is licensed under the ISC license.
|
|
7905
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7906
|
+
*/
|
|
7907
|
+
|
|
7908
|
+
var defaultAttributes = {
|
|
7909
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7910
|
+
width: 24,
|
|
7911
|
+
height: 24,
|
|
7912
|
+
viewBox: "0 0 24 24",
|
|
7913
|
+
fill: "none",
|
|
7914
|
+
stroke: "currentColor",
|
|
7915
|
+
strokeWidth: 2,
|
|
7916
|
+
strokeLinecap: "round",
|
|
7917
|
+
strokeLinejoin: "round"
|
|
7918
|
+
};
|
|
7919
|
+
|
|
7920
|
+
/**
|
|
7921
|
+
* @license lucide-react v0.577.0 - ISC
|
|
7922
|
+
*
|
|
7923
|
+
* This source code is licensed under the ISC license.
|
|
7924
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7925
|
+
*/
|
|
7926
|
+
|
|
7927
|
+
const hasA11yProp = (props) => {
|
|
7928
|
+
for (const prop in props) {
|
|
7929
|
+
if (prop.startsWith("aria-") || prop === "role" || prop === "title") {
|
|
7930
|
+
return true;
|
|
7931
|
+
}
|
|
7932
|
+
}
|
|
7933
|
+
return false;
|
|
7934
|
+
};
|
|
7935
|
+
|
|
7936
|
+
/**
|
|
7937
|
+
* @license lucide-react v0.577.0 - ISC
|
|
7938
|
+
*
|
|
7939
|
+
* This source code is licensed under the ISC license.
|
|
7940
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7941
|
+
*/
|
|
7942
|
+
|
|
7943
|
+
|
|
7944
|
+
const Icon = React.forwardRef(
|
|
7945
|
+
({
|
|
7946
|
+
color = "currentColor",
|
|
7947
|
+
size = 24,
|
|
7948
|
+
strokeWidth = 2,
|
|
7949
|
+
absoluteStrokeWidth,
|
|
7950
|
+
className = "",
|
|
7951
|
+
children,
|
|
7952
|
+
iconNode,
|
|
7953
|
+
...rest
|
|
7954
|
+
}, ref) => React.createElement(
|
|
7955
|
+
"svg",
|
|
7956
|
+
{
|
|
7957
|
+
ref,
|
|
7958
|
+
...defaultAttributes,
|
|
7959
|
+
width: size,
|
|
7960
|
+
height: size,
|
|
7961
|
+
stroke: color,
|
|
7962
|
+
strokeWidth: absoluteStrokeWidth ? Number(strokeWidth) * 24 / Number(size) : strokeWidth,
|
|
7963
|
+
className: mergeClasses("lucide", className),
|
|
7964
|
+
...!children && !hasA11yProp(rest) && { "aria-hidden": "true" },
|
|
7965
|
+
...rest
|
|
7966
|
+
},
|
|
7967
|
+
[
|
|
7968
|
+
...iconNode.map(([tag, attrs]) => React.createElement(tag, attrs)),
|
|
7969
|
+
...Array.isArray(children) ? children : [children]
|
|
7970
|
+
]
|
|
7971
|
+
)
|
|
7972
|
+
);
|
|
7973
|
+
|
|
7974
|
+
/**
|
|
7975
|
+
* @license lucide-react v0.577.0 - ISC
|
|
7976
|
+
*
|
|
7977
|
+
* This source code is licensed under the ISC license.
|
|
7978
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7979
|
+
*/
|
|
7980
|
+
|
|
7981
|
+
|
|
7982
|
+
const createLucideIcon = (iconName, iconNode) => {
|
|
7983
|
+
const Component = React.forwardRef(
|
|
7984
|
+
({ className, ...props }, ref) => React.createElement(Icon, {
|
|
7985
|
+
ref,
|
|
7986
|
+
iconNode,
|
|
7987
|
+
className: mergeClasses(
|
|
7988
|
+
`lucide-${toKebabCase(toPascalCase(iconName))}`,
|
|
7989
|
+
`lucide-${iconName}`,
|
|
7990
|
+
className
|
|
7991
|
+
),
|
|
7992
|
+
...props
|
|
7993
|
+
})
|
|
7994
|
+
);
|
|
7995
|
+
Component.displayName = toPascalCase(iconName);
|
|
7996
|
+
return Component;
|
|
7756
7997
|
};
|
|
7757
|
-
const twMerge = /*#__PURE__*/createTailwindMerge(getDefaultConfig);
|
|
7758
7998
|
|
|
7759
|
-
|
|
7760
|
-
|
|
7761
|
-
|
|
7999
|
+
/**
|
|
8000
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8001
|
+
*
|
|
8002
|
+
* This source code is licensed under the ISC license.
|
|
8003
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8004
|
+
*/
|
|
8005
|
+
|
|
8006
|
+
|
|
8007
|
+
const __iconNode$o = [
|
|
8008
|
+
[
|
|
8009
|
+
"path",
|
|
8010
|
+
{
|
|
8011
|
+
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",
|
|
8012
|
+
key: "169zse"
|
|
8013
|
+
}
|
|
8014
|
+
]
|
|
8015
|
+
];
|
|
8016
|
+
const Activity = createLucideIcon("activity", __iconNode$o);
|
|
7762
8017
|
|
|
7763
8018
|
/**
|
|
7764
|
-
*
|
|
7765
|
-
*
|
|
8019
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8020
|
+
*
|
|
8021
|
+
* This source code is licensed under the ISC license.
|
|
8022
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7766
8023
|
*/
|
|
7767
|
-
|
|
7768
|
-
|
|
7769
|
-
|
|
7770
|
-
|
|
7771
|
-
|
|
7772
|
-
|
|
7773
|
-
|
|
7774
|
-
|
|
7775
|
-
|
|
7776
|
-
|
|
7777
|
-
|
|
7778
|
-
|
|
7779
|
-
|
|
7780
|
-
|
|
7781
|
-
|
|
7782
|
-
|
|
7783
|
-
|
|
7784
|
-
|
|
7785
|
-
|
|
7786
|
-
|
|
7787
|
-
|
|
7788
|
-
|
|
7789
|
-
|
|
7790
|
-
|
|
7791
|
-
|
|
7792
|
-
|
|
7793
|
-
|
|
7794
|
-
|
|
7795
|
-
|
|
7796
|
-
|
|
7797
|
-
|
|
7798
|
-
|
|
7799
|
-
|
|
7800
|
-
|
|
7801
|
-
|
|
7802
|
-
|
|
7803
|
-
|
|
7804
|
-
|
|
7805
|
-
|
|
7806
|
-
|
|
7807
|
-
|
|
7808
|
-
|
|
7809
|
-
|
|
7810
|
-
|
|
7811
|
-
|
|
7812
|
-
|
|
7813
|
-
|
|
7814
|
-
|
|
7815
|
-
|
|
7816
|
-
|
|
7817
|
-
|
|
7818
|
-
|
|
7819
|
-
|
|
7820
|
-
|
|
7821
|
-
|
|
8024
|
+
|
|
8025
|
+
|
|
8026
|
+
const __iconNode$n = [
|
|
8027
|
+
["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
|
|
8028
|
+
[
|
|
8029
|
+
"path",
|
|
8030
|
+
{
|
|
8031
|
+
d: "M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326",
|
|
8032
|
+
key: "11g9vi"
|
|
8033
|
+
}
|
|
8034
|
+
]
|
|
8035
|
+
];
|
|
8036
|
+
const Bell = createLucideIcon("bell", __iconNode$n);
|
|
8037
|
+
|
|
8038
|
+
/**
|
|
8039
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8040
|
+
*
|
|
8041
|
+
* This source code is licensed under the ISC license.
|
|
8042
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8043
|
+
*/
|
|
8044
|
+
|
|
8045
|
+
|
|
8046
|
+
const __iconNode$m = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
|
|
8047
|
+
const Check = createLucideIcon("check", __iconNode$m);
|
|
8048
|
+
|
|
8049
|
+
/**
|
|
8050
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8051
|
+
*
|
|
8052
|
+
* This source code is licensed under the ISC license.
|
|
8053
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8054
|
+
*/
|
|
8055
|
+
|
|
8056
|
+
|
|
8057
|
+
const __iconNode$l = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
|
|
8058
|
+
const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
|
|
8059
|
+
|
|
8060
|
+
/**
|
|
8061
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8062
|
+
*
|
|
8063
|
+
* This source code is licensed under the ISC license.
|
|
8064
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8065
|
+
*/
|
|
8066
|
+
|
|
8067
|
+
|
|
8068
|
+
const __iconNode$k = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
|
|
8069
|
+
const ChevronRight = createLucideIcon("chevron-right", __iconNode$k);
|
|
8070
|
+
|
|
8071
|
+
/**
|
|
8072
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8073
|
+
*
|
|
8074
|
+
* This source code is licensed under the ISC license.
|
|
8075
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8076
|
+
*/
|
|
8077
|
+
|
|
8078
|
+
|
|
8079
|
+
const __iconNode$j = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
|
|
8080
|
+
const ChevronUp = createLucideIcon("chevron-up", __iconNode$j);
|
|
8081
|
+
|
|
8082
|
+
/**
|
|
8083
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8084
|
+
*
|
|
8085
|
+
* This source code is licensed under the ISC license.
|
|
8086
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8087
|
+
*/
|
|
8088
|
+
|
|
8089
|
+
|
|
8090
|
+
const __iconNode$i = [
|
|
8091
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
8092
|
+
["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
|
|
8093
|
+
["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
|
|
8094
|
+
];
|
|
8095
|
+
const CircleAlert = createLucideIcon("circle-alert", __iconNode$i);
|
|
8096
|
+
|
|
8097
|
+
/**
|
|
8098
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8099
|
+
*
|
|
8100
|
+
* This source code is licensed under the ISC license.
|
|
8101
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8102
|
+
*/
|
|
8103
|
+
|
|
8104
|
+
|
|
8105
|
+
const __iconNode$h = [
|
|
8106
|
+
["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
|
|
8107
|
+
["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
|
|
8108
|
+
];
|
|
8109
|
+
const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$h);
|
|
7822
8110
|
|
|
7823
8111
|
/**
|
|
7824
|
-
*
|
|
8112
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8113
|
+
*
|
|
8114
|
+
* This source code is licensed under the ISC license.
|
|
8115
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
7825
8116
|
*/
|
|
7826
|
-
function TimeRangeDropdown({ presets, selectedPreset, onPresetSelect, onCustomRangeApply, customStart: initialCustomStart, customEnd: initialCustomEnd, disabled = false, className, displayLabel, }) {
|
|
7827
|
-
const [open, setOpen] = React__namespace.useState(false);
|
|
7828
|
-
const [showCustomInputs, setShowCustomInputs] = React__namespace.useState(false);
|
|
7829
|
-
const [customStart, setCustomStart] = React__namespace.useState(initialCustomStart || '');
|
|
7830
|
-
const [customEnd, setCustomEnd] = React__namespace.useState(initialCustomEnd || '');
|
|
7831
|
-
// Update custom values when props change
|
|
7832
|
-
React__namespace.useEffect(() => {
|
|
7833
|
-
if (initialCustomStart)
|
|
7834
|
-
setCustomStart(initialCustomStart);
|
|
7835
|
-
if (initialCustomEnd)
|
|
7836
|
-
setCustomEnd(initialCustomEnd);
|
|
7837
|
-
}, [initialCustomStart, initialCustomEnd]);
|
|
7838
|
-
const selectedPresetObj = presets.find((p) => p.key === selectedPreset);
|
|
7839
|
-
const label$1 = displayLabel || selectedPresetObj?.label || 'Select time range';
|
|
7840
|
-
const handlePresetClick = (presetKey) => {
|
|
7841
|
-
onPresetSelect(presetKey);
|
|
7842
|
-
setShowCustomInputs(false);
|
|
7843
|
-
setOpen(false);
|
|
7844
|
-
};
|
|
7845
|
-
const handleCustomClick = () => {
|
|
7846
|
-
setShowCustomInputs(true);
|
|
7847
|
-
};
|
|
7848
|
-
const handleCustomApply = () => {
|
|
7849
|
-
if (customStart && customEnd) {
|
|
7850
|
-
onCustomRangeApply(customStart, customEnd);
|
|
7851
|
-
setShowCustomInputs(false);
|
|
7852
|
-
setOpen(false);
|
|
7853
|
-
}
|
|
7854
|
-
};
|
|
7855
|
-
const handleCustomCancel = () => {
|
|
7856
|
-
setShowCustomInputs(false);
|
|
7857
|
-
};
|
|
7858
|
-
return (jsxRuntime.jsxs(Popover__namespace.Root, { open: open, onOpenChange: setOpen, 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-md border border-input bg-background px-2 text-xs ring-offset-background', 'hover:bg-accent hover:text-accent-foreground', 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', 'disabled:cursor-not-allowed disabled:opacity-50', className), children: [jsxRuntime.jsx(Calendar, { className: "h-4 w-4 text-muted-foreground" }), jsxRuntime.jsx("span", { className: "whitespace-nowrap", children: label$1 }), jsxRuntime.jsx(ChevronDown, { className: "h-4 w-4 text-muted-foreground" })] }) }), jsxRuntime.jsx(Popover__namespace.Portal, { children: jsxRuntime.jsx(Popover__namespace.Content, { className: cn('z-50 min-w-[200px] 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: "end", children: !showCustomInputs ? (jsxRuntime.jsxs("div", { className: "p-1", children: [presets.map((preset) => (jsxRuntime.jsx("button", { type: "button", onClick: () => handlePresetClick(preset.key), className: cn('relative flex w-full cursor-pointer select-none items-center rounded-sm px-3 py-2 text-sm outline-none', 'hover:bg-accent hover:text-accent-foreground', selectedPreset === preset.key && 'bg-accent text-accent-foreground font-medium'), children: preset.label }, preset.key))), jsxRuntime.jsx("div", { className: "my-1 h-px bg-border" }), jsxRuntime.jsx("button", { type: "button", onClick: handleCustomClick, className: cn('relative flex w-full cursor-pointer select-none items-center rounded-sm px-3 py-2 text-sm outline-none', 'hover:bg-accent hover:text-accent-foreground', selectedPreset === 'custom' && 'bg-accent text-accent-foreground font-medium'), children: "Custom range..." })] })) : (jsxRuntime.jsxs("div", { className: "p-4 min-w-[280px]", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [jsxRuntime.jsx(label.Label, { htmlFor: "time-range-start", className: "text-xs text-muted-foreground font-semibold uppercase tracking-tight", children: "Start" }), jsxRuntime.jsx(input.Input, { id: "time-range-start", type: "datetime-local", value: customStart, onChange: (e) => setCustomStart(e.target.value), className: "w-full", disabled: disabled })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-1.5", children: [jsxRuntime.jsx(label.Label, { htmlFor: "time-range-end", className: "text-xs text-muted-foreground font-semibold uppercase tracking-tight", children: "End" }), jsxRuntime.jsx(input.Input, { id: "time-range-end", type: "datetime-local", value: customEnd, onChange: (e) => setCustomEnd(e.target.value), className: "w-full", disabled: disabled })] })] }), jsxRuntime.jsxs("div", { className: "flex justify-end gap-2 mt-4 pt-3 border-t border-border", children: [jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "small", onClick: handleCustomCancel, children: "Back" }), jsxRuntime.jsx(button.Button, { htmlType: "button", size: "small", onClick: handleCustomApply, disabled: !customStart || !customEnd, children: "Apply" })] })] })) }) })] }));
|
|
7859
|
-
}
|
|
7860
8117
|
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
getValue: () => ({
|
|
7866
|
-
start: formatISO(subMinutes(new Date())),
|
|
7867
|
-
end: formatISO(new Date()),
|
|
7868
|
-
}),
|
|
7869
|
-
},
|
|
7870
|
-
{
|
|
7871
|
-
key: 'last1hour',
|
|
7872
|
-
label: 'Last hour',
|
|
7873
|
-
getValue: () => ({
|
|
7874
|
-
start: formatISO(subHours(new Date(), 1)),
|
|
7875
|
-
end: formatISO(new Date()),
|
|
7876
|
-
}),
|
|
7877
|
-
},
|
|
7878
|
-
{
|
|
7879
|
-
key: 'last6hours',
|
|
7880
|
-
label: 'Last 6 hours',
|
|
7881
|
-
getValue: () => ({
|
|
7882
|
-
start: formatISO(subHours(new Date(), 6)),
|
|
7883
|
-
end: formatISO(new Date()),
|
|
7884
|
-
}),
|
|
7885
|
-
},
|
|
7886
|
-
{
|
|
7887
|
-
key: 'last24hours',
|
|
7888
|
-
label: 'Last 24 hours',
|
|
7889
|
-
getValue: () => ({
|
|
7890
|
-
start: formatISO(subHours(new Date(), 24)),
|
|
7891
|
-
end: formatISO(new Date()),
|
|
7892
|
-
}),
|
|
7893
|
-
},
|
|
7894
|
-
{
|
|
7895
|
-
key: 'last7days',
|
|
7896
|
-
label: 'Last 7 days',
|
|
7897
|
-
getValue: () => ({
|
|
7898
|
-
start: formatISO(subDays(new Date(), 7)),
|
|
7899
|
-
end: formatISO(new Date()),
|
|
7900
|
-
}),
|
|
7901
|
-
},
|
|
7902
|
-
{
|
|
7903
|
-
key: 'last30days',
|
|
7904
|
-
label: 'Last 30 days',
|
|
7905
|
-
getValue: () => ({
|
|
7906
|
-
start: formatISO(subDays(new Date(), 30)),
|
|
7907
|
-
end: formatISO(new Date()),
|
|
7908
|
-
}),
|
|
7909
|
-
},
|
|
8118
|
+
|
|
8119
|
+
const __iconNode$g = [
|
|
8120
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
8121
|
+
["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
|
|
7910
8122
|
];
|
|
7911
|
-
|
|
7912
|
-
|
|
8123
|
+
const CircleCheck = createLucideIcon("circle-check", __iconNode$g);
|
|
8124
|
+
|
|
7913
8125
|
/**
|
|
7914
|
-
*
|
|
7915
|
-
|
|
7916
|
-
|
|
7917
|
-
|
|
7918
|
-
|
|
7919
|
-
|
|
7920
|
-
|
|
7921
|
-
|
|
7922
|
-
|
|
7923
|
-
|
|
7924
|
-
}
|
|
7925
|
-
|
|
7926
|
-
|
|
7927
|
-
const [filters, setFilters] = React.useState({
|
|
7928
|
-
verb: '',
|
|
7929
|
-
resourceType: '',
|
|
7930
|
-
namespace: '',
|
|
7931
|
-
resourceName: '',
|
|
7932
|
-
username: '',
|
|
7933
|
-
});
|
|
7934
|
-
const [limit, setLimit] = React.useState(initialLimit);
|
|
7935
|
-
const [advancedFilter, setAdvancedFilter] = React.useState('');
|
|
7936
|
-
const [useAdvancedFilter, setUseAdvancedFilter] = React.useState(false);
|
|
7937
|
-
// Time range state
|
|
7938
|
-
const [selectedPreset, setSelectedPreset] = React.useState('last24hours');
|
|
7939
|
-
const [timeRange, setTimeRange] = React.useState(null);
|
|
7940
|
-
const [customStart, setCustomStart] = React.useState(() => formatDatetimeLocal$4(formatISO(subDays(new Date(), 1))));
|
|
7941
|
-
const [customEnd, setCustomEnd] = React.useState(() => formatDatetimeLocal$4(formatISO(new Date())));
|
|
7942
|
-
// Fetch facets for dynamic filter options
|
|
7943
|
-
const { verbs, resources, namespaces, usernames, isLoading: facetsLoading, error: facetsError } = useAuditLogFacets(client, timeRange);
|
|
7944
|
-
// Log facets error for debugging
|
|
7945
|
-
if (facetsError) {
|
|
7946
|
-
console.error('Failed to load audit log facets:', facetsError);
|
|
7947
|
-
}
|
|
7948
|
-
// Refs for debouncing
|
|
7949
|
-
const debounceTimerRef = React.useRef(null);
|
|
7950
|
-
const isInitialMount = React.useRef(true);
|
|
7951
|
-
// Initialize with default time range and trigger initial query
|
|
7952
|
-
React.useEffect(() => {
|
|
7953
|
-
const defaultRange = TIME_PRESETS$3.find(p => p.key === 'last24hours')?.getValue();
|
|
7954
|
-
if (defaultRange) {
|
|
7955
|
-
setTimeRange(defaultRange);
|
|
7956
|
-
}
|
|
7957
|
-
}, []);
|
|
7958
|
-
const generateCEL = React.useCallback(() => {
|
|
7959
|
-
const parts = [];
|
|
7960
|
-
if (filters.verb) {
|
|
7961
|
-
parts.push(`verb == "${filters.verb}"`);
|
|
7962
|
-
}
|
|
7963
|
-
if (filters.resourceType) {
|
|
7964
|
-
parts.push(`objectRef.resource == "${filters.resourceType}"`);
|
|
7965
|
-
}
|
|
7966
|
-
if (filters.namespace) {
|
|
7967
|
-
parts.push(`objectRef.namespace == "${filters.namespace}"`);
|
|
7968
|
-
}
|
|
7969
|
-
if (filters.resourceName) {
|
|
7970
|
-
parts.push(`objectRef.name.contains("${filters.resourceName}")`);
|
|
7971
|
-
}
|
|
7972
|
-
if (filters.username) {
|
|
7973
|
-
parts.push(`user.username.contains("${filters.username}")`);
|
|
7974
|
-
}
|
|
7975
|
-
return parts.join(' && ');
|
|
7976
|
-
}, [filters]);
|
|
7977
|
-
// Execute query when filters change (with debouncing for text inputs)
|
|
7978
|
-
const executeQuery = React.useCallback(() => {
|
|
7979
|
-
if (!timeRange || disabled)
|
|
7980
|
-
return;
|
|
7981
|
-
const filter = useAdvancedFilter ? advancedFilter : generateCEL();
|
|
7982
|
-
onFilterChange({
|
|
7983
|
-
filter,
|
|
7984
|
-
limit,
|
|
7985
|
-
startTime: timeRange.start,
|
|
7986
|
-
endTime: timeRange.end
|
|
7987
|
-
});
|
|
7988
|
-
}, [useAdvancedFilter, advancedFilter, generateCEL, onFilterChange, limit, timeRange, disabled]);
|
|
7989
|
-
// Auto-execute query when dropdown filters or time range change (immediate)
|
|
7990
|
-
React.useEffect(() => {
|
|
7991
|
-
// Skip the initial mount - we want to wait for timeRange to be set
|
|
7992
|
-
if (isInitialMount.current) {
|
|
7993
|
-
isInitialMount.current = false;
|
|
7994
|
-
return;
|
|
7995
|
-
}
|
|
7996
|
-
// Clear any pending debounced query
|
|
7997
|
-
if (debounceTimerRef.current) {
|
|
7998
|
-
clearTimeout(debounceTimerRef.current);
|
|
7999
|
-
}
|
|
8000
|
-
executeQuery();
|
|
8001
|
-
}, [filters.verb, filters.resourceType, timeRange, limit, useAdvancedFilter]);
|
|
8002
|
-
// Auto-execute query when text filters change (debounced)
|
|
8003
|
-
React.useEffect(() => {
|
|
8004
|
-
if (isInitialMount.current || !timeRange)
|
|
8005
|
-
return;
|
|
8006
|
-
// Clear previous timer
|
|
8007
|
-
if (debounceTimerRef.current) {
|
|
8008
|
-
clearTimeout(debounceTimerRef.current);
|
|
8009
|
-
}
|
|
8010
|
-
// Set new debounced timer
|
|
8011
|
-
debounceTimerRef.current = setTimeout(() => {
|
|
8012
|
-
executeQuery();
|
|
8013
|
-
}, DEBOUNCE_DELAY);
|
|
8014
|
-
return () => {
|
|
8015
|
-
if (debounceTimerRef.current) {
|
|
8016
|
-
clearTimeout(debounceTimerRef.current);
|
|
8017
|
-
}
|
|
8018
|
-
};
|
|
8019
|
-
}, [filters.namespace, filters.resourceName, filters.username, advancedFilter]);
|
|
8020
|
-
const handleFilterChange = React.useCallback((field, value) => {
|
|
8021
|
-
setFilters(prev => ({ ...prev, [field]: value }));
|
|
8022
|
-
}, []);
|
|
8023
|
-
const handleTimePresetSelect = React.useCallback((presetKey) => {
|
|
8024
|
-
const preset = TIME_PRESETS$3.find(p => p.key === presetKey);
|
|
8025
|
-
if (preset) {
|
|
8026
|
-
setSelectedPreset(presetKey);
|
|
8027
|
-
setTimeRange(preset.getValue());
|
|
8028
|
-
}
|
|
8029
|
-
}, []);
|
|
8030
|
-
const handleCustomRangeApply = React.useCallback((start, end) => {
|
|
8031
|
-
setSelectedPreset('custom');
|
|
8032
|
-
setCustomStart(start);
|
|
8033
|
-
setCustomEnd(end);
|
|
8034
|
-
setTimeRange({
|
|
8035
|
-
start: new Date(start).toISOString(),
|
|
8036
|
-
end: new Date(end).toISOString(),
|
|
8037
|
-
});
|
|
8038
|
-
}, []);
|
|
8039
|
-
const handleLimitChange = React.useCallback((newLimit) => {
|
|
8040
|
-
const validLimit = Math.min(Math.max(1, newLimit), 1000);
|
|
8041
|
-
setLimit(validLimit);
|
|
8042
|
-
}, []);
|
|
8043
|
-
const handleAdvancedToggle = React.useCallback(() => {
|
|
8044
|
-
if (!isAdvancedExpanded) {
|
|
8045
|
-
// When expanding, populate advanced filter with generated CEL
|
|
8046
|
-
setAdvancedFilter(generateCEL());
|
|
8047
|
-
}
|
|
8048
|
-
setIsAdvancedExpanded(!isAdvancedExpanded);
|
|
8049
|
-
}, [isAdvancedExpanded, generateCEL]);
|
|
8050
|
-
const handleUseAdvancedChange = React.useCallback((checked) => {
|
|
8051
|
-
setUseAdvancedFilter(checked === true);
|
|
8052
|
-
}, []);
|
|
8053
|
-
// Get display label for time range
|
|
8054
|
-
const getTimeRangeLabel = () => {
|
|
8055
|
-
if (selectedPreset === 'custom') {
|
|
8056
|
-
if (timeRange?.start && timeRange?.end) {
|
|
8057
|
-
const start = new Date(timeRange.start);
|
|
8058
|
-
const end = new Date(timeRange.end);
|
|
8059
|
-
return `${start.toLocaleDateString()} - ${end.toLocaleDateString()}`;
|
|
8060
|
-
}
|
|
8061
|
-
return 'Custom';
|
|
8062
|
-
}
|
|
8063
|
-
const preset = TIME_PRESETS$3.find(p => p.key === selectedPreset);
|
|
8064
|
-
return preset?.label || 'Select time range';
|
|
8065
|
-
};
|
|
8066
|
-
return (jsxRuntime.jsxs("div", { className: `mb-6 pb-6 border-b border-border ${className}`, children: [jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-4 items-end", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Action" }), jsxRuntime.jsx(Combobox, { options: verbs
|
|
8067
|
-
.filter(facet => facet.value)
|
|
8068
|
-
.map(facet => ({
|
|
8069
|
-
value: facet.value,
|
|
8070
|
-
label: facet.value,
|
|
8071
|
-
count: facet.count,
|
|
8072
|
-
})), value: filters.verb, onValueChange: (value) => handleFilterChange('verb', value), placeholder: "All", searchPlaceholder: "Search actions...", allOptionLabel: "All", disabled: disabled || useAdvancedFilter, loading: facetsLoading, className: "min-w-[130px]" })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Resource" }), jsxRuntime.jsx(Combobox, { options: resources
|
|
8073
|
-
.filter(facet => facet.value)
|
|
8074
|
-
.map(facet => ({
|
|
8075
|
-
value: facet.value,
|
|
8076
|
-
label: facet.value,
|
|
8077
|
-
count: facet.count,
|
|
8078
|
-
})), value: filters.resourceType, onValueChange: (value) => handleFilterChange('resourceType', value), placeholder: "All", searchPlaceholder: "Search resources...", allOptionLabel: "All", disabled: disabled || useAdvancedFilter, loading: facetsLoading, className: "min-w-[130px]" })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Namespace" }), jsxRuntime.jsx(Combobox, { options: namespaces
|
|
8079
|
-
.filter(facet => facet.value)
|
|
8080
|
-
.map(facet => ({
|
|
8081
|
-
value: facet.value,
|
|
8082
|
-
label: facet.value,
|
|
8083
|
-
count: facet.count,
|
|
8084
|
-
})), value: filters.namespace, onValueChange: (value) => handleFilterChange('namespace', value), placeholder: "All", searchPlaceholder: "Search namespaces...", allOptionLabel: "All", disabled: disabled || useAdvancedFilter, loading: facetsLoading, className: "min-w-[130px]" })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "User" }), jsxRuntime.jsx(Combobox, { options: usernames
|
|
8085
|
-
.filter(facet => facet.value)
|
|
8086
|
-
.map(facet => ({
|
|
8087
|
-
value: facet.value,
|
|
8088
|
-
label: facet.value,
|
|
8089
|
-
count: facet.count,
|
|
8090
|
-
})), value: filters.username, onValueChange: (value) => handleFilterChange('username', value), placeholder: "All", searchPlaceholder: "Search users...", allOptionLabel: "All", disabled: disabled || useAdvancedFilter, loading: facetsLoading, className: "min-w-[130px]" })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Name" }), jsxRuntime.jsx(input.Input, { type: "text", value: filters.resourceName, onChange: (e) => handleFilterChange('resourceName', e.target.value), placeholder: "Filter by name...", className: "min-w-[140px]", disabled: disabled || useAdvancedFilter })] }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Limit" }), jsxRuntime.jsx(input.Input, { type: "number", value: limit, onChange: (e) => handleLimitChange(parseInt(e.target.value) || 100), min: 1, max: 1000, className: "w-[80px]", disabled: disabled })] }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "small", className: "whitespace-nowrap text-muted-foreground hover:text-foreground", onClick: handleAdvancedToggle, "aria-expanded": isAdvancedExpanded, children: isAdvancedExpanded ? '- CEL' : '+ CEL' }), jsxRuntime.jsxs("div", { className: "flex flex-col gap-2 ml-auto", children: [jsxRuntime.jsx(label.Label, { className: "text-xs font-semibold text-muted-foreground uppercase tracking-wide", children: "Time Range" }), jsxRuntime.jsx(TimeRangeDropdown, { presets: TIME_PRESETS$3.map(p => ({ key: p.key, label: p.label })), selectedPreset: selectedPreset, onPresetSelect: handleTimePresetSelect, onCustomRangeApply: handleCustomRangeApply, customStart: customStart, customEnd: customEnd, disabled: disabled, displayLabel: getTimeRangeLabel() })] })] }), isAdvancedExpanded && (jsxRuntime.jsxs("div", { className: "mt-4 pt-4", children: [jsxRuntime.jsx(separator.Separator, { className: "mb-4" }), jsxRuntime.jsx("div", { className: "mb-3", children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(checkbox.Checkbox, { id: "use-cel-expression", checked: useAdvancedFilter, onCheckedChange: handleUseAdvancedChange, disabled: disabled }), jsxRuntime.jsx(label.Label, { htmlFor: "use-cel-expression", className: "text-sm font-medium text-foreground cursor-pointer", children: "Use CEL Expression" })] }) }), useAdvancedFilter && (jsxRuntime.jsxs("div", { className: "mt-3", children: [jsxRuntime.jsx("p", { className: "m-0 mb-2 text-sm text-muted-foreground", children: "Write your query using CEL syntax for complex filters" }), jsxRuntime.jsx(textarea.Textarea, { value: advancedFilter, onChange: (e) => setAdvancedFilter(e.target.value), placeholder: 'Example: verb == "delete" && objectRef.namespace == "production"', rows: 3, className: "w-full font-mono resize-y", disabled: disabled })] }))] }))] }));
|
|
8091
|
-
}
|
|
8126
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8127
|
+
*
|
|
8128
|
+
* This source code is licensed under the ISC license.
|
|
8129
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8130
|
+
*/
|
|
8131
|
+
|
|
8132
|
+
|
|
8133
|
+
const __iconNode$f = [
|
|
8134
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
8135
|
+
["path", { d: "m15 9-6 6", key: "1uzhvr" }],
|
|
8136
|
+
["path", { d: "m9 9 6 6", key: "z0biqf" }]
|
|
8137
|
+
];
|
|
8138
|
+
const CircleX = createLucideIcon("circle-x", __iconNode$f);
|
|
8092
8139
|
|
|
8093
8140
|
/**
|
|
8094
|
-
*
|
|
8141
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8142
|
+
*
|
|
8143
|
+
* This source code is licensed under the ISC license.
|
|
8144
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8095
8145
|
*/
|
|
8096
|
-
|
|
8097
|
-
|
|
8098
|
-
|
|
8099
|
-
|
|
8100
|
-
|
|
8101
|
-
|
|
8102
|
-
|
|
8103
|
-
|
|
8104
|
-
|
|
8105
|
-
|
|
8106
|
-
|
|
8107
|
-
|
|
8146
|
+
|
|
8147
|
+
|
|
8148
|
+
const __iconNode$e = [
|
|
8149
|
+
["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
|
|
8150
|
+
["path", { d: "M12 6v6l4 2", key: "mmk7yg" }]
|
|
8151
|
+
];
|
|
8152
|
+
const Clock = createLucideIcon("clock", __iconNode$e);
|
|
8153
|
+
|
|
8154
|
+
/**
|
|
8155
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8156
|
+
*
|
|
8157
|
+
* This source code is licensed under the ISC license.
|
|
8158
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8159
|
+
*/
|
|
8160
|
+
|
|
8161
|
+
|
|
8162
|
+
const __iconNode$d = [
|
|
8163
|
+
["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
|
|
8164
|
+
["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" }]
|
|
8165
|
+
];
|
|
8166
|
+
const Copy = createLucideIcon("copy", __iconNode$d);
|
|
8167
|
+
|
|
8168
|
+
/**
|
|
8169
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8170
|
+
*
|
|
8171
|
+
* This source code is licensed under the ISC license.
|
|
8172
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8173
|
+
*/
|
|
8174
|
+
|
|
8175
|
+
|
|
8176
|
+
const __iconNode$c = [
|
|
8177
|
+
[
|
|
8178
|
+
"path",
|
|
8179
|
+
{
|
|
8180
|
+
d: "M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0",
|
|
8181
|
+
key: "1nclc0"
|
|
8108
8182
|
}
|
|
8109
|
-
|
|
8183
|
+
],
|
|
8184
|
+
["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
|
|
8185
|
+
];
|
|
8186
|
+
const Eye = createLucideIcon("eye", __iconNode$c);
|
|
8187
|
+
|
|
8110
8188
|
/**
|
|
8111
|
-
*
|
|
8189
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8190
|
+
*
|
|
8191
|
+
* This source code is licensed under the ISC license.
|
|
8192
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8112
8193
|
*/
|
|
8113
|
-
|
|
8114
|
-
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8119
|
-
|
|
8120
|
-
|
|
8121
|
-
|
|
8122
|
-
|
|
8123
|
-
|
|
8124
|
-
|
|
8194
|
+
|
|
8195
|
+
|
|
8196
|
+
const __iconNode$b = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
|
|
8197
|
+
const LoaderCircle = createLucideIcon("loader-circle", __iconNode$b);
|
|
8198
|
+
|
|
8199
|
+
/**
|
|
8200
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8201
|
+
*
|
|
8202
|
+
* This source code is licensed under the ISC license.
|
|
8203
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8204
|
+
*/
|
|
8205
|
+
|
|
8206
|
+
|
|
8207
|
+
const __iconNode$a = [
|
|
8208
|
+
[
|
|
8209
|
+
"path",
|
|
8210
|
+
{
|
|
8211
|
+
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",
|
|
8212
|
+
key: "1a8usu"
|
|
8125
8213
|
}
|
|
8126
|
-
|
|
8214
|
+
],
|
|
8215
|
+
["path", { d: "m15 5 4 4", key: "1mk7zo" }]
|
|
8216
|
+
];
|
|
8217
|
+
const Pencil = createLucideIcon("pencil", __iconNode$a);
|
|
8218
|
+
|
|
8127
8219
|
/**
|
|
8128
|
-
*
|
|
8129
|
-
*
|
|
8220
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8221
|
+
*
|
|
8222
|
+
* This source code is licensed under the ISC license.
|
|
8223
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8130
8224
|
*/
|
|
8131
|
-
|
|
8132
|
-
|
|
8133
|
-
|
|
8134
|
-
|
|
8135
|
-
|
|
8136
|
-
|
|
8137
|
-
|
|
8225
|
+
|
|
8226
|
+
|
|
8227
|
+
const __iconNode$9 = [
|
|
8228
|
+
["path", { d: "M5 12h14", key: "1ays0h" }],
|
|
8229
|
+
["path", { d: "M12 5v14", key: "s699le" }]
|
|
8230
|
+
];
|
|
8231
|
+
const Plus = createLucideIcon("plus", __iconNode$9);
|
|
8232
|
+
|
|
8233
|
+
/**
|
|
8234
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8235
|
+
*
|
|
8236
|
+
* This source code is licensed under the ISC license.
|
|
8237
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8238
|
+
*/
|
|
8239
|
+
|
|
8240
|
+
|
|
8241
|
+
const __iconNode$8 = [
|
|
8242
|
+
["path", { d: "M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8", key: "v9h5vc" }],
|
|
8243
|
+
["path", { d: "M21 3v5h-5", key: "1q7to0" }],
|
|
8244
|
+
["path", { d: "M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16", key: "3uifl3" }],
|
|
8245
|
+
["path", { d: "M8 16H3v5", key: "1cv678" }]
|
|
8246
|
+
];
|
|
8247
|
+
const RefreshCw = createLucideIcon("refresh-cw", __iconNode$8);
|
|
8248
|
+
|
|
8249
|
+
/**
|
|
8250
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8251
|
+
*
|
|
8252
|
+
* This source code is licensed under the ISC license.
|
|
8253
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8254
|
+
*/
|
|
8255
|
+
|
|
8256
|
+
|
|
8257
|
+
const __iconNode$7 = [
|
|
8258
|
+
["path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", key: "1p45f6" }],
|
|
8259
|
+
["path", { d: "M21 3v5h-5", key: "1q7to0" }]
|
|
8260
|
+
];
|
|
8261
|
+
const RotateCw = createLucideIcon("rotate-cw", __iconNode$7);
|
|
8262
|
+
|
|
8263
|
+
/**
|
|
8264
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8265
|
+
*
|
|
8266
|
+
* This source code is licensed under the ISC license.
|
|
8267
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8268
|
+
*/
|
|
8269
|
+
|
|
8270
|
+
|
|
8271
|
+
const __iconNode$6 = [
|
|
8272
|
+
["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
|
|
8273
|
+
["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
|
|
8274
|
+
];
|
|
8275
|
+
const Search = createLucideIcon("search", __iconNode$6);
|
|
8276
|
+
|
|
8277
|
+
/**
|
|
8278
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8279
|
+
*
|
|
8280
|
+
* This source code is licensed under the ISC license.
|
|
8281
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8282
|
+
*/
|
|
8283
|
+
|
|
8284
|
+
|
|
8285
|
+
const __iconNode$5 = [
|
|
8286
|
+
["path", { d: "M10 5H3", key: "1qgfaw" }],
|
|
8287
|
+
["path", { d: "M12 19H3", key: "yhmn1j" }],
|
|
8288
|
+
["path", { d: "M14 3v4", key: "1sua03" }],
|
|
8289
|
+
["path", { d: "M16 17v4", key: "1q0r14" }],
|
|
8290
|
+
["path", { d: "M21 12h-9", key: "1o4lsq" }],
|
|
8291
|
+
["path", { d: "M21 19h-5", key: "1rlt1p" }],
|
|
8292
|
+
["path", { d: "M21 5h-7", key: "1oszz2" }],
|
|
8293
|
+
["path", { d: "M8 10v4", key: "tgpxqk" }],
|
|
8294
|
+
["path", { d: "M8 12H3", key: "a7s4jb" }]
|
|
8295
|
+
];
|
|
8296
|
+
const SlidersHorizontal = createLucideIcon("sliders-horizontal", __iconNode$5);
|
|
8297
|
+
|
|
8298
|
+
/**
|
|
8299
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8300
|
+
*
|
|
8301
|
+
* This source code is licensed under the ISC license.
|
|
8302
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8303
|
+
*/
|
|
8304
|
+
|
|
8305
|
+
|
|
8306
|
+
const __iconNode$4 = [
|
|
8307
|
+
["path", { d: "M12 3H5a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7", key: "1m0v6g" }],
|
|
8308
|
+
[
|
|
8309
|
+
"path",
|
|
8310
|
+
{
|
|
8311
|
+
d: "M18.375 2.625a1 1 0 0 1 3 3l-9.013 9.014a2 2 0 0 1-.853.505l-2.873.84a.5.5 0 0 1-.62-.62l.84-2.873a2 2 0 0 1 .506-.852z",
|
|
8312
|
+
key: "ohrbg2"
|
|
8138
8313
|
}
|
|
8139
|
-
|
|
8140
|
-
|
|
8314
|
+
]
|
|
8315
|
+
];
|
|
8316
|
+
const SquarePen = createLucideIcon("square-pen", __iconNode$4);
|
|
8141
8317
|
|
|
8142
8318
|
/**
|
|
8143
|
-
*
|
|
8144
|
-
*
|
|
8319
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8320
|
+
*
|
|
8321
|
+
* This source code is licensed under the ISC license.
|
|
8322
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8145
8323
|
*/
|
|
8146
|
-
|
|
8147
|
-
|
|
8148
|
-
|
|
8149
|
-
|
|
8150
|
-
|
|
8151
|
-
|
|
8152
|
-
|
|
8153
|
-
|
|
8154
|
-
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
|
|
8163
|
-
|
|
8164
|
-
|
|
8324
|
+
|
|
8325
|
+
|
|
8326
|
+
const __iconNode$3 = [
|
|
8327
|
+
["path", { d: "M10 11v6", key: "nco0om" }],
|
|
8328
|
+
["path", { d: "M14 11v6", key: "outv1u" }],
|
|
8329
|
+
["path", { d: "M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6", key: "miytrc" }],
|
|
8330
|
+
["path", { d: "M3 6h18", key: "d0wm0j" }],
|
|
8331
|
+
["path", { d: "M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2", key: "e791ji" }]
|
|
8332
|
+
];
|
|
8333
|
+
const Trash2 = createLucideIcon("trash-2", __iconNode$3);
|
|
8334
|
+
|
|
8335
|
+
/**
|
|
8336
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8337
|
+
*
|
|
8338
|
+
* This source code is licensed under the ISC license.
|
|
8339
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8340
|
+
*/
|
|
8341
|
+
|
|
8342
|
+
|
|
8343
|
+
const __iconNode$2 = [
|
|
8344
|
+
[
|
|
8345
|
+
"path",
|
|
8346
|
+
{
|
|
8347
|
+
d: "m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3",
|
|
8348
|
+
key: "wmoenq"
|
|
8165
8349
|
}
|
|
8166
|
-
|
|
8167
|
-
}
|
|
8350
|
+
],
|
|
8351
|
+
["path", { d: "M12 9v4", key: "juzpu7" }],
|
|
8352
|
+
["path", { d: "M12 17h.01", key: "p32p05" }]
|
|
8353
|
+
];
|
|
8354
|
+
const TriangleAlert = createLucideIcon("triangle-alert", __iconNode$2);
|
|
8355
|
+
|
|
8356
|
+
/**
|
|
8357
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8358
|
+
*
|
|
8359
|
+
* This source code is licensed under the ISC license.
|
|
8360
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8361
|
+
*/
|
|
8362
|
+
|
|
8363
|
+
|
|
8364
|
+
const __iconNode$1 = [
|
|
8365
|
+
["path", { d: "M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2", key: "975kel" }],
|
|
8366
|
+
["circle", { cx: "12", cy: "7", r: "4", key: "17ys0d" }]
|
|
8367
|
+
];
|
|
8368
|
+
const User = createLucideIcon("user", __iconNode$1);
|
|
8369
|
+
|
|
8168
8370
|
/**
|
|
8169
|
-
*
|
|
8371
|
+
* @license lucide-react v0.577.0 - ISC
|
|
8372
|
+
*
|
|
8373
|
+
* This source code is licensed under the ISC license.
|
|
8374
|
+
* See the LICENSE file in the root directory of this source tree.
|
|
8170
8375
|
*/
|
|
8171
|
-
|
|
8172
|
-
|
|
8173
|
-
|
|
8174
|
-
|
|
8175
|
-
|
|
8176
|
-
|
|
8177
|
-
|
|
8178
|
-
}
|
|
8179
|
-
else {
|
|
8180
|
-
newExpanded.add(auditId);
|
|
8181
|
-
}
|
|
8182
|
-
setExpandedEvents(newExpanded);
|
|
8183
|
-
};
|
|
8184
|
-
const handleEventClick = (event) => {
|
|
8185
|
-
setSelectedEvent(event);
|
|
8186
|
-
if (onEventSelect) {
|
|
8187
|
-
onEventSelect(event);
|
|
8188
|
-
}
|
|
8189
|
-
};
|
|
8190
|
-
const formatTimestamp = (timestamp) => {
|
|
8191
|
-
if (!timestamp)
|
|
8192
|
-
return "N/A";
|
|
8193
|
-
try {
|
|
8194
|
-
return format(new Date(timestamp), "yyyy-MM-dd HH:mm:ss");
|
|
8195
|
-
}
|
|
8196
|
-
catch {
|
|
8197
|
-
return timestamp;
|
|
8198
|
-
}
|
|
8199
|
-
};
|
|
8200
|
-
const getVerbBadgeVariant = (verb) => {
|
|
8201
|
-
switch (verb?.toLowerCase()) {
|
|
8202
|
-
case "create":
|
|
8203
|
-
return "success";
|
|
8204
|
-
case "update":
|
|
8205
|
-
case "patch":
|
|
8206
|
-
return "warning";
|
|
8207
|
-
case "delete":
|
|
8208
|
-
return "destructive";
|
|
8209
|
-
case "get":
|
|
8210
|
-
case "list":
|
|
8211
|
-
case "watch":
|
|
8212
|
-
return "default";
|
|
8213
|
-
default:
|
|
8214
|
-
return "secondary";
|
|
8215
|
-
}
|
|
8216
|
-
};
|
|
8217
|
-
if (events.length === 0) {
|
|
8218
|
-
return (jsxRuntime.jsx("div", { className: `bg-muted rounded-lg border border-border ${className}`, children: jsxRuntime.jsx("div", { className: "p-12 text-center text-muted-foreground text-sm", children: "No events found" }) }));
|
|
8219
|
-
}
|
|
8220
|
-
return (jsxRuntime.jsx("div", { className: `bg-muted rounded-lg border border-border ${className}`, children: jsxRuntime.jsx("div", { className: "p-4", children: events.map((event) => {
|
|
8221
|
-
const auditId = event.auditID || "";
|
|
8222
|
-
const isExpanded = expandedEvents.has(auditId);
|
|
8223
|
-
const tenant = extractTenantFromAnnotations(event);
|
|
8224
|
-
return (jsxRuntime.jsxs(card.Card, { className: `p-5 mb-3 cursor-pointer transition-all hover:border-primary/50 hover:shadow-sm hover:-translate-y-px ${selectedEvent?.auditID === auditId
|
|
8225
|
-
? "border-primary bg-primary/5 shadow-md"
|
|
8226
|
-
: ""}`, onClick: () => handleEventClick(event), children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [jsxRuntime.jsxs("div", { className: "flex gap-3 items-center flex-1", children: [jsxRuntime.jsx(Badge, { variant: getVerbBadgeVariant(event.verb), className: "px-3 py-1", children: event.verb?.toUpperCase() || "UNKNOWN" }), jsxRuntime.jsx("span", { className: "font-semibold", children: event.objectRef?.resource || "N/A" }), event.objectRef?.namespace && (jsxRuntime.jsxs("span", { className: "text-muted-foreground text-sm", children: ["ns: ", event.objectRef.namespace] })), event.objectRef?.name && (jsxRuntime.jsx("span", { className: "text-foreground/80 text-sm", children: event.objectRef.name })), tenant && (jsxRuntime.jsx(TenantBadge, { tenant: tenant, tenantLinkResolver: tenantLinkResolver, size: "compact" }))] }), jsxRuntime.jsxs("div", { className: "flex gap-4 items-center", children: [jsxRuntime.jsx("span", { className: "text-foreground/80 text-sm", children: event.user?.username || "N/A" }), jsxRuntime.jsx("span", { className: "text-muted-foreground text-sm font-mono", children: formatTimestamp(event.stageTimestamp) }), jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", onClick: (e) => {
|
|
8227
|
-
e.stopPropagation();
|
|
8228
|
-
toggleEventExpansion(auditId);
|
|
8229
|
-
}, className: "text-primary", children: isExpanded ? "▼" : "▶" })] })] }), isExpanded && (jsxRuntime.jsxs("div", { className: "mt-4 pt-4 border-t border-border", children: [jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Event Information" }), jsxRuntime.jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-2 m-0", children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Audit ID:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.auditID || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Stage:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.stage || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Level:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.level || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Request URI:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground font-mono text-sm break-all", children: event.requestURI || "N/A" }), event.userAgent && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "User Agent:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground font-mono text-sm break-all", children: event.userAgent })] })), event.sourceIPs && event.sourceIPs.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Source IPs:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.sourceIPs.join(", ") })] }))] })] }), tenant && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Tenant" }), jsxRuntime.jsx(TenantBadge, { tenant: tenant, tenantLinkResolver: tenantLinkResolver })] })), event.user && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "User Information" }), jsxRuntime.jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-2 m-0", children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Username:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.user.username || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "UID:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.user.uid || "N/A" }), event.user.groups && event.user.groups.length > 0 && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Groups:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.user.groups.join(", ") })] }))] })] })), event.responseStatus && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Response Status" }), jsxRuntime.jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-2 m-0", children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Code:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.responseStatus.code || "N/A" }), jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Status:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.responseStatus.status || "N/A" }), event.responseStatus.message && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("dt", { className: "font-semibold text-foreground/80", children: "Message:" }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: event.responseStatus.message })] }))] })] })), event.annotations &&
|
|
8230
|
-
Object.keys(event.annotations).length > 0 && (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Annotations" }), jsxRuntime.jsx("dl", { className: "grid grid-cols-[auto_1fr] gap-2 m-0", children: Object.entries(event.annotations).map(([key, value]) => (jsxRuntime.jsxs("div", { className: "contents", children: [jsxRuntime.jsxs("dt", { className: "font-semibold text-foreground/80", children: [key, ":"] }), jsxRuntime.jsx("dd", { className: "m-0 text-foreground", children: value })] }, key))) })] })), event.requestObject || event.responseObject ? (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "mt-0 mb-2 text-base text-foreground/80", children: "Request/Response Data" }), event.requestObject ? (jsxRuntime.jsxs("details", { className: "mt-2", children: [jsxRuntime.jsx("summary", { className: "cursor-pointer font-semibold p-2 bg-muted rounded", children: "Request Object" }), jsxRuntime.jsx("pre", { className: "mt-2 p-4 bg-muted rounded overflow-x-auto text-sm", children: JSON.stringify(event.requestObject, null, 2) })] })) : null, event.responseObject ? (jsxRuntime.jsxs("details", { className: "mt-2", children: [jsxRuntime.jsx("summary", { className: "cursor-pointer font-semibold p-2 bg-muted rounded", children: "Response Object" }), jsxRuntime.jsx("pre", { className: "mt-2 p-4 bg-muted rounded overflow-x-auto text-sm", children: JSON.stringify(event.responseObject, null, 2) })] })) : null] })) : null] }))] }, auditId));
|
|
8231
|
-
}) }) }));
|
|
8232
|
-
}
|
|
8376
|
+
|
|
8377
|
+
|
|
8378
|
+
const __iconNode = [
|
|
8379
|
+
["path", { d: "M18 6 6 18", key: "1bl5f8" }],
|
|
8380
|
+
["path", { d: "m6 6 12 12", key: "d8bk6v" }]
|
|
8381
|
+
];
|
|
8382
|
+
const X = createLucideIcon("x", __iconNode);
|
|
8233
8383
|
|
|
8234
8384
|
/**
|
|
8235
8385
|
* FilterChip - A compact pill/chip showing "Label: Values" with clear button
|
|
@@ -8354,7 +8504,7 @@ function FilterChip({ label, values, options = [], onValuesChange, onClear, inpu
|
|
|
8354
8504
|
}, [options]);
|
|
8355
8505
|
// Find selected options for chips display
|
|
8356
8506
|
const selectedOptions = options.filter((opt) => values.includes(opt.value));
|
|
8357
|
-
return (jsxRuntime.jsxs(
|
|
8507
|
+
return (jsxRuntime.jsxs(buttonGroup.ButtonGroup, { "aria-label": `${label} filter`, className: className, children: [jsxRuntime.jsxs(popover.Popover, { open: open, onOpenChange: handleOpenChange, children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(button.Button, { htmlType: "button", type: "quaternary", theme: "outline", size: "small", disabled: disabled, className: "gap-2 font-normal data-[state=open]:bg-btn-neutral-bg", children: [jsxRuntime.jsxs("span", { className: "font-medium", children: [label, ":"] }), jsxRuntime.jsx("span", { className: "truncate max-w-[120px]", children: displayValue }), jsxRuntime.jsx(ChevronDown, { className: "h-3 w-3 text-muted-foreground" })] }) }), jsxRuntime.jsx(popover.PopoverContent, { className: "w-auto min-w-[var(--radix-popover-trigger-width)] max-w-[320px] p-0", sideOffset: 4, align: "start", children: inputMode === 'typeahead' ? (jsxRuntime.jsxs(command.Command, { filter: filterOptions, children: [jsxRuntime.jsx(command.CommandInput, { placeholder: searchPlaceholder, value: search, onValueChange: setSearch }), 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(command.CommandList, { children: [jsxRuntime.jsx(command.CommandEmpty, { children: "No results found." }), jsxRuntime.jsx(command.CommandGroup, { children: options.map((option) => (jsxRuntime.jsxs(command.CommandItem, { value: option.value, onSelect: () => handleSelect(option.value), 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.Input, { type: "text", value: textValue, onChange: handleTextChange, placeholder: placeholder, className: "w-full", autoFocus: true }) })) })] }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "outline", size: "small", onClick: handleClearAll, disabled: disabled, "aria-label": `Clear ${label} filter`, children: jsxRuntime.jsx(X, { className: "h-3 w-3 text-muted-foreground" }) })] }));
|
|
8358
8508
|
}
|
|
8359
8509
|
|
|
8360
8510
|
/**
|
|
@@ -8371,12 +8521,12 @@ function AddFilterDropdown({ availableFilters, activeFilterIds, onAddFilter, has
|
|
|
8371
8521
|
const isFilterActive = (filterId) => activeFilterIds.includes(filterId);
|
|
8372
8522
|
// Get button label
|
|
8373
8523
|
const buttonLabel = hasActiveFilters ? 'Filters' : 'Add Filters';
|
|
8374
|
-
return (jsxRuntime.jsxs(
|
|
8375
|
-
|
|
8376
|
-
|
|
8377
|
-
|
|
8378
|
-
|
|
8379
|
-
|
|
8524
|
+
return (jsxRuntime.jsxs(popover.Popover, { open: open, onOpenChange: setOpen, children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(button.Button, { htmlType: "button", type: "quaternary", theme: "outline", size: "small", disabled: disabled, className: cn('gap-1.5 border-dashed text-muted-foreground hover:text-foreground', className), children: [jsxRuntime.jsx(Plus, { className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "font-medium", children: buttonLabel })] }) }), jsxRuntime.jsx(popover.PopoverContent, { className: "w-auto min-w-[180px] p-0", sideOffset: 4, align: "start", children: jsxRuntime.jsx("div", { className: "p-1", children: availableFilters.map((filter) => {
|
|
8525
|
+
const active = isFilterActive(filter.id);
|
|
8526
|
+
return (jsxRuntime.jsxs("button", { type: "button", onClick: () => !active && handleFilterClick(filter.id), disabled: active, className: cn('relative flex w-full items-center gap-2 rounded-sm px-3 py-2 text-sm outline-none transition-colors', active
|
|
8527
|
+
? 'cursor-not-allowed opacity-40'
|
|
8528
|
+
: 'cursor-pointer hover:bg-accent hover:text-accent-foreground'), children: [filter.icon && jsxRuntime.jsx("span", { className: "text-muted-foreground", children: filter.icon }), jsxRuntime.jsx("span", { children: filter.label }), active && (jsxRuntime.jsx("span", { className: "ml-auto text-xs text-muted-foreground", children: "(active)" }))] }, filter.id));
|
|
8529
|
+
}) }) })] }));
|
|
8380
8530
|
}
|
|
8381
8531
|
|
|
8382
8532
|
/**
|
|
@@ -8400,10 +8550,10 @@ function ActionMultiSelect({ value, onChange, className = '', disabled = false,
|
|
|
8400
8550
|
return '1 action';
|
|
8401
8551
|
return `${value.length} actions`;
|
|
8402
8552
|
}, [value.length]);
|
|
8403
|
-
return (jsxRuntime.jsxs(
|
|
8404
|
-
|
|
8405
|
-
|
|
8406
|
-
|
|
8553
|
+
return (jsxRuntime.jsxs(popover.Popover, { open: open, onOpenChange: setOpen, children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(button.Button, { htmlType: "button", type: "quaternary", theme: "outline", size: "small", disabled: disabled || isLoading, className: cn('min-w-[100px] justify-between gap-2', className), children: [jsxRuntime.jsx("span", { className: "font-medium", children: displayText }), jsxRuntime.jsx(ChevronDown, { className: "h-3 w-3 text-muted-foreground shrink-0" })] }) }), jsxRuntime.jsx(popover.PopoverContent, { className: "w-auto min-w-[160px] p-0", sideOffset: 4, align: "start", children: jsxRuntime.jsx("div", { className: "p-1", children: isLoading ? (jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: "Loading..." })) : options.length === 0 ? (jsxRuntime.jsx("div", { className: "px-3 py-2 text-sm text-muted-foreground", children: "No actions found" })) : (options.map((option) => {
|
|
8554
|
+
const checked = value.includes(option.value);
|
|
8555
|
+
return (jsxRuntime.jsxs("label", { className: cn('flex items-center gap-2 rounded-sm px-3 py-2 text-sm cursor-pointer', 'hover:bg-accent hover:text-accent-foreground transition-colors'), children: [jsxRuntime.jsx(checkbox.Checkbox, { checked: checked, onCheckedChange: () => handleToggle(option.value), className: "h-4 w-4" }), jsxRuntime.jsx("span", { className: "flex-1", children: option.label }), option.count !== undefined && (jsxRuntime.jsxs("span", { className: "text-xs text-muted-foreground", children: ["(", option.count, ")"] }))] }, option.value));
|
|
8556
|
+
})) }) })] }));
|
|
8407
8557
|
}
|
|
8408
8558
|
|
|
8409
8559
|
/**
|
|
@@ -8435,7 +8585,7 @@ function UserSelect({ value, options, onChange, className = '', disabled = false
|
|
|
8435
8585
|
e.stopPropagation();
|
|
8436
8586
|
onChange(undefined);
|
|
8437
8587
|
}, [onChange]);
|
|
8438
|
-
return (jsxRuntime.jsxs(
|
|
8588
|
+
return (jsxRuntime.jsxs(popover.Popover, { open: open, onOpenChange: setOpen, children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs(button.Button, { htmlType: "button", type: "tertiary", theme: "outline", size: "small", disabled: disabled, className: cn('gap-1.5', value && 'pr-1.5', className), children: [jsxRuntime.jsx(User, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { children: displayLabel }), value && (jsxRuntime.jsx("button", { onClick: handleClear, className: "ml-1 rounded-sm opacity-70 hover:opacity-100 hover:bg-muted p-0.5", "aria-label": "Clear user filter", children: jsxRuntime.jsx(X, { className: "h-3 w-3" }) }))] }) }), jsxRuntime.jsxs(popover.PopoverContent, { className: "w-64 p-0", align: "start", sideOffset: 4, children: [jsxRuntime.jsx("div", { className: "border-b p-2", children: jsxRuntime.jsx("input", { type: "text", placeholder: "Search users...", value: search, onChange: (e) => setSearch(e.target.value), className: "w-full rounded-md border border-input bg-background px-2 py-1.5 text-xs placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-0", autoFocus: true }) }), jsxRuntime.jsxs("div", { className: "max-h-64 overflow-y-auto p-1", children: [jsxRuntime.jsxs("button", { onClick: () => handleSelect(undefined), className: cn('w-full flex items-center justify-between rounded-sm px-2 py-1.5 text-xs cursor-pointer hover:bg-accent hover:text-accent-foreground', !value && 'bg-accent text-accent-foreground'), children: [jsxRuntime.jsx("span", { className: "font-medium", children: "All Users" }), options.length > 0 && (jsxRuntime.jsx("span", { className: "text-muted-foreground", children: options.reduce((sum, opt) => sum + (opt.count || 0), 0) }))] }), isLoading && (jsxRuntime.jsx("div", { className: "px-2 py-4 text-center text-xs text-muted-foreground", children: "Loading users..." })), !isLoading && filteredOptions.length > 0 && (jsxRuntime.jsx("div", { className: "mt-1 border-t pt-1", children: filteredOptions.map((option) => (jsxRuntime.jsxs("button", { onClick: () => handleSelect(option.value), className: cn('w-full flex items-center justify-between rounded-sm px-2 py-1.5 text-xs cursor-pointer hover:bg-accent hover:text-accent-foreground', value === option.value && 'bg-accent text-accent-foreground'), children: [jsxRuntime.jsx("span", { className: "truncate font-medium", children: option.label }), option.count !== undefined && (jsxRuntime.jsx("span", { className: "text-muted-foreground ml-2 flex-shrink-0", children: option.count }))] }, option.value))) })), !isLoading && filteredOptions.length === 0 && search && (jsxRuntime.jsx("div", { className: "px-2 py-4 text-center text-xs text-muted-foreground", children: "No users found" })), !isLoading && options.length === 0 && !search && (jsxRuntime.jsx("div", { className: "px-2 py-4 text-center text-xs text-muted-foreground", children: "No users available" }))] })] })] }));
|
|
8439
8589
|
}
|
|
8440
8590
|
|
|
8441
8591
|
/**
|
|
@@ -8782,7 +8932,7 @@ function AuditLogFilters({ client, filters, timeRange, onFiltersChange, onTimeRa
|
|
|
8782
8932
|
label: facet.value,
|
|
8783
8933
|
count: facet.count,
|
|
8784
8934
|
}));
|
|
8785
|
-
return (jsxRuntime.jsx("div", { className: `border-b border-border py-4 pt-0 ${className}`, children: jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [jsxRuntime.jsx(ActionMultiSelect, { value: getActionValues(), onChange: handleActionChange, options: actionOptions, disabled: disabled, isLoading: !verbs.length && !facetsError, className: "
|
|
8935
|
+
return (jsxRuntime.jsx("div", { className: `border-b border-border py-4 pt-0 ${className}`, children: jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [jsxRuntime.jsx(ActionMultiSelect, { value: getActionValues(), onChange: handleActionChange, options: actionOptions, disabled: disabled, isLoading: !verbs.length && !facetsError, className: "min-w-[180px]" }), jsxRuntime.jsx(UserSelect, { value: getCurrentUser(), options: userOptions, onChange: handleUserChange, disabled: disabled, isLoading: !usernames.length && !facetsError }), activeFilterIds.map((filterId) => {
|
|
8786
8936
|
const config = FILTER_CONFIGS$2[filterId];
|
|
8787
8937
|
return (jsxRuntime.jsx(FilterChip, { label: config.label, values: getFilterValues(filterId), options: config.inputMode === "typeahead"
|
|
8788
8938
|
? getFilterOptions(filterId)
|
|
@@ -8918,7 +9068,7 @@ function CopyButton({ value, label }) {
|
|
|
8918
9068
|
console.error('Failed to copy:', err);
|
|
8919
9069
|
}
|
|
8920
9070
|
};
|
|
8921
|
-
return (jsxRuntime.jsxs(Tooltip, { delayDuration: 400, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("button", { type: "button", onClick: handleCopy, className: "inline-flex items-center justify-center p-0.5 rounded hover:bg-
|
|
9071
|
+
return (jsxRuntime.jsxs(Tooltip, { delayDuration: 400, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("button", { type: "button", onClick: handleCopy, className: "inline-flex items-center justify-center p-0.5 rounded hover:bg-muted transition-opacity cursor-pointer ml-1 opacity-0 group-hover:opacity-100", "aria-label": `Copy ${label}`, children: isCopied ? (jsxRuntime.jsx(Check, { className: "h-3 w-3 text-[var(--success-500)]" })) : (jsxRuntime.jsx(Copy, { className: "h-3 w-3 text-muted-foreground" })) }) }), jsxRuntime.jsx(TooltipContent, { side: "top", children: jsxRuntime.jsx("p", { className: "text-xs", children: isCopied ? 'Copied!' : `Copy ${label}` }) })] }));
|
|
8922
9072
|
}
|
|
8923
9073
|
/**
|
|
8924
9074
|
* A label / value row inside a Section. The value is truncated to one
|
|
@@ -8996,8 +9146,8 @@ function AuditLogExpandedDetails({ event, compact = true }) {
|
|
|
8996
9146
|
const status = event.responseStatus;
|
|
8997
9147
|
const isOk = status?.code != null && status.code >= 200 && status.code < 300;
|
|
8998
9148
|
const body = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(DetailGrid, { children: [jsxRuntime.jsxs(Section, { title: "Request", children: [jsxRuntime.jsx(Field, { label: "Verb", value: event.verb || 'Unknown', copyValue: event.verb || undefined, copyLabel: "verb" }), event.requestURI ? (jsxRuntime.jsx(Field, { label: "URI", value: event.requestURI, copyValue: event.requestURI, mono: true })) : null] }), status ? (jsxRuntime.jsxs(Section, { title: "Response", children: [status.code != null ? (jsxRuntime.jsx(Field, { label: "Status code", value: jsxRuntime.jsxs("span", { className: isOk
|
|
8999
|
-
? 'text-
|
|
9000
|
-
: 'text-
|
|
9149
|
+
? 'text-[var(--success-500)]'
|
|
9150
|
+
: 'text-destructive', children: [isOk ? '✓ ' : '✗ ', status.code] }), copyValue: String(status.code), copyLabel: "status code" })) : null, status.status ? jsxRuntime.jsx(Field, { label: "Status", value: status.status }) : null, status.reason ? jsxRuntime.jsx(Field, { label: "Reason", value: status.reason }) : null, status.message ? (jsxRuntime.jsx(Field, { label: "Message", value: status.message, copyValue: status.message })) : null] })) : null, jsxRuntime.jsx(Section, { title: "When", children: jsxRuntime.jsx(Field, { label: "Timestamp", value: jsxRuntime.jsx(Timestamp, { value: timestamp, variant: "iso-utc" }), copyValue: timestamp || '', copyLabel: "timestamp", disableTooltip: true }) }), event.user ? (jsxRuntime.jsxs(Section, { title: "User", children: [event.user.username ? (jsxRuntime.jsx(Field, { label: "Username", value: event.user.username, copyValue: event.user.username })) : null, event.user.uid ? (jsxRuntime.jsx(Field, { label: "UID", value: event.user.uid, copyValue: event.user.uid, mono: true })) : null, event.user.groups && event.user.groups.length > 0 ? (jsxRuntime.jsx(Field, { label: "Groups", value: event.user.groups.join(', ') })) : null] })) : null, event.objectRef ? (jsxRuntime.jsxs(Section, { title: "Resource", children: [jsxRuntime.jsx(Field, { label: "Kind", value: jsxRuntime.jsxs("span", { children: [event.objectRef.resource || 'Unknown', event.objectRef.apiGroup ? (jsxRuntime.jsxs("span", { className: "ml-1 text-muted-foreground", children: ["\u00B7 ", event.objectRef.apiGroup] })) : null] }), copyValue: event.objectRef.resource, copyLabel: "resource kind" }), event.objectRef.name ? (jsxRuntime.jsx(Field, { label: "Name", value: event.objectRef.name, copyValue: event.objectRef.name, copyLabel: "resource name" })) : null, event.objectRef.namespace ? (jsxRuntime.jsx(Field, { label: "Namespace", value: event.objectRef.namespace, copyValue: event.objectRef.namespace })) : null, event.objectRef.apiVersion ? (jsxRuntime.jsx(Field, { label: "API version", value: event.objectRef.apiVersion })) : null, event.objectRef.subresource ? (jsxRuntime.jsx(Field, { label: "Subresource", value: event.objectRef.subresource })) : null, event.objectRef.uid ? (jsxRuntime.jsx(Field, { label: "UID", value: event.objectRef.uid, copyValue: event.objectRef.uid, mono: true })) : null] })) : null, event.userAgent || (event.sourceIPs && event.sourceIPs.length > 0) ? (jsxRuntime.jsxs(Section, { title: "Source", children: [event.sourceIPs && event.sourceIPs.length > 0 ? (jsxRuntime.jsx(Field, { label: "Source IPs", value: event.sourceIPs.join(', ') })) : null, event.userAgent ? (jsxRuntime.jsx(Field, { label: "User agent", value: event.userAgent, copyValue: event.userAgent, mono: true })) : null] })) : null] }), event.auditID || event.stage || event.level ||
|
|
9001
9151
|
(event.annotations && Object.keys(event.annotations).length > 0) ? (jsxRuntime.jsxs("details", { className: "group mt-5", children: [jsxRuntime.jsx("summary", { className: "cursor-pointer list-none", children: jsxRuntime.jsxs("h4", { className: "inline-flex items-center m-0 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/80 hover:text-foreground", children: [jsxRuntime.jsx("span", { className: "mr-1 group-open:rotate-90 transition-transform", children: "\u25B8" }), "Advanced"] }) }), jsxRuntime.jsx("div", { className: "mt-3 pl-3", children: jsxRuntime.jsxs(DetailGrid, { children: [jsxRuntime.jsxs(Section, { title: "Audit", children: [event.auditID ? (jsxRuntime.jsx(Field, { label: "Audit ID", value: event.auditID, copyValue: event.auditID, mono: true })) : null, event.stage ? jsxRuntime.jsx(Field, { label: "Stage", value: event.stage }) : null, event.level ? jsxRuntime.jsx(Field, { label: "Level", value: event.level }) : null] }), event.annotations && Object.keys(event.annotations).length > 0 ? (jsxRuntime.jsx(Section, { title: "Annotations", children: Object.entries(event.annotations).map(([key, value]) => (jsxRuntime.jsx(Field, { label: key, value: value, mono: true }, key))) })) : null] }) })] })) : null, event.requestObject || event.responseObject ? (jsxRuntime.jsxs("details", { className: "group mt-3", children: [jsxRuntime.jsx("summary", { className: "cursor-pointer list-none", children: jsxRuntime.jsxs("h4", { className: "inline-flex items-center m-0 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/80 hover:text-foreground", children: [jsxRuntime.jsx("span", { className: "mr-1 group-open:rotate-90 transition-transform", children: "\u25B8" }), "Raw objects"] }) }), jsxRuntime.jsxs("div", { className: "mt-3 space-y-3", children: [event.requestObject ? (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground", children: "Request" }), jsxRuntime.jsx("pre", { className: "m-0 p-3 bg-muted rounded overflow-x-auto text-xs font-mono", children: JSON.stringify(event.requestObject, null, 2) })] })) : null, event.responseObject ? (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "mb-1 text-[10px] font-medium uppercase tracking-wider text-muted-foreground", children: "Response" }), jsxRuntime.jsx("pre", { className: "m-0 p-3 bg-muted rounded overflow-x-auto text-xs font-mono", children: JSON.stringify(event.responseObject, null, 2) })] })) : null] })] })) : null] }));
|
|
9002
9152
|
return (jsxRuntime.jsx(TooltipProvider, { children: compact ? (jsxRuntime.jsx(DetailPanelShell, { children: body })) : (jsxRuntime.jsx("div", { className: "mt-4 pt-4 border-t border-border", children: body })) }));
|
|
9003
9153
|
}
|
|
@@ -9005,22 +9155,21 @@ function AuditLogExpandedDetails({ event, compact = true }) {
|
|
|
9005
9155
|
// Number of columns rendered for the audit log table. Used by the colSpan
|
|
9006
9156
|
// on the expanded-detail row so it spans the full width.
|
|
9007
9157
|
const AUDIT_LOG_COLUMN_COUNT = 5;
|
|
9158
|
+
const VERB_BADGE_CLASSES = 'text-[0.55rem] h-5 px-2 py-1 leading-3';
|
|
9008
9159
|
/**
|
|
9009
|
-
* Get
|
|
9160
|
+
* Get the badge variant for a verb
|
|
9010
9161
|
*/
|
|
9011
|
-
function
|
|
9012
|
-
|
|
9013
|
-
const normalized = verb?.toLowerCase();
|
|
9014
|
-
switch (normalized) {
|
|
9162
|
+
function getVerbBadgeVariant(verb) {
|
|
9163
|
+
switch (verb?.toLowerCase()) {
|
|
9015
9164
|
case 'create':
|
|
9016
|
-
return
|
|
9165
|
+
return 'success';
|
|
9017
9166
|
case 'update':
|
|
9018
9167
|
case 'patch':
|
|
9019
|
-
return
|
|
9168
|
+
return 'warning';
|
|
9020
9169
|
case 'delete':
|
|
9021
|
-
return
|
|
9170
|
+
return 'destructive';
|
|
9022
9171
|
default:
|
|
9023
|
-
return
|
|
9172
|
+
return 'outline';
|
|
9024
9173
|
}
|
|
9025
9174
|
}
|
|
9026
9175
|
/**
|
|
@@ -9031,9 +9180,9 @@ function getResponseStatusIndicator(code) {
|
|
|
9031
9180
|
return { icon: '?', className: 'text-muted-foreground' };
|
|
9032
9181
|
}
|
|
9033
9182
|
if (code >= 200 && code < 300) {
|
|
9034
|
-
return { icon: '✓', className: 'text-
|
|
9183
|
+
return { icon: '✓', className: 'text-[var(--success-500)]' };
|
|
9035
9184
|
}
|
|
9036
|
-
return { icon: '✗', className: 'text-
|
|
9185
|
+
return { icon: '✗', className: 'text-destructive' };
|
|
9037
9186
|
}
|
|
9038
9187
|
/**
|
|
9039
9188
|
* Build human-readable summary
|
|
@@ -9074,14 +9223,14 @@ function AuditLogFeedItem({ event, onEventClick, isSelected = false, className =
|
|
|
9074
9223
|
verb === 'delete' ? Trash2 :
|
|
9075
9224
|
verb === 'update' || verb === 'patch' ? Pencil :
|
|
9076
9225
|
Activity;
|
|
9077
|
-
const iconBg = verb === 'create' ? 'bg-
|
|
9078
|
-
verb === 'delete' ? 'bg-
|
|
9079
|
-
verb === 'update' || verb === 'patch' ? 'bg-
|
|
9080
|
-
'bg-
|
|
9081
|
-
const iconColor = verb === 'create' ? 'text-
|
|
9082
|
-
verb === 'delete' ? 'text-
|
|
9083
|
-
verb === 'update' || verb === 'patch' ? 'text-
|
|
9084
|
-
'text-
|
|
9226
|
+
const iconBg = verb === 'create' ? 'bg-[var(--success-100)]' :
|
|
9227
|
+
verb === 'delete' ? 'bg-destructive/10' :
|
|
9228
|
+
verb === 'update' || verb === 'patch' ? 'bg-[color-mix(in_oklab,var(--badge-warning)_15%,transparent)]' :
|
|
9229
|
+
'bg-muted';
|
|
9230
|
+
const iconColor = verb === 'create' ? 'text-[var(--success-500)]' :
|
|
9231
|
+
verb === 'delete' ? 'text-destructive' :
|
|
9232
|
+
verb === 'update' || verb === 'patch' ? 'text-[var(--badge-warning)]' :
|
|
9233
|
+
'text-muted-foreground';
|
|
9085
9234
|
return (jsxRuntime.jsxs("div", { className: cn(!isLast && !isExpanded && 'border-b border-border', className), children: [jsxRuntime.jsxs("div", { className: cn('flex items-center gap-3 cursor-pointer group', compact ? 'py-2' : 'py-3', 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), title: event.verb, children: jsxRuntime.jsx(Icon, { size: 16, strokeWidth: 2 }) }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0 text-sm leading-snug", style: { minWidth: 0 }, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("div", { className: "text-foreground", style: {
|
|
9086
9235
|
display: 'block',
|
|
9087
9236
|
overflow: 'hidden',
|
|
@@ -9090,10 +9239,10 @@ function AuditLogFeedItem({ event, onEventClick, isSelected = false, className =
|
|
|
9090
9239
|
cursor: 'help',
|
|
9091
9240
|
}, children: summary }) }), jsxRuntime.jsx(TooltipContent, { className: "max-w-[480px] whitespace-normal break-words", children: summary })] }) }), jsxRuntime.jsxs("span", { className: cn('inline-flex items-center gap-1 text-xs font-semibold shrink-0', statusIndicator.className), children: [jsxRuntime.jsx("span", { children: statusIndicator.icon }), event.responseStatus?.code ? jsxRuntime.jsx("span", { children: event.responseStatus.code }) : null] }), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0", children: jsxRuntime.jsx(Timestamp, { value: timestamp }) }), jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", htmlType: "button", className: "h-5 py-0 px-1 text-base text-muted-foreground hover:text-foreground shrink-0", onClick: toggleExpand, "aria-expanded": isExpanded, "aria-label": isExpanded ? 'Collapse details' : 'Expand details', children: isExpanded ? '−' : '+' })] }), isExpanded ? jsxRuntime.jsx(AuditLogExpandedDetails, { event: event }) : null] }));
|
|
9092
9241
|
}
|
|
9093
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(table.TableRow, { "data-state": isSelected ? 'selected' : undefined, className: cn('cursor-pointer', isNew && 'bg-
|
|
9242
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(table.TableRow, { "data-state": isSelected ? 'selected' : undefined, className: cn('cursor-pointer', isNew && 'bg-[var(--success-100)]/60', className), onClick: (e) => {
|
|
9094
9243
|
toggleExpand(e);
|
|
9095
9244
|
handleClick();
|
|
9096
|
-
}, "aria-expanded": isExpanded, children: [jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle whitespace-nowrap", children: jsxRuntime.jsx(Badge, {
|
|
9245
|
+
}, "aria-expanded": isExpanded, children: [jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle whitespace-nowrap", children: jsxRuntime.jsx(Badge, { variant: getVerbBadgeVariant(event.verb), className: VERB_BADGE_CLASSES, children: event.verb?.toUpperCase() || 'UNKNOWN' }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle", style: { width: '100%', maxWidth: 0, overflow: 'hidden' }, children: jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("div", { className: "text-sm leading-snug", style: {
|
|
9097
9246
|
overflow: 'hidden',
|
|
9098
9247
|
textOverflow: 'ellipsis',
|
|
9099
9248
|
whiteSpace: 'nowrap',
|
|
@@ -9103,7 +9252,7 @@ function AuditLogFeedItem({ event, onEventClick, isSelected = false, className =
|
|
|
9103
9252
|
/**
|
|
9104
9253
|
* React hook for executing audit log queries
|
|
9105
9254
|
*/
|
|
9106
|
-
function useAuditLogQuery({ client,
|
|
9255
|
+
function useAuditLogQuery({ client, }) {
|
|
9107
9256
|
const [query, setQuery] = React.useState(null);
|
|
9108
9257
|
const [events, setEvents] = React.useState([]);
|
|
9109
9258
|
const [isLoading, setIsLoading] = React.useState(false);
|
|
@@ -10270,40 +10419,10 @@ function ActivityExpandedDetails({ activity, compact = false, }) {
|
|
|
10270
10419
|
const timestamp = metadata?.creationTimestamp;
|
|
10271
10420
|
const actorDisplay = actor.displayName || actor.name;
|
|
10272
10421
|
const actorIsUser = actor.type === 'user';
|
|
10273
|
-
const body = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [changes && changes.length > 0 ? (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "m-0 mb-2 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/80", children: "Changes" }), jsxRuntime.jsx("div", { className: "flex flex-col gap-1.5", children: changes.map((change, index) => (jsxRuntime.jsxs("div", { className: "rounded bg-muted px-2.5 py-1.5 text-xs", children: [jsxRuntime.jsx("span", { className: "block font-mono text-[11px] font-semibold text-foreground", children: change.field }), change.old ? (jsxRuntime.jsxs("span", { className: "block ml-2 text-
|
|
10422
|
+
const body = (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [changes && changes.length > 0 ? (jsxRuntime.jsxs("div", { className: "mb-4", children: [jsxRuntime.jsx("h4", { className: "m-0 mb-2 text-[10px] font-semibold uppercase tracking-widest text-muted-foreground/80", children: "Changes" }), jsxRuntime.jsx("div", { className: "flex flex-col gap-1.5", children: changes.map((change, index) => (jsxRuntime.jsxs("div", { className: "rounded bg-muted px-2.5 py-1.5 text-xs", children: [jsxRuntime.jsx("span", { className: "block font-mono text-[11px] font-semibold text-foreground", children: change.field }), change.old ? (jsxRuntime.jsxs("span", { className: "block ml-2 text-destructive", children: [jsxRuntime.jsx("span", { className: "mr-1 font-medium", children: "\u2212" }), jsxRuntime.jsx("span", { className: "line-through", children: change.old })] })) : null, change.new ? (jsxRuntime.jsxs("span", { className: "block ml-2 text-[var(--success-500)]", children: [jsxRuntime.jsx("span", { className: "mr-1 font-medium", children: "+" }), change.new] })) : null] }, index))) })] })) : null, jsxRuntime.jsxs(DetailGrid, { children: [jsxRuntime.jsx(Section, { title: "When", children: jsxRuntime.jsx(Field, { label: "Timestamp", value: jsxRuntime.jsx(Timestamp, { value: timestamp, variant: "iso-utc" }), copyValue: timestamp ?? '', copyLabel: "timestamp", disableTooltip: true }) }), jsxRuntime.jsxs(Section, { title: "Actor", children: [jsxRuntime.jsx(Field, { label: "Name", value: jsxRuntime.jsxs("span", { children: [actorDisplay, actor.type ? (jsxRuntime.jsxs("span", { className: "ml-1 text-muted-foreground", children: ["(", actor.type, ")"] })) : null] }), copyValue: actorDisplay, copyLabel: "actor name" }), actorIsUser && actor.email ? (jsxRuntime.jsx(Field, { label: "Email", value: actor.email, copyValue: actor.email, mono: true })) : null, actor.uid ? (jsxRuntime.jsx(Field, { label: "UID", value: actor.uid, copyValue: actor.uid, mono: true })) : null] }), jsxRuntime.jsxs(Section, { title: "Resource", children: [jsxRuntime.jsx(Field, { label: "Kind", value: jsxRuntime.jsxs("span", { children: [resource.kind, resource.apiGroup ? (jsxRuntime.jsxs("span", { className: "ml-1 text-muted-foreground", children: ["\u00B7 ", resource.apiGroup] })) : null] }), copyValue: resource.kind, copyLabel: "resource kind" }), resource.name ? (jsxRuntime.jsx(Field, { label: "Name", value: resource.name, copyValue: resource.name, copyLabel: "resource name" })) : null, resource.namespace ? (jsxRuntime.jsx(Field, { label: "Namespace", value: resource.namespace, copyValue: resource.namespace })) : null, resource.uid ? (jsxRuntime.jsx(Field, { label: "UID", value: resource.uid, copyValue: resource.uid, mono: true })) : null] }), jsxRuntime.jsxs(Section, { title: "Origin", children: [jsxRuntime.jsx(Field, { label: "Source", value: origin.type, copyValue: origin.type, copyLabel: "origin type" }), origin.id ? (jsxRuntime.jsx(Field, { label: "ID", value: origin.id, copyValue: origin.id, mono: true })) : null] })] })] }));
|
|
10274
10423
|
return (jsxRuntime.jsx(TooltipProvider, { children: compact ? (jsxRuntime.jsx(DetailPanelShell, { children: body })) : (jsxRuntime.jsx("div", { className: "mt-4 pt-4 border-t border-border", children: body })) }));
|
|
10275
10424
|
}
|
|
10276
10425
|
|
|
10277
|
-
// Number of columns rendered for the feed variant. Used as the colSpan on
|
|
10278
|
-
// the expanded-detail row so it stretches across the full width.
|
|
10279
|
-
const ACTIVITY_FEED_COLUMN_COUNT = 5;
|
|
10280
|
-
/**
|
|
10281
|
-
* Get avatar initials from actor name
|
|
10282
|
-
*/
|
|
10283
|
-
function getActorInitials(name) {
|
|
10284
|
-
const parts = name.split(/[@\s.]+/).filter(Boolean);
|
|
10285
|
-
if (parts.length === 0)
|
|
10286
|
-
return "?";
|
|
10287
|
-
if (parts.length === 1)
|
|
10288
|
-
return parts[0].charAt(0).toUpperCase();
|
|
10289
|
-
return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
|
|
10290
|
-
}
|
|
10291
|
-
/**
|
|
10292
|
-
* Get Tailwind classes for actor avatar based on actor type
|
|
10293
|
-
*/
|
|
10294
|
-
function getActorAvatarClasses(actorType, compact) {
|
|
10295
|
-
const baseClasses = cn("rounded-full flex items-center justify-center shrink-0 font-semibold", compact ? "w-5 h-5 text-1xs" : "w-6 h-6 text-1xs");
|
|
10296
|
-
switch (actorType) {
|
|
10297
|
-
case "user":
|
|
10298
|
-
return cn(baseClasses, "bg-primary text-primary-foreground");
|
|
10299
|
-
case "controller":
|
|
10300
|
-
return cn(baseClasses, "bg-secondary text-secondary-foreground");
|
|
10301
|
-
case "machine account":
|
|
10302
|
-
return cn(baseClasses, "bg-muted text-muted-foreground");
|
|
10303
|
-
default:
|
|
10304
|
-
return cn(baseClasses, "bg-muted text-muted-foreground");
|
|
10305
|
-
}
|
|
10306
|
-
}
|
|
10307
10426
|
/**
|
|
10308
10427
|
* Extract verb from activity summary (e.g., "alice created HTTPProxy" -> "created")
|
|
10309
10428
|
*/
|
|
@@ -10312,24 +10431,24 @@ function extractVerb(summary) {
|
|
|
10312
10431
|
if (words.length >= 2) {
|
|
10313
10432
|
return words[1].toLowerCase();
|
|
10314
10433
|
}
|
|
10315
|
-
return
|
|
10434
|
+
return 'unknown';
|
|
10316
10435
|
}
|
|
10317
10436
|
/**
|
|
10318
|
-
* Normalize verb to a canonical form for coloring
|
|
10437
|
+
* Normalize a verb to a canonical form used for coloring/icons/grouping.
|
|
10319
10438
|
*/
|
|
10320
10439
|
function normalizeVerb(verb) {
|
|
10321
10440
|
const normalized = verb.toLowerCase();
|
|
10322
|
-
if (normalized.includes(
|
|
10323
|
-
return
|
|
10324
|
-
if (normalized.includes(
|
|
10325
|
-
return
|
|
10326
|
-
if (normalized.includes(
|
|
10327
|
-
normalized.includes(
|
|
10328
|
-
normalized.includes(
|
|
10329
|
-
normalized.includes(
|
|
10330
|
-
normalized.includes(
|
|
10331
|
-
return
|
|
10332
|
-
return
|
|
10441
|
+
if (normalized.includes('create') || normalized.includes('add'))
|
|
10442
|
+
return 'create';
|
|
10443
|
+
if (normalized.includes('delete') || normalized.includes('remove'))
|
|
10444
|
+
return 'delete';
|
|
10445
|
+
if (normalized.includes('update') ||
|
|
10446
|
+
normalized.includes('patch') ||
|
|
10447
|
+
normalized.includes('modify') ||
|
|
10448
|
+
normalized.includes('change') ||
|
|
10449
|
+
normalized.includes('edit'))
|
|
10450
|
+
return 'update';
|
|
10451
|
+
return 'other';
|
|
10333
10452
|
}
|
|
10334
10453
|
/**
|
|
10335
10454
|
* Get icon container + icon color classes based on verb
|
|
@@ -10337,25 +10456,25 @@ function normalizeVerb(verb) {
|
|
|
10337
10456
|
function getActionIconClasses(verb) {
|
|
10338
10457
|
const normalizedVerb = normalizeVerb(verb);
|
|
10339
10458
|
switch (normalizedVerb) {
|
|
10340
|
-
case
|
|
10459
|
+
case 'create':
|
|
10341
10460
|
return {
|
|
10342
|
-
container:
|
|
10343
|
-
icon:
|
|
10461
|
+
container: 'bg-blue-50 dark:bg-blue-950',
|
|
10462
|
+
icon: 'text-blue-500 dark:text-blue-400',
|
|
10344
10463
|
};
|
|
10345
|
-
case
|
|
10464
|
+
case 'update':
|
|
10346
10465
|
return {
|
|
10347
|
-
container:
|
|
10348
|
-
icon:
|
|
10466
|
+
container: 'bg-green-50 dark:bg-green-950',
|
|
10467
|
+
icon: 'text-green-600 dark:text-green-400',
|
|
10349
10468
|
};
|
|
10350
|
-
case
|
|
10469
|
+
case 'delete':
|
|
10351
10470
|
return {
|
|
10352
|
-
container:
|
|
10353
|
-
icon:
|
|
10471
|
+
container: 'bg-red-50 dark:bg-red-950',
|
|
10472
|
+
icon: 'text-red-500 dark:text-red-400',
|
|
10354
10473
|
};
|
|
10355
10474
|
default:
|
|
10356
10475
|
return {
|
|
10357
|
-
container:
|
|
10358
|
-
icon:
|
|
10476
|
+
container: 'bg-slate-100 dark:bg-slate-800',
|
|
10477
|
+
icon: 'text-slate-500 dark:text-slate-400',
|
|
10359
10478
|
};
|
|
10360
10479
|
}
|
|
10361
10480
|
}
|
|
@@ -10365,20 +10484,51 @@ function getActionIconClasses(verb) {
|
|
|
10365
10484
|
function getTimelineIcon(verb) {
|
|
10366
10485
|
const normalizedVerb = normalizeVerb(verb);
|
|
10367
10486
|
switch (normalizedVerb) {
|
|
10368
|
-
case
|
|
10487
|
+
case 'create':
|
|
10369
10488
|
return Plus;
|
|
10370
|
-
case
|
|
10489
|
+
case 'update':
|
|
10371
10490
|
return Pencil;
|
|
10372
|
-
case
|
|
10491
|
+
case 'delete':
|
|
10373
10492
|
return Trash2;
|
|
10374
10493
|
default:
|
|
10375
10494
|
return Activity;
|
|
10376
10495
|
}
|
|
10377
10496
|
}
|
|
10497
|
+
|
|
10498
|
+
// Number of columns rendered for the feed variant. Used as the colSpan on
|
|
10499
|
+
// the expanded-detail row so it stretches across the full width.
|
|
10500
|
+
const ACTIVITY_FEED_COLUMN_COUNT = 5;
|
|
10501
|
+
/**
|
|
10502
|
+
* Get avatar initials from actor name
|
|
10503
|
+
*/
|
|
10504
|
+
function getActorInitials(name) {
|
|
10505
|
+
const parts = name.split(/[@\s.]+/).filter(Boolean);
|
|
10506
|
+
if (parts.length === 0)
|
|
10507
|
+
return "?";
|
|
10508
|
+
if (parts.length === 1)
|
|
10509
|
+
return parts[0].charAt(0).toUpperCase();
|
|
10510
|
+
return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
|
|
10511
|
+
}
|
|
10512
|
+
/**
|
|
10513
|
+
* Get Tailwind classes for actor avatar based on actor type
|
|
10514
|
+
*/
|
|
10515
|
+
function getActorAvatarClasses(actorType, compact) {
|
|
10516
|
+
const baseClasses = cn("rounded-full flex items-center justify-center shrink-0 font-semibold", compact ? "w-5 h-5 text-1xs" : "w-6 h-6 text-1xs");
|
|
10517
|
+
switch (actorType) {
|
|
10518
|
+
case "user":
|
|
10519
|
+
return cn(baseClasses, "bg-primary text-primary-foreground");
|
|
10520
|
+
case "controller":
|
|
10521
|
+
return cn(baseClasses, "bg-secondary text-secondary-foreground");
|
|
10522
|
+
case "machine account":
|
|
10523
|
+
return cn(baseClasses, "bg-muted text-muted-foreground");
|
|
10524
|
+
default:
|
|
10525
|
+
return cn(baseClasses, "bg-muted text-muted-foreground");
|
|
10526
|
+
}
|
|
10527
|
+
}
|
|
10378
10528
|
/**
|
|
10379
10529
|
* ActivityFeedItem renders a single activity in the feed or timeline
|
|
10380
10530
|
*/
|
|
10381
|
-
function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isSelected = false, className = "", compact = false, isNew = false, variant = "feed", isLast = false, defaultExpanded = false, }) {
|
|
10531
|
+
function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isSelected = false, className = "", compact = false, isNew = false, variant = "feed", isLast = false, defaultExpanded = false, density = "default", }) {
|
|
10382
10532
|
const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);
|
|
10383
10533
|
const { spec, metadata } = activity;
|
|
10384
10534
|
const { actor, summary, links, tenant } = spec;
|
|
@@ -10399,7 +10549,7 @@ function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, ten
|
|
|
10399
10549
|
if (isTimeline) {
|
|
10400
10550
|
const { container: iconBg, icon: iconColor } = getActionIconClasses(verb);
|
|
10401
10551
|
const Icon = getTimelineIcon(verb);
|
|
10402
|
-
return (jsxRuntime.jsxs("div", { className: cn(!isLast && !isExpanded && "border-b border-border", className), children: [jsxRuntime.jsxs("div", { className: cn("flex items-center gap-3
|
|
10552
|
+
return (jsxRuntime.jsxs("div", { className: cn(!isLast && !isExpanded && "border-b border-border", className), children: [jsxRuntime.jsxs("div", { className: cn("flex items-center gap-3 cursor-pointer group", density === "compact" ? "py-1.5" : "py-3", isSelected && "bg-muted/40"), onClick: toggleExpand, children: [jsxRuntime.jsx("div", { className: cn("rounded-md shrink-0 flex items-center justify-center", density === "compact" ? "w-6 h-6" : "w-8 h-8", 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", children: jsxRuntime.jsx(Timestamp, { value: timestamp }) }), jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", 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 }))] }));
|
|
10403
10553
|
}
|
|
10404
10554
|
// Feed variant — flat-column table row. Columns: Actor | Summary |
|
|
10405
10555
|
// Tenant | When | expand toggle. Renders an additional TableRow with a
|
|
@@ -10413,7 +10563,7 @@ function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, ten
|
|
|
10413
10563
|
// surfaced via a hover tooltip on the avatar so the column stays narrow.
|
|
10414
10564
|
const actorTooltipBody = (jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5 text-xs", children: [jsxRuntime.jsx("span", { className: "font-medium", children: actorVisible }), actor.email && actor.email !== actorVisible ? (jsxRuntime.jsx("span", { className: "font-mono", children: actor.email })) : null, actor.uid ? (jsxRuntime.jsx("span", { className: "font-mono opacity-70", children: actor.uid })) : null] }));
|
|
10415
10565
|
const actorCell = (jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: avatar }), jsxRuntime.jsx(TooltipContent, { children: actorTooltipBody })] }));
|
|
10416
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(table.TableRow, { "data-state": isSelected ? "selected" : undefined, className: cn("cursor-pointer", isNew && "bg-
|
|
10566
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(table.TableRow, { "data-state": isSelected ? "selected" : undefined, className: cn("cursor-pointer", isNew && "bg-[var(--success-100)]/60", className), onClick: (e) => {
|
|
10417
10567
|
// Row-level click toggles expansion. Inner interactive elements
|
|
10418
10568
|
// (links, avatar, expand button) call e.stopPropagation() so
|
|
10419
10569
|
// they don't double-fire. If a parent passed onActivityClick,
|
|
@@ -10584,6 +10734,18 @@ function useFacets(client, timeRange, filters = {}) {
|
|
|
10584
10734
|
};
|
|
10585
10735
|
}
|
|
10586
10736
|
|
|
10737
|
+
/**
|
|
10738
|
+
* SegmentedToggle - a single-select control built on datum-ui's ButtonGroup.
|
|
10739
|
+
* The active segment is a solid primary Button; inactive segments sit on the
|
|
10740
|
+
* neutral (muted) button surface so the control reads in both themes.
|
|
10741
|
+
*/
|
|
10742
|
+
function SegmentedToggle({ options, value, onChange, ariaLabel, className, disabled = false, }) {
|
|
10743
|
+
return (jsxRuntime.jsx(buttonGroup.ButtonGroup, { "aria-label": ariaLabel, className: className, children: options.map((option) => {
|
|
10744
|
+
const active = value === option.value;
|
|
10745
|
+
return (jsxRuntime.jsx(button.Button, { htmlType: "button", size: "small", type: active ? 'primary' : 'quaternary', theme: active ? 'solid' : 'light', className: cn('font-medium', !active && 'border border-border'), onClick: () => onChange(option.value), disabled: disabled, "aria-pressed": active, title: option.description, children: option.label }, option.value));
|
|
10746
|
+
}) }));
|
|
10747
|
+
}
|
|
10748
|
+
|
|
10587
10749
|
/**
|
|
10588
10750
|
* Options for the change source toggle
|
|
10589
10751
|
*/
|
|
@@ -10607,17 +10769,8 @@ const OPTIONS$1 = [
|
|
|
10607
10769
|
/**
|
|
10608
10770
|
* ChangeSourceToggle provides a segmented control for filtering by change source
|
|
10609
10771
|
*/
|
|
10610
|
-
function ChangeSourceToggle({ value, onChange, className
|
|
10611
|
-
return (jsxRuntime.jsx(
|
|
10612
|
-
const active = value === option.value;
|
|
10613
|
-
return (jsxRuntime.jsx(button.Button, { htmlType: "button", type: active ? 'primary' : 'quaternary', theme: active ? 'solid' : 'borderless', className: cn('px-2 h-7 text-xs font-medium transition-all duration-200', index < OPTIONS$1.length - 1 && 'border-r border-input', !active && 'bg-muted text-foreground hover:bg-muted/80'),
|
|
10614
|
-
// Inline styles win over datum-ui's baked-in `rounded-lg` and
|
|
10615
|
-
// (for the primary/solid active button) its own `border`. The
|
|
10616
|
-
// outer wrapper's rounded-md + overflow-hidden draws the
|
|
10617
|
-
// segmented control's outer corners; per-button border-right
|
|
10618
|
-
// (className) draws the separators between inactive buttons.
|
|
10619
|
-
style: active ? { borderRadius: 0, border: 0 } : { borderRadius: 0 }, onClick: () => onChange(option.value), disabled: disabled, "aria-pressed": active, title: option.description, children: option.label }, option.value));
|
|
10620
|
-
}) }));
|
|
10772
|
+
function ChangeSourceToggle({ value, onChange, className, disabled = false, }) {
|
|
10773
|
+
return (jsxRuntime.jsx(SegmentedToggle, { options: OPTIONS$1, value: value, onChange: onChange, ariaLabel: "Filter by change source", className: className, disabled: disabled }));
|
|
10621
10774
|
}
|
|
10622
10775
|
|
|
10623
10776
|
/**
|
|
@@ -10689,7 +10842,7 @@ const getSelectedPreset$1 = (timeRange) => {
|
|
|
10689
10842
|
/**
|
|
10690
10843
|
* ActivityFeedFilters provides filter controls for the activity feed
|
|
10691
10844
|
*/
|
|
10692
|
-
function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTimeRangeChange, disabled = false, hiddenFilters = [], className = "", extraFilters, }) {
|
|
10845
|
+
function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTimeRangeChange, disabled = false, hiddenFilters = [], className = "", extraFilters, layout = "inline", }) {
|
|
10693
10846
|
const { resourceKinds, actorNames, apiGroups, resourceNamespaces, error: facetsError, } = useFacets(client, timeRange, filters);
|
|
10694
10847
|
// Log facets error for debugging
|
|
10695
10848
|
if (facetsError) {
|
|
@@ -10909,12 +11062,186 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
|
|
|
10909
11062
|
clearTimeout(searchDebounceRef.current);
|
|
10910
11063
|
onFiltersChangeRef.current({ ...filtersRef.current, search: undefined });
|
|
10911
11064
|
}, []);
|
|
10912
|
-
|
|
11065
|
+
const searchInput = (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.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" }) }))] }));
|
|
11066
|
+
const changeSourceControl = !hiddenFilters.includes("changeSource") && (jsxRuntime.jsx(ChangeSourceToggle, { value: filters.changeSource || "all", onChange: handleChangeSourceChange, disabled: disabled }));
|
|
11067
|
+
const filterChips = activeFilterIds.map((filterId) => {
|
|
11068
|
+
const config = FILTER_CONFIGS$1[filterId];
|
|
11069
|
+
return (jsxRuntime.jsx(FilterChip, { label: config.label, values: getFilterValues(filterId), options: config.inputMode === "typeahead"
|
|
11070
|
+
? getFilterOptions(filterId)
|
|
11071
|
+
: 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));
|
|
11072
|
+
});
|
|
11073
|
+
const addFilterControl = (jsxRuntime.jsx(AddFilterDropdown, { availableFilters: availableFilters, activeFilterIds: activeFilterIds, onAddFilter: handleAddFilter, hasActiveFilters: activeFilterIds.length > 0, disabled: disabled }));
|
|
11074
|
+
const timeRangeControl = (jsxRuntime.jsx(TimeRangeDropdown, { presets: TIME_PRESETS$1, selectedPreset: selectedPreset, onPresetSelect: handleTimePresetSelect, onCustomRangeApply: handleCustomRangeApply, customStart: customStart, customEnd: customEnd, disabled: disabled, displayLabel: getTimeRangeLabel() }));
|
|
11075
|
+
if (layout === "compact") {
|
|
11076
|
+
const activeFilterCount = activeFilterIds.length +
|
|
11077
|
+
(!hiddenFilters.includes("changeSource") &&
|
|
11078
|
+
filters.changeSource &&
|
|
11079
|
+
filters.changeSource !== "all"
|
|
11080
|
+
? 1
|
|
11081
|
+
: 0);
|
|
11082
|
+
return (jsxRuntime.jsx("div", { className: `border-b border-border py-4 ${className}`, children: jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [searchInput, jsxRuntime.jsxs(popover.Popover, { children: [jsxRuntime.jsx(popover.PopoverTrigger, { asChild: true, children: jsxRuntime.jsxs("button", { type: "button", disabled: disabled, className: cn("flex h-7 items-center gap-1.5 rounded-md border border-border bg-background px-2 text-xs", "text-muted-foreground hover:text-foreground hover:border-foreground/50 transition-colors", "focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2", "disabled:cursor-not-allowed disabled:opacity-50"), children: [jsxRuntime.jsx(SlidersHorizontal, { className: "h-3.5 w-3.5" }), jsxRuntime.jsx("span", { className: "font-medium", children: "Filters" }), activeFilterCount > 0 && (jsxRuntime.jsx("span", { className: "ml-0.5 rounded-full bg-primary text-primary-foreground text-[10px] font-semibold leading-none px-1.5 py-0.5", children: activeFilterCount }))] }) }), jsxRuntime.jsx(popover.PopoverContent, { className: "w-[320px] p-3", sideOffset: 4, align: "start", children: jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [changeSourceControl, jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [filterChips, addFilterControl] }), extraFilters, timeRangeControl] }) })] })] }) }));
|
|
11083
|
+
}
|
|
11084
|
+
return (jsxRuntime.jsx("div", { className: `border-b border-border py-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: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), jsxRuntime.jsx(input.Input, { type: "text", placeholder: "Search activities...", value: searchInputValue, onChange: handleSearchChange, className: "h-9 pl-9 pr-9 text-xs md:text-xs" }), searchInputValue && (jsxRuntime.jsx("button", { onClick: handleSearchClear, className: "absolute right-0 top-0 flex h-9 w-9 items-center justify-center rounded-r-lg text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "aria-label": "Clear search", children: jsxRuntime.jsx(X, { className: "h-3.5 w-3.5" }) }))] }), activeFilterIds.map((filterId) => {
|
|
10913
11085
|
const config = FILTER_CONFIGS$1[filterId];
|
|
10914
11086
|
return (jsxRuntime.jsx(FilterChip, { label: config.label, values: getFilterValues(filterId), options: config.inputMode === "typeahead"
|
|
10915
11087
|
? getFilterOptions(filterId)
|
|
10916
11088
|
: 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));
|
|
10917
|
-
}), jsxRuntime.jsx(AddFilterDropdown, { availableFilters: availableFilters, activeFilterIds: activeFilterIds, onAddFilter: handleAddFilter, hasActiveFilters: activeFilterIds.length > 0, disabled: disabled }), extraFilters, jsxRuntime.jsx("div", { className: "flex-1 min-w-[20px]" }),
|
|
11089
|
+
}), jsxRuntime.jsx(AddFilterDropdown, { availableFilters: availableFilters, activeFilterIds: activeFilterIds, onAddFilter: handleAddFilter, hasActiveFilters: activeFilterIds.length > 0, disabled: disabled }), extraFilters, jsxRuntime.jsx("div", { className: "flex-1 min-w-[20px]" }), timeRangeControl] }) }));
|
|
11090
|
+
}
|
|
11091
|
+
|
|
11092
|
+
const KIND_PLURALS = {
|
|
11093
|
+
DNSRecordSet: "DNS records",
|
|
11094
|
+
};
|
|
11095
|
+
function pluralizeKind(kind, count) {
|
|
11096
|
+
if (count === 1)
|
|
11097
|
+
return kind;
|
|
11098
|
+
return KIND_PLURALS[kind] ?? `${kind}s`;
|
|
11099
|
+
}
|
|
11100
|
+
const VERB_LABEL = {
|
|
11101
|
+
create: "created",
|
|
11102
|
+
update: "updated",
|
|
11103
|
+
delete: "deleted",
|
|
11104
|
+
other: "changed",
|
|
11105
|
+
};
|
|
11106
|
+
/**
|
|
11107
|
+
* ActivityFeedGroupItem renders a run of consecutive same verb/kind/actor
|
|
11108
|
+
* activities (see `groupActivities`) as a single collapsed row in the
|
|
11109
|
+
* "digest" timeline. A group of size 1 renders exactly like a normal
|
|
11110
|
+
* `ActivityFeedItem` — no visual change for ungrouped activities. Larger
|
|
11111
|
+
* groups render a synthesized summary ("{actor} created 12 DNS records")
|
|
11112
|
+
* that expands to reveal the individual activities underneath.
|
|
11113
|
+
*/
|
|
11114
|
+
function ActivityFeedGroupItem({ group, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isLast = false, }) {
|
|
11115
|
+
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
11116
|
+
if (group.count === 1) {
|
|
11117
|
+
return (jsxRuntime.jsx(ActivityFeedItem, { activity: group.activities[0], resourceLinkResolver: resourceLinkResolver, tenantLinkResolver: tenantLinkResolver, tenantRenderer: tenantRenderer, onActorClick: onActorClick, onActivityClick: onActivityClick, variant: "timeline", density: "compact", isLast: isLast }));
|
|
11118
|
+
}
|
|
11119
|
+
const { container: iconBg, icon: iconColor } = getActionIconClasses(group.verb);
|
|
11120
|
+
const Icon = getTimelineIcon(group.verb);
|
|
11121
|
+
const actorVisible = group.actorDisplayName || group.actorName;
|
|
11122
|
+
const summary = `${actorVisible} ${VERB_LABEL[group.verb]} ${group.count} ${pluralizeKind(group.kind, group.count)}`;
|
|
11123
|
+
const toggleExpand = (e) => {
|
|
11124
|
+
e.stopPropagation();
|
|
11125
|
+
setIsExpanded((prev) => !prev);
|
|
11126
|
+
};
|
|
11127
|
+
return (jsxRuntime.jsxs("div", { className: cn(!isLast && !isExpanded && "border-b border-border"), children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-3 py-1.5 cursor-pointer group", onClick: toggleExpand, children: [jsxRuntime.jsxs("div", { className: cn("w-6 h-6 rounded-md shrink-0 flex items-center justify-center relative", iconBg, iconColor), children: [jsxRuntime.jsx(Icon, { size: 14, strokeWidth: 2 }), jsxRuntime.jsx("span", { className: "absolute -bottom-1 -right-1 rounded-full bg-background border border-border px-1 text-[10px] font-semibold leading-tight text-foreground", children: group.count })] }), jsxRuntime.jsx("div", { className: "flex-1 min-w-0 text-xs text-foreground leading-normal", children: summary }), group.tenant && (jsxRuntime.jsx("div", { className: "shrink-0", children: tenantRenderer ? (tenantRenderer(group.tenant)) : (jsxRuntime.jsx(TenantBadge, { tenant: group.tenant, tenantLinkResolver: tenantLinkResolver, size: "compact" })) })), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0", children: jsxRuntime.jsx(Timestamp, { value: group.latestTimestamp }) }), jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", 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("div", { className: "pl-11 flex flex-col", children: group.activities.map((activity, index) => (jsxRuntime.jsx(ActivityFeedItem, { activity: activity, resourceLinkResolver: resourceLinkResolver, tenantLinkResolver: tenantLinkResolver, tenantRenderer: tenantRenderer, onActorClick: onActorClick, onActivityClick: onActivityClick, compact: true, density: "compact", variant: "timeline", isLast: index === group.activities.length - 1 }, activity.metadata?.uid || activity.metadata?.name))) }))] }));
|
|
11128
|
+
}
|
|
11129
|
+
|
|
11130
|
+
/**
|
|
11131
|
+
* Thin stat strip summarizing the activities currently loaded in the feed —
|
|
11132
|
+
* e.g. "18 changes · 3 people · 1 system". Computed client-side over the
|
|
11133
|
+
* loaded/paginated activities; it is a quick-glance headline, not a
|
|
11134
|
+
* full-range aggregate (that would require a backend facet query).
|
|
11135
|
+
*/
|
|
11136
|
+
function ActivityDigestSummary({ activities, className = "" }) {
|
|
11137
|
+
const stats = React.useMemo(() => {
|
|
11138
|
+
const humanActors = new Set();
|
|
11139
|
+
const systemActors = new Set();
|
|
11140
|
+
for (const activity of activities) {
|
|
11141
|
+
const { actor, changeSource } = activity.spec;
|
|
11142
|
+
if (changeSource === "human") {
|
|
11143
|
+
humanActors.add(actor.name);
|
|
11144
|
+
}
|
|
11145
|
+
else {
|
|
11146
|
+
systemActors.add(actor.name);
|
|
11147
|
+
}
|
|
11148
|
+
}
|
|
11149
|
+
return {
|
|
11150
|
+
total: activities.length,
|
|
11151
|
+
people: humanActors.size,
|
|
11152
|
+
systems: systemActors.size,
|
|
11153
|
+
};
|
|
11154
|
+
}, [activities]);
|
|
11155
|
+
if (stats.total === 0)
|
|
11156
|
+
return null;
|
|
11157
|
+
const parts = [`${stats.total} ${stats.total === 1 ? "change" : "changes"}`];
|
|
11158
|
+
if (stats.people > 0)
|
|
11159
|
+
parts.push(`${stats.people} ${stats.people === 1 ? "person" : "people"}`);
|
|
11160
|
+
if (stats.systems > 0)
|
|
11161
|
+
parts.push(`${stats.systems} ${stats.systems === 1 ? "system" : "systems"}`);
|
|
11162
|
+
return (jsxRuntime.jsx("div", { className: `px-1 pt-4 pb-2 text-xs text-muted-foreground ${className}`, children: parts.join(" · ") }));
|
|
11163
|
+
}
|
|
11164
|
+
|
|
11165
|
+
function tenantKey(tenant) {
|
|
11166
|
+
if (!tenant)
|
|
11167
|
+
return '';
|
|
11168
|
+
return `${tenant.type}:${tenant.name}`;
|
|
11169
|
+
}
|
|
11170
|
+
function groupSignature(activity) {
|
|
11171
|
+
const { spec } = activity;
|
|
11172
|
+
const verb = normalizeVerb(extractVerb(spec.summary));
|
|
11173
|
+
return [verb, spec.resource.kind, spec.actor.name, tenantKey(spec.tenant)].join('|');
|
|
11174
|
+
}
|
|
11175
|
+
/**
|
|
11176
|
+
* Group consecutive activities that share verb + resource kind + actor +
|
|
11177
|
+
* tenant. Activities are assumed to already be sorted newest-first (as
|
|
11178
|
+
* returned by `useActivityFeed`); only adjacent items are merged, so a
|
|
11179
|
+
* burst of matching activities collapses into one group without needing
|
|
11180
|
+
* any time-window heuristics.
|
|
11181
|
+
*/
|
|
11182
|
+
function groupActivities(activities) {
|
|
11183
|
+
const groups = [];
|
|
11184
|
+
for (const activity of activities) {
|
|
11185
|
+
const signature = groupSignature(activity);
|
|
11186
|
+
const last = groups[groups.length - 1];
|
|
11187
|
+
if (last && last.key === signature) {
|
|
11188
|
+
last.activities.push(activity);
|
|
11189
|
+
last.count += 1;
|
|
11190
|
+
continue;
|
|
11191
|
+
}
|
|
11192
|
+
const { spec } = activity;
|
|
11193
|
+
groups.push({
|
|
11194
|
+
key: signature,
|
|
11195
|
+
verb: normalizeVerb(extractVerb(spec.summary)),
|
|
11196
|
+
kind: spec.resource.kind,
|
|
11197
|
+
actorName: spec.actor.name,
|
|
11198
|
+
actorDisplayName: spec.actor.displayName,
|
|
11199
|
+
tenant: spec.tenant,
|
|
11200
|
+
activities: [activity],
|
|
11201
|
+
count: 1,
|
|
11202
|
+
latestTimestamp: activity.metadata?.creationTimestamp,
|
|
11203
|
+
});
|
|
11204
|
+
}
|
|
11205
|
+
return groups;
|
|
11206
|
+
}
|
|
11207
|
+
function dayLabel(timestamp) {
|
|
11208
|
+
if (!timestamp)
|
|
11209
|
+
return 'Unknown date';
|
|
11210
|
+
const date = new Date(timestamp);
|
|
11211
|
+
if (Number.isNaN(date.getTime()))
|
|
11212
|
+
return 'Unknown date';
|
|
11213
|
+
if (isToday(date))
|
|
11214
|
+
return 'Today';
|
|
11215
|
+
if (isYesterday(date))
|
|
11216
|
+
return 'Yesterday';
|
|
11217
|
+
return format(date, 'MMMM d, yyyy');
|
|
11218
|
+
}
|
|
11219
|
+
/**
|
|
11220
|
+
* Bucket activities into calendar-day sections (Today / Yesterday / a
|
|
11221
|
+
* formatted date), then group consecutive matching activities within each
|
|
11222
|
+
* day. Bucketing by day first (rather than grouping across the whole list)
|
|
11223
|
+
* keeps a group from silently spanning a day boundary.
|
|
11224
|
+
*/
|
|
11225
|
+
function groupActivitiesByDay(activities) {
|
|
11226
|
+
const sections = [];
|
|
11227
|
+
let currentLabel = null;
|
|
11228
|
+
let currentBucket = [];
|
|
11229
|
+
const flush = () => {
|
|
11230
|
+
if (currentLabel !== null && currentBucket.length > 0) {
|
|
11231
|
+
sections.push({ label: currentLabel, groups: groupActivities(currentBucket) });
|
|
11232
|
+
}
|
|
11233
|
+
};
|
|
11234
|
+
for (const activity of activities) {
|
|
11235
|
+
const label = dayLabel(activity.metadata?.creationTimestamp);
|
|
11236
|
+
if (label !== currentLabel) {
|
|
11237
|
+
flush();
|
|
11238
|
+
currentLabel = label;
|
|
11239
|
+
currentBucket = [];
|
|
11240
|
+
}
|
|
11241
|
+
currentBucket.push(activity);
|
|
11242
|
+
}
|
|
11243
|
+
flush();
|
|
11244
|
+
return sections;
|
|
10918
11245
|
}
|
|
10919
11246
|
|
|
10920
11247
|
/**
|
|
@@ -10984,26 +11311,28 @@ function ActivityFeed({ client, initialFilters = { changeSource: "human" }, init
|
|
|
10984
11311
|
React.useEffect(() => {
|
|
10985
11312
|
isLoadingRef.current = isLoading;
|
|
10986
11313
|
}, [isLoading]);
|
|
10987
|
-
// Infinite scroll using Intersection Observer
|
|
11314
|
+
// Infinite scroll using Intersection Observer.
|
|
11315
|
+
// The list container is the root only when it actually scrolls. Host apps
|
|
11316
|
+
// such as cloud-portal scroll at the page level, so the container never
|
|
11317
|
+
// overflows; in that case observe against the viewport instead.
|
|
10988
11318
|
React.useEffect(() => {
|
|
10989
11319
|
if (!infiniteScroll || !hasMore || !loadMoreTriggerRef.current)
|
|
10990
11320
|
return;
|
|
11321
|
+
const container = scrollContainerRef.current;
|
|
11322
|
+
const containerScrolls = !!container && container.scrollHeight > container.clientHeight + 1;
|
|
10991
11323
|
const observer = new IntersectionObserver((entries) => {
|
|
10992
11324
|
const entry = entries[0];
|
|
10993
11325
|
if (entry.isIntersecting && !isLoadingRef.current) {
|
|
10994
|
-
// Call through the ref to always use the latest function
|
|
10995
11326
|
loadMoreRef.current();
|
|
10996
11327
|
}
|
|
10997
11328
|
}, {
|
|
10998
|
-
root:
|
|
11329
|
+
root: containerScrolls ? container : null,
|
|
10999
11330
|
rootMargin: `${loadMoreThreshold}px`,
|
|
11000
11331
|
threshold: 0,
|
|
11001
11332
|
});
|
|
11002
11333
|
observer.observe(loadMoreTriggerRef.current);
|
|
11003
|
-
return () =>
|
|
11004
|
-
|
|
11005
|
-
};
|
|
11006
|
-
}, [infiniteScroll, loadMoreThreshold, hasMore]);
|
|
11334
|
+
return () => observer.disconnect();
|
|
11335
|
+
}, [infiniteScroll, loadMoreThreshold, hasMore, activities.length]);
|
|
11007
11336
|
// Handle filter changes - refresh is automatic via the hook
|
|
11008
11337
|
const handleFiltersChange = React.useCallback((newFilters) => {
|
|
11009
11338
|
setFilters(newFilters);
|
|
@@ -11043,10 +11372,10 @@ function ActivityFeed({ client, initialFilters = { changeSource: "human" }, init
|
|
|
11043
11372
|
// Parent containers must have proper height constraints (h-screen/h-full + overflow-hidden)
|
|
11044
11373
|
const effectiveMaxHeight = maxHeight === "none" ? undefined : maxHeight;
|
|
11045
11374
|
const listClasses = "flex-1 min-h-0 overflow-y-auto flex flex-col";
|
|
11046
|
-
return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: jsxRuntime.jsxs(card.Card, { className: containerClasses, children: [enableStreaming && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [jsxRuntime.jsxs("div", { className: "flex items-center", 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-
|
|
11375
|
+
return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: jsxRuntime.jsxs(card.Card, { className: containerClasses, children: [enableStreaming && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [jsxRuntime.jsxs("div", { className: "flex items-center", 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-[var(--success-500)] opacity-75" }), jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-[var(--success-500)]" })] }), 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-destructive" }) }), 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.Button, { type: "tertiary", theme: "outline", size: "small", onClick: handleStreamingToggle, 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, layout: variant === "digest" ? "compact" : "inline" })), variant === "digest" && !isLoading && activities.length > 0 && (jsxRuntime.jsx(ActivityDigestSummary, { activities: activities })), 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.Button, { onClick: onCreatePolicy, children: "Create Policy" }))] })), jsxRuntime.jsxs("div", { className: listClasses, ref: scrollContainerRef, style: effectiveMaxHeight ? { maxHeight: effectiveMaxHeight } : undefined, children: [!isLoading &&
|
|
11047
11376
|
activities.length === 0 &&
|
|
11048
11377
|
hasPolicies !== false &&
|
|
11049
|
-
variant === "timeline" && (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" })] })), variant === "timeline" ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isLoading && activities.length === 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsx(ActivityFeedItemSkeleton, { compact: compact }, index))) })), 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)))] })) : (jsxRuntime.jsxs(table.Table, { className: "w-full", children: [jsxRuntime.jsx(table.TableHeader, { children: jsxRuntime.jsxs(table.TableRow, { children: [jsxRuntime.jsx(table.TableHead, { className: "w-12", "aria-label": "Actor" }), jsxRuntime.jsx(table.TableHead, { children: "Summary" }), jsxRuntime.jsx(table.TableHead, { children: "Tenant" }), jsxRuntime.jsx(table.TableHead, { className: "w-[170px]", children: "When" }), jsxRuntime.jsx(table.TableHead, { className: "w-10", "aria-label": "Expand" })] }) }), jsxRuntime.jsxs(table.TableBody, { children: [isLoading && activities.length === 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsxs(table.TableRow, { children: [jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-6 w-6 rounded-full" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-3/4" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-5 w-32 rounded-full" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-6 w-6" }) })] }, `sk-${index}`))) })), !isLoading &&
|
|
11378
|
+
(variant === "timeline" || variant === "digest") && (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" })] })), variant === "digest" ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isLoading && activities.length === 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsx(ActivityFeedItemSkeleton, { compact: compact }, index))) })), groupActivitiesByDay(activities).map((section) => (jsxRuntime.jsxs("div", { className: "flex flex-col", children: [jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-card pt-2 pb-1 text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: section.label }), section.groups.map((group, index) => (jsxRuntime.jsx(ActivityFeedGroupItem, { group: group, resourceLinkResolver: resourceLinkResolver, tenantLinkResolver: tenantLinkResolver, tenantRenderer: tenantRenderer, onActorClick: handleActorClick, onActivityClick: onActivityClick, isLast: index === section.groups.length - 1 }, `${section.label}-${group.key}-${index}`)))] }, section.label)))] })) : variant === "timeline" ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [isLoading && activities.length === 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsx(ActivityFeedItemSkeleton, { compact: compact }, index))) })), 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)))] })) : (jsxRuntime.jsxs(table.Table, { className: "w-full", children: [jsxRuntime.jsx(table.TableHeader, { children: jsxRuntime.jsxs(table.TableRow, { children: [jsxRuntime.jsx(table.TableHead, { className: "w-12", "aria-label": "Actor" }), jsxRuntime.jsx(table.TableHead, { children: "Summary" }), jsxRuntime.jsx(table.TableHead, { children: "Tenant" }), jsxRuntime.jsx(table.TableHead, { className: "w-[170px]", children: "When" }), jsxRuntime.jsx(table.TableHead, { className: "w-10", "aria-label": "Expand" })] }) }), jsxRuntime.jsxs(table.TableBody, { children: [isLoading && activities.length === 0 && (jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsxs(table.TableRow, { children: [jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-6 w-6 rounded-full" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-3/4" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-5 w-32 rounded-full" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-6 w-6" }) })] }, `sk-${index}`))) })), !isLoading &&
|
|
11050
11379
|
activities.length === 0 &&
|
|
11051
11380
|
hasPolicies !== false && (jsxRuntime.jsx(table.TableRow, { children: jsxRuntime.jsxs(table.TableCell, { colSpan: ACTIVITY_FEED_COLUMN_COUNT, className: "text-center py-12 text-muted-foreground", children: [jsxRuntime.jsx("div", { children: "No activities found" }), jsxRuntime.jsx("div", { className: "text-sm mt-2", 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 && activities.length > 0 ? (jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-4 px-4 py-3 border-t border-border text-sm text-muted-foreground", children: [jsxRuntime.jsxs("span", { children: [activities.length, " ", activities.length === 1 ? "activity" : "activities", hasMore ? " so far" : ""] }), hasMore ? (jsxRuntime.jsx(button.Button, { type: "tertiary", theme: "outline", size: "small", htmlType: "button", onClick: handleLoadMoreClick, disabled: isLoading, children: isLoading ? "Loading…" : "Load more" })) : (jsxRuntime.jsx("span", { children: "End of results" }))] })) : null] })] }) }));
|
|
11052
11381
|
}
|
|
@@ -11697,7 +12026,7 @@ function useEventsFeed({ client, initialFilters = {}, initialTimeRange = { start
|
|
|
11697
12026
|
function getRegarding$1(event) {
|
|
11698
12027
|
return event.regarding || event.involvedObject || {};
|
|
11699
12028
|
}
|
|
11700
|
-
function getReportingController
|
|
12029
|
+
function getReportingController(event) {
|
|
11701
12030
|
return event.reportingController || event.reportingComponent || event.source?.component;
|
|
11702
12031
|
}
|
|
11703
12032
|
function getReportingInstance(event) {
|
|
@@ -11710,7 +12039,7 @@ function getReportingInstance(event) {
|
|
|
11710
12039
|
*/
|
|
11711
12040
|
function EventExpandedDetails({ event, compact = true }) {
|
|
11712
12041
|
const regarding = getRegarding$1(event);
|
|
11713
|
-
const reportingController = getReportingController
|
|
12042
|
+
const reportingController = getReportingController(event);
|
|
11714
12043
|
const reportingInstance = getReportingInstance(event);
|
|
11715
12044
|
const { eventTime, action, metadata, related } = event;
|
|
11716
12045
|
const firstTimestamp = event.firstTimestamp || event.deprecatedFirstTimestamp;
|
|
@@ -11737,12 +12066,6 @@ function getRegarding(event) {
|
|
|
11737
12066
|
function getNote(event) {
|
|
11738
12067
|
return event.note || event.message;
|
|
11739
12068
|
}
|
|
11740
|
-
/**
|
|
11741
|
-
* Get the reporting controller (handling both new and deprecated field names)
|
|
11742
|
-
*/
|
|
11743
|
-
function getReportingController(event) {
|
|
11744
|
-
return event.reportingController || event.source?.component;
|
|
11745
|
-
}
|
|
11746
12069
|
/**
|
|
11747
12070
|
* Get the event count (handling both new and deprecated field names)
|
|
11748
12071
|
*/
|
|
@@ -11778,7 +12101,6 @@ function EventFeedItem({ event, onEventClick, onResourceClick, isSelected = fals
|
|
|
11778
12101
|
const note = getNote(event);
|
|
11779
12102
|
const count = getCount(event);
|
|
11780
12103
|
const timestamp = getTimestamp(event);
|
|
11781
|
-
getReportingController(event);
|
|
11782
12104
|
const { type, reason } = event;
|
|
11783
12105
|
const handleClick = () => {
|
|
11784
12106
|
onEventClick?.(event);
|
|
@@ -11821,11 +12143,11 @@ function EventFeedItem({ event, onEventClick, onResourceClick, isSelected = fals
|
|
|
11821
12143
|
if (variant === 'timeline') {
|
|
11822
12144
|
const TypeIcon = isWarning ? TriangleAlert : Bell;
|
|
11823
12145
|
const iconBg = isWarning
|
|
11824
|
-
? 'bg-
|
|
11825
|
-
: 'bg-
|
|
12146
|
+
? 'bg-destructive/10'
|
|
12147
|
+
: 'bg-[var(--info-100)]';
|
|
11826
12148
|
const iconColor = isWarning
|
|
11827
|
-
? 'text-
|
|
11828
|
-
: 'text-
|
|
12149
|
+
? 'text-destructive'
|
|
12150
|
+
: 'text-[var(--info-500)]';
|
|
11829
12151
|
const objectLabel = regarding.namespace
|
|
11830
12152
|
? `${regarding.kind || 'Unknown'} · ${regarding.namespace}/${regarding.name || ''}`
|
|
11831
12153
|
: `${regarding.kind || 'Unknown'} · ${regarding.name || ''}`;
|
|
@@ -11838,18 +12160,16 @@ function EventFeedItem({ event, onEventClick, onResourceClick, isSelected = fals
|
|
|
11838
12160
|
cursor: 'help',
|
|
11839
12161
|
}, children: summary }) }), jsxRuntime.jsx(TooltipContent, { className: "max-w-[480px] whitespace-normal break-words", children: summary })] })] }), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0 max-w-[200px] truncate", title: objectLabel, children: regarding.name }), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground whitespace-nowrap shrink-0", children: jsxRuntime.jsx(Timestamp, { value: timestamp }) }), jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", htmlType: "button", className: "h-5 py-0 px-1 text-muted-foreground hover:text-foreground shrink-0", onClick: toggleExpand, "aria-expanded": isExpanded, children: isExpanded ? jsxRuntime.jsx(ChevronDown, { className: "h-4 w-4" }) : jsxRuntime.jsx(ChevronRight, { className: "h-4 w-4" }) })] }), isExpanded ? jsxRuntime.jsx(EventExpandedDetails, { event: event }) : null] }));
|
|
11840
12162
|
}
|
|
11841
|
-
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(table.TableRow, { "data-state": isSelected ? 'selected' : undefined, className: cn('cursor-pointer', isNew && 'bg-
|
|
12163
|
+
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs(table.TableRow, { "data-state": isSelected ? 'selected' : undefined, className: cn('cursor-pointer', isNew && 'bg-[var(--success-100)]/60', isWarning && !isSelected && 'border-l-2 border-l-destructive', className), onClick: (e) => {
|
|
11842
12164
|
toggleExpand(e);
|
|
11843
12165
|
handleClick();
|
|
11844
|
-
}, "aria-expanded": isExpanded, children: [jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle whitespace-nowrap", children: jsxRuntime.jsx(
|
|
11845
|
-
? 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300'
|
|
11846
|
-
: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-300'), children: type || 'Unknown' }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle whitespace-nowrap text-sm font-medium", children: reason || '' }), jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle", style: { width: '100%', maxWidth: 0, overflow: 'hidden' }, children: note ? (jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground leading-snug", style: {
|
|
12166
|
+
}, "aria-expanded": isExpanded, children: [jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle whitespace-nowrap", children: jsxRuntime.jsx(badge.Badge, { type: isWarning ? 'danger' : 'info', theme: "light", className: "px-1.5 py-0.5 text-xs font-medium", children: type || 'Unknown' }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle whitespace-nowrap text-sm font-medium", children: reason || '' }), jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle", style: { width: '100%', maxWidth: 0, overflow: 'hidden' }, children: note ? (jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("div", { className: "text-sm text-muted-foreground leading-snug", style: {
|
|
11847
12167
|
overflow: 'hidden',
|
|
11848
12168
|
textOverflow: 'ellipsis',
|
|
11849
12169
|
whiteSpace: 'nowrap',
|
|
11850
12170
|
}, children: noteWithCount }) }), jsxRuntime.jsx(TooltipContent, { className: "max-w-[480px] whitespace-normal break-words", children: noteWithCount })] })) : null }), jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle", children: jsxRuntime.jsxs("div", { className: "flex items-center gap-1 min-w-0", children: [jsxRuntime.jsxs(Tooltip, { children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("span", { className: cn('text-sm font-medium text-foreground truncate', onResourceClick && 'cursor-pointer hover:underline hover:text-primary'), onClick: onResourceClick ? handleResourceClick : undefined, style: { maxWidth: 200 }, children: regarding.name || 'Unknown' }) }), jsxRuntime.jsx(TooltipContent, { children: regarding.namespace
|
|
11851
12171
|
? `${regarding.kind || 'Unknown'} · ${regarding.namespace}/${regarding.name}`
|
|
11852
|
-
: `${regarding.kind || 'Unknown'} · ${regarding.name}` })] }), jsxRuntime.jsx("button", { onClick: handleCopyResourceName, className: "inline-flex items-center justify-center p-0.5 rounded opacity-0 group-hover:opacity-100 hover:bg-
|
|
12172
|
+
: `${regarding.kind || 'Unknown'} · ${regarding.name}` })] }), jsxRuntime.jsx("button", { onClick: handleCopyResourceName, className: "inline-flex items-center justify-center p-0.5 rounded opacity-0 group-hover:opacity-100 hover:bg-muted cursor-pointer", "aria-label": "Copy resource name", type: "button", children: isCopied ? (jsxRuntime.jsx(Check, { className: "h-3 w-3 text-[var(--success-500)]" })) : (jsxRuntime.jsx(Copy, { className: "h-3 w-3 text-muted-foreground" })) })] }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle whitespace-nowrap text-sm text-muted-foreground", children: jsxRuntime.jsx(Timestamp, { value: timestamp }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2 align-middle w-10", children: jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", htmlType: "button", className: "h-6 w-6 p-0 text-muted-foreground hover:text-foreground", onClick: toggleExpand, "aria-expanded": isExpanded, "aria-label": isExpanded ? 'Collapse details' : 'Expand details', children: isExpanded ? (jsxRuntime.jsx(ChevronDown, { className: "h-4 w-4" })) : (jsxRuntime.jsx(ChevronRight, { className: "h-4 w-4" })) }) })] }), isExpanded ? (jsxRuntime.jsx(table.TableRow, { className: "bg-muted/30 hover:bg-muted/30", children: jsxRuntime.jsx(table.TableCell, { colSpan: EVENT_COLUMN_COUNT, className: "p-0", children: jsxRuntime.jsx(EventExpandedDetails, { event: event }) }) })) : null] }));
|
|
11853
12173
|
}
|
|
11854
12174
|
|
|
11855
12175
|
/**
|
|
@@ -11962,11 +12282,8 @@ const OPTIONS = [
|
|
|
11962
12282
|
/**
|
|
11963
12283
|
* EventTypeToggle provides a segmented control for filtering by event type
|
|
11964
12284
|
*/
|
|
11965
|
-
function EventTypeToggle({ value, onChange, className
|
|
11966
|
-
return (jsxRuntime.jsx(
|
|
11967
|
-
const active = value === option.value;
|
|
11968
|
-
return (jsxRuntime.jsx(button.Button, { htmlType: "button", type: active ? 'primary' : 'quaternary', theme: active ? 'solid' : 'borderless', className: cn('px-2 h-7 text-xs font-medium transition-all duration-200', index < OPTIONS.length - 1 && 'border-r border-input', !active && 'bg-muted text-foreground hover:bg-muted/80'), style: active ? { borderRadius: 0, border: 0 } : { borderRadius: 0 }, onClick: () => onChange(option.value), disabled: disabled, "aria-pressed": active, title: option.description, children: option.label }, option.value));
|
|
11969
|
-
}) }));
|
|
12285
|
+
function EventTypeToggle({ value, onChange, className, disabled = false, }) {
|
|
12286
|
+
return (jsxRuntime.jsx(SegmentedToggle, { options: OPTIONS, value: value, onChange: onChange, ariaLabel: "Filter by event type", className: className, disabled: disabled }));
|
|
11970
12287
|
}
|
|
11971
12288
|
|
|
11972
12289
|
/**
|
|
@@ -12210,7 +12527,7 @@ function EventsFeedFilters({ client, filters, timeRange, onFiltersChange, onTime
|
|
|
12210
12527
|
search: value || undefined,
|
|
12211
12528
|
});
|
|
12212
12529
|
}, [filters, onFiltersChange]);
|
|
12213
|
-
return (jsxRuntime.jsx("div", { className: `border-b border-border py-4 ${className}`, children: jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [!hiddenFilters.includes('eventType') && (jsxRuntime.jsx(EventTypeToggle, { value: eventTypeValue, onChange: handleEventTypeChange, disabled: disabled })), jsxRuntime.jsxs("div", { className: "relative min-w-[200px] flex-1 max-w-xs", children: [jsxRuntime.jsx(Search, { className: "absolute left-
|
|
12530
|
+
return (jsxRuntime.jsx("div", { className: `border-b border-border py-4 ${className}`, children: jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2 items-center", children: [!hiddenFilters.includes('eventType') && (jsxRuntime.jsx(EventTypeToggle, { value: eventTypeValue, onChange: handleEventTypeChange, disabled: disabled })), jsxRuntime.jsxs("div", { className: "relative min-w-[200px] flex-1 max-w-xs", children: [jsxRuntime.jsx(Search, { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground" }), jsxRuntime.jsx(input.Input, { type: "text", placeholder: "Search events...", value: filters.search || '', onChange: handleSearchChange, disabled: disabled, className: "h-9 pl-9 pr-9 text-xs md:text-xs" }), filters.search ? (jsxRuntime.jsx("button", { type: "button", onClick: () => onFiltersChange({ ...filters, search: undefined }), className: "absolute right-0 top-0 flex h-9 w-9 items-center justify-center rounded-r-lg text-muted-foreground transition-colors hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring", "aria-label": "Clear search", children: jsxRuntime.jsx(X, { className: "h-3.5 w-3.5" }) })) : null] }), activeFilterIds.map((filterId) => {
|
|
12214
12531
|
const config = FILTER_CONFIGS[filterId];
|
|
12215
12532
|
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));
|
|
12216
12533
|
}), 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, selectedPreset: selectedPreset, onPresetSelect: handleTimePresetSelect, onCustomRangeApply: handleCustomRangeApply, customStart: customStart, customEnd: customEnd, disabled: disabled, displayLabel: getTimeRangeLabel() })] }) }));
|
|
@@ -12278,7 +12595,7 @@ function EventsFeed({ client, initialFilters = {}, initialTimeRange = { start: "
|
|
|
12278
12595
|
: `flex-1 min-h-0 flex flex-col p-3 gap-0 ${className}`;
|
|
12279
12596
|
// Build list classes - use flex-1 min-h-0 for flex-based scrolling
|
|
12280
12597
|
const listClasses = "flex-1 min-h-0 overflow-y-auto pr-2";
|
|
12281
|
-
return (jsxRuntime.jsxs(card.Card, { className: containerClasses, children: [enableStreaming && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [jsxRuntime.jsxs("div", { className: "flex items-center", children: [isStreaming ? (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-
|
|
12598
|
+
return (jsxRuntime.jsxs(card.Card, { className: containerClasses, children: [enableStreaming && (jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [jsxRuntime.jsxs("div", { className: "flex items-center", children: [isStreaming ? (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-[var(--success-500)] opacity-75" }), jsxRuntime.jsx("span", { className: "relative inline-flex rounded-full h-2 w-2 bg-[var(--success-500)]" })] }), jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: "Streaming events..." })] }) }), jsxRuntime.jsx(TooltipContent, { className: "text-xs", children: jsxRuntime.jsx("p", { children: "New events will appear automatically" }) })] }) })) : null, newEventsCount > 0 ? (jsxRuntime.jsxs(Badge, { variant: "secondary", className: "text-xs ml-2", children: ["+", newEventsCount, " new"] })) : null] }), jsxRuntime.jsx(button.Button, { type: "tertiary", theme: "outline", size: "small", onClick: handleStreamingToggle, children: 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(EventsFeedFilters, { client: client, filters: filters, timeRange: timeRange, onFiltersChange: handleFiltersChange, onTimeRangeChange: handleTimeRangeChange, disabled: isLoading, namespace: namespace, hiddenFilters: hiddenFilters })), jsxRuntime.jsx(ApiErrorAlert, { error: error, onRetry: refresh, className: "mb-4", errorFormatter: errorFormatter }), jsxRuntime.jsxs("div", { className: listClasses, ref: scrollContainerRef, children: [jsxRuntime.jsx(TooltipProvider, { delayDuration: 200, children: variant === 'timeline' ? (jsxRuntime.jsxs("div", { children: [(isLoading || isRefreshing) && events.length === 0
|
|
12282
12599
|
? Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsx("div", { className: cn(index < 7 && 'border-b border-border', compact ? 'py-2' : 'py-3'), children: jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx(skeleton.Skeleton, { className: "w-8 h-8 rounded-md shrink-0" }), jsxRuntime.jsxs("div", { className: "flex-1 min-w-0 flex flex-col gap-1", children: [jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }), jsxRuntime.jsx(skeleton.Skeleton, { className: "h-3 w-3/4" })] }), jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-32 shrink-0" }), jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24 shrink-0" }), jsxRuntime.jsx(skeleton.Skeleton, { className: "h-5 w-5 shrink-0" })] }) }, `sk-${index}`)))
|
|
12283
12600
|
: null, !isLoading && !isRefreshing && events.length === 0 ? (jsxRuntime.jsxs("div", { className: "py-12 text-center text-muted-foreground", children: [jsxRuntime.jsx("div", { children: "No events found" }), jsxRuntime.jsx("div", { className: "text-sm mt-2", children: "Try adjusting your filters or time range" })] })) : null, events.map((event, index) => (jsxRuntime.jsx(EventFeedItem, { event: event, onEventClick: onEventClick, onResourceClick: onResourceClick, compact: compact, isNew: enableStreaming && index < newEventsCount, variant: "timeline", isLast: index === events.length - 1 }, event.metadata?.uid || event.metadata?.name)))] })) : (jsxRuntime.jsxs(table.Table, { className: "w-full", children: [jsxRuntime.jsx(table.TableHeader, { children: jsxRuntime.jsxs(table.TableRow, { children: [jsxRuntime.jsx(table.TableHead, { className: "w-[90px]", children: "Type" }), jsxRuntime.jsx(table.TableHead, { className: "w-[160px]", children: "Reason" }), jsxRuntime.jsx(table.TableHead, { children: "Note" }), jsxRuntime.jsx(table.TableHead, { className: "w-[220px]", children: "Object" }), jsxRuntime.jsx(table.TableHead, { className: "w-[170px]", children: "When" }), jsxRuntime.jsx(table.TableHead, { className: "w-10", "aria-label": "Expand" })] }) }), jsxRuntime.jsxs(table.TableBody, { children: [(isLoading || isRefreshing) && events.length === 0
|
|
12284
12601
|
? Array.from({ length: 8 }).map((_, index) => (jsxRuntime.jsxs(table.TableRow, { children: [jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-5 w-14 rounded" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-3/4" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-32" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-4 w-24" }) }), jsxRuntime.jsx(table.TableCell, { className: "py-2", children: jsxRuntime.jsx(skeleton.Skeleton, { className: "h-6 w-6" }) })] }, `sk-${index}`)))
|
|
@@ -12458,14 +12775,14 @@ function PolicyList({ client, onViewPolicy, onEditPolicy, onCreatePolicy, groupB
|
|
|
12458
12775
|
policyList.policies.length === 0 && (jsxRuntime.jsxs("div", { className: "text-center py-8 px-6 text-muted-foreground", children: [jsxRuntime.jsx("div", { className: "text-4xl mb-3", children: "\uD83D\uDCCB" }), jsxRuntime.jsx("h3", { className: "m-0 mb-1.5 text-foreground", children: "No policies found" }), jsxRuntime.jsx("p", { className: "m-0 mb-4 max-w-[400px] mx-auto", children: "Activity policies define how audit events and Kubernetes events are translated into human-readable activity summaries." }), onCreatePolicy && (jsxRuntime.jsx(button.Button, { size: "small", onClick: onCreatePolicy, className: "bg-primary text-primary-foreground hover:bg-primary/90 h-7 text-xs", children: "Create your first policy" }))] })), policyList.groups.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-col gap-2.5", children: policyList.groups.map((group) => (jsxRuntime.jsxs("div", { className: "border border-input rounded-lg overflow-hidden", children: [jsxRuntime.jsxs("button", { type: "button", className: "w-full flex items-center gap-2.5 px-3 py-2 bg-muted border-none cursor-pointer text-left text-xs font-medium text-foreground transition-colors duration-200 hover:bg-accent", onClick: () => toggleGroup(group.apiGroup), children: [jsxRuntime.jsx("span", { className: `text-xs text-muted-foreground transition-transform duration-200 ${expandedGroups.has(group.apiGroup) ? "rotate-90" : ""}`, children: "\u25B6" }), jsxRuntime.jsx("span", { className: "flex-1 font-mono", children: group.apiGroup }), jsxRuntime.jsx(Badge, { variant: "secondary", className: "rounded-full", children: group.policies.length })] }), expandedGroups.has(group.apiGroup) && (jsxRuntime.jsx("div", { className: "p-1.5", children: jsxRuntime.jsxs("table", { className: "w-full border-collapse text-sm", children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsx("th", { className: "text-left px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap", children: "Kind" }), jsxRuntime.jsx("th", { className: "text-left px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input w-24 text-xs whitespace-nowrap", children: "Audit Rules" }), jsxRuntime.jsx("th", { className: "text-left px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input w-24 text-xs whitespace-nowrap", children: "Event Rules" })] }) }), jsxRuntime.jsx("tbody", { children: group.policies.map((policy) => {
|
|
12459
12776
|
const rules = countRules(policy);
|
|
12460
12777
|
const policyStatus = getPolicyStatus(policy);
|
|
12461
|
-
return (jsxRuntime.jsxs("tr", { className: `hover:bg-muted transition-colors ${handlePolicyClick ? "cursor-pointer" : ""}`, onClick: () => handlePolicyClick?.(policy.metadata?.name || ""), children: [jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0", children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [policyStatus.status === "ready" ? (jsxRuntime.jsx("div", { className: "w-2 h-2 rounded-full bg-
|
|
12462
|
-
? "text-
|
|
12778
|
+
return (jsxRuntime.jsxs("tr", { className: `hover:bg-muted transition-colors ${handlePolicyClick ? "cursor-pointer" : ""}`, onClick: () => handlePolicyClick?.(policy.metadata?.name || ""), children: [jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0", children: jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [policyStatus.status === "ready" ? (jsxRuntime.jsx("div", { className: "w-2 h-2 rounded-full bg-[var(--success-500)]", title: policyStatus.message })) : (jsxRuntime.jsx("div", { title: policyStatus.message, children: jsxRuntime.jsx(TriangleAlert, { className: `w-4 h-4 ${policyStatus.status === "error"
|
|
12779
|
+
? "text-destructive"
|
|
12463
12780
|
: policyStatus.status === "pending"
|
|
12464
|
-
? "text-
|
|
12465
|
-
: "text-
|
|
12466
|
-
? "bg-
|
|
12781
|
+
? "text-[var(--badge-warning)]"
|
|
12782
|
+
: "text-muted-foreground"}` }) })), jsxRuntime.jsx("span", { className: "text-xs font-medium", children: policy.spec.resource.kind })] }) }), jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0 text-center w-24", children: jsxRuntime.jsx(Badge, { variant: rules.audit > 0 ? "success" : "secondary", className: rules.audit === 0
|
|
12783
|
+
? "bg-muted text-muted-foreground"
|
|
12467
12784
|
: "", children: rules.audit }) }), jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0 text-center w-24", children: jsxRuntime.jsx(Badge, { variant: rules.event > 0 ? "success" : "secondary", className: rules.event === 0
|
|
12468
|
-
? "bg-
|
|
12785
|
+
? "bg-muted text-muted-foreground"
|
|
12469
12786
|
: "", children: rules.event }) })] }, policy.metadata?.name));
|
|
12470
12787
|
}) })] }) }))] }, group.apiGroup))) }))] })] }));
|
|
12471
12788
|
}
|
|
@@ -12913,7 +13230,7 @@ function PolicyRuleListItem({ rule, ruleType, index, onEdit, onDelete, onMoveUp,
|
|
|
12913
13230
|
flex items-center gap-2 p-2 rounded-md border transition-all duration-200
|
|
12914
13231
|
border-border bg-background hover:bg-muted/50
|
|
12915
13232
|
${className}
|
|
12916
|
-
`, children: [jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsx("div", { className: "flex items-center gap-2 mb-0.5", children: jsxRuntime.jsx("span", { className: "font-medium text-xs text-foreground truncate", children: rule.name || `${ruleType === 'audit' ? 'Audit' : 'Event'} Rule #${index + 1}` }) }), rule.description && (jsxRuntime.jsx("div", { className: "text-[11px] text-muted-foreground mb-0.5 truncate", children: rule.description })), jsxRuntime.jsx("div", { className: "text-[11px] font-mono text-muted-foreground truncate", title: rule.match, children: truncatedMatch })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "h-5 w-5 p-0", onClick: onMoveUp, disabled: !canMoveUp, title: "Move up", "aria-label": "Move rule up", children: jsxRuntime.jsx(ChevronUp, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "h-5 w-5 p-0", onClick: onMoveDown, disabled: !canMoveDown, title: "Move down", "aria-label": "Move rule down", children: jsxRuntime.jsx(ChevronDown, { className: "h-3.5 w-3.5" }) })] }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "h-6 w-6 text-muted-foreground hover:text-foreground hover:bg-muted", onClick: onEdit, title: "Edit rule", "aria-label": "Edit rule", children: jsxRuntime.jsx(SquarePen, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "h-6 w-6 text-muted-foreground hover:text-
|
|
13233
|
+
`, children: [jsxRuntime.jsxs("div", { className: "flex-1 min-w-0", children: [jsxRuntime.jsx("div", { className: "flex items-center gap-2 mb-0.5", children: jsxRuntime.jsx("span", { className: "font-medium text-xs text-foreground truncate", children: rule.name || `${ruleType === 'audit' ? 'Audit' : 'Event'} Rule #${index + 1}` }) }), rule.description && (jsxRuntime.jsx("div", { className: "text-[11px] text-muted-foreground mb-0.5 truncate", children: rule.description })), jsxRuntime.jsx("div", { className: "text-[11px] font-mono text-muted-foreground truncate", title: rule.match, children: truncatedMatch })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1 shrink-0", children: [jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "h-5 w-5 p-0", onClick: onMoveUp, disabled: !canMoveUp, title: "Move up", "aria-label": "Move rule up", children: jsxRuntime.jsx(ChevronUp, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "h-5 w-5 p-0", onClick: onMoveDown, disabled: !canMoveDown, title: "Move down", "aria-label": "Move rule down", children: jsxRuntime.jsx(ChevronDown, { className: "h-3.5 w-3.5" }) })] }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "h-6 w-6 text-muted-foreground hover:text-foreground hover:bg-muted", onClick: onEdit, title: "Edit rule", "aria-label": "Edit rule", children: jsxRuntime.jsx(SquarePen, { className: "h-3.5 w-3.5" }) }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "h-6 w-6 text-muted-foreground hover:text-destructive hover:bg-destructive/10", onClick: onDelete, title: "Delete rule", "aria-label": "Delete rule", children: jsxRuntime.jsx(Trash2, { className: "h-3.5 w-3.5" }) })] })] }));
|
|
12917
13234
|
}
|
|
12918
13235
|
|
|
12919
13236
|
/**
|
|
@@ -13034,7 +13351,7 @@ const registeredLanguages = new Set();
|
|
|
13034
13351
|
* Lazy-loaded Monaco editor for CEL expressions and templates
|
|
13035
13352
|
* Provides autocomplete based on available field paths
|
|
13036
13353
|
*/
|
|
13037
|
-
function CelEditor({ value, onChange, language = 'cel', availableFields = [],
|
|
13354
|
+
function CelEditor({ value, onChange, language = 'cel', availableFields = [], height = '100px', className, error = false, readOnly = false, 'data-testid': testId, }) {
|
|
13038
13355
|
const [Editor, setEditor] = React.useState(null);
|
|
13039
13356
|
const [loadError, setLoadError] = React.useState(null);
|
|
13040
13357
|
const [isLoading, setIsLoading] = React.useState(true);
|
|
@@ -13193,7 +13510,7 @@ function CelEditor({ value, onChange, language = 'cel', availableFields = [], pl
|
|
|
13193
13510
|
*/
|
|
13194
13511
|
function requiresBracketNotation(key) {
|
|
13195
13512
|
// Keys with dots, slashes, or other special characters need bracket notation
|
|
13196
|
-
return /[
|
|
13513
|
+
return /[./\-:]/.test(key) || /^\d/.test(key);
|
|
13197
13514
|
}
|
|
13198
13515
|
/**
|
|
13199
13516
|
* Build the CEL path for a key, using bracket notation when needed
|
|
@@ -13400,7 +13717,7 @@ function PolicyRuleEditorDialog({ open, onOpenChange, rule, ruleType, existingNa
|
|
|
13400
13717
|
const [previewError, setPreviewError] = React.useState(null);
|
|
13401
13718
|
// Sample data for autocomplete (fetched once when dialog opens)
|
|
13402
13719
|
const [sampleData, setSampleData] = React.useState([]);
|
|
13403
|
-
const [
|
|
13720
|
+
const [, setSampleDataLoading] = React.useState(false);
|
|
13404
13721
|
// Extract field paths from sample data OR preview data for autocomplete
|
|
13405
13722
|
const availableFields = React.useMemo(() => {
|
|
13406
13723
|
// First try to use preview data if available
|
|
@@ -13849,10 +14166,10 @@ function PolicyEditor({ client, policyName, onSaveSuccess, onCancel, onResourceC
|
|
|
13849
14166
|
};
|
|
13850
14167
|
const policyStatus = getPolicyStatus();
|
|
13851
14168
|
return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 0, children: jsxRuntime.jsxs(card.Card, { className: `rounded-xl ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-center p-4 border-b border-border space-y-0", children: [jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: editor.isNew ? (jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [jsxRuntime.jsx(label.Label, { htmlFor: "policy-name", className: "text-xs text-muted-foreground", children: "Policy Name" }), jsxRuntime.jsx(input.Input, { id: "policy-name", type: "text", className: "w-[300px] text-base font-medium", value: editor.name, onChange: (e) => editor.setName(e.target.value), placeholder: "e.g., httpproxy-policy" })] })) : (jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [policyStatus && (jsxRuntime.jsxs(Tooltip, { delayDuration: 300, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("span", { className: `w-2 h-2 rounded-full ${policyStatus.status === 'ready'
|
|
13852
|
-
? 'bg-
|
|
14169
|
+
? 'bg-[var(--success-500)]'
|
|
13853
14170
|
: policyStatus.status === 'error'
|
|
13854
|
-
? 'bg-
|
|
13855
|
-
: 'bg-
|
|
14171
|
+
? 'bg-destructive'
|
|
14172
|
+
: 'bg-[var(--badge-warning)]'}`, "aria-label": `Policy status: ${policyStatus.status}` }) }), jsxRuntime.jsx(TooltipContent, { children: jsxRuntime.jsx("p", { className: "text-xs", children: policyStatus.message }) })] })), jsxRuntime.jsx("h2", { className: "m-0 text-xl font-semibold text-foreground leading-tight", children: editor.spec.resource.kind || 'Untitled Policy' })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [editor.spec.resource.apiGroup && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("span", { children: ["API Group: ", editor.spec.resource.apiGroup] }), jsxRuntime.jsx("span", { className: "text-muted-foreground/50", children: "\u2022" })] })), jsxRuntime.jsxs("span", { children: ["Resource: ", editor.name] }), jsxRuntime.jsxs(Tooltip, { delayDuration: 500, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("button", { onClick: handleCopyResourceName, className: "inline-flex items-center justify-center p-0.5 rounded hover:bg-muted transition-opacity cursor-pointer", "aria-label": "Copy resource name", children: isCopied ? (jsxRuntime.jsx(Check, { className: "h-3 w-3 text-[var(--success-500)]" })) : (jsxRuntime.jsx(Copy, { className: "h-3 w-3 text-muted-foreground" })) }) }), jsxRuntime.jsx(TooltipContent, { children: jsxRuntime.jsx("p", { className: "text-xs", children: "Click to copy" }) })] })] })] })) }), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [onCancel && (jsxRuntime.jsx(button.Button, { htmlType: "button", type: "tertiary", theme: "outline", size: "small", onClick: onCancel, disabled: editor.isSaving, className: "h-7 text-xs", children: "Cancel" })), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "tertiary", theme: "outline", size: "small", onClick: () => handleSave(true), disabled: !canSave || editor.isSaving, title: "Validate without saving", className: "h-7 text-xs", children: "Validate" }), jsxRuntime.jsx(button.Button, { htmlType: "button", size: "small", onClick: () => handleSave(false), disabled: !canSave || editor.isSaving || !editor.isDirty, className: "bg-primary text-primary-foreground border-primary hover:bg-primary/90 hover:border-primary/90 h-7 text-xs", children: editor.isSaving ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-3.5 h-3.5 border-2 border-border border-t-[#BF9595] rounded-full animate-spin" }), "Saving..."] })) : ('Save Policy') })] })] }), jsxRuntime.jsx(ApiErrorAlert, { error: editor.error, className: "mx-4 mt-3", errorFormatter: errorFormatter }), editor.isLoading && (jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 py-8 text-muted-foreground", children: [jsxRuntime.jsx("span", { className: "w-5 h-5 border-[3px] border-border border-t-[#BF9595] rounded-full animate-spin" }), "Loading policy..."] })), !editor.isLoading && (jsxRuntime.jsx(card.CardContent, { className: "p-4", children: jsxRuntime.jsxs(tabs.Tabs, { defaultValue: "activity", value: activeTab, onValueChange: setActiveTab, className: "w-full", children: [jsxRuntime.jsxs(tabs.TabsList, { className: "grid w-full grid-cols-2 mb-4", children: [jsxRuntime.jsx(tabs.TabsTrigger, { value: "activity", children: "Activity" }), jsxRuntime.jsx(tabs.TabsTrigger, { value: "editor", children: "Editor" })] }), jsxRuntime.jsx(tabs.TabsContent, { value: "activity", className: "mt-0", children: jsxRuntime.jsx(PolicyActivityView, { client: client, policyResource: editor.spec.resource, policyName: editor.name, onResourceClick: onResourceClick, errorFormatter: errorFormatter }) }), jsxRuntime.jsx(tabs.TabsContent, { value: "editor", className: "mt-0", children: jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [jsxRuntime.jsx(PolicyResourceForm, { resource: editor.spec.resource, onChange: editor.setResource, client: client, isEditMode: !editor.isNew }), jsxRuntime.jsx(PolicyRuleList, { auditRules: editor.spec.auditRules || [], eventRules: editor.spec.eventRules || [], policyResource: editor.spec.resource, apiClient: client, onAuditRulesChange: editor.setAuditRules, onEventRulesChange: editor.setEventRules }), !editor.isNew && (jsxRuntime.jsx("div", { className: "mt-6 pt-4 border-t border-border", children: jsxRuntime.jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 p-4", children: jsxRuntime.jsx("div", { className: "flex items-start gap-3", children: jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsxs("h3", { className: "text-base font-semibold text-foreground mb-1.5 flex items-center gap-2", children: [jsxRuntime.jsx(TriangleAlert, { className: "h-5 w-5 text-destructive" }), "Danger Zone"] }), jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: ["Deleting this policy will stop translating audit logs and events for", ' ', jsxRuntime.jsx("strong", { className: "text-foreground", children: editor.spec.resource.kind }), ' ', "resources. Existing activities will be preserved, but no new activities will be generated."] }), jsxRuntime.jsxs(button.Button, { type: "danger", theme: "solid", size: "small", onClick: () => setShowDeleteDialog(true), className: "h-8 text-xs", children: [jsxRuntime.jsx(Trash2, { className: "h-3.5 w-3.5 mr-1.5" }), "Delete Policy"] })] }) }) }) }))] }) })] }) })), jsxRuntime.jsx(Dialog, { open: showDeleteDialog, onOpenChange: setShowDeleteDialog, children: jsxRuntime.jsxs(DialogContent, { className: "max-w-[500px]", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { children: "Delete Policy" }), jsxRuntime.jsxs(DialogDescription, { children: ["Are you sure you want to delete", ' ', jsxRuntime.jsx("strong", { className: "text-foreground", children: editor.name }), "?"] })] }), jsxRuntime.jsxs(alert.Alert, { variant: "destructive", className: "mt-2", children: [jsxRuntime.jsx(CircleAlert, { className: "h-4 w-4" }), jsxRuntime.jsxs(alert.AlertDescription, { children: [jsxRuntime.jsx("strong", { children: "This action cannot be undone." }), jsxRuntime.jsx("br", {}), "Activities already generated by this policy will remain in the system, but no new activities will be created for ", editor.spec.resource.kind, " resources."] })] }), jsxRuntime.jsxs(DialogFooter, { children: [jsxRuntime.jsx(button.Button, { type: "tertiary", theme: "outline", size: "small", onClick: () => setShowDeleteDialog(false), disabled: isDeleting, className: "h-8 text-xs", children: "Cancel" }), jsxRuntime.jsx(button.Button, { type: "danger", theme: "solid", size: "small", onClick: handleDelete, disabled: isDeleting, className: "h-8 text-xs", children: isDeleting ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-3.5 h-3.5 border-2 border-current border-t-transparent rounded-full animate-spin mr-2" }), "Deleting..."] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Trash2, { className: "h-3.5 w-3.5 mr-1.5" }), "Delete Policy"] })) })] })] }) })] }) }));
|
|
13856
14173
|
}
|
|
13857
14174
|
|
|
13858
14175
|
/**
|
|
@@ -13936,12 +14253,12 @@ function PolicyDetailView({ client, policyName, onEdit, onResourceClick, classNa
|
|
|
13936
14253
|
const policyStatus = getPolicyStatus();
|
|
13937
14254
|
const isUnhealthy = policyStatus && policyStatus.status !== 'ready';
|
|
13938
14255
|
return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 0, children: jsxRuntime.jsxs(card.Card, { className: `rounded-xl ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-center p-6 border-b border-border space-y-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [isLoading && (jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(skeleton.Skeleton, { className: "w-2 h-2 rounded-full" }), jsxRuntime.jsx(skeleton.Skeleton, { className: "h-6 w-32" })] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx(skeleton.Skeleton, { className: "h-3 w-24" }), jsxRuntime.jsx(skeleton.Skeleton, { className: "h-3 w-32" })] })] })), !isLoading && policy && (jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [jsxRuntime.jsxs("h2", { className: "m-0 text-xl font-semibold text-foreground leading-tight flex items-center gap-2", children: [jsxRuntime.jsxs(Tooltip, { delayDuration: 500, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("span", { className: `w-2 h-2 rounded-full ${policyStatus?.status === 'ready'
|
|
13939
|
-
? 'bg-
|
|
14256
|
+
? 'bg-[var(--success-500)]'
|
|
13940
14257
|
: policyStatus?.status === 'error'
|
|
13941
|
-
? 'bg-
|
|
14258
|
+
? 'bg-destructive'
|
|
13942
14259
|
: policyStatus?.status === 'pending'
|
|
13943
|
-
? 'bg-
|
|
13944
|
-
: 'bg-
|
|
14260
|
+
? 'bg-[var(--badge-warning)]'
|
|
14261
|
+
: 'bg-[var(--success-500)]'}` }) }), jsxRuntime.jsx(TooltipContent, { children: jsxRuntime.jsx("p", { className: "text-xs", children: policyStatus?.message || 'Policy is active' }) })] }), policy.spec.resource.kind || 'Untitled Policy'] }), jsxRuntime.jsxs("div", { className: "flex items-center gap-2 text-xs text-muted-foreground", children: [policy.spec.resource.apiGroup && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("span", { children: ["API Group: ", policy.spec.resource.apiGroup] }), jsxRuntime.jsx("span", { className: "text-muted-foreground/50", children: "\u2022" })] })), jsxRuntime.jsxs("span", { children: ["Resource: ", policyName] }), jsxRuntime.jsxs(Tooltip, { delayDuration: 500, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("button", { onClick: handleCopyResourceName, className: "inline-flex items-center justify-center p-0.5 rounded hover:bg-muted transition-opacity cursor-pointer", "aria-label": "Copy resource name", children: isCopied ? (jsxRuntime.jsx(Check, { className: "h-3 w-3 text-[var(--success-500)]" })) : (jsxRuntime.jsx(Copy, { className: "h-3 w-3 text-muted-foreground" })) }) }), jsxRuntime.jsx(TooltipContent, { children: jsxRuntime.jsx("p", { className: "text-xs", children: "Click to copy" }) })] })] })] }))] }), jsxRuntime.jsx("div", { className: "flex gap-3", children: onEdit && (jsxRuntime.jsxs(button.Button, { htmlType: "button", size: "small", onClick: onEdit, className: "bg-primary text-primary-foreground border-primary hover:bg-primary/90 hover:border-primary/90 h-7 text-xs", children: [jsxRuntime.jsx(SquarePen, { className: "h-3.5 w-3.5 mr-1.5" }), "Edit Policy"] })) })] }), jsxRuntime.jsx(ApiErrorAlert, { error: error, className: "mx-6 mt-4", errorFormatter: errorFormatter }), isUnhealthy && policyStatus && (jsxRuntime.jsxs(alert.Alert, { variant: policyStatus.status === 'error' ? 'destructive' : 'warning', className: "mx-6 mt-4", children: [policyStatus.status === 'error' ? (jsxRuntime.jsx(CircleAlert, { className: "h-4 w-4" })) : (jsxRuntime.jsx(TriangleAlert, { className: "h-4 w-4" })), jsxRuntime.jsxs(alert.AlertDescription, { children: [jsxRuntime.jsx("strong", { children: policyStatus.status === 'error' ? 'Policy Error: ' : 'Policy Pending: ' }), policyStatus.message] })] })), isLoading && (jsxRuntime.jsx(card.CardContent, { className: "p-6", children: jsxRuntime.jsx(PolicyActivityViewSkeleton, {}) })), !isLoading && policy && (jsxRuntime.jsx(card.CardContent, { className: "p-6", children: jsxRuntime.jsx(PolicyActivityView, { client: client, policyResource: policy.spec.resource, policyName: policyName, onResourceClick: onResourceClick, errorFormatter: errorFormatter }) }))] }) }));
|
|
13945
14262
|
}
|
|
13946
14263
|
|
|
13947
14264
|
/**
|
|
@@ -14041,7 +14358,7 @@ function PolicyEditView({ client, policyName, onSaveSuccess, onCancel, className
|
|
|
14041
14358
|
};
|
|
14042
14359
|
const policyStatus = getPolicyStatus();
|
|
14043
14360
|
const isUnhealthy = policyStatus && policyStatus.status !== 'ready';
|
|
14044
|
-
return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 0, children: jsxRuntime.jsxs(card.Card, { className: `rounded-xl ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-center p-4 border-b border-border space-y-0", children: [jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: editor.isNew ? (jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [jsxRuntime.jsx(label.Label, { htmlFor: "policy-name", className: "text-xs text-muted-foreground", children: "Policy Name" }), jsxRuntime.jsx(input.Input, { id: "policy-name", type: "text", className: "w-[300px] text-base font-medium", value: editor.name, onChange: (e) => editor.setName(e.target.value), placeholder: "e.g., httpproxy-policy" })] })) : (jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [jsxRuntime.jsx("h2", { className: "m-0 text-xl font-semibold text-foreground leading-tight", children: editor.spec.resource.kind || 'Untitled Policy' }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [editor.spec.resource.apiGroup && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("span", { children: ["API Group: ", editor.spec.resource.apiGroup] }), jsxRuntime.jsx("span", { className: "text-muted-foreground/50", children: "\u2022" })] })), jsxRuntime.jsxs("span", { children: ["Resource: ", editor.name] }), jsxRuntime.jsxs(Tooltip, { delayDuration: 500, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("button", { onClick: handleCopyResourceName, className: "inline-flex items-center justify-center p-0.5 rounded hover:bg-
|
|
14361
|
+
return (jsxRuntime.jsx(TooltipProvider, { delayDuration: 0, children: jsxRuntime.jsxs(card.Card, { className: `rounded-xl ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-center p-4 border-b border-border space-y-0", children: [jsxRuntime.jsx("div", { className: "flex items-center gap-3", children: editor.isNew ? (jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [jsxRuntime.jsx(label.Label, { htmlFor: "policy-name", className: "text-xs text-muted-foreground", children: "Policy Name" }), jsxRuntime.jsx(input.Input, { id: "policy-name", type: "text", className: "w-[300px] text-base font-medium", value: editor.name, onChange: (e) => editor.setName(e.target.value), placeholder: "e.g., httpproxy-policy" })] })) : (jsxRuntime.jsxs("div", { className: "flex flex-col gap-0.5", children: [jsxRuntime.jsx("h2", { className: "m-0 text-xl font-semibold text-foreground leading-tight", children: editor.spec.resource.kind || 'Untitled Policy' }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [editor.spec.resource.apiGroup && (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsxs("span", { children: ["API Group: ", editor.spec.resource.apiGroup] }), jsxRuntime.jsx("span", { className: "text-muted-foreground/50", children: "\u2022" })] })), jsxRuntime.jsxs("span", { children: ["Resource: ", editor.name] }), jsxRuntime.jsxs(Tooltip, { delayDuration: 500, children: [jsxRuntime.jsx(TooltipTrigger, { asChild: true, children: jsxRuntime.jsx("button", { onClick: handleCopyResourceName, className: "inline-flex items-center justify-center p-0.5 rounded hover:bg-muted transition-opacity cursor-pointer", "aria-label": "Copy resource name", children: isCopied ? (jsxRuntime.jsx(Check, { className: "h-3 w-3 text-[var(--success-500)]" })) : (jsxRuntime.jsx(Copy, { className: "h-3 w-3 text-muted-foreground" })) }) }), jsxRuntime.jsx(TooltipContent, { children: jsxRuntime.jsx("p", { className: "text-xs", children: "Click to copy" }) })] })] })] })) }), jsxRuntime.jsxs("div", { className: "flex gap-2", children: [onCancel && (jsxRuntime.jsx(button.Button, { htmlType: "button", type: "tertiary", theme: "outline", size: "small", onClick: onCancel, disabled: editor.isSaving, className: "h-7 text-xs", children: "Cancel" })), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "tertiary", theme: "outline", size: "small", onClick: () => handleSave(true), disabled: !canSave || editor.isSaving, title: "Validate without saving", className: "h-7 text-xs", children: "Validate" }), jsxRuntime.jsx(button.Button, { htmlType: "button", size: "small", onClick: () => handleSave(false), disabled: !canSave || editor.isSaving || !editor.isDirty, className: "bg-primary text-primary-foreground border-primary hover:bg-primary/90 hover:border-primary/90 h-7 text-xs", children: editor.isSaving ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-3.5 h-3.5 border-2 border-border border-t-[#BF9595] rounded-full animate-spin" }), "Saving..."] })) : ('Save Policy') })] })] }), jsxRuntime.jsx(ApiErrorAlert, { error: editor.error, className: "mx-4 mt-3", errorFormatter: errorFormatter }), isUnhealthy && policyStatus && (jsxRuntime.jsxs(alert.Alert, { variant: policyStatus.status === 'error' ? 'destructive' : 'warning', className: "mx-4 mt-3", children: [policyStatus.status === 'error' ? (jsxRuntime.jsx(CircleAlert, { className: "h-4 w-4" })) : (jsxRuntime.jsx(TriangleAlert, { className: "h-4 w-4" })), jsxRuntime.jsxs(alert.AlertDescription, { children: [jsxRuntime.jsx("strong", { children: policyStatus.status === 'error' ? 'Policy Error: ' : 'Policy Pending: ' }), policyStatus.message] })] })), editor.isLoading && (jsxRuntime.jsxs("div", { className: "flex items-center justify-center gap-2 py-8 text-muted-foreground", children: [jsxRuntime.jsx("span", { className: "w-5 h-5 border-[3px] border-border border-t-[#BF9595] rounded-full animate-spin" }), "Loading policy..."] })), !editor.isLoading && (jsxRuntime.jsx(card.CardContent, { className: "p-4", children: jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [jsxRuntime.jsx(PolicyResourceForm, { resource: editor.spec.resource, onChange: editor.setResource, client: client, isEditMode: !editor.isNew }), jsxRuntime.jsx(PolicyRuleList, { auditRules: editor.spec.auditRules || [], eventRules: editor.spec.eventRules || [], policyResource: editor.spec.resource, apiClient: client, onAuditRulesChange: editor.setAuditRules, onEventRulesChange: editor.setEventRules }), !editor.isNew && (jsxRuntime.jsx("div", { className: "mt-6 pt-4 border-t border-border", children: jsxRuntime.jsx("div", { className: "rounded-lg border border-destructive/30 bg-destructive/5 p-4", children: jsxRuntime.jsx("div", { className: "flex items-start gap-3", children: jsxRuntime.jsxs("div", { className: "flex-1", children: [jsxRuntime.jsxs("h3", { className: "text-base font-semibold text-foreground mb-1.5 flex items-center gap-2", children: [jsxRuntime.jsx(TriangleAlert, { className: "h-5 w-5 text-destructive" }), "Danger Zone"] }), jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground mb-3", children: ["Deleting this policy will stop translating audit logs and events for", ' ', jsxRuntime.jsx("strong", { className: "text-foreground", children: editor.spec.resource.kind }), ' ', "resources. Existing activities will be preserved, but no new activities will be generated."] }), jsxRuntime.jsxs(button.Button, { type: "danger", theme: "solid", size: "small", onClick: () => setShowDeleteDialog(true), className: "h-8 text-xs", children: [jsxRuntime.jsx(Trash2, { className: "h-3.5 w-3.5 mr-1.5" }), "Delete Policy"] })] }) }) }) }))] }) })), jsxRuntime.jsx(Dialog, { open: showDeleteDialog, onOpenChange: setShowDeleteDialog, children: jsxRuntime.jsxs(DialogContent, { className: "max-w-[500px]", children: [jsxRuntime.jsxs(DialogHeader, { children: [jsxRuntime.jsx(DialogTitle, { children: "Delete Policy" }), jsxRuntime.jsxs(DialogDescription, { children: ["Are you sure you want to delete", ' ', jsxRuntime.jsx("strong", { className: "text-foreground", children: editor.name }), "?"] })] }), jsxRuntime.jsxs(alert.Alert, { variant: "destructive", className: "mt-2", children: [jsxRuntime.jsx(CircleAlert, { className: "h-4 w-4" }), jsxRuntime.jsxs(alert.AlertDescription, { children: [jsxRuntime.jsx("strong", { children: "This action cannot be undone." }), jsxRuntime.jsx("br", {}), "Activities already generated by this policy will remain in the system, but no new activities will be created for ", editor.spec.resource.kind, " resources."] })] }), jsxRuntime.jsxs(DialogFooter, { children: [jsxRuntime.jsx(button.Button, { type: "tertiary", theme: "outline", size: "small", onClick: () => setShowDeleteDialog(false), disabled: isDeleting, className: "h-8 text-xs", children: "Cancel" }), jsxRuntime.jsx(button.Button, { type: "danger", theme: "solid", size: "small", onClick: handleDelete, disabled: isDeleting, className: "h-8 text-xs", children: isDeleting ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("span", { className: "w-3.5 h-3.5 border-2 border-current border-t-transparent rounded-full animate-spin mr-2" }), "Deleting..."] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(Trash2, { className: "h-3.5 w-3.5 mr-1.5" }), "Delete Policy"] })) })] })] }) })] }) }));
|
|
14045
14362
|
}
|
|
14046
14363
|
|
|
14047
14364
|
/**
|
|
@@ -14122,8 +14439,8 @@ function PolicyRuleEditor({ rule, index, ruleType, isHighlighted = false, onChan
|
|
|
14122
14439
|
onChange({ ...rule, summary: example });
|
|
14123
14440
|
};
|
|
14124
14441
|
return (jsxRuntime.jsxs(card.Card, { className: `mb-3 transition-all duration-200 ${isHighlighted
|
|
14125
|
-
? 'border-
|
|
14126
|
-
: 'bg-muted'} ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-center p-3 pb-0", children: [jsxRuntime.jsxs("span", { className: `text-xs font-semibold uppercase tracking-wide ${isHighlighted ? 'text-
|
|
14442
|
+
? 'border-[var(--success-500)] bg-[var(--success-100)]'
|
|
14443
|
+
: 'bg-muted'} ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-center p-3 pb-0", children: [jsxRuntime.jsxs("span", { className: `text-xs font-semibold uppercase tracking-wide ${isHighlighted ? 'text-[var(--success-500)]' : 'text-muted-foreground'}`, children: [ruleType === 'audit' ? 'Audit' : 'Event', " Rule #", index + 1] }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "quaternary", theme: "borderless", size: "icon", className: "w-6 h-6 text-xl leading-none text-muted-foreground hover:bg-destructive/10 hover:text-destructive", onClick: onDelete, title: "Delete rule", children: "\u00D7" })] }), jsxRuntime.jsxs(card.CardContent, { className: "p-3", children: [jsxRuntime.jsxs("div", { className: "mb-3", children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-1", children: [jsxRuntime.jsx(label.Label, { htmlFor: `rule-${index}-match`, children: "Match Expression (CEL)" }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "tertiary", theme: "outline", size: "small", className: "px-2 py-0.5 h-auto text-xs", onClick: () => setShowMatchHelp(!showMatchHelp), children: showMatchHelp ? 'Hide Help' : 'Show Help' })] }), jsxRuntime.jsx(textarea.Textarea, { id: `rule-${index}-match`, className: "font-mono text-sm resize-y min-h-[60px]", value: rule.match, onChange: handleMatchChange, placeholder: `e.g., ${celHelp.examples[0]}`, rows: 2, spellCheck: false }), showMatchHelp && (jsxRuntime.jsxs("div", { className: "mt-2 p-3 bg-background border border-border rounded-md text-xs", children: [jsxRuntime.jsxs("div", { className: "mb-3 last:mb-0", children: [jsxRuntime.jsx("strong", { className: "block mb-1.5 text-foreground", children: "Available Variables:" }), jsxRuntime.jsx("ul", { className: "m-0 pl-5 list-disc", children: celHelp.variables.map((v) => (jsxRuntime.jsxs("li", { className: "mb-0.5", children: [jsxRuntime.jsx("code", { className: "bg-muted px-1.5 py-0.5 rounded text-xs", children: v.name }), " - ", v.description] }, v.name))) })] }), jsxRuntime.jsxs("div", { className: "mb-3 last:mb-0", children: [jsxRuntime.jsx("strong", { className: "block mb-1.5 text-foreground", children: "Examples:" }), jsxRuntime.jsx("ul", { className: "m-0 p-0 list-none", children: celHelp.examples.map((ex, i) => (jsxRuntime.jsxs("li", { className: "flex items-center gap-2 mb-1 px-2 py-1 bg-muted rounded", children: [jsxRuntime.jsx("code", { className: "flex-1 text-xs break-all", children: ex }), jsxRuntime.jsx(button.Button, { htmlType: "button", size: "small", className: "px-2 py-0.5 h-auto bg-primary text-primary-foreground border-none text-xs font-medium uppercase hover:bg-primary/90", onClick: () => insertMatchExample(ex), children: "Use" })] }, i))) })] })] }))] }), jsxRuntime.jsxs("div", { className: "mb-3 last:mb-0", children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center mb-1", children: [jsxRuntime.jsx(label.Label, { htmlFor: `rule-${index}-summary`, children: "Summary Template (CEL)" }), jsxRuntime.jsx(button.Button, { htmlType: "button", type: "tertiary", theme: "outline", size: "small", className: "px-2 py-0.5 h-auto text-xs", onClick: () => setShowSummaryHelp(!showSummaryHelp), children: showSummaryHelp ? 'Hide Help' : 'Show Help' })] }), jsxRuntime.jsx(textarea.Textarea, { id: `rule-${index}-summary`, className: "font-mono text-sm resize-y min-h-[60px]", value: rule.summary, onChange: handleSummaryChange, placeholder: `e.g., ${SUMMARY_HELP.examples[0]}`, rows: 2, spellCheck: false }), showSummaryHelp && (jsxRuntime.jsxs("div", { className: "mt-2 p-3 bg-background border border-border rounded-md text-xs", children: [jsxRuntime.jsxs("div", { className: "mb-3 last:mb-0", children: [jsxRuntime.jsx("strong", { className: "block mb-1.5 text-foreground", children: "Available Variables:" }), jsxRuntime.jsx("ul", { className: "m-0 pl-5 list-disc", children: SUMMARY_HELP.variables.map((v) => (jsxRuntime.jsxs("li", { className: "mb-0.5", children: [jsxRuntime.jsx("code", { className: "bg-muted px-1.5 py-0.5 rounded text-xs", children: '{{ ' + v.name + ' }}' }), " - ", v.description] }, v.name))) })] }), jsxRuntime.jsxs("div", { className: "mb-3 last:mb-0", children: [jsxRuntime.jsx("strong", { className: "block mb-1.5 text-foreground", children: "Examples:" }), jsxRuntime.jsx("ul", { className: "m-0 p-0 list-none", children: SUMMARY_HELP.examples.map((ex, i) => (jsxRuntime.jsxs("li", { className: "flex items-center gap-2 mb-1 px-2 py-1 bg-muted rounded", children: [jsxRuntime.jsx("code", { className: "flex-1 text-xs break-all", children: ex }), jsxRuntime.jsx(button.Button, { htmlType: "button", size: "small", className: "px-2 py-0.5 h-auto bg-primary text-primary-foreground border-none text-xs font-medium uppercase hover:bg-primary/90", onClick: () => insertSummaryExample(ex), children: "Use" })] }, i))) })] })] }))] })] })] }));
|
|
14127
14444
|
}
|
|
14128
14445
|
|
|
14129
14446
|
/**
|
|
@@ -14781,7 +15098,7 @@ function ReindexJobList({ client, onViewJob, onCreateJob, watch = true, classNam
|
|
|
14781
15098
|
const bTime = b.metadata?.creationTimestamp || '';
|
|
14782
15099
|
return bTime.localeCompare(aTime);
|
|
14783
15100
|
});
|
|
14784
|
-
return (jsxRuntime.jsxs(card.Card, { className: `rounded-xl ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "pb-1.5", children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground m-0", children: "Re-process historical events through updated policies" }), isWatching && (jsxRuntime.jsxs(Badge, { variant: "success", className: "text-xs", children: [jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 bg-
|
|
15101
|
+
return (jsxRuntime.jsxs(card.Card, { className: `rounded-xl ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "pb-1.5", children: [jsxRuntime.jsxs("div", { className: "flex justify-between items-center", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [jsxRuntime.jsx("p", { className: "text-sm text-muted-foreground m-0", children: "Re-process historical events through updated policies" }), isWatching && (jsxRuntime.jsxs(Badge, { variant: "success", className: "text-xs", children: [jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 bg-[var(--success-500)] rounded-full mr-1.5 animate-pulse" }), "Live"] }))] }), jsxRuntime.jsxs("div", { className: "flex gap-1.5", children: [jsxRuntime.jsx(button.Button, { type: "tertiary", theme: "outline", size: "small", onClick: refresh, disabled: isLoading, title: "Refresh job list", className: "h-7 px-2", children: isLoading ? (jsxRuntime.jsx("span", { className: "w-3.5 h-3.5 border-2 border-border border-t-primary rounded-full animate-spin" })) : ('↻') }), onCreateJob && (jsxRuntime.jsx(button.Button, { size: "small", onClick: onCreateJob, className: "bg-primary text-primary-foreground hover:bg-primary/90 h-7 text-xs", children: "+ Create Job" }))] })] }), jsxRuntime.jsx(separator.Separator, { className: "mt-1.5" })] }), jsxRuntime.jsxs(card.CardContent, { className: "pt-3", children: [jsxRuntime.jsx(ApiErrorAlert, { error: error, onRetry: refresh, className: "mb-3", errorFormatter: errorFormatter }), isLoading && jobs.length === 0 && (jsxRuntime.jsx("div", { className: "border border-input rounded-lg overflow-hidden", children: jsxRuntime.jsxs("table", { className: "w-full border-collapse text-sm", children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsx("th", { className: "text-left px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap", children: "Job Name" }), jsxRuntime.jsx("th", { className: "text-center px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap w-24", children: "Status" }), jsxRuntime.jsx("th", { className: "text-left px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap", children: "Message" }), jsxRuntime.jsx("th", { className: "text-center px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap w-24", children: "Duration" }), jsxRuntime.jsx("th", { className: "text-center px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap w-24", children: "Actions" })] }) }), jsxRuntime.jsxs("tbody", { children: [jsxRuntime.jsx(ReindexJobSkeletonRow, {}), jsxRuntime.jsx(ReindexJobSkeletonRow, {}), jsxRuntime.jsx(ReindexJobSkeletonRow, {})] })] }) })), !isLoading && !error && jobs.length === 0 && (jsxRuntime.jsxs("div", { className: "text-center py-8 px-6 text-muted-foreground", children: [jsxRuntime.jsx("div", { className: "text-4xl mb-3", children: "\uD83D\uDD04" }), jsxRuntime.jsx("h3", { className: "m-0 mb-1.5 text-foreground", children: "No reindex jobs found" }), jsxRuntime.jsx("p", { className: "m-0 mb-4 max-w-[400px] mx-auto", children: "Create a reindex job to re-process historical audit logs and events through current ActivityPolicy rules." }), onCreateJob && (jsxRuntime.jsx(button.Button, { size: "small", onClick: onCreateJob, className: "bg-primary text-primary-foreground hover:bg-primary/90 h-7 text-xs", children: "Create your first reindex job" }))] })), sortedJobs.length > 0 && (jsxRuntime.jsx("div", { className: "border border-input rounded-lg overflow-hidden", children: jsxRuntime.jsxs("table", { className: "w-full border-collapse text-sm", children: [jsxRuntime.jsx("thead", { children: jsxRuntime.jsxs("tr", { children: [jsxRuntime.jsx("th", { className: "text-left px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap", children: "Job Name" }), jsxRuntime.jsx("th", { className: "text-center px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap w-24", children: "Status" }), jsxRuntime.jsx("th", { className: "text-left px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap", children: "Message" }), jsxRuntime.jsx("th", { className: "text-center px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap w-24", children: "Duration" }), jsxRuntime.jsx("th", { className: "text-center px-3 py-2 bg-muted text-muted-foreground font-medium border-b border-input text-xs whitespace-nowrap w-24", children: "Actions" })] }) }), jsxRuntime.jsx("tbody", { children: sortedJobs.map((job) => {
|
|
14785
15102
|
const duration = getReindexJobDuration(job);
|
|
14786
15103
|
return (jsxRuntime.jsxs("tr", { className: "hover:bg-muted transition-colors", children: [jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0", children: jsxRuntime.jsx("span", { className: "text-xs font-medium font-mono", children: job.metadata?.name }) }), jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0 text-center", children: jsxRuntime.jsxs(Badge, { variant: getPhaseBadgeVariant(job.status?.phase), className: "inline-flex items-center gap-1", children: [getPhaseIcon$1(job.status?.phase), job.status?.phase || 'Unknown'] }) }), jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0", children: job.status?.phase === 'Failed' ? (jsxRuntime.jsx("span", { className: "text-xs text-destructive", children: job.status?.message || 'Job failed' })) : (jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: job.status?.message || 'Waiting to start' })) }), jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0 text-center", children: jsxRuntime.jsx("span", { className: "text-xs text-muted-foreground", children: duration || '-' }) }), jsxRuntime.jsx("td", { className: "px-3 py-2 border-b border-border last:border-b-0 text-center", children: onViewJob && (jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", onClick: () => onViewJob(job.metadata?.name || ''), className: "h-7 px-2", title: "View job details", children: jsxRuntime.jsx(Eye, { className: "h-3.5 w-3.5" }) })) })] }, job.metadata?.name));
|
|
14787
15104
|
}) })] }) }))] })] }));
|
|
@@ -14793,11 +15110,11 @@ function ReindexJobList({ client, onViewJob, onCreateJob, watch = true, classNam
|
|
|
14793
15110
|
function getPhaseIcon(phase) {
|
|
14794
15111
|
switch (phase) {
|
|
14795
15112
|
case 'Succeeded':
|
|
14796
|
-
return jsxRuntime.jsx(CircleCheck, { className: "h-8 w-8 text-
|
|
15113
|
+
return jsxRuntime.jsx(CircleCheck, { className: "h-8 w-8 text-[var(--success-500)]" });
|
|
14797
15114
|
case 'Failed':
|
|
14798
|
-
return jsxRuntime.jsx(CircleX, { className: "h-8 w-8 text-
|
|
15115
|
+
return jsxRuntime.jsx(CircleX, { className: "h-8 w-8 text-destructive" });
|
|
14799
15116
|
case 'Running':
|
|
14800
|
-
return jsxRuntime.jsx(LoaderCircle, { className: "h-8 w-8 text-
|
|
15117
|
+
return jsxRuntime.jsx(LoaderCircle, { className: "h-8 w-8 text-[var(--info-500)] animate-spin" });
|
|
14801
15118
|
case 'Pending':
|
|
14802
15119
|
default:
|
|
14803
15120
|
return jsxRuntime.jsx(Clock, { className: "h-8 w-8 text-muted-foreground" });
|
|
@@ -14878,7 +15195,7 @@ function ReindexJobDetailView({ client, jobName, onDelete, watch = true, classNa
|
|
|
14878
15195
|
const duration = job ? getReindexJobDuration(job) : null;
|
|
14879
15196
|
const statusMessage = job ? getReindexJobStatusMessage(job) : '';
|
|
14880
15197
|
const isTerminal = job ? isReindexJobTerminal(job) : false;
|
|
14881
|
-
return (jsxRuntime.jsxs(card.Card, { className: `rounded-xl max-w-md ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-start p-6 border-b border-border space-y-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [isLoading ? (jsxRuntime.jsx(skeleton.Skeleton, { className: "h-8 w-8 rounded-full" })) : (getPhaseIcon(job?.status?.phase)), jsxRuntime.jsx("div", { children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(skeleton.Skeleton, { className: "h-5 w-32 mb-2" }), jsxRuntime.jsx(skeleton.Skeleton, { className: "h-3 w-24" })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-foreground m-0", children: statusMessage }), jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground m-0", children: [duration && jsxRuntime.jsx(jsxRuntime.Fragment, { children: duration }), isWatching && !isTerminal && (jsxRuntime.jsx(Badge, { variant: "outline", className: "ml-2 text-xs text-
|
|
15198
|
+
return (jsxRuntime.jsxs(card.Card, { className: `rounded-xl max-w-md ${className}`, children: [jsxRuntime.jsxs(card.CardHeader, { className: "flex flex-row justify-between items-start p-6 border-b border-border space-y-0", children: [jsxRuntime.jsxs("div", { className: "flex items-center gap-4", children: [isLoading ? (jsxRuntime.jsx(skeleton.Skeleton, { className: "h-8 w-8 rounded-full" })) : (getPhaseIcon(job?.status?.phase)), jsxRuntime.jsx("div", { children: isLoading ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(skeleton.Skeleton, { className: "h-5 w-32 mb-2" }), jsxRuntime.jsx(skeleton.Skeleton, { className: "h-3 w-24" })] })) : (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("h2", { className: "text-lg font-semibold text-foreground m-0", children: statusMessage }), jsxRuntime.jsxs("p", { className: "text-xs text-muted-foreground m-0", children: [duration && jsxRuntime.jsx(jsxRuntime.Fragment, { children: duration }), isWatching && !isTerminal && (jsxRuntime.jsx(Badge, { variant: "outline", className: "ml-2 text-xs text-[var(--success-500)] border-[var(--success-300)]", children: "Live" }))] })] })) })] }), isTerminal && onDelete && (jsxRuntime.jsx(button.Button, { type: "quaternary", theme: "borderless", size: "small", onClick: handleDelete, disabled: isDeleting, className: "h-8 w-8 p-0", children: isDeleting ? (jsxRuntime.jsx(LoaderCircle, { className: "h-4 w-4 animate-spin" })) : (jsxRuntime.jsx(Trash2, { className: "h-4 w-4" })) }))] }), jsxRuntime.jsx(ApiErrorAlert, { error: error, onRetry: loadJob, className: "mx-6 mt-4", errorFormatter: errorFormatter }), !isLoading && job && (jsxRuntime.jsxs(card.CardContent, { className: "p-6 space-y-4", children: [job.status?.phase === 'Failed' && job.status?.message && (jsxRuntime.jsx("div", { className: "p-3 bg-destructive/10 border border-destructive/30 rounded-lg text-sm text-destructive", children: job.status.message })), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground mb-1", children: "Time Range" }), jsxRuntime.jsxs("div", { className: "text-sm font-mono", children: [job.spec.timeRange.startTime, job.spec.timeRange.endTime && jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [" \u2192 ", job.spec.timeRange.endTime] })] })] }), job.spec.policySelector?.names && (jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("div", { className: "text-xs text-muted-foreground mb-1", children: "Policy" }), jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: job.spec.policySelector.names.map((name) => (jsxRuntime.jsx(Badge, { variant: "secondary", className: "text-xs font-mono", children: name }, name))) })] }))] }))] }));
|
|
14882
15199
|
}
|
|
14883
15200
|
|
|
14884
15201
|
const TIME_RANGE_OPTIONS$1 = [
|
|
@@ -14981,76 +15298,11 @@ function ReindexJobDialog({ client, policyName, open, onOpenChange, onSuccess, e
|
|
|
14981
15298
|
return (jsxRuntime.jsx(Dialog, { open: open, onOpenChange: onOpenChange, children: jsxRuntime.jsxs(DialogContent, { className: "sm:max-w-sm", children: [jsxRuntime.jsx(DialogHeader, { children: jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [jsxRuntime.jsx("div", { className: "p-2 bg-primary/10 rounded-lg", children: jsxRuntime.jsx(RefreshCw, { className: "h-5 w-5 text-primary" }) }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx(DialogTitle, { children: "Reindex Policy" }), jsxRuntime.jsxs(DialogDescription, { className: "text-xs", children: ["Re-process events for \"", policyName, "\""] })] })] }) }), jsxRuntime.jsxs("div", { className: "space-y-4 py-2", children: [jsxRuntime.jsx(ApiErrorAlert, { error: error, errorFormatter: errorFormatter }), jsxRuntime.jsxs("div", { children: [jsxRuntime.jsx("label", { className: "block text-sm font-medium text-foreground mb-2", children: "Time range" }), jsxRuntime.jsxs(select.Select, { value: selectedRange, onValueChange: setSelectedRange, children: [jsxRuntime.jsx(select.SelectTrigger, { className: "w-full", children: jsxRuntime.jsx(select.SelectValue, { placeholder: "Select time range" }) }), jsxRuntime.jsx(select.SelectContent, { children: TIME_RANGE_OPTIONS.map((option) => (jsxRuntime.jsx(select.SelectItem, { value: option.value, children: option.label }, option.value))) })] })] }), jsxRuntime.jsxs("p", { className: "text-sm text-muted-foreground", children: ["Events from ", selectedOption?.label.toLowerCase(), " will be re-processed."] })] }), jsxRuntime.jsxs("div", { className: "flex justify-end gap-2", children: [jsxRuntime.jsx(button.Button, { htmlType: "button", type: "tertiary", theme: "outline", onClick: () => onOpenChange(false), disabled: isSubmitting, children: "Cancel" }), jsxRuntime.jsx(button.Button, { htmlType: "button", onClick: handleSubmit, disabled: isSubmitting, children: isSubmitting ? (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx(LoaderCircle, { className: "h-4 w-4 mr-2 animate-spin" }), "Starting..."] })) : ('Start Reindex') })] })] }) }));
|
|
14982
15299
|
}
|
|
14983
15300
|
|
|
14984
|
-
|
|
14985
|
-
|
|
14986
|
-
|
|
14987
|
-
|
|
14988
|
-
|
|
14989
|
-
const [open, setOpen] = React__namespace.useState(false);
|
|
14990
|
-
const [search, setSearch] = React__namespace.useState('');
|
|
14991
|
-
// Find selected options for display
|
|
14992
|
-
const selectedOptions = options.filter((opt) => values.includes(opt.value));
|
|
14993
|
-
const displayValue = React__namespace.useMemo(() => {
|
|
14994
|
-
if (loading)
|
|
14995
|
-
return 'Loading...';
|
|
14996
|
-
if (selectedOptions.length === 0)
|
|
14997
|
-
return placeholder;
|
|
14998
|
-
if (selectedOptions.length <= maxDisplayed) {
|
|
14999
|
-
return selectedOptions.map((opt) => opt.label).join(', ');
|
|
15000
|
-
}
|
|
15001
|
-
return `${selectedOptions.slice(0, maxDisplayed).map((opt) => opt.label).join(', ')} +${selectedOptions.length - maxDisplayed} more`;
|
|
15002
|
-
}, [loading, selectedOptions, placeholder, maxDisplayed]);
|
|
15003
|
-
const handleSelect = React__namespace.useCallback((selectedValue) => {
|
|
15004
|
-
if (values.includes(selectedValue)) {
|
|
15005
|
-
// Remove from selection
|
|
15006
|
-
onValuesChange(values.filter((v) => v !== selectedValue));
|
|
15007
|
-
}
|
|
15008
|
-
else {
|
|
15009
|
-
// Add to selection
|
|
15010
|
-
onValuesChange([...values, selectedValue]);
|
|
15011
|
-
}
|
|
15012
|
-
}, [onValuesChange, values]);
|
|
15013
|
-
const handleClear = React__namespace.useCallback((e) => {
|
|
15014
|
-
e.stopPropagation();
|
|
15015
|
-
onValuesChange([]);
|
|
15016
|
-
}, [onValuesChange]);
|
|
15017
|
-
const handleRemove = React__namespace.useCallback((e, valueToRemove) => {
|
|
15018
|
-
e.stopPropagation();
|
|
15019
|
-
onValuesChange(values.filter((v) => v !== valueToRemove));
|
|
15020
|
-
}, [onValuesChange, values]);
|
|
15021
|
-
// Custom fuzzy filter function
|
|
15022
|
-
const filterOptions = React__namespace.useCallback((optionValue, searchQuery) => {
|
|
15023
|
-
if (!searchQuery)
|
|
15024
|
-
return 1;
|
|
15025
|
-
const option = options.find((o) => o.value === optionValue);
|
|
15026
|
-
const label = option?.label || optionValue;
|
|
15027
|
-
const lowerLabel = label.toLowerCase();
|
|
15028
|
-
const lowerSearch = searchQuery.toLowerCase();
|
|
15029
|
-
// Exact match
|
|
15030
|
-
if (lowerLabel === lowerSearch)
|
|
15031
|
-
return 1;
|
|
15032
|
-
// Starts with
|
|
15033
|
-
if (lowerLabel.startsWith(lowerSearch))
|
|
15034
|
-
return 0.9;
|
|
15035
|
-
// Contains
|
|
15036
|
-
if (lowerLabel.includes(lowerSearch))
|
|
15037
|
-
return 0.8;
|
|
15038
|
-
// Fuzzy match - check if all search chars appear in order
|
|
15039
|
-
let searchIdx = 0;
|
|
15040
|
-
for (let i = 0; i < lowerLabel.length && searchIdx < lowerSearch.length; i++) {
|
|
15041
|
-
if (lowerLabel[i] === lowerSearch[searchIdx]) {
|
|
15042
|
-
searchIdx++;
|
|
15043
|
-
}
|
|
15044
|
-
}
|
|
15045
|
-
if (searchIdx === lowerSearch.length)
|
|
15046
|
-
return 0.6;
|
|
15047
|
-
return 0;
|
|
15048
|
-
}, [options]);
|
|
15049
|
-
return (jsxRuntime.jsxs(Popover__namespace.Root, { open: open, onOpenChange: setOpen, children: [jsxRuntime.jsx(Popover__namespace.Trigger, { asChild: true, children: jsxRuntime.jsxs("button", { type: "button", role: "combobox", "aria-expanded": open, "aria-haspopup": "listbox", disabled: disabled || loading, className: cn('flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background', 'placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2', 'disabled:cursor-not-allowed disabled:opacity-50', 'whitespace-nowrap', className), children: [jsxRuntime.jsx("span", { className: "truncate text-left flex-1", children: displayValue }), jsxRuntime.jsxs("div", { className: "flex items-center gap-1 ml-2", children: [values.length > 0 && !disabled && (jsxRuntime.jsx("span", { role: "button", tabIndex: 0, onClick: handleClear, onKeyDown: (e) => {
|
|
15050
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
15051
|
-
handleClear(e);
|
|
15052
|
-
}
|
|
15053
|
-
}, 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))) })] })] }) }) })] }));
|
|
15301
|
+
function MultiCombobox({ options, values, onValuesChange, placeholder = 'Select…',
|
|
15302
|
+
// searchPlaceholder is accepted for API compatibility but MultiSelect has no counterpart.
|
|
15303
|
+
emptyMessage = 'No results', disabled, loading, className, maxDisplayed = 3, }) {
|
|
15304
|
+
const items = React__namespace.useMemo(() => options.map((o) => ({ value: o.value, label: o.label })), [options]);
|
|
15305
|
+
return (jsxRuntime.jsx(multiSelect.MultiSelect, { className: className, options: items, value: values, onValueChange: onValuesChange, placeholder: placeholder, emptyContent: emptyMessage, isLoading: loading, disabled: disabled, maxCount: maxDisplayed }));
|
|
15054
15306
|
}
|
|
15055
15307
|
|
|
15056
15308
|
/**
|
|
@@ -15760,7 +16012,7 @@ class ActivityApiClient {
|
|
|
15760
16012
|
const reader = response.body.getReader();
|
|
15761
16013
|
const decoder = new TextDecoder();
|
|
15762
16014
|
let buffer = '';
|
|
15763
|
-
|
|
16015
|
+
for (;;) {
|
|
15764
16016
|
const { done, value } = await reader.read();
|
|
15765
16017
|
if (done) {
|
|
15766
16018
|
options?.onClose?.();
|
|
@@ -16160,7 +16412,7 @@ class ActivityApiClient {
|
|
|
16160
16412
|
const reader = response.body.getReader();
|
|
16161
16413
|
const decoder = new TextDecoder();
|
|
16162
16414
|
let buffer = '';
|
|
16163
|
-
|
|
16415
|
+
for (;;) {
|
|
16164
16416
|
const { done, value } = await reader.read();
|
|
16165
16417
|
if (done) {
|
|
16166
16418
|
options?.onClose?.();
|
|
@@ -16276,7 +16528,7 @@ class ActivityApiClient {
|
|
|
16276
16528
|
const reader = response.body.getReader();
|
|
16277
16529
|
const decoder = new TextDecoder();
|
|
16278
16530
|
let buffer = '';
|
|
16279
|
-
|
|
16531
|
+
for (;;) {
|
|
16280
16532
|
const { done, value } = await reader.read();
|
|
16281
16533
|
if (done) {
|
|
16282
16534
|
options?.onClose?.();
|
|
@@ -16633,9 +16885,11 @@ exports.AUDIT_TEMPLATES = AUDIT_TEMPLATES;
|
|
|
16633
16885
|
exports.ActionMultiSelect = ActionMultiSelect;
|
|
16634
16886
|
exports.ActionToggle = ActionToggle;
|
|
16635
16887
|
exports.ActivityApiClient = ActivityApiClient;
|
|
16888
|
+
exports.ActivityDigestSummary = ActivityDigestSummary;
|
|
16636
16889
|
exports.ActivityExpandedDetails = ActivityExpandedDetails;
|
|
16637
16890
|
exports.ActivityFeed = ActivityFeed;
|
|
16638
16891
|
exports.ActivityFeedFilters = ActivityFeedFilters;
|
|
16892
|
+
exports.ActivityFeedGroupItem = ActivityFeedGroupItem;
|
|
16639
16893
|
exports.ActivityFeedItem = ActivityFeedItem;
|
|
16640
16894
|
exports.ActivityFeedItemSkeleton = ActivityFeedItemSkeleton;
|
|
16641
16895
|
exports.ActivityFeedSummary = ActivityFeedSummary;
|
|
@@ -16715,6 +16969,8 @@ exports.extractFieldPathsFromMany = extractFieldPathsFromMany;
|
|
|
16715
16969
|
exports.generateShareableUrl = generateShareableUrl;
|
|
16716
16970
|
exports.getReindexJobDuration = getReindexJobDuration;
|
|
16717
16971
|
exports.getReindexJobStatusMessage = getReindexJobStatusMessage;
|
|
16972
|
+
exports.groupActivities = groupActivities;
|
|
16973
|
+
exports.groupActivitiesByDay = groupActivitiesByDay;
|
|
16718
16974
|
exports.isEventRecord = isEventRecord;
|
|
16719
16975
|
exports.isReindexJobRunning = isReindexJobRunning;
|
|
16720
16976
|
exports.isReindexJobTerminal = isReindexJobTerminal;
|