@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.
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  normalizeAuditEventItem
4
- } from "../chunk-WA7TMG65.mjs";
4
+ } from "../chunk-LOKBGU6S.mjs";
5
5
  import {
6
6
  useArchivaContext
7
7
  } from "../chunk-H4TGL57C.mjs";
@@ -76,8 +76,9 @@ var CloudCogIcon = ({ className }) => /* @__PURE__ */ jsxs(
76
76
  }
77
77
  );
78
78
  function eventToTimelineItem(event, getActorAvatar) {
79
- const action = event.action.charAt(0).toUpperCase() + event.action.slice(1);
80
- const description = action;
79
+ const actionValue = event.actionKey || event.action || "";
80
+ const action = actionValue.charAt(0).toUpperCase() + actionValue.slice(1);
81
+ const description = event.actionDescription || "";
81
82
  const actorId = event.actorId || "unknown";
82
83
  const userName = actorId.includes(":") ? actorId.split(":")[1] || actorId : actorId;
83
84
  const userHandle = userName;
@@ -124,7 +125,8 @@ function eventToTimelineItem(event, getActorAvatar) {
124
125
  // Matches ActivityLog.tsx line 361
125
126
  statusIndicator: false,
126
127
  // Can be set to true for recent items - matches ActivityLog.tsx line 362
127
- data: event
128
+ data: event,
129
+ badge: action
128
130
  };
129
131
  }
130
132
  async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, params) {
@@ -132,14 +134,21 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
132
134
  if (params.entityId) {
133
135
  url.searchParams.set("entityId", params.entityId);
134
136
  }
137
+ if (params.tenantId) {
138
+ url.searchParams.set("tenantId", params.tenantId);
139
+ }
135
140
  if (params.actorId) {
136
141
  url.searchParams.set("actorId", params.actorId);
137
142
  }
138
143
  if (params.entityType) {
139
144
  url.searchParams.set("entityType", params.entityType);
140
145
  }
146
+ if (params.actionKey) {
147
+ url.searchParams.set("actionKey", params.actionKey);
148
+ }
141
149
  if (params.actorType) {
142
- url.searchParams.set("actorType", params.actorType);
150
+ const actorTypeValue = Array.isArray(params.actorType) ? params.actorType.join(",") : params.actorType;
151
+ url.searchParams.set("actorType", actorTypeValue);
143
152
  }
144
153
  if (params.limit) {
145
154
  url.searchParams.set("limit", String(params.limit));
@@ -147,6 +156,9 @@ async function fetchEventsWithRetry(apiBaseUrl, getToken, forceRefreshToken, par
147
156
  if (params.cursor) {
148
157
  url.searchParams.set("cursor", params.cursor);
149
158
  }
159
+ if (params.q) {
160
+ url.searchParams.set("q", params.q);
161
+ }
150
162
  const makeRequest = async (token2) => {
151
163
  return fetch(url.toString(), {
152
164
  headers: {
@@ -279,8 +291,15 @@ function SimpleAvatar({
279
291
  }
280
292
  );
281
293
  }
282
- function applyClientSideFilters(events, searchQuery, showSystemAndServices) {
294
+ function applyClientSideFilters(events, searchQuery, showSystemAndServices, actionDescription) {
283
295
  let filtered = events;
296
+ if (actionDescription) {
297
+ filtered = filtered.filter((event) => {
298
+ const eventActionDescription = (event.actionDescription || "").toLowerCase();
299
+ const filterActionDescription = actionDescription.toLowerCase();
300
+ return eventActionDescription.includes(filterActionDescription);
301
+ });
302
+ }
284
303
  if (!showSystemAndServices) {
285
304
  filtered = filtered.filter((event) => {
286
305
  if (event.actorType) {
@@ -298,13 +317,19 @@ function applyClientSideFilters(events, searchQuery, showSystemAndServices) {
298
317
  }
299
318
  const query = searchQuery.toLowerCase();
300
319
  return filtered.filter((event) => {
301
- 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);
320
+ const actionValue = (event.actionKey || event.action || "").toLowerCase();
321
+ const actionDescValue = (event.actionDescription || "").toLowerCase();
322
+ 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);
302
323
  });
303
324
  }
304
325
  function Timeline({
305
326
  entityId,
327
+ tenantId,
306
328
  actorId,
307
329
  entityType,
330
+ actionKey,
331
+ actionDescription,
332
+ actorType,
308
333
  initialLimit = 100,
309
334
  className,
310
335
  emptyMessage = "No events yet.",
@@ -321,25 +346,64 @@ function Timeline({
321
346
  const [error, setError] = React.useState(null);
322
347
  const [hasMore, setHasMore] = React.useState(false);
323
348
  const [searchQuery, setSearchQuery] = React.useState("");
349
+ const baseFilters = React.useMemo(() => {
350
+ const filters = {};
351
+ if (entityId) filters.entityId = entityId;
352
+ if (tenantId) filters.tenantId = tenantId;
353
+ if (actorId) filters.actorId = actorId;
354
+ if (entityType) filters.entityType = entityType;
355
+ if (actionKey) filters.actionKey = actionKey;
356
+ if (actorType) filters.actorType = actorType;
357
+ if (!showSystemAndServices && !actorType) {
358
+ filters.actorType = "user";
359
+ }
360
+ return filters;
361
+ }, [entityId, tenantId, actorId, entityType, actionKey, actorType, showSystemAndServices]);
362
+ const [uiFilters, setUiFilters] = React.useState({});
363
+ const mergedFilters = React.useMemo(() => {
364
+ const merged = {
365
+ ...baseFilters,
366
+ limit: initialLimit
367
+ };
368
+ if (!baseFilters.tenantId && uiFilters.tenantId) {
369
+ merged.tenantId = uiFilters.tenantId;
370
+ }
371
+ if (!baseFilters.actionKey && uiFilters.actionKey) {
372
+ merged.actionKey = uiFilters.actionKey;
373
+ }
374
+ if (!baseFilters.entityId && uiFilters.entityId) {
375
+ merged.entityId = uiFilters.entityId;
376
+ }
377
+ if (!baseFilters.entityType && uiFilters.entityType) {
378
+ merged.entityType = uiFilters.entityType;
379
+ }
380
+ if (!baseFilters.actorId && uiFilters.actorId) {
381
+ merged.actorId = uiFilters.actorId;
382
+ }
383
+ if (!baseFilters.actorType && uiFilters.actorType) {
384
+ merged.actorType = uiFilters.actorType;
385
+ }
386
+ return merged;
387
+ }, [baseFilters, uiFilters, initialLimit]);
388
+ const lockedFilters = React.useMemo(() => ({
389
+ tenantId: !!tenantId,
390
+ actionKey: !!actionKey,
391
+ entityId: !!entityId,
392
+ entityType: !!entityType,
393
+ actorId: !!actorId,
394
+ actorType: !!actorType
395
+ }), [tenantId, actionKey, entityId, entityType, actorId, actorType]);
324
396
  const queryParamsRef = React.useRef({});
325
397
  const queryParamsKeyRef = React.useRef("");
326
398
  const queryParams = React.useMemo(() => {
327
- const params = {
328
- entityId,
329
- actorId,
330
- entityType,
331
- // Filter by actorType on API side
332
- actorType: showSystemAndServices ? void 0 : "user",
333
- limit: initialLimit
334
- };
335
- const key = JSON.stringify(params);
399
+ const key = JSON.stringify(mergedFilters);
336
400
  if (key !== queryParamsKeyRef.current) {
337
401
  queryParamsKeyRef.current = key;
338
- queryParamsRef.current = params;
339
- return params;
402
+ queryParamsRef.current = mergedFilters;
403
+ return mergedFilters;
340
404
  }
341
405
  return queryParamsRef.current;
342
- }, [entityId, actorId, entityType, initialLimit, showSystemAndServices]);
406
+ }, [mergedFilters]);
343
407
  const allEventsRef = React.useRef([]);
344
408
  React.useEffect(() => {
345
409
  allEventsRef.current = allEvents;
@@ -386,12 +450,13 @@ function Timeline({
386
450
  },
387
451
  [queryParams, apiBaseUrl, getToken, forceRefreshToken, cursor]
388
452
  );
453
+ const filterKey = React.useMemo(() => JSON.stringify(mergedFilters), [mergedFilters]);
389
454
  React.useEffect(() => {
390
455
  setCursor(void 0);
391
456
  setAllEvents([]);
392
457
  setPreviousEvents([]);
393
458
  void load({ reset: true });
394
- }, [entityId, actorId, entityType, showSystemAndServices, initialLimit]);
459
+ }, [filterKey]);
395
460
  const eventsToFilter = React.useMemo(() => {
396
461
  if (loading && allEvents.length === 0 && previousEvents.length > 0) {
397
462
  return previousEvents;
@@ -399,8 +464,8 @@ function Timeline({
399
464
  return allEvents;
400
465
  }, [allEvents, loading, previousEvents]);
401
466
  const filteredEvents = React.useMemo(() => {
402
- return applyClientSideFilters(eventsToFilter, searchQuery, showSystemAndServices);
403
- }, [eventsToFilter, searchQuery, showSystemAndServices]);
467
+ return applyClientSideFilters(eventsToFilter, searchQuery, showSystemAndServices, actionDescription);
468
+ }, [eventsToFilter, searchQuery, showSystemAndServices, actionDescription]);
404
469
  const timelineItems = React.useMemo(() => {
405
470
  return filteredEvents.slice(0, 10).map(
406
471
  (event) => eventToTimelineItem(event, getActorAvatar)
@@ -425,6 +490,144 @@ function Timeline({
425
490
  placeholder: "Search actions, entities, IDs, actors, sources..."
426
491
  }
427
492
  ) }),
493
+ showFilters && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "1rem", padding: "1rem", backgroundColor: "#f9fafb", borderRadius: "0.375rem", display: "flex", flexWrap: "wrap", gap: "0.75rem" }, children: [
494
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
495
+ /* @__PURE__ */ jsxs("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: [
496
+ "Tenant ID ",
497
+ lockedFilters.tenantId && /* @__PURE__ */ jsx("span", { style: { color: "#9ca3af" }, children: "(Locked)" })
498
+ ] }),
499
+ /* @__PURE__ */ jsx(
500
+ "input",
501
+ {
502
+ type: "text",
503
+ placeholder: "All tenants",
504
+ value: lockedFilters.tenantId ? tenantId ?? "" : uiFilters.tenantId ?? "",
505
+ onChange: (e) => {
506
+ if (!lockedFilters.tenantId) {
507
+ setUiFilters((prev) => ({ ...prev, tenantId: e.target.value || void 0 }));
508
+ }
509
+ },
510
+ disabled: lockedFilters.tenantId,
511
+ style: {
512
+ padding: "0.375rem 0.5rem",
513
+ border: "1px solid #d1d5db",
514
+ borderRadius: "0.375rem",
515
+ fontSize: "0.875rem",
516
+ backgroundColor: lockedFilters.tenantId ? "#f3f4f6" : "white",
517
+ cursor: lockedFilters.tenantId ? "not-allowed" : "text"
518
+ }
519
+ }
520
+ )
521
+ ] }),
522
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
523
+ /* @__PURE__ */ jsxs("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: [
524
+ "Action Key ",
525
+ lockedFilters.actionKey && /* @__PURE__ */ jsx("span", { style: { color: "#9ca3af" }, children: "(Locked)" })
526
+ ] }),
527
+ /* @__PURE__ */ jsx(
528
+ "input",
529
+ {
530
+ type: "text",
531
+ placeholder: "All actions",
532
+ value: lockedFilters.actionKey ? actionKey ?? "" : uiFilters.actionKey ?? "",
533
+ onChange: (e) => {
534
+ if (!lockedFilters.actionKey) {
535
+ setUiFilters((prev) => ({ ...prev, actionKey: e.target.value || void 0 }));
536
+ }
537
+ },
538
+ disabled: lockedFilters.actionKey,
539
+ style: {
540
+ padding: "0.375rem 0.5rem",
541
+ border: "1px solid #d1d5db",
542
+ borderRadius: "0.375rem",
543
+ fontSize: "0.875rem",
544
+ backgroundColor: lockedFilters.actionKey ? "#f3f4f6" : "white",
545
+ cursor: lockedFilters.actionKey ? "not-allowed" : "text"
546
+ }
547
+ }
548
+ )
549
+ ] }),
550
+ !lockedFilters.entityId && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
551
+ /* @__PURE__ */ jsx("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: "Entity ID" }),
552
+ /* @__PURE__ */ jsx(
553
+ "input",
554
+ {
555
+ type: "text",
556
+ placeholder: "All entities",
557
+ value: uiFilters.entityId ?? "",
558
+ onChange: (e) => {
559
+ setUiFilters((prev) => ({ ...prev, entityId: e.target.value || void 0 }));
560
+ },
561
+ style: {
562
+ padding: "0.375rem 0.5rem",
563
+ border: "1px solid #d1d5db",
564
+ borderRadius: "0.375rem",
565
+ fontSize: "0.875rem"
566
+ }
567
+ }
568
+ )
569
+ ] }),
570
+ !lockedFilters.entityType && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
571
+ /* @__PURE__ */ jsx("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: "Entity Type" }),
572
+ /* @__PURE__ */ jsx(
573
+ "input",
574
+ {
575
+ type: "text",
576
+ placeholder: "All types",
577
+ value: uiFilters.entityType ?? "",
578
+ onChange: (e) => {
579
+ setUiFilters((prev) => ({ ...prev, entityType: e.target.value || void 0 }));
580
+ },
581
+ style: {
582
+ padding: "0.375rem 0.5rem",
583
+ border: "1px solid #d1d5db",
584
+ borderRadius: "0.375rem",
585
+ fontSize: "0.875rem"
586
+ }
587
+ }
588
+ )
589
+ ] }),
590
+ !lockedFilters.actorId && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexDirection: "column", gap: "0.25rem" }, children: [
591
+ /* @__PURE__ */ jsx("label", { style: { fontSize: "0.75rem", fontWeight: 500, color: "#6b7280" }, children: "Actor ID" }),
592
+ /* @__PURE__ */ jsx(
593
+ "input",
594
+ {
595
+ type: "text",
596
+ placeholder: "All actors",
597
+ value: uiFilters.actorId ?? "",
598
+ onChange: (e) => {
599
+ setUiFilters((prev) => ({ ...prev, actorId: e.target.value || void 0 }));
600
+ },
601
+ style: {
602
+ padding: "0.375rem 0.5rem",
603
+ border: "1px solid #d1d5db",
604
+ borderRadius: "0.375rem",
605
+ fontSize: "0.875rem"
606
+ }
607
+ }
608
+ )
609
+ ] }),
610
+ (Object.keys(uiFilters).length > 0 || searchQuery) && /* @__PURE__ */ jsx("div", { style: { display: "flex", alignItems: "flex-end" }, children: /* @__PURE__ */ jsx(
611
+ "button",
612
+ {
613
+ type: "button",
614
+ onClick: () => {
615
+ setUiFilters({});
616
+ setSearchQuery("");
617
+ },
618
+ style: {
619
+ padding: "0.375rem 0.75rem",
620
+ backgroundColor: "#ef4444",
621
+ color: "white",
622
+ border: "none",
623
+ borderRadius: "0.375rem",
624
+ fontSize: "0.875rem",
625
+ cursor: "pointer"
626
+ },
627
+ children: "Clear"
628
+ }
629
+ ) })
630
+ ] }),
428
631
  (searchQuery || filteredEvents.length !== eventsToFilter.length) && /* @__PURE__ */ jsxs("div", { style: { marginBottom: "0.5rem", fontSize: "0.875rem", color: "#6b7280" }, children: [
429
632
  "Showing ",
430
633
  filteredEvents.length,
@@ -1,2 +1,2 @@
1
- export { f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from '../index-Bk4DxULy.mjs';
1
+ export { f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from '../index-DfJ2Gf0Y.mjs';
2
2
  import 'next/server';
@@ -1,2 +1,2 @@
1
- export { f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from '../index-Bk4DxULy.js';
1
+ export { f as AuditEventListItem, C as CreateEventInput, e as CreateEventOptions, F as FrontendTokenResponse, G as GET, L as LoadEventsParams, P as PageResult, c as createEvent, a as createEvents, b as createFrontendTokenGET, d as createFrontendTokenRoute, l as loadEvents } from '../index-DfJ2Gf0Y.js';
2
2
  import 'next/server';
@@ -178,10 +178,17 @@ var normalizeAuditEventItem = (event) => {
178
178
  "actor_id",
179
179
  "id"
180
180
  ]);
181
+ const actionKeyValue = coerceString(event.actionKey ?? event.action_key ?? event.action);
182
+ const actionDescriptionValue = coerceString(event.actionDescription ?? event.action_description);
183
+ const tenantIdValue = coerceString(event.tenantId ?? event.tenant_id);
181
184
  return {
182
185
  id: coerceString(event.id) ?? "",
183
186
  receivedAt: coerceString(event.receivedAt ?? event.received_at) ?? "",
184
- action: coerceString(event.action) ?? "",
187
+ actionKey: actionKeyValue ?? "",
188
+ actionDescription: actionDescriptionValue ?? void 0,
189
+ tenantId: tenantIdValue ?? void 0,
190
+ // Legacy support: include action for backward compatibility
191
+ action: actionKeyValue ?? "",
185
192
  entityType: coerceString(event.entityType ?? event.entity_type) ?? "",
186
193
  entityId: coerceString(event.entityId ?? event.entity_id) ?? "",
187
194
  actorId: coerceNullableString(actorIdValue),
@@ -252,7 +259,20 @@ async function loadEvents(apiKey, params, baseUrl = DEFAULT_BASE_URL) {
252
259
  url.searchParams.set("entityType", params.entityType);
253
260
  }
254
261
  if (params.actorType) {
255
- url.searchParams.set("actorType", params.actorType);
262
+ if (Array.isArray(params.actorType)) {
263
+ url.searchParams.set("actorType", params.actorType.join(","));
264
+ } else {
265
+ url.searchParams.set("actorType", params.actorType);
266
+ }
267
+ }
268
+ if (params.tenantId) {
269
+ url.searchParams.set("tenantId", params.tenantId);
270
+ }
271
+ if (params.actionKey) {
272
+ url.searchParams.set("actionKey", params.actionKey);
273
+ }
274
+ if (params.q) {
275
+ url.searchParams.set("q", params.q);
256
276
  }
257
277
  if (params.limit) {
258
278
  url.searchParams.set("limit", String(params.limit));
@@ -5,8 +5,8 @@ import {
5
5
  createFrontendTokenGET,
6
6
  createFrontendTokenRoute,
7
7
  loadEvents
8
- } from "../chunk-A3Q4YKTK.mjs";
9
- import "../chunk-WA7TMG65.mjs";
8
+ } from "../chunk-5ZJUGBTU.mjs";
9
+ import "../chunk-LOKBGU6S.mjs";
10
10
  export {
11
11
  GET,
12
12
  createEvent,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@archiva/archiva-nextjs",
3
- "version": "0.2.94",
3
+ "version": "0.3.1",
4
4
  "description": "Archiva Next.js SDK - Server Actions and Timeline Component",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",