@datum-cloud/activity-ui 0.1.0 → 0.3.0-dev.e099a6f
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ActivityLayout.d.ts +26 -0
- package/dist/components/ActivityLayout.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +214 -1
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +221 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/activity-filters.d.ts +25 -0
- package/dist/lib/activity-filters.d.ts.map +1 -0
- package/dist/lib/activity-share.d.ts +23 -0
- package/dist/lib/activity-share.d.ts.map +1 -0
- package/package.json +18 -14
package/dist/index.js
CHANGED
|
@@ -14456,6 +14456,20 @@ function RulePreviewPanel({ rule, ruleType, policyResource, apiClient, className
|
|
|
14456
14456
|
}) }) }) }), stats.matched === 0 && stats.errors === 0 && (jsxRuntime.jsxs(Alert, { children: [jsxRuntime.jsx(CircleAlert, { className: "h-4 w-4" }), jsxRuntime.jsxs(AlertDescription, { children: ["This rule did not match any of the ", stats.total, " sample", stats.total !== 1 ? 's' : '', ". Check your match expression."] })] }))] }))] }));
|
|
14457
14457
|
}
|
|
14458
14458
|
|
|
14459
|
+
const defaultTabs = (basePath) => [
|
|
14460
|
+
{ label: 'Activity Feed', value: 'feed', href: basePath },
|
|
14461
|
+
{ label: 'Events', value: 'events', href: `${basePath}/events` },
|
|
14462
|
+
{ label: 'Audit Logs', value: 'audit-logs', href: `${basePath}/audit-logs` },
|
|
14463
|
+
];
|
|
14464
|
+
/**
|
|
14465
|
+
* Shared activity layout with tab navigation for Activity Feed, Events, and Audit Logs.
|
|
14466
|
+
* Framework-agnostic — pass a linkComponent (e.g., react-router's Link) for navigation.
|
|
14467
|
+
*/
|
|
14468
|
+
function ActivityLayout({ basePath, activeTab, tabs, linkComponent: LinkComp, children, className, }) {
|
|
14469
|
+
const resolvedTabs = tabs ?? defaultTabs(basePath);
|
|
14470
|
+
return (jsxRuntime.jsxs("div", { className: cn('flex h-full flex-col overflow-hidden', className), children: [jsxRuntime.jsx("div", { className: "shrink-0 border-b px-4 pt-3", children: jsxRuntime.jsx(Tabs, { value: activeTab, children: jsxRuntime.jsx(TabsList, { children: resolvedTabs.map((tab) => (jsxRuntime.jsx(TabsTrigger, { value: tab.value, asChild: !!LinkComp, children: LinkComp ? (jsxRuntime.jsx(LinkComp, { to: tab.href, children: tab.label })) : (jsxRuntime.jsx("span", { children: tab.label })) }, tab.value))) }) }) }), jsxRuntime.jsx("div", { className: "min-h-0 flex-1 overflow-hidden p-4", children: jsxRuntime.jsx("div", { className: "flex h-full flex-col", children: children }) })] }));
|
|
14471
|
+
}
|
|
14472
|
+
|
|
14459
14473
|
/**
|
|
14460
14474
|
* React hook for managing ReindexJobs with optional real-time watching
|
|
14461
14475
|
*/
|
|
@@ -14987,6 +15001,205 @@ function MultiCombobox({ options, values, onValuesChange, placeholder = 'Select.
|
|
|
14987
15001
|
}, className: "rounded-sm opacity-50 hover:opacity-100 cursor-pointer", children: jsxRuntime.jsx(X, { className: "h-3 w-3" }) })), jsxRuntime.jsx(ChevronsUpDown, { className: "h-4 w-4 shrink-0 opacity-50" })] })] }) }), jsxRuntime.jsx(Popover__namespace.Portal, { children: jsxRuntime.jsx(Popover__namespace.Content, { className: cn('z-50 min-w-[var(--radix-popover-trigger-width)] overflow-hidden rounded-md border shadow-md', 'bg-white dark:bg-slate-900 text-foreground', 'data-[state=open]:animate-in data-[state=closed]:animate-out', 'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0', 'data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95', 'data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2'), sideOffset: 4, align: "start", children: jsxRuntime.jsxs(cmdk.Command, { filter: filterOptions, className: "w-full", children: [jsxRuntime.jsx("div", { className: "flex items-center border-b px-3", children: jsxRuntime.jsx(cmdk.CommandInput, { placeholder: searchPlaceholder, value: search, onValueChange: setSearch, className: "flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50" }) }), values.length > 0 && (jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1 p-2 border-b", children: selectedOptions.map((option) => (jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-md bg-secondary text-secondary-foreground text-xs", children: [option.label, jsxRuntime.jsx("button", { type: "button", onClick: (e) => handleRemove(e, option.value), className: "rounded-sm hover:bg-secondary-foreground/20", children: jsxRuntime.jsx(X, { className: "h-3 w-3" }) })] }, option.value))) })), jsxRuntime.jsxs(cmdk.CommandList, { className: "max-h-[300px] overflow-y-auto p-1", children: [jsxRuntime.jsx(cmdk.CommandEmpty, { className: "py-6 text-center text-sm text-muted-foreground", children: emptyMessage }), jsxRuntime.jsx(cmdk.CommandGroup, { children: options.map((option) => (jsxRuntime.jsxs(cmdk.CommandItem, { value: option.value, onSelect: () => handleSelect(option.value), className: cn('relative flex cursor-pointer select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none', 'data-[selected=true]:bg-accent data-[selected=true]:text-accent-foreground', 'hover:bg-accent hover:text-accent-foreground'), children: [jsxRuntime.jsx(Check, { className: cn('mr-2 h-4 w-4', values.includes(option.value) ? 'opacity-100' : 'opacity-0') }), jsxRuntime.jsx("span", { className: "flex-1 truncate", children: option.label }), option.count !== undefined && (jsxRuntime.jsxs("span", { className: "ml-2 text-xs text-muted-foreground", children: ["(", option.count, ")"] }))] }, option.value))) })] })] }) }) })] }));
|
|
14988
15002
|
}
|
|
14989
15003
|
|
|
15004
|
+
/**
|
|
15005
|
+
* Serialize Activity Feed filters to URL search params.
|
|
15006
|
+
* Used to sync filter changes back to the URL for deep linking.
|
|
15007
|
+
*/
|
|
15008
|
+
function serializeActivityFilters(filters, timeRange, streamingEnabled = true) {
|
|
15009
|
+
const params = new URLSearchParams();
|
|
15010
|
+
if (timeRange.start) {
|
|
15011
|
+
params.set('start', timeRange.start);
|
|
15012
|
+
}
|
|
15013
|
+
if (timeRange.end) {
|
|
15014
|
+
params.set('end', timeRange.end);
|
|
15015
|
+
}
|
|
15016
|
+
if (!streamingEnabled) {
|
|
15017
|
+
params.set('streaming', 'false');
|
|
15018
|
+
}
|
|
15019
|
+
if (filters.changeSource && filters.changeSource !== 'human') {
|
|
15020
|
+
params.set('changeSource', filters.changeSource);
|
|
15021
|
+
}
|
|
15022
|
+
if (filters.actorNames && filters.actorNames.length > 0) {
|
|
15023
|
+
params.set('actorNames', filters.actorNames.join(','));
|
|
15024
|
+
}
|
|
15025
|
+
if (filters.resourceKinds && filters.resourceKinds.length > 0) {
|
|
15026
|
+
params.set('resourceKinds', filters.resourceKinds.join(','));
|
|
15027
|
+
}
|
|
15028
|
+
if (filters.apiGroups && filters.apiGroups.length > 0) {
|
|
15029
|
+
params.set('apiGroups', filters.apiGroups.join(','));
|
|
15030
|
+
}
|
|
15031
|
+
if (filters.resourceNamespaces && filters.resourceNamespaces.length > 0) {
|
|
15032
|
+
params.set('resourceNamespaces', filters.resourceNamespaces.join(','));
|
|
15033
|
+
}
|
|
15034
|
+
if (filters.resourceUid) {
|
|
15035
|
+
params.set('resourceUid', filters.resourceUid);
|
|
15036
|
+
}
|
|
15037
|
+
if (filters.resourceName) {
|
|
15038
|
+
params.set('resourceName', filters.resourceName);
|
|
15039
|
+
}
|
|
15040
|
+
if (filters.search) {
|
|
15041
|
+
params.set('search', filters.search);
|
|
15042
|
+
}
|
|
15043
|
+
return params;
|
|
15044
|
+
}
|
|
15045
|
+
/**
|
|
15046
|
+
* Serialize Events Feed filters to URL search params.
|
|
15047
|
+
* Used to sync filter changes back to the URL for deep linking.
|
|
15048
|
+
*/
|
|
15049
|
+
function serializeEventFilters(filters, timeRange, streamingEnabled = true) {
|
|
15050
|
+
const params = new URLSearchParams();
|
|
15051
|
+
if (timeRange.start) {
|
|
15052
|
+
params.set('start', timeRange.start);
|
|
15053
|
+
}
|
|
15054
|
+
if (timeRange.end) {
|
|
15055
|
+
params.set('end', timeRange.end);
|
|
15056
|
+
}
|
|
15057
|
+
if (!streamingEnabled) {
|
|
15058
|
+
params.set('streaming', 'false');
|
|
15059
|
+
}
|
|
15060
|
+
if (filters.eventType && filters.eventType !== 'all') {
|
|
15061
|
+
params.set('eventType', filters.eventType);
|
|
15062
|
+
}
|
|
15063
|
+
if (filters.reasons && filters.reasons.length > 0) {
|
|
15064
|
+
params.set('reasons', filters.reasons.join(','));
|
|
15065
|
+
}
|
|
15066
|
+
if (filters.namespaces && filters.namespaces.length > 0) {
|
|
15067
|
+
params.set('namespaces', filters.namespaces.join(','));
|
|
15068
|
+
}
|
|
15069
|
+
if (filters.involvedKinds && filters.involvedKinds.length > 0) {
|
|
15070
|
+
params.set('involvedKinds', filters.involvedKinds.join(','));
|
|
15071
|
+
}
|
|
15072
|
+
if (filters.search) {
|
|
15073
|
+
params.set('search', filters.search);
|
|
15074
|
+
}
|
|
15075
|
+
return params;
|
|
15076
|
+
}
|
|
15077
|
+
/**
|
|
15078
|
+
* Parse Activity Feed filters from URL query params
|
|
15079
|
+
*/
|
|
15080
|
+
function parseActivityFilters(searchParams) {
|
|
15081
|
+
const filters = {};
|
|
15082
|
+
const changeSource = searchParams.get('changeSource');
|
|
15083
|
+
if (changeSource === 'human' || changeSource === 'system' || changeSource === 'all') {
|
|
15084
|
+
filters.changeSource = changeSource;
|
|
15085
|
+
}
|
|
15086
|
+
else {
|
|
15087
|
+
filters.changeSource = 'human';
|
|
15088
|
+
}
|
|
15089
|
+
const actorNames = searchParams.get('actorNames');
|
|
15090
|
+
if (actorNames) {
|
|
15091
|
+
filters.actorNames = actorNames.split(',').filter(Boolean);
|
|
15092
|
+
}
|
|
15093
|
+
const resourceKinds = searchParams.get('resourceKinds');
|
|
15094
|
+
if (resourceKinds) {
|
|
15095
|
+
filters.resourceKinds = resourceKinds.split(',').filter(Boolean);
|
|
15096
|
+
}
|
|
15097
|
+
const apiGroups = searchParams.get('apiGroups');
|
|
15098
|
+
if (apiGroups) {
|
|
15099
|
+
filters.apiGroups = apiGroups.split(',').filter(Boolean);
|
|
15100
|
+
}
|
|
15101
|
+
const resourceNamespaces = searchParams.get('resourceNamespaces');
|
|
15102
|
+
if (resourceNamespaces) {
|
|
15103
|
+
filters.resourceNamespaces = resourceNamespaces.split(',').filter(Boolean);
|
|
15104
|
+
}
|
|
15105
|
+
const resourceUid = searchParams.get('resourceUid');
|
|
15106
|
+
if (resourceUid) {
|
|
15107
|
+
filters.resourceUid = resourceUid;
|
|
15108
|
+
}
|
|
15109
|
+
const resourceName = searchParams.get('resourceName');
|
|
15110
|
+
if (resourceName) {
|
|
15111
|
+
filters.resourceName = resourceName;
|
|
15112
|
+
}
|
|
15113
|
+
const search = searchParams.get('search');
|
|
15114
|
+
if (search) {
|
|
15115
|
+
filters.search = search;
|
|
15116
|
+
}
|
|
15117
|
+
return filters;
|
|
15118
|
+
}
|
|
15119
|
+
/**
|
|
15120
|
+
* Parse Events Feed filters from URL query params
|
|
15121
|
+
*/
|
|
15122
|
+
function parseEventFilters(searchParams) {
|
|
15123
|
+
const filters = {};
|
|
15124
|
+
const eventType = searchParams.get('eventType');
|
|
15125
|
+
if (eventType === 'Normal' || eventType === 'Warning' || eventType === 'all') {
|
|
15126
|
+
filters.eventType = eventType;
|
|
15127
|
+
}
|
|
15128
|
+
const reasons = searchParams.get('reasons');
|
|
15129
|
+
if (reasons) {
|
|
15130
|
+
filters.reasons = reasons.split(',').filter(Boolean);
|
|
15131
|
+
}
|
|
15132
|
+
const namespaces = searchParams.get('namespaces');
|
|
15133
|
+
if (namespaces) {
|
|
15134
|
+
filters.namespaces = namespaces.split(',').filter(Boolean);
|
|
15135
|
+
}
|
|
15136
|
+
const involvedKinds = searchParams.get('involvedKinds');
|
|
15137
|
+
if (involvedKinds) {
|
|
15138
|
+
filters.involvedKinds = involvedKinds.split(',').filter(Boolean);
|
|
15139
|
+
}
|
|
15140
|
+
const search = searchParams.get('search');
|
|
15141
|
+
if (search) {
|
|
15142
|
+
filters.search = search;
|
|
15143
|
+
}
|
|
15144
|
+
return filters;
|
|
15145
|
+
}
|
|
15146
|
+
/**
|
|
15147
|
+
* Parse time range from URL query params
|
|
15148
|
+
*/
|
|
15149
|
+
function parseTimeRange(searchParams) {
|
|
15150
|
+
const start = searchParams.get('start');
|
|
15151
|
+
const end = searchParams.get('end');
|
|
15152
|
+
if (!start) {
|
|
15153
|
+
return undefined;
|
|
15154
|
+
}
|
|
15155
|
+
return { start, end: end || undefined };
|
|
15156
|
+
}
|
|
15157
|
+
|
|
15158
|
+
/**
|
|
15159
|
+
* Generate a shareable URL for the current activity view.
|
|
15160
|
+
*
|
|
15161
|
+
* The shareable URL:
|
|
15162
|
+
* - Uses absolute timestamps (not relative like "now-1h")
|
|
15163
|
+
* - Disables streaming so the view is static
|
|
15164
|
+
* - Preserves all current filters
|
|
15165
|
+
*
|
|
15166
|
+
* This ensures the shared link shows the exact same data regardless of
|
|
15167
|
+
* when someone opens it.
|
|
15168
|
+
*
|
|
15169
|
+
* @param basePath - Current route path (e.g., "/activity/feed")
|
|
15170
|
+
* @param effectiveTimeRange - Server-calculated effective time range
|
|
15171
|
+
* @param filters - Current filter state
|
|
15172
|
+
* @param origin - Window origin for absolute URL (e.g., "https://staff.datum.cloud")
|
|
15173
|
+
*/
|
|
15174
|
+
function generateShareableUrl(basePath, effectiveTimeRange, filters, origin = typeof window !== 'undefined' ? window.location.origin : '') {
|
|
15175
|
+
const params = new URLSearchParams();
|
|
15176
|
+
// Use absolute timestamps from server-calculated range
|
|
15177
|
+
params.set('start', effectiveTimeRange.startTime);
|
|
15178
|
+
params.set('end', effectiveTimeRange.endTime);
|
|
15179
|
+
// Disable streaming for shared links (static view)
|
|
15180
|
+
params.set('streaming', 'false');
|
|
15181
|
+
// Preserve all current filters
|
|
15182
|
+
for (const [key, value] of Object.entries(filters)) {
|
|
15183
|
+
if (value && key !== 'start' && key !== 'end' && key !== 'streaming') {
|
|
15184
|
+
params.set(key, value);
|
|
15185
|
+
}
|
|
15186
|
+
}
|
|
15187
|
+
return `${origin}${basePath}?${params.toString()}`;
|
|
15188
|
+
}
|
|
15189
|
+
/**
|
|
15190
|
+
* Copy text to clipboard and return success status
|
|
15191
|
+
*/
|
|
15192
|
+
async function copyToClipboard(text) {
|
|
15193
|
+
try {
|
|
15194
|
+
await navigator.clipboard.writeText(text);
|
|
15195
|
+
return true;
|
|
15196
|
+
}
|
|
15197
|
+
catch (err) {
|
|
15198
|
+
console.error('Failed to copy to clipboard:', err);
|
|
15199
|
+
return false;
|
|
15200
|
+
}
|
|
15201
|
+
}
|
|
15202
|
+
|
|
14990
15203
|
/**
|
|
14991
15204
|
* Create an empty audit event for preview
|
|
14992
15205
|
*/
|
|
@@ -16257,6 +16470,7 @@ exports.ActivityFeed = ActivityFeed;
|
|
|
16257
16470
|
exports.ActivityFeedItem = ActivityFeedItem;
|
|
16258
16471
|
exports.ActivityFeedItemSkeleton = ActivityFeedItemSkeleton;
|
|
16259
16472
|
exports.ActivityFeedSummary = ActivityFeedSummary;
|
|
16473
|
+
exports.ActivityLayout = ActivityLayout;
|
|
16260
16474
|
exports.Alert = Alert;
|
|
16261
16475
|
exports.AlertDescription = AlertDescription;
|
|
16262
16476
|
exports.AlertTitle = AlertTitle;
|
|
@@ -16353,17 +16567,24 @@ exports.badgeVariants = badgeVariants;
|
|
|
16353
16567
|
exports.buildAuditLogCEL = buildAuditLogCEL;
|
|
16354
16568
|
exports.buttonVariants = buttonVariants;
|
|
16355
16569
|
exports.cn = cn;
|
|
16570
|
+
exports.copyToClipboard = copyToClipboard;
|
|
16356
16571
|
exports.defaultErrorFormatter = defaultErrorFormatter;
|
|
16357
16572
|
exports.defaultResourceLinkResolver = defaultResourceLinkResolver;
|
|
16358
16573
|
exports.extractEvent = extractEvent;
|
|
16359
16574
|
exports.extractFieldPaths = extractFieldPaths;
|
|
16360
16575
|
exports.extractFieldPathsFromMany = extractFieldPathsFromMany;
|
|
16576
|
+
exports.generateShareableUrl = generateShareableUrl;
|
|
16361
16577
|
exports.getReindexJobDuration = getReindexJobDuration;
|
|
16362
16578
|
exports.getReindexJobStatusMessage = getReindexJobStatusMessage;
|
|
16363
16579
|
exports.isEventRecord = isEventRecord;
|
|
16364
16580
|
exports.isReindexJobRunning = isReindexJobRunning;
|
|
16365
16581
|
exports.isReindexJobTerminal = isReindexJobTerminal;
|
|
16582
|
+
exports.parseActivityFilters = parseActivityFilters;
|
|
16366
16583
|
exports.parseApiError = parseApiError;
|
|
16584
|
+
exports.parseEventFilters = parseEventFilters;
|
|
16585
|
+
exports.parseTimeRange = parseTimeRange;
|
|
16586
|
+
exports.serializeActivityFilters = serializeActivityFilters;
|
|
16587
|
+
exports.serializeEventFilters = serializeEventFilters;
|
|
16367
16588
|
exports.useActivityFeed = useActivityFeed;
|
|
16368
16589
|
exports.useAuditLogFacets = useAuditLogFacets;
|
|
16369
16590
|
exports.useAuditLogQuery = useAuditLogQuery;
|