@growth-operations/ui-shared 1.6.8 → 1.6.10

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@growth-operations/ui-shared",
3
- "version": "1.6.8",
3
+ "version": "1.6.10",
4
4
  "description": "Shared HubSpot UI-extension modules (Home, Billing) for Growth Operations apps.",
5
5
  "license": "MIT",
6
6
  "private": false,
@@ -64,6 +64,7 @@ function DefaultAlertRow({
64
64
  context,
65
65
  alert,
66
66
  refresh,
67
+ onDismissed,
67
68
  fetchOptions,
68
69
  renderRowActions,
69
70
  }) {
@@ -73,7 +74,9 @@ function DefaultAlertRow({
73
74
  setDismissing(true);
74
75
  try {
75
76
  await dismissAlert(context, alert.id, fetchOptions);
76
- await refresh();
77
+ // Optimistically drop just this row from local state — no full re-fetch
78
+ // of the whole alert list on every dismiss.
79
+ onDismissed(alert.id);
77
80
  } finally {
78
81
  setDismissing(false);
79
82
  }
@@ -161,6 +164,29 @@ export function AlertsTab({
161
164
  }
162
165
  };
163
166
 
167
+ // Optimistically remove a dismissed alert from local state instead of
168
+ // re-fetching the whole list. Keeps the dismiss interaction to a single API
169
+ // call (the dismiss itself) in the common case. But if removing the row empties
170
+ // the current page while other pages still have alerts, fall back to a fetch so
171
+ // the user isn't stranded on a falsely-empty "No alerts" view: backfill this
172
+ // page, or step back a page if we just cleared the last one.
173
+ const removeAlertLocally = (id) => {
174
+ const remainingHere = alerts.filter((a) => a.id !== id);
175
+ const newTotal = Math.max(0, total - 1);
176
+
177
+ if (remainingHere.length === 0 && newTotal > 0) {
178
+ // Page emptied but more remain — reload. If this was the last page and it's
179
+ // now gone, step back one; otherwise reload the same page to pull the next
180
+ // page's rows up into it.
181
+ const lastPage = Math.max(1, Math.ceil(newTotal / PAGE_SIZE));
182
+ load(Math.min(page, lastPage), level);
183
+ return;
184
+ }
185
+
186
+ setAlerts(remainingHere);
187
+ setTotal(newTotal);
188
+ };
189
+
164
190
  useEffect(() => {
165
191
  load(1, level);
166
192
  // eslint-disable-next-line react-hooks/exhaustive-deps
@@ -212,8 +238,12 @@ export function AlertsTab({
212
238
  const refresh = () => load(page, level);
213
239
  // Full-row override escape hatch: the app owns the cells.
214
240
  if (renderRow) {
241
+ // Optimistic dismiss (drop the row locally); refresh stays
242
+ // available for apps that want a full reload.
215
243
  const dismiss = () =>
216
- dismissAlert(context, alert.id, fetchOptions).then(refresh);
244
+ dismissAlert(context, alert.id, fetchOptions).then(() =>
245
+ removeAlertLocally(alert.id)
246
+ );
217
247
  return (
218
248
  <React.Fragment key={alert.id}>
219
249
  {renderRow(alert, {
@@ -232,6 +262,7 @@ export function AlertsTab({
232
262
  alert={alert}
233
263
  fetchOptions={fetchOptions}
234
264
  refresh={refresh}
265
+ onDismissed={removeAlertLocally}
235
266
  renderRowActions={renderRowActions}
236
267
  />
237
268
  );