@datum-cloud/activity-ui 0.6.0-dev.917556e → 0.6.0

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
@@ -1198,48 +1198,6 @@ function constructNow(date) {
1198
1198
  return constructFrom(date, Date.now());
1199
1199
  }
1200
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
-
1243
1201
  /**
1244
1202
  * @name isDate
1245
1203
  * @category Common Helpers
@@ -3976,36 +3934,6 @@ function formatISO(date, options) {
3976
3934
  return result;
3977
3935
  }
3978
3936
 
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
-
4009
3937
  /**
4010
3938
  * The {@link subDays} function options.
4011
3939
  */
@@ -4033,36 +3961,6 @@ function subDays(date, amount, options) {
4033
3961
  return addDays(date, -amount, options);
4034
3962
  }
4035
3963
 
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
-
4066
3964
  /**
4067
3965
  * The {@link subHours} function options.
4068
3966
  */
@@ -8004,7 +7902,7 @@ const createLucideIcon = (iconName, iconNode) => {
8004
7902
  */
8005
7903
 
8006
7904
 
8007
- const __iconNode$o = [
7905
+ const __iconNode$n = [
8008
7906
  [
8009
7907
  "path",
8010
7908
  {
@@ -8013,7 +7911,7 @@ const __iconNode$o = [
8013
7911
  }
8014
7912
  ]
8015
7913
  ];
8016
- const Activity = createLucideIcon("activity", __iconNode$o);
7914
+ const Activity = createLucideIcon("activity", __iconNode$n);
8017
7915
 
8018
7916
  /**
8019
7917
  * @license lucide-react v0.577.0 - ISC
@@ -8023,7 +7921,7 @@ const Activity = createLucideIcon("activity", __iconNode$o);
8023
7921
  */
8024
7922
 
8025
7923
 
8026
- const __iconNode$n = [
7924
+ const __iconNode$m = [
8027
7925
  ["path", { d: "M10.268 21a2 2 0 0 0 3.464 0", key: "vwvbt9" }],
8028
7926
  [
8029
7927
  "path",
@@ -8033,7 +7931,7 @@ const __iconNode$n = [
8033
7931
  }
8034
7932
  ]
8035
7933
  ];
8036
- const Bell = createLucideIcon("bell", __iconNode$n);
7934
+ const Bell = createLucideIcon("bell", __iconNode$m);
8037
7935
 
8038
7936
  /**
8039
7937
  * @license lucide-react v0.577.0 - ISC
@@ -8043,8 +7941,8 @@ const Bell = createLucideIcon("bell", __iconNode$n);
8043
7941
  */
8044
7942
 
8045
7943
 
8046
- const __iconNode$m = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
8047
- const Check = createLucideIcon("check", __iconNode$m);
7944
+ const __iconNode$l = [["path", { d: "M20 6 9 17l-5-5", key: "1gmf2c" }]];
7945
+ const Check = createLucideIcon("check", __iconNode$l);
8048
7946
 
8049
7947
  /**
8050
7948
  * @license lucide-react v0.577.0 - ISC
@@ -8054,8 +7952,8 @@ const Check = createLucideIcon("check", __iconNode$m);
8054
7952
  */
8055
7953
 
8056
7954
 
8057
- const __iconNode$l = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
8058
- const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
7955
+ const __iconNode$k = [["path", { d: "m6 9 6 6 6-6", key: "qrunsl" }]];
7956
+ const ChevronDown = createLucideIcon("chevron-down", __iconNode$k);
8059
7957
 
8060
7958
  /**
8061
7959
  * @license lucide-react v0.577.0 - ISC
@@ -8065,8 +7963,8 @@ const ChevronDown = createLucideIcon("chevron-down", __iconNode$l);
8065
7963
  */
8066
7964
 
8067
7965
 
8068
- const __iconNode$k = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
8069
- const ChevronRight = createLucideIcon("chevron-right", __iconNode$k);
7966
+ const __iconNode$j = [["path", { d: "m9 18 6-6-6-6", key: "mthhwq" }]];
7967
+ const ChevronRight = createLucideIcon("chevron-right", __iconNode$j);
8070
7968
 
8071
7969
  /**
8072
7970
  * @license lucide-react v0.577.0 - ISC
@@ -8076,8 +7974,8 @@ const ChevronRight = createLucideIcon("chevron-right", __iconNode$k);
8076
7974
  */
8077
7975
 
8078
7976
 
8079
- const __iconNode$j = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
8080
- const ChevronUp = createLucideIcon("chevron-up", __iconNode$j);
7977
+ const __iconNode$i = [["path", { d: "m18 15-6-6-6 6", key: "153udz" }]];
7978
+ const ChevronUp = createLucideIcon("chevron-up", __iconNode$i);
8081
7979
 
8082
7980
  /**
8083
7981
  * @license lucide-react v0.577.0 - ISC
@@ -8087,12 +7985,12 @@ const ChevronUp = createLucideIcon("chevron-up", __iconNode$j);
8087
7985
  */
8088
7986
 
8089
7987
 
8090
- const __iconNode$i = [
7988
+ const __iconNode$h = [
8091
7989
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
8092
7990
  ["line", { x1: "12", x2: "12", y1: "8", y2: "12", key: "1pkeuh" }],
8093
7991
  ["line", { x1: "12", x2: "12.01", y1: "16", y2: "16", key: "4dfq90" }]
8094
7992
  ];
8095
- const CircleAlert = createLucideIcon("circle-alert", __iconNode$i);
7993
+ const CircleAlert = createLucideIcon("circle-alert", __iconNode$h);
8096
7994
 
8097
7995
  /**
8098
7996
  * @license lucide-react v0.577.0 - ISC
@@ -8102,11 +8000,11 @@ const CircleAlert = createLucideIcon("circle-alert", __iconNode$i);
8102
8000
  */
8103
8001
 
8104
8002
 
8105
- const __iconNode$h = [
8003
+ const __iconNode$g = [
8106
8004
  ["path", { d: "M21.801 10A10 10 0 1 1 17 3.335", key: "yps3ct" }],
8107
8005
  ["path", { d: "m9 11 3 3L22 4", key: "1pflzl" }]
8108
8006
  ];
8109
- const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$h);
8007
+ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$g);
8110
8008
 
8111
8009
  /**
8112
8010
  * @license lucide-react v0.577.0 - ISC
@@ -8116,11 +8014,11 @@ const CircleCheckBig = createLucideIcon("circle-check-big", __iconNode$h);
8116
8014
  */
8117
8015
 
8118
8016
 
8119
- const __iconNode$g = [
8017
+ const __iconNode$f = [
8120
8018
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
8121
8019
  ["path", { d: "m9 12 2 2 4-4", key: "dzmm74" }]
8122
8020
  ];
8123
- const CircleCheck = createLucideIcon("circle-check", __iconNode$g);
8021
+ const CircleCheck = createLucideIcon("circle-check", __iconNode$f);
8124
8022
 
8125
8023
  /**
8126
8024
  * @license lucide-react v0.577.0 - ISC
@@ -8130,12 +8028,12 @@ const CircleCheck = createLucideIcon("circle-check", __iconNode$g);
8130
8028
  */
8131
8029
 
8132
8030
 
8133
- const __iconNode$f = [
8031
+ const __iconNode$e = [
8134
8032
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
8135
8033
  ["path", { d: "m15 9-6 6", key: "1uzhvr" }],
8136
8034
  ["path", { d: "m9 9 6 6", key: "z0biqf" }]
8137
8035
  ];
8138
- const CircleX = createLucideIcon("circle-x", __iconNode$f);
8036
+ const CircleX = createLucideIcon("circle-x", __iconNode$e);
8139
8037
 
8140
8038
  /**
8141
8039
  * @license lucide-react v0.577.0 - ISC
@@ -8145,11 +8043,11 @@ const CircleX = createLucideIcon("circle-x", __iconNode$f);
8145
8043
  */
8146
8044
 
8147
8045
 
8148
- const __iconNode$e = [
8046
+ const __iconNode$d = [
8149
8047
  ["circle", { cx: "12", cy: "12", r: "10", key: "1mglay" }],
8150
8048
  ["path", { d: "M12 6v6l4 2", key: "mmk7yg" }]
8151
8049
  ];
8152
- const Clock = createLucideIcon("clock", __iconNode$e);
8050
+ const Clock = createLucideIcon("clock", __iconNode$d);
8153
8051
 
8154
8052
  /**
8155
8053
  * @license lucide-react v0.577.0 - ISC
@@ -8159,11 +8057,11 @@ const Clock = createLucideIcon("clock", __iconNode$e);
8159
8057
  */
8160
8058
 
8161
8059
 
8162
- const __iconNode$d = [
8060
+ const __iconNode$c = [
8163
8061
  ["rect", { width: "14", height: "14", x: "8", y: "8", rx: "2", ry: "2", key: "17jyea" }],
8164
8062
  ["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
8063
  ];
8166
- const Copy = createLucideIcon("copy", __iconNode$d);
8064
+ const Copy = createLucideIcon("copy", __iconNode$c);
8167
8065
 
8168
8066
  /**
8169
8067
  * @license lucide-react v0.577.0 - ISC
@@ -8173,7 +8071,7 @@ const Copy = createLucideIcon("copy", __iconNode$d);
8173
8071
  */
8174
8072
 
8175
8073
 
8176
- const __iconNode$c = [
8074
+ const __iconNode$b = [
8177
8075
  [
8178
8076
  "path",
8179
8077
  {
@@ -8183,7 +8081,7 @@ const __iconNode$c = [
8183
8081
  ],
8184
8082
  ["circle", { cx: "12", cy: "12", r: "3", key: "1v7zrd" }]
8185
8083
  ];
8186
- const Eye = createLucideIcon("eye", __iconNode$c);
8084
+ const Eye = createLucideIcon("eye", __iconNode$b);
8187
8085
 
8188
8086
  /**
8189
8087
  * @license lucide-react v0.577.0 - ISC
@@ -8193,8 +8091,8 @@ const Eye = createLucideIcon("eye", __iconNode$c);
8193
8091
  */
8194
8092
 
8195
8093
 
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);
8094
+ const __iconNode$a = [["path", { d: "M21 12a9 9 0 1 1-6.219-8.56", key: "13zald" }]];
8095
+ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$a);
8198
8096
 
8199
8097
  /**
8200
8098
  * @license lucide-react v0.577.0 - ISC
@@ -8204,7 +8102,7 @@ const LoaderCircle = createLucideIcon("loader-circle", __iconNode$b);
8204
8102
  */
8205
8103
 
8206
8104
 
8207
- const __iconNode$a = [
8105
+ const __iconNode$9 = [
8208
8106
  [
8209
8107
  "path",
8210
8108
  {
@@ -8214,7 +8112,7 @@ const __iconNode$a = [
8214
8112
  ],
8215
8113
  ["path", { d: "m15 5 4 4", key: "1mk7zo" }]
8216
8114
  ];
8217
- const Pencil = createLucideIcon("pencil", __iconNode$a);
8115
+ const Pencil = createLucideIcon("pencil", __iconNode$9);
8218
8116
 
8219
8117
  /**
8220
8118
  * @license lucide-react v0.577.0 - ISC
@@ -8224,11 +8122,11 @@ const Pencil = createLucideIcon("pencil", __iconNode$a);
8224
8122
  */
8225
8123
 
8226
8124
 
8227
- const __iconNode$9 = [
8125
+ const __iconNode$8 = [
8228
8126
  ["path", { d: "M5 12h14", key: "1ays0h" }],
8229
8127
  ["path", { d: "M12 5v14", key: "s699le" }]
8230
8128
  ];
8231
- const Plus = createLucideIcon("plus", __iconNode$9);
8129
+ const Plus = createLucideIcon("plus", __iconNode$8);
8232
8130
 
8233
8131
  /**
8234
8132
  * @license lucide-react v0.577.0 - ISC
@@ -8238,13 +8136,13 @@ const Plus = createLucideIcon("plus", __iconNode$9);
8238
8136
  */
8239
8137
 
8240
8138
 
8241
- const __iconNode$8 = [
8139
+ const __iconNode$7 = [
8242
8140
  ["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
8141
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }],
8244
8142
  ["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
8143
  ["path", { d: "M8 16H3v5", key: "1cv678" }]
8246
8144
  ];
8247
- const RefreshCw = createLucideIcon("refresh-cw", __iconNode$8);
8145
+ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$7);
8248
8146
 
8249
8147
  /**
8250
8148
  * @license lucide-react v0.577.0 - ISC
@@ -8254,11 +8152,11 @@ const RefreshCw = createLucideIcon("refresh-cw", __iconNode$8);
8254
8152
  */
8255
8153
 
8256
8154
 
8257
- const __iconNode$7 = [
8155
+ const __iconNode$6 = [
8258
8156
  ["path", { d: "M21 12a9 9 0 1 1-9-9c2.52 0 4.93 1 6.74 2.74L21 8", key: "1p45f6" }],
8259
8157
  ["path", { d: "M21 3v5h-5", key: "1q7to0" }]
8260
8158
  ];
8261
- const RotateCw = createLucideIcon("rotate-cw", __iconNode$7);
8159
+ const RotateCw = createLucideIcon("rotate-cw", __iconNode$6);
8262
8160
 
8263
8161
  /**
8264
8162
  * @license lucide-react v0.577.0 - ISC
@@ -8268,32 +8166,11 @@ const RotateCw = createLucideIcon("rotate-cw", __iconNode$7);
8268
8166
  */
8269
8167
 
8270
8168
 
8271
- const __iconNode$6 = [
8169
+ const __iconNode$5 = [
8272
8170
  ["path", { d: "m21 21-4.34-4.34", key: "14j7rj" }],
8273
8171
  ["circle", { cx: "11", cy: "11", r: "8", key: "4ej97u" }]
8274
8172
  ];
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);
8173
+ const Search = createLucideIcon("search", __iconNode$5);
8297
8174
 
8298
8175
  /**
8299
8176
  * @license lucide-react v0.577.0 - ISC
@@ -9794,14 +9671,6 @@ function ActionToggle({ value, onChange, className = '', disabled = false, }) {
9794
9671
 
9795
9672
  // Debounce delay for filter changes (ms)
9796
9673
  const FILTER_DEBOUNCE_MS$1 = 300;
9797
- // Backoff for watch stream reconnects. Without this, a persistently failing
9798
- // upstream gets re-opened on every render with no delay — see
9799
- // https://github.com/datum-cloud/infra/issues/5060, where a single browser
9800
- // tab reconnected roughly 2.5 times a minute against a stream that kept
9801
- // aborting, driving the proxy's memory up until the process was OOMKilled.
9802
- const RECONNECT_BASE_DELAY_MS = 1000;
9803
- const RECONNECT_MAX_DELAY_MS = 30000;
9804
- const MAX_RECONNECT_ATTEMPTS = 8;
9805
9674
  /**
9806
9675
  * Escape a value for safe interpolation into a CEL string literal.
9807
9676
  * Prevents injection via values containing backslashes or double quotes.
@@ -9896,12 +9765,6 @@ function useActivityFeed({ client, initialFilters = {}, initialTimeRange = { sta
9896
9765
  const resourceVersionRef = React.useRef();
9897
9766
  // Track the watch stop function
9898
9767
  const watchStopRef = React.useRef(null);
9899
- // Consecutive watch failures since the last successful event, used to back
9900
- // off reconnect attempts. Reset on any real event (including BOOKMARK) and
9901
- // on a manual startStreaming() call.
9902
- const reconnectAttemptsRef = React.useRef(0);
9903
- // Pending scheduled reconnect, if any.
9904
- const reconnectTimerRef = React.useRef(null);
9905
9768
  // Track whether streaming should restart after filter change
9906
9769
  const shouldRestartStreamingRef = React.useRef(false);
9907
9770
  // Track if we've done the initial load
@@ -9976,9 +9839,6 @@ function useActivityFeed({ client, initialFilters = {}, initialTimeRange = { sta
9976
9839
  console.error('Watch error:', event.object);
9977
9840
  return;
9978
9841
  }
9979
- // A real event (including a BOOKMARK keep-alive) means the connection is
9980
- // healthy — reset backoff so a later failure starts from the base delay.
9981
- reconnectAttemptsRef.current = 0;
9982
9842
  if (event.type === 'BOOKMARK') {
9983
9843
  // Update resource version for resume capability
9984
9844
  if (event.object.metadata?.resourceVersion) {
@@ -10044,13 +9904,15 @@ function useActivityFeed({ client, initialFilters = {}, initialTimeRange = { sta
10044
9904
  setActivities((prev) => prev.filter((a) => a.metadata?.name !== event.object.metadata?.name));
10045
9905
  }
10046
9906
  }, [filters]);
10047
- // Open the watch connection. Does not touch userPaused/backoff state —
10048
- // callers (startStreaming, scheduleReconnect) own that.
10049
- const connectWatch = React.useCallback(() => {
9907
+ // Start watching for real-time updates
9908
+ const startStreaming = React.useCallback(() => {
10050
9909
  if (watchStopRef.current) {
10051
9910
  // Already watching
10052
9911
  return;
10053
9912
  }
9913
+ // Explicit start clears the user-paused flag so the auto-restart
9914
+ // effects can keep the stream alive after subsequent filter changes.
9915
+ setUserPaused(false);
10054
9916
  // Clear any previous watch error when starting a new stream
10055
9917
  setWatchError(null);
10056
9918
  const params = buildWatchParams();
@@ -10064,7 +9926,6 @@ function useActivityFeed({ client, initialFilters = {}, initialTimeRange = { sta
10064
9926
  setWatchError(streamError);
10065
9927
  setIsStreaming(false);
10066
9928
  watchStopRef.current = null;
10067
- reconnectAttemptsRef.current += 1;
10068
9929
  },
10069
9930
  onClose: () => {
10070
9931
  setIsStreaming(false);
@@ -10075,50 +9936,11 @@ function useActivityFeed({ client, initialFilters = {}, initialTimeRange = { sta
10075
9936
  setIsStreaming(true);
10076
9937
  setNewActivitiesCount(0);
10077
9938
  }, [client, buildWatchParams, handleWatchEvent]);
10078
- // Reconnect with exponential backoff. The first attempt (no prior
10079
- // failures) connects immediately; each subsequent failure doubles the
10080
- // delay up to RECONNECT_MAX_DELAY_MS. After MAX_RECONNECT_ATTEMPTS
10081
- // consecutive failures, this stops retrying automatically — the watch
10082
- // stays stopped (with watchError set) until the user calls
10083
- // startStreaming() again, which resets the attempt count.
10084
- const scheduleReconnect = React.useCallback(() => {
10085
- if (reconnectTimerRef.current) {
10086
- // A reconnect is already scheduled.
10087
- return;
10088
- }
10089
- if (reconnectAttemptsRef.current >= MAX_RECONNECT_ATTEMPTS) {
10090
- return;
10091
- }
10092
- const attempt = reconnectAttemptsRef.current;
10093
- const delay = attempt === 0 ? 0 : Math.min(RECONNECT_MAX_DELAY_MS, RECONNECT_BASE_DELAY_MS * 2 ** (attempt - 1));
10094
- reconnectTimerRef.current = setTimeout(() => {
10095
- reconnectTimerRef.current = null;
10096
- connectWatch();
10097
- }, delay);
10098
- }, [connectWatch]);
10099
- // Start watching for real-time updates. This is the user/effect-facing
10100
- // entry point: it resets backoff and any pending scheduled reconnect
10101
- // before connecting, so a manual retry always starts from a clean slate.
10102
- const startStreaming = React.useCallback(() => {
10103
- // Explicit start clears the user-paused flag so the auto-restart
10104
- // effects can keep the stream alive after subsequent filter changes.
10105
- setUserPaused(false);
10106
- reconnectAttemptsRef.current = 0;
10107
- if (reconnectTimerRef.current) {
10108
- clearTimeout(reconnectTimerRef.current);
10109
- reconnectTimerRef.current = null;
10110
- }
10111
- connectWatch();
10112
- }, [connectWatch]);
10113
9939
  // Stop watching. Marks the user as paused so the auto-start effects
10114
9940
  // below don't immediately re-open the stream this call just closed.
10115
9941
  const stopStreaming = React.useCallback(() => {
10116
9942
  setUserPaused(true);
10117
9943
  setIsStreaming(false);
10118
- if (reconnectTimerRef.current) {
10119
- clearTimeout(reconnectTimerRef.current);
10120
- reconnectTimerRef.current = null;
10121
- }
10122
9944
  if (watchStopRef.current) {
10123
9945
  watchStopRef.current();
10124
9946
  watchStopRef.current = null;
@@ -10281,10 +10103,9 @@ function useActivityFeed({ client, initialFilters = {}, initialTimeRange = { sta
10281
10103
  }
10282
10104
  };
10283
10105
  }, [filters, timeRange]); // eslint-disable-line react-hooks/exhaustive-deps
10284
- // Auto-start streaming after initial load when enabled, and reconnect
10285
- // (with backoff — see scheduleReconnect) whenever a connection drops.
10286
- // Skipped when the user has explicitly paused — otherwise clicking Pause
10287
- // would be immediately undone by this effect on the next render.
10106
+ // Auto-start streaming after initial load when enabled. Skipped when
10107
+ // the user has explicitly paused — otherwise clicking Pause would be
10108
+ // immediately undone by this effect on the next render.
10288
10109
  React.useEffect(() => {
10289
10110
  if (enableStreaming &&
10290
10111
  autoStartStreaming &&
@@ -10292,9 +10113,9 @@ function useActivityFeed({ client, initialFilters = {}, initialTimeRange = { sta
10292
10113
  activities.length > 0 &&
10293
10114
  !isStreaming &&
10294
10115
  !isLoading) {
10295
- scheduleReconnect();
10116
+ startStreaming();
10296
10117
  }
10297
- }, [enableStreaming, autoStartStreaming, userPaused, activities.length, isStreaming, isLoading, scheduleReconnect]);
10118
+ }, [enableStreaming, autoStartStreaming, userPaused, activities.length, isStreaming, isLoading, startStreaming]);
10298
10119
  // Restart streaming after filter change refresh completes. Also skipped
10299
10120
  // when the user has paused — a filter change shouldn't silently resume
10300
10121
  // a stream the user intentionally stopped.
@@ -10306,18 +10127,15 @@ function useActivityFeed({ client, initialFilters = {}, initialTimeRange = { sta
10306
10127
  !isStreaming &&
10307
10128
  !isLoading) {
10308
10129
  shouldRestartStreamingRef.current = false;
10309
- scheduleReconnect();
10130
+ startStreaming();
10310
10131
  }
10311
- }, [enableStreaming, userPaused, activities.length, isStreaming, isLoading, scheduleReconnect]);
10132
+ }, [enableStreaming, userPaused, activities.length, isStreaming, isLoading, startStreaming]);
10312
10133
  // Cleanup on unmount
10313
10134
  React.useEffect(() => {
10314
10135
  return () => {
10315
10136
  if (watchStopRef.current) {
10316
10137
  watchStopRef.current();
10317
10138
  }
10318
- if (reconnectTimerRef.current) {
10319
- clearTimeout(reconnectTimerRef.current);
10320
- }
10321
10139
  if (filterDebounceRef.current) {
10322
10140
  clearTimeout(filterDebounceRef.current);
10323
10141
  }
@@ -10482,6 +10300,36 @@ function ActivityExpandedDetails({ activity, compact = false, }) {
10482
10300
  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 })) }));
10483
10301
  }
10484
10302
 
10303
+ // Number of columns rendered for the feed variant. Used as the colSpan on
10304
+ // the expanded-detail row so it stretches across the full width.
10305
+ const ACTIVITY_FEED_COLUMN_COUNT = 5;
10306
+ /**
10307
+ * Get avatar initials from actor name
10308
+ */
10309
+ function getActorInitials(name) {
10310
+ const parts = name.split(/[@\s.]+/).filter(Boolean);
10311
+ if (parts.length === 0)
10312
+ return "?";
10313
+ if (parts.length === 1)
10314
+ return parts[0].charAt(0).toUpperCase();
10315
+ return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
10316
+ }
10317
+ /**
10318
+ * Get Tailwind classes for actor avatar based on actor type
10319
+ */
10320
+ function getActorAvatarClasses(actorType, compact) {
10321
+ 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");
10322
+ switch (actorType) {
10323
+ case "user":
10324
+ return cn(baseClasses, "bg-primary text-primary-foreground");
10325
+ case "controller":
10326
+ return cn(baseClasses, "bg-secondary text-secondary-foreground");
10327
+ case "machine account":
10328
+ return cn(baseClasses, "bg-muted text-muted-foreground");
10329
+ default:
10330
+ return cn(baseClasses, "bg-muted text-muted-foreground");
10331
+ }
10332
+ }
10485
10333
  /**
10486
10334
  * Extract verb from activity summary (e.g., "alice created HTTPProxy" -> "created")
10487
10335
  */
@@ -10490,24 +10338,24 @@ function extractVerb(summary) {
10490
10338
  if (words.length >= 2) {
10491
10339
  return words[1].toLowerCase();
10492
10340
  }
10493
- return 'unknown';
10341
+ return "unknown";
10494
10342
  }
10495
10343
  /**
10496
- * Normalize a verb to a canonical form used for coloring/icons/grouping.
10344
+ * Normalize verb to a canonical form for coloring
10497
10345
  */
10498
10346
  function normalizeVerb(verb) {
10499
10347
  const normalized = verb.toLowerCase();
10500
- if (normalized.includes('create') || normalized.includes('add'))
10501
- return 'create';
10502
- if (normalized.includes('delete') || normalized.includes('remove'))
10503
- return 'delete';
10504
- if (normalized.includes('update') ||
10505
- normalized.includes('patch') ||
10506
- normalized.includes('modify') ||
10507
- normalized.includes('change') ||
10508
- normalized.includes('edit'))
10509
- return 'update';
10510
- return 'other';
10348
+ if (normalized.includes("create") || normalized.includes("add"))
10349
+ return "create";
10350
+ if (normalized.includes("delete") || normalized.includes("remove"))
10351
+ return "delete";
10352
+ if (normalized.includes("update") ||
10353
+ normalized.includes("patch") ||
10354
+ normalized.includes("modify") ||
10355
+ normalized.includes("change") ||
10356
+ normalized.includes("edit"))
10357
+ return "update";
10358
+ return "other";
10511
10359
  }
10512
10360
  /**
10513
10361
  * Get icon container + icon color classes based on verb
@@ -10515,25 +10363,25 @@ function normalizeVerb(verb) {
10515
10363
  function getActionIconClasses(verb) {
10516
10364
  const normalizedVerb = normalizeVerb(verb);
10517
10365
  switch (normalizedVerb) {
10518
- case 'create':
10366
+ case "create":
10519
10367
  return {
10520
- container: 'bg-blue-50 dark:bg-blue-950',
10521
- icon: 'text-blue-500 dark:text-blue-400',
10368
+ container: "bg-[var(--success-100)]",
10369
+ icon: "text-[var(--success-500)]",
10522
10370
  };
10523
- case 'update':
10371
+ case "update":
10524
10372
  return {
10525
- container: 'bg-green-50 dark:bg-green-950',
10526
- icon: 'text-green-600 dark:text-green-400',
10373
+ container: "bg-[var(--info-100)]",
10374
+ icon: "text-[var(--info-500)]",
10527
10375
  };
10528
- case 'delete':
10376
+ case "delete":
10529
10377
  return {
10530
- container: 'bg-red-50 dark:bg-red-950',
10531
- icon: 'text-red-500 dark:text-red-400',
10378
+ container: "bg-destructive/10",
10379
+ icon: "text-destructive",
10532
10380
  };
10533
10381
  default:
10534
10382
  return {
10535
- container: 'bg-slate-100 dark:bg-slate-800',
10536
- icon: 'text-slate-500 dark:text-slate-400',
10383
+ container: "bg-muted",
10384
+ icon: "text-muted-foreground",
10537
10385
  };
10538
10386
  }
10539
10387
  }
@@ -10543,51 +10391,20 @@ function getActionIconClasses(verb) {
10543
10391
  function getTimelineIcon(verb) {
10544
10392
  const normalizedVerb = normalizeVerb(verb);
10545
10393
  switch (normalizedVerb) {
10546
- case 'create':
10394
+ case "create":
10547
10395
  return Plus;
10548
- case 'update':
10396
+ case "update":
10549
10397
  return Pencil;
10550
- case 'delete':
10398
+ case "delete":
10551
10399
  return Trash2;
10552
10400
  default:
10553
10401
  return Activity;
10554
10402
  }
10555
10403
  }
10556
-
10557
- // Number of columns rendered for the feed variant. Used as the colSpan on
10558
- // the expanded-detail row so it stretches across the full width.
10559
- const ACTIVITY_FEED_COLUMN_COUNT = 5;
10560
- /**
10561
- * Get avatar initials from actor name
10562
- */
10563
- function getActorInitials(name) {
10564
- const parts = name.split(/[@\s.]+/).filter(Boolean);
10565
- if (parts.length === 0)
10566
- return "?";
10567
- if (parts.length === 1)
10568
- return parts[0].charAt(0).toUpperCase();
10569
- return (parts[0].charAt(0) + parts[parts.length - 1].charAt(0)).toUpperCase();
10570
- }
10571
- /**
10572
- * Get Tailwind classes for actor avatar based on actor type
10573
- */
10574
- function getActorAvatarClasses(actorType, compact) {
10575
- 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");
10576
- switch (actorType) {
10577
- case "user":
10578
- return cn(baseClasses, "bg-primary text-primary-foreground");
10579
- case "controller":
10580
- return cn(baseClasses, "bg-secondary text-secondary-foreground");
10581
- case "machine account":
10582
- return cn(baseClasses, "bg-muted text-muted-foreground");
10583
- default:
10584
- return cn(baseClasses, "bg-muted text-muted-foreground");
10585
- }
10586
- }
10587
10404
  /**
10588
10405
  * ActivityFeedItem renders a single activity in the feed or timeline
10589
10406
  */
10590
- function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isSelected = false, className = "", compact = false, isNew = false, variant = "feed", isLast = false, defaultExpanded = false, density = "default", }) {
10407
+ function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isSelected = false, className = "", compact = false, isNew = false, variant = "feed", isLast = false, defaultExpanded = false, }) {
10591
10408
  const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);
10592
10409
  const { spec, metadata } = activity;
10593
10410
  const { actor, summary, links, tenant } = spec;
@@ -10608,7 +10425,7 @@ function ActivityFeedItem({ activity, onResourceClick, resourceLinkResolver, ten
10608
10425
  if (isTimeline) {
10609
10426
  const { container: iconBg, icon: iconColor } = getActionIconClasses(verb);
10610
10427
  const Icon = getTimelineIcon(verb);
10611
- 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 }))] }));
10428
+ return (jsxRuntime.jsxs("div", { className: cn(!isLast && !isExpanded && "border-b border-border", className), children: [jsxRuntime.jsxs("div", { className: cn("flex items-center gap-3 py-3 cursor-pointer group", 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), 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 }))] }));
10612
10429
  }
10613
10430
  // Feed variant — flat-column table row. Columns: Actor | Summary |
10614
10431
  // Tenant | When | expand toggle. Renders an additional TableRow with a
@@ -10901,7 +10718,7 @@ const getSelectedPreset$1 = (timeRange) => {
10901
10718
  /**
10902
10719
  * ActivityFeedFilters provides filter controls for the activity feed
10903
10720
  */
10904
- function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTimeRangeChange, disabled = false, hiddenFilters = [], className = "", extraFilters, layout = "inline", }) {
10721
+ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTimeRangeChange, disabled = false, hiddenFilters = [], className = "", extraFilters, }) {
10905
10722
  const { resourceKinds, actorNames, apiGroups, resourceNamespaces, error: facetsError, } = useFacets(client, timeRange, filters);
10906
10723
  // Log facets error for debugging
10907
10724
  if (facetsError) {
@@ -11121,186 +10938,12 @@ function ActivityFeedFilters({ client, filters, timeRange, onFiltersChange, onTi
11121
10938
  clearTimeout(searchDebounceRef.current);
11122
10939
  onFiltersChangeRef.current({ ...filtersRef.current, search: undefined });
11123
10940
  }, []);
11124
- 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" }) }))] }));
11125
- const changeSourceControl = !hiddenFilters.includes("changeSource") && (jsxRuntime.jsx(ChangeSourceToggle, { value: filters.changeSource || "all", onChange: handleChangeSourceChange, disabled: disabled }));
11126
- const filterChips = activeFilterIds.map((filterId) => {
11127
- const config = FILTER_CONFIGS$1[filterId];
11128
- return (jsxRuntime.jsx(FilterChip, { label: config.label, values: getFilterValues(filterId), options: config.inputMode === "typeahead"
11129
- ? getFilterOptions(filterId)
11130
- : 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));
11131
- });
11132
- const addFilterControl = (jsxRuntime.jsx(AddFilterDropdown, { availableFilters: availableFilters, activeFilterIds: activeFilterIds, onAddFilter: handleAddFilter, hasActiveFilters: activeFilterIds.length > 0, disabled: disabled }));
11133
- const timeRangeControl = (jsxRuntime.jsx(TimeRangeDropdown, { presets: TIME_PRESETS$1, selectedPreset: selectedPreset, onPresetSelect: handleTimePresetSelect, onCustomRangeApply: handleCustomRangeApply, customStart: customStart, customEnd: customEnd, disabled: disabled, displayLabel: getTimeRangeLabel() }));
11134
- if (layout === "compact") {
11135
- const activeFilterCount = activeFilterIds.length +
11136
- (!hiddenFilters.includes("changeSource") &&
11137
- filters.changeSource &&
11138
- filters.changeSource !== "all"
11139
- ? 1
11140
- : 0);
11141
- 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] }) })] })] }) }));
11142
- }
11143
10941
  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) => {
11144
10942
  const config = FILTER_CONFIGS$1[filterId];
11145
10943
  return (jsxRuntime.jsx(FilterChip, { label: config.label, values: getFilterValues(filterId), options: config.inputMode === "typeahead"
11146
10944
  ? getFilterOptions(filterId)
11147
10945
  : 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));
11148
- }), 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] }) }));
11149
- }
11150
-
11151
- const KIND_PLURALS = {
11152
- DNSRecordSet: "DNS records",
11153
- };
11154
- function pluralizeKind(kind, count) {
11155
- if (count === 1)
11156
- return kind;
11157
- return KIND_PLURALS[kind] ?? `${kind}s`;
11158
- }
11159
- const VERB_LABEL = {
11160
- create: "created",
11161
- update: "updated",
11162
- delete: "deleted",
11163
- other: "changed",
11164
- };
11165
- /**
11166
- * ActivityFeedGroupItem renders a run of consecutive same verb/kind/actor
11167
- * activities (see `groupActivities`) as a single collapsed row in the
11168
- * "digest" timeline. A group of size 1 renders exactly like a normal
11169
- * `ActivityFeedItem` — no visual change for ungrouped activities. Larger
11170
- * groups render a synthesized summary ("{actor} created 12 DNS records")
11171
- * that expands to reveal the individual activities underneath.
11172
- */
11173
- function ActivityFeedGroupItem({ group, resourceLinkResolver, tenantLinkResolver, tenantRenderer, onActorClick, onActivityClick, isLast = false, }) {
11174
- const [isExpanded, setIsExpanded] = React.useState(false);
11175
- if (group.count === 1) {
11176
- return (jsxRuntime.jsx(ActivityFeedItem, { activity: group.activities[0], resourceLinkResolver: resourceLinkResolver, tenantLinkResolver: tenantLinkResolver, tenantRenderer: tenantRenderer, onActorClick: onActorClick, onActivityClick: onActivityClick, variant: "timeline", density: "compact", isLast: isLast }));
11177
- }
11178
- const { container: iconBg, icon: iconColor } = getActionIconClasses(group.verb);
11179
- const Icon = getTimelineIcon(group.verb);
11180
- const actorVisible = group.actorDisplayName || group.actorName;
11181
- const summary = `${actorVisible} ${VERB_LABEL[group.verb]} ${group.count} ${pluralizeKind(group.kind, group.count)}`;
11182
- const toggleExpand = (e) => {
11183
- e.stopPropagation();
11184
- setIsExpanded((prev) => !prev);
11185
- };
11186
- 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))) }))] }));
11187
- }
11188
-
11189
- /**
11190
- * Thin stat strip summarizing the activities currently loaded in the feed —
11191
- * e.g. "18 changes · 3 people · 1 system". Computed client-side over the
11192
- * loaded/paginated activities; it is a quick-glance headline, not a
11193
- * full-range aggregate (that would require a backend facet query).
11194
- */
11195
- function ActivityDigestSummary({ activities, className = "" }) {
11196
- const stats = React.useMemo(() => {
11197
- const humanActors = new Set();
11198
- const systemActors = new Set();
11199
- for (const activity of activities) {
11200
- const { actor, changeSource } = activity.spec;
11201
- if (changeSource === "human") {
11202
- humanActors.add(actor.name);
11203
- }
11204
- else {
11205
- systemActors.add(actor.name);
11206
- }
11207
- }
11208
- return {
11209
- total: activities.length,
11210
- people: humanActors.size,
11211
- systems: systemActors.size,
11212
- };
11213
- }, [activities]);
11214
- if (stats.total === 0)
11215
- return null;
11216
- const parts = [`${stats.total} ${stats.total === 1 ? "change" : "changes"}`];
11217
- if (stats.people > 0)
11218
- parts.push(`${stats.people} ${stats.people === 1 ? "person" : "people"}`);
11219
- if (stats.systems > 0)
11220
- parts.push(`${stats.systems} ${stats.systems === 1 ? "system" : "systems"}`);
11221
- return (jsxRuntime.jsx("div", { className: `px-1 pt-4 pb-2 text-xs text-muted-foreground ${className}`, children: parts.join(" · ") }));
11222
- }
11223
-
11224
- function tenantKey(tenant) {
11225
- if (!tenant)
11226
- return '';
11227
- return `${tenant.type}:${tenant.name}`;
11228
- }
11229
- function groupSignature(activity) {
11230
- const { spec } = activity;
11231
- const verb = normalizeVerb(extractVerb(spec.summary));
11232
- return [verb, spec.resource.kind, spec.actor.name, tenantKey(spec.tenant)].join('|');
11233
- }
11234
- /**
11235
- * Group consecutive activities that share verb + resource kind + actor +
11236
- * tenant. Activities are assumed to already be sorted newest-first (as
11237
- * returned by `useActivityFeed`); only adjacent items are merged, so a
11238
- * burst of matching activities collapses into one group without needing
11239
- * any time-window heuristics.
11240
- */
11241
- function groupActivities(activities) {
11242
- const groups = [];
11243
- for (const activity of activities) {
11244
- const signature = groupSignature(activity);
11245
- const last = groups[groups.length - 1];
11246
- if (last && last.key === signature) {
11247
- last.activities.push(activity);
11248
- last.count += 1;
11249
- continue;
11250
- }
11251
- const { spec } = activity;
11252
- groups.push({
11253
- key: signature,
11254
- verb: normalizeVerb(extractVerb(spec.summary)),
11255
- kind: spec.resource.kind,
11256
- actorName: spec.actor.name,
11257
- actorDisplayName: spec.actor.displayName,
11258
- tenant: spec.tenant,
11259
- activities: [activity],
11260
- count: 1,
11261
- latestTimestamp: activity.metadata?.creationTimestamp,
11262
- });
11263
- }
11264
- return groups;
11265
- }
11266
- function dayLabel(timestamp) {
11267
- if (!timestamp)
11268
- return 'Unknown date';
11269
- const date = new Date(timestamp);
11270
- if (Number.isNaN(date.getTime()))
11271
- return 'Unknown date';
11272
- if (isToday(date))
11273
- return 'Today';
11274
- if (isYesterday(date))
11275
- return 'Yesterday';
11276
- return format(date, 'MMMM d, yyyy');
11277
- }
11278
- /**
11279
- * Bucket activities into calendar-day sections (Today / Yesterday / a
11280
- * formatted date), then group consecutive matching activities within each
11281
- * day. Bucketing by day first (rather than grouping across the whole list)
11282
- * keeps a group from silently spanning a day boundary.
11283
- */
11284
- function groupActivitiesByDay(activities) {
11285
- const sections = [];
11286
- let currentLabel = null;
11287
- let currentBucket = [];
11288
- const flush = () => {
11289
- if (currentLabel !== null && currentBucket.length > 0) {
11290
- sections.push({ label: currentLabel, groups: groupActivities(currentBucket) });
11291
- }
11292
- };
11293
- for (const activity of activities) {
11294
- const label = dayLabel(activity.metadata?.creationTimestamp);
11295
- if (label !== currentLabel) {
11296
- flush();
11297
- currentLabel = label;
11298
- currentBucket = [];
11299
- }
11300
- currentBucket.push(activity);
11301
- }
11302
- flush();
11303
- return sections;
10946
+ }), 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]" }), jsxRuntime.jsx(TimeRangeDropdown, { presets: TIME_PRESETS$1, selectedPreset: selectedPreset, onPresetSelect: handleTimePresetSelect, onCustomRangeApply: handleCustomRangeApply, customStart: customStart, customEnd: customEnd, disabled: disabled, displayLabel: getTimeRangeLabel() })] }) }));
11304
10947
  }
11305
10948
 
11306
10949
  /**
@@ -11431,10 +11074,10 @@ function ActivityFeed({ client, initialFilters = { changeSource: "human" }, init
11431
11074
  // Parent containers must have proper height constraints (h-screen/h-full + overflow-hidden)
11432
11075
  const effectiveMaxHeight = maxHeight === "none" ? undefined : maxHeight;
11433
11076
  const listClasses = "flex-1 min-h-0 overflow-y-auto flex flex-col";
11434
- 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 &&
11077
+ 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 })), 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 &&
11435
11078
  activities.length === 0 &&
11436
11079
  hasPolicies !== false &&
11437
- (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 &&
11080
+ 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 &&
11438
11081
  activities.length === 0 &&
11439
11082
  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] })] }) }));
11440
11083
  }
@@ -16944,11 +16587,9 @@ exports.AUDIT_TEMPLATES = AUDIT_TEMPLATES;
16944
16587
  exports.ActionMultiSelect = ActionMultiSelect;
16945
16588
  exports.ActionToggle = ActionToggle;
16946
16589
  exports.ActivityApiClient = ActivityApiClient;
16947
- exports.ActivityDigestSummary = ActivityDigestSummary;
16948
16590
  exports.ActivityExpandedDetails = ActivityExpandedDetails;
16949
16591
  exports.ActivityFeed = ActivityFeed;
16950
16592
  exports.ActivityFeedFilters = ActivityFeedFilters;
16951
- exports.ActivityFeedGroupItem = ActivityFeedGroupItem;
16952
16593
  exports.ActivityFeedItem = ActivityFeedItem;
16953
16594
  exports.ActivityFeedItemSkeleton = ActivityFeedItemSkeleton;
16954
16595
  exports.ActivityFeedSummary = ActivityFeedSummary;
@@ -17028,8 +16669,6 @@ exports.extractFieldPathsFromMany = extractFieldPathsFromMany;
17028
16669
  exports.generateShareableUrl = generateShareableUrl;
17029
16670
  exports.getReindexJobDuration = getReindexJobDuration;
17030
16671
  exports.getReindexJobStatusMessage = getReindexJobStatusMessage;
17031
- exports.groupActivities = groupActivities;
17032
- exports.groupActivitiesByDay = groupActivitiesByDay;
17033
16672
  exports.isEventRecord = isEventRecord;
17034
16673
  exports.isReindexJobRunning = isReindexJobRunning;
17035
16674
  exports.isReindexJobTerminal = isReindexJobTerminal;