@archiva/archiva-nextjs 0.2.94 → 0.3.1

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/index.js CHANGED
@@ -304,10 +304,17 @@ var normalizeAuditEventItem = (event) => {
304
304
  "actor_id",
305
305
  "id"
306
306
  ]);
307
+ const actionKeyValue = coerceString(event.actionKey ?? event.action_key ?? event.action);
308
+ const actionDescriptionValue = coerceString(event.actionDescription ?? event.action_description);
309
+ const tenantIdValue = coerceString(event.tenantId ?? event.tenant_id);
307
310
  return {
308
311
  id: coerceString(event.id) ?? "",
309
312
  receivedAt: coerceString(event.receivedAt ?? event.received_at) ?? "",
310
- action: coerceString(event.action) ?? "",
313
+ actionKey: actionKeyValue ?? "",
314
+ actionDescription: actionDescriptionValue ?? void 0,
315
+ tenantId: tenantIdValue ?? void 0,
316
+ // Legacy support: include action for backward compatibility
317
+ action: actionKeyValue ?? "",
311
318
  entityType: coerceString(event.entityType ?? event.entity_type) ?? "",
312
319
  entityId: coerceString(event.entityId ?? event.entity_id) ?? "",
313
320
  actorId: coerceNullableString(actorIdValue),
@@ -378,7 +385,20 @@ async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
378
385
  url.searchParams.set("entityType", params.entityType);
379
386
  }
380
387
  if (params.actorType) {
381
- url.searchParams.set("actorType", params.actorType);
388
+ if (Array.isArray(params.actorType)) {
389
+ url.searchParams.set("actorType", params.actorType.join(","));
390
+ } else {
391
+ url.searchParams.set("actorType", params.actorType);
392
+ }
393
+ }
394
+ if (params.tenantId) {
395
+ url.searchParams.set("tenantId", params.tenantId);
396
+ }
397
+ if (params.actionKey) {
398
+ url.searchParams.set("actionKey", params.actionKey);
399
+ }
400
+ if (params.q) {
401
+ url.searchParams.set("q", params.q);
382
402
  }
383
403
  if (params.limit) {
384
404
  url.searchParams.set("limit", String(params.limit));
package/dist/index.mjs CHANGED
@@ -9,8 +9,8 @@ import {
9
9
  createFrontendTokenGET,
10
10
  createFrontendTokenRoute,
11
11
  loadEvents
12
- } from "./chunk-A3Q4YKTK.mjs";
13
- import "./chunk-WA7TMG65.mjs";
12
+ } from "./chunk-5ZJUGBTU.mjs";
13
+ import "./chunk-LOKBGU6S.mjs";
14
14
  export {
15
15
  ArchivaError,
16
16
  ArchivaProvider,
@@ -22,8 +22,12 @@ type TimelineItem = {
22
22
  };
23
23
  type TimelineProps = {
24
24
  entityId?: string;
25
+ tenantId?: string;
25
26
  actorId?: string;
26
27
  entityType?: string;
28
+ actionKey?: string;
29
+ actionDescription?: string;
30
+ actorType?: 'user' | 'service' | 'system' | ('user' | 'service' | 'system')[];
27
31
  initialLimit?: number;
28
32
  className?: string;
29
33
  emptyMessage?: string;
@@ -34,7 +38,7 @@ type TimelineProps = {
34
38
  className?: string;
35
39
  }> | undefined;
36
40
  };
37
- declare function Timeline({ entityId, actorId, entityType, initialLimit, className, emptyMessage, showSearch, showFilters, showSystemAndServices, getActorAvatar, }: TimelineProps): react_jsx_runtime.JSX.Element;
41
+ declare function Timeline({ entityId, tenantId, actorId, entityType, actionKey, actionDescription, actorType, initialLimit, className, emptyMessage, showSearch, showFilters, showSystemAndServices, getActorAvatar, }: TimelineProps): react_jsx_runtime.JSX.Element;
38
42
 
39
43
  type ArchivaContextValue = {
40
44
  apiBaseUrl: string;
@@ -22,8 +22,12 @@ type TimelineItem = {
22
22
  };
23
23
  type TimelineProps = {
24
24
  entityId?: string;
25
+ tenantId?: string;
25
26
  actorId?: string;
26
27
  entityType?: string;
28
+ actionKey?: string;
29
+ actionDescription?: string;
30
+ actorType?: 'user' | 'service' | 'system' | ('user' | 'service' | 'system')[];
27
31
  initialLimit?: number;
28
32
  className?: string;
29
33
  emptyMessage?: string;
@@ -34,7 +38,7 @@ type TimelineProps = {
34
38
  className?: string;
35
39
  }> | undefined;
36
40
  };
37
- declare function Timeline({ entityId, actorId, entityType, initialLimit, className, emptyMessage, showSearch, showFilters, showSystemAndServices, getActorAvatar, }: TimelineProps): react_jsx_runtime.JSX.Element;
41
+ declare function Timeline({ entityId, tenantId, actorId, entityType, actionKey, actionDescription, actorType, initialLimit, className, emptyMessage, showSearch, showFilters, showSystemAndServices, getActorAvatar, }: TimelineProps): react_jsx_runtime.JSX.Element;
38
42
 
39
43
  type ArchivaContextValue = {
40
44
  apiBaseUrl: string;
@@ -121,10 +121,17 @@ var normalizeAuditEventItem = (event) => {
121
121
  "actor_id",
122
122
  "id"
123
123
  ]);
124
+ const actionKeyValue = coerceString(event.actionKey ?? event.action_key ?? event.action);
125
+ const actionDescriptionValue = coerceString(event.actionDescription ?? event.action_description);
126
+ const tenantIdValue = coerceString(event.tenantId ?? event.tenant_id);
124
127
  return {
125
128
  id: coerceString(event.id) ?? "",
126
129
  receivedAt: coerceString(event.receivedAt ?? event.received_at) ?? "",
127
- action: coerceString(event.action) ?? "",
130
+ actionKey: actionKeyValue ?? "",
131
+ actionDescription: actionDescriptionValue ?? void 0,
132
+ tenantId: tenantIdValue ?? void 0,
133
+ // Legacy support: include action for backward compatibility
134
+ action: actionKeyValue ?? "",
128
135
  entityType: coerceString(event.entityType ?? event.entity_type) ?? "",
129
136
  entityId: coerceString(event.entityId ?? event.entity_id) ?? "",
130
137
  actorId: coerceNullableString(actorIdValue),
@@ -196,8 +203,9 @@ var CloudCogIcon = ({ className }) => /* @__PURE__ */ (0, import_jsx_runtime2.js
196
203
  }
197
204
  );
198
205
  function eventToTimelineItem(event, getActorAvatar) {
199
- const action = event.action.charAt(0).toUpperCase() + event.action.slice(1);
200
- const description = action;
206
+ const actionValue = event.actionKey || event.action || "";
207
+ const action = actionValue.charAt(0).toUpperCase() + actionValue.slice(1);
208
+ const description = event.actionDescription || "";
201
209
  const actorId = event.actorId || "unknown";
202
210
  const userName = actorId.includes(":") ? actorId.split(":")[1] || actorId : actorId;
203
211
  const userHandle = userName;
@@ -244,7 +252,8 @@ function eventToTimelineItem(event, getActorAvatar) {
244
252
  // Matches ActivityLog.tsx line 361
245
253
  statusIndicator: false,
246
254
  // Can be set to true for recent items - matches ActivityLog.tsx line 362
247
- data: event
255
+ data: event,
256
+ badge: action
248
257
  };
249
258
  }
250
259
  async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, params) {
@@ -252,14 +261,21 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
252
261
  if (params.entityId) {
253
262
  url.searchParams.set("entityId", params.entityId);
254
263
  }
264
+ if (params.tenantId) {
265
+ url.searchParams.set("tenantId", params.tenantId);
266
+ }
255
267
  if (params.actorId) {
256
268
  url.searchParams.set("actorId", params.actorId);
257
269
  }
258
270
  if (params.entityType) {
259
271
  url.searchParams.set("entityType", params.entityType);
260
272
  }
273
+ if (params.actionKey) {
274
+ url.searchParams.set("actionKey", params.actionKey);
275
+ }
261
276
  if (params.actorType) {
262
- url.searchParams.set("actorType", params.actorType);
277
+ const actorTypeValue = Array.isArray(params.actorType) ? params.actorType.join(",") : params.actorType;
278
+ url.searchParams.set("actorType", actorTypeValue);
263
279
  }
264
280
  if (params.limit) {
265
281
  url.searchParams.set("limit", String(params.limit));
@@ -267,6 +283,9 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
267
283
  if (params.cursor) {
268
284
  url.searchParams.set("cursor", params.cursor);
269
285
  }
286
+ if (params.q) {
287
+ url.searchParams.set("q", params.q);
288
+ }
270
289
  const makeRequest = async (token2) => {
271
290
  return fetch(url.toString(), {
272
291
  headers: {
@@ -399,8 +418,15 @@ function SimpleAvatar({
399
418
  }
400
419
  );
401
420
  }
402
- function applyClientSideFilters(events, searchQuery, showSystemAndServices) {
421
+ function applyClientSideFilters(events, searchQuery, showSystemAndServices, actionDescription) {
403
422
  let filtered = events;
423
+ if (actionDescription) {
424
+ filtered = filtered.filter((event) => {
425
+ const eventActionDescription = (event.actionDescription || "").toLowerCase();
426
+ const filterActionDescription = actionDescription.toLowerCase();
427
+ return eventActionDescription.includes(filterActionDescription);
428
+ });
429
+ }
404
430
  if (!showSystemAndServices) {
405
431
  filtered = filtered.filter((event) => {
406
432
  if (event.actorType) {
@@ -418,13 +444,19 @@ function applyClientSideFilters(events, searchQuery, showSystemAndServices) {
418
444
  }
419
445
  const query = searchQuery.toLowerCase();
420
446
  return filtered.filter((event) => {
421
- return event.action.toLowerCase().includes(query) || event.entityType.toLowerCase().includes(query) || event.entityId.toLowerCase().includes(query) || event.actorId && event.actorId.toLowerCase().includes(query) || event.source && event.source.toLowerCase().includes(query) || event.actorDisplay && event.actorDisplay.toLowerCase().includes(query);
447
+ const actionValue = (event.actionKey || event.action || "").toLowerCase();
448
+ const actionDescValue = (event.actionDescription || "").toLowerCase();
449
+ return actionValue.includes(query) || actionDescValue.includes(query) || event.entityType.toLowerCase().includes(query) || event.entityId.toLowerCase().includes(query) || event.actorId && event.actorId.toLowerCase().includes(query) || event.source && event.source.toLowerCase().includes(query) || event.actorDisplay && event.actorDisplay.toLowerCase().includes(query);
422
450
  });
423
451
  }
424
452
  function Timeline({
425
453
  entityId,
454
+ tenantId,
426
455
  actorId,
427
456
  entityType,
457
+ actionKey,
458
+ actionDescription,
459
+ actorType,
428
460
  initialLimit = 100,
429
461
  className,
430
462
  emptyMessage = "No events yet.",
@@ -441,25 +473,64 @@ function Timeline({
441
473
  const [error, setError] = React2.useState(null);
442
474
  const [hasMore, setHasMore] = React2.useState(false);
443
475
  const [searchQuery, setSearchQuery] = React2.useState("");
476
+ const baseFilters = React2.useMemo(() => {
477
+ const filters = {};
478
+ if (entityId) filters.entityId = entityId;
479
+ if (tenantId) filters.tenantId = tenantId;
480
+ if (actorId) filters.actorId = actorId;
481
+ if (entityType) filters.entityType = entityType;
482
+ if (actionKey) filters.actionKey = actionKey;
483
+ if (actorType) filters.actorType = actorType;
484
+ if (!showSystemAndServices && !actorType) {
485
+ filters.actorType = "user";
486
+ }
487
+ return filters;
488
+ }, [entityId, tenantId, actorId, entityType, actionKey, actorType, showSystemAndServices]);
489
+ const [uiFilters, setUiFilters] = React2.useState({});
490
+ const mergedFilters = React2.useMemo(() => {
491
+ const merged = {
492
+ ...baseFilters,
493
+ limit: initialLimit
494
+ };
495
+ if (!baseFilters.tenantId && uiFilters.tenantId) {
496
+ merged.tenantId = uiFilters.tenantId;
497
+ }
498
+ if (!baseFilters.actionKey && uiFilters.actionKey) {
499
+ merged.actionKey = uiFilters.actionKey;
500
+ }
501
+ if (!baseFilters.entityId && uiFilters.entityId) {
502
+ merged.entityId = uiFilters.entityId;
503
+ }
504
+ if (!baseFilters.entityType && uiFilters.entityType) {
505
+ merged.entityType = uiFilters.entityType;
506
+ }
507
+ if (!baseFilters.actorId && uiFilters.actorId) {
508
+ merged.actorId = uiFilters.actorId;
509
+ }
510
+ if (!baseFilters.actorType && uiFilters.actorType) {
511
+ merged.actorType = uiFilters.actorType;
512
+ }
513
+ return merged;
514
+ }, [baseFilters, uiFilters, initialLimit]);
515
+ const lockedFilters = React2.useMemo(() => ({
516
+ tenantId: !!tenantId,
517
+ actionKey: !!actionKey,
518
+ entityId: !!entityId,
519
+ entityType: !!entityType,
520
+ actorId: !!actorId,
521
+ actorType: !!actorType
522
+ }), [tenantId, actionKey, entityId, entityType, actorId, actorType]);
444
523
  const queryParamsRef = React2.useRef({});
445
524
  const queryParamsKeyRef = React2.useRef("");
446
525
  const queryParams = React2.useMemo(() => {
447
- const params = {
448
- entityId,
449
- actorId,
450
- entityType,
451
- // Filter by actorType on API side
452
- actorType: showSystemAndServices ? void 0 : "user",
453
- limit: initialLimit
454
- };
455
- const key = JSON.stringify(params);
526
+ const key = JSON.stringify(mergedFilters);
456
527
  if (key !== queryParamsKeyRef.current) {
457
528
  queryParamsKeyRef.current = key;
458
- queryParamsRef.current = params;
459
- return params;
529
+ queryParamsRef.current = mergedFilters;
530
+ return mergedFilters;
460
531
  }
461
532
  return queryParamsRef.current;
462
- }, [entityId, actorId, entityType, initialLimit, showSystemAndServices]);
533
+ }, [mergedFilters]);
463
534
  const allEventsRef = React2.useRef([]);
464
535
  React2.useEffect(() => {
465
536
  allEventsRef.current = allEvents;
@@ -506,12 +577,13 @@ function Timeline({
506
577
  },
507
578
  [queryParams, apiBaseUrl, getToken, forceRefreshToken, cursor]
508
579
  );
580
+ const filterKey = React2.useMemo(() => JSON.stringify(mergedFilters), [mergedFilters]);
509
581
  React2.useEffect(() => {
510
582
  setCursor(void 0);
511
583
  setAllEvents([]);
512
584
  setPreviousEvents([]);
513
585
  void load({ reset: true });
514
- }, [entityId, actorId, entityType, showSystemAndServices, initialLimit]);
586
+ }, [filterKey]);
515
587
  const eventsToFilter = React2.useMemo(() => {
516
588
  if (loading && allEvents.length === 0 && previousEvents.length > 0) {
517
589
  return previousEvents;
@@ -519,8 +591,8 @@ function Timeline({
519
591
  return allEvents;
520
592
  }, [allEvents, loading, previousEvents]);
521
593
  const filteredEvents = React2.useMemo(() => {
522
- return applyClientSideFilters(eventsToFilter, searchQuery, showSystemAndServices);
523
- }, [eventsToFilter, searchQuery, showSystemAndServices]);
594
+ return applyClientSideFilters(eventsToFilter, searchQuery, showSystemAndServices, actionDescription);
595
+ }, [eventsToFilter, searchQuery, showSystemAndServices, actionDescription]);
524
596
  const timelineItems = React2.useMemo(() => {
525
597
  return filteredEvents.slice(0, 10).map(
526
598
  (event) => eventToTimelineItem(event, getActorAvatar)
@@ -545,6 +617,144 @@ function Timeline({
545
617
  placeholder: "Search actions, entities, IDs, actors, sources..."
546
618
  }
547
619
  ) }),
620
+ showFilters && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "1rem", padding: "1rem", backgroundColor: "#f9fafb", borderRadius: "0.375rem", display: "flex", flexWrap: "wrap", gap: "0.75rem" }, children: [
621
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
622
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: [
623
+ "Tenant ID ",
624
+ lockedFilters.tenantId && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#9ca3af" }, children: "(Locked)" })
625
+ ] }),
626
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
627
+ "input",
628
+ {
629
+ type: "text",
630
+ placeholder: "All tenants",
631
+ value: lockedFilters.tenantId ? tenantId ?? "" : uiFilters.tenantId ?? "",
632
+ onChange: (e) => {
633
+ if (!lockedFilters.tenantId) {
634
+ setUiFilters((prev) => ({ ...prev, tenantId: e.target.value || void 0 }));
635
+ }
636
+ },
637
+ disabled: lockedFilters.tenantId,
638
+ style: {
639
+ padding: "0.375rem 0.5rem",
640
+ border: "1px solid #d1d5db",
641
+ borderRadius: "0.375rem",
642
+ fontSize: "0.875rem",
643
+ backgroundColor: lockedFilters.tenantId ? "#f3f4f6" : "white",
644
+ cursor: lockedFilters.tenantId ? "not-allowed" : "text"
645
+ }
646
+ }
647
+ )
648
+ ] }),
649
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
650
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: [
651
+ "Action Key ",
652
+ lockedFilters.actionKey && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#9ca3af" }, children: "(Locked)" })
653
+ ] }),
654
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
655
+ "input",
656
+ {
657
+ type: "text",
658
+ placeholder: "All actions",
659
+ value: lockedFilters.actionKey ? actionKey ?? "" : uiFilters.actionKey ?? "",
660
+ onChange: (e) => {
661
+ if (!lockedFilters.actionKey) {
662
+ setUiFilters((prev) => ({ ...prev, actionKey: e.target.value || void 0 }));
663
+ }
664
+ },
665
+ disabled: lockedFilters.actionKey,
666
+ style: {
667
+ padding: "0.375rem 0.5rem",
668
+ border: "1px solid #d1d5db",
669
+ borderRadius: "0.375rem",
670
+ fontSize: "0.875rem",
671
+ backgroundColor: lockedFilters.actionKey ? "#f3f4f6" : "white",
672
+ cursor: lockedFilters.actionKey ? "not-allowed" : "text"
673
+ }
674
+ }
675
+ )
676
+ ] }),
677
+ !lockedFilters.entityId && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
678
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: "Entity ID" }),
679
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
680
+ "input",
681
+ {
682
+ type: "text",
683
+ placeholder: "All entities",
684
+ value: uiFilters.entityId ?? "",
685
+ onChange: (e) => {
686
+ setUiFilters((prev) => ({ ...prev, entityId: e.target.value || void 0 }));
687
+ },
688
+ style: {
689
+ padding: "0.375rem 0.5rem",
690
+ border: "1px solid #d1d5db",
691
+ borderRadius: "0.375rem",
692
+ fontSize: "0.875rem"
693
+ }
694
+ }
695
+ )
696
+ ] }),
697
+ !lockedFilters.entityType && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
698
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: "Entity Type" }),
699
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
700
+ "input",
701
+ {
702
+ type: "text",
703
+ placeholder: "All types",
704
+ value: uiFilters.entityType ?? "",
705
+ onChange: (e) => {
706
+ setUiFilters((prev) => ({ ...prev, entityType: e.target.value || void 0 }));
707
+ },
708
+ style: {
709
+ padding: "0.375rem 0.5rem",
710
+ border: "1px solid #d1d5db",
711
+ borderRadius: "0.375rem",
712
+ fontSize: "0.875rem"
713
+ }
714
+ }
715
+ )
716
+ ] }),
717
+ !lockedFilters.actorId && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
718
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: "Actor ID" }),
719
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
720
+ "input",
721
+ {
722
+ type: "text",
723
+ placeholder: "All actors",
724
+ value: uiFilters.actorId ?? "",
725
+ onChange: (e) => {
726
+ setUiFilters((prev) => ({ ...prev, actorId: e.target.value || void 0 }));
727
+ },
728
+ style: {
729
+ padding: "0.375rem 0.5rem",
730
+ border: "1px solid #d1d5db",
731
+ borderRadius: "0.375rem",
732
+ fontSize: "0.875rem"
733
+ }
734
+ }
735
+ )
736
+ ] }),
737
+ (Object.keys(uiFilters).length > 0 || searchQuery) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", alignItems: "flex-end" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
738
+ "button",
739
+ {
740
+ type: "button",
741
+ onClick: () => {
742
+ setUiFilters({});
743
+ setSearchQuery("");
744
+ },
745
+ style: {
746
+ padding: "0.375rem 0.75rem",
747
+ backgroundColor: "#ef4444",
748
+ color: "white",
749
+ border: "none",
750
+ borderRadius: "0.375rem",
751
+ fontSize: "0.875rem",
752
+ cursor: "pointer"
753
+ },
754
+ children: "Clear"
755
+ }
756
+ ) })
757
+ ] }),
548
758
  (searchQuery || filteredEvents.length !== eventsToFilter.length) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { marginBottom: "0.5rem", fontSize: "0.875rem", color: "#6b7280" }, children: [
549
759
  "Showing ",
550
760
  filteredEvents.length,