@lunora/studio 1.0.0-alpha.4 → 1.0.0-alpha.41

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.
Files changed (187) hide show
  1. package/LICENSE.md +6 -0
  2. package/__assets__/package-og.svg +1 -1
  3. package/dist/index.d.ts +33 -18
  4. package/dist/index.js +29 -29
  5. package/dist/mount.d.ts +1 -1
  6. package/dist/mount.js +3 -2
  7. package/dist/{packem_shared/ApiTab-W3no0KOj.js → packem_chunks/ApiTab.js} +5 -5
  8. package/dist/{packem_shared/AuditPanel-Bq4o_IqT.js → packem_chunks/AuditPanel.js} +29 -41
  9. package/dist/{packem_shared/ExportImportPanel-dxY56TDF.js → packem_chunks/ExportImportPanel.js} +16 -11
  10. package/dist/{packem_shared/FileBrowser-Dhy4zES8.js → packem_chunks/FileBrowser.js} +15 -15
  11. package/dist/{packem_shared/FunctionRunner--fQJRPAD.js → packem_chunks/FunctionRunner.js} +10 -10
  12. package/dist/{packem_shared/FunctionStatsPanel-BjRUA_G3.js → packem_chunks/FunctionStatsPanel.js} +153 -208
  13. package/dist/{packem_shared/HealthPanel-PxclMWmA.js → packem_chunks/HealthPanel.js} +37 -29
  14. package/dist/{packem_shared/InsightsPanel-CWS_C-xW.js → packem_chunks/InsightsPanel.js} +108 -69
  15. package/dist/{packem_shared/LogsPanel-CTW8CFcM.js → packem_chunks/LogsPanel.js} +46 -58
  16. package/dist/{packem_shared/MailPanel-BwkvfIHF.js → packem_chunks/MailPanel.js} +45 -139
  17. package/dist/{packem_shared/MetricsPanel-BLuOhZQ4.js → packem_chunks/MetricsPanel.js} +41 -322
  18. package/dist/{packem_shared/MigrationsPanel-DT3lnwHF.js → packem_chunks/MigrationsPanel.js} +44 -51
  19. package/dist/{packem_shared/PitrPanel-CdErL7EJ.js → packem_chunks/PitrPanel.js} +9 -9
  20. package/dist/{packem_shared/SchemaViewer-LJDcmNIO.js → packem_chunks/SchemaViewer.js} +17 -16
  21. package/dist/{packem_shared/SecurityAdvisorPanel-C_ETsPih.js → packem_chunks/SecurityAdvisorPanel.js} +47 -31
  22. package/dist/packem_chunks/SettingsPanel.js +391 -0
  23. package/dist/{packem_shared/sql-editor-panel-BFRpzj6r.js → packem_chunks/SqlEditorPanel.js} +158 -387
  24. package/dist/{packem_shared/TableEditor-ChfUOZec.js → packem_chunks/TableEditor.js} +10 -68
  25. package/dist/packem_chunks/analytics-panel.js +261 -0
  26. package/dist/packem_chunks/auth-config-panel.js +365 -0
  27. package/dist/packem_chunks/auth-sessions-panel.js +175 -0
  28. package/dist/packem_chunks/containers-panel.js +247 -0
  29. package/dist/packem_chunks/dashboards-panel.js +780 -0
  30. package/dist/packem_chunks/fanout-panel.js +482 -0
  31. package/dist/packem_chunks/flags-panel.js +176 -0
  32. package/dist/packem_chunks/kv-browser.js +1896 -0
  33. package/dist/packem_chunks/log-drains-panel.js +273 -0
  34. package/dist/packem_chunks/organizations-panel.js +3178 -0
  35. package/dist/packem_chunks/payments-panel.js +186 -0
  36. package/dist/packem_chunks/permissions-panel.js +805 -0
  37. package/dist/packem_chunks/queues-panel.js +1075 -0
  38. package/dist/packem_chunks/rls-panel.js +315 -0
  39. package/dist/packem_chunks/schedule-panel.js +831 -0
  40. package/dist/packem_chunks/sparkline.js +79 -0
  41. package/dist/packem_chunks/storage-rules-panel.js +140 -0
  42. package/dist/packem_chunks/subscriptions-panel.js +238 -0
  43. package/dist/packem_chunks/users-panel.js +1731 -0
  44. package/dist/packem_chunks/vector-browser.js +281 -0
  45. package/dist/packem_chunks/workflows-panel.js +562 -0
  46. package/dist/packem_shared/{ADMIN_FUNCTIONS-DmBqMZ-z.js → ADMIN_FUNCTIONS-BHHJi3Gb.js} +7 -0
  47. package/dist/packem_shared/{ApiDocsPanel-C5-yJ1p7.js → ApiDocsPanel-CBma-lnp.js} +2 -2
  48. package/dist/packem_shared/{ApiReferencePanel-1vubqG5s.js → ApiReferencePanel-CQM3pPN7.js} +2 -1
  49. package/dist/packem_shared/{CommandPalette-BtgkBzZI.js → CommandPalette-X2tkbyHk.js} +1 -1
  50. package/dist/packem_shared/{DataBrowser-CtBe1So9.js → DataBrowser-D2ywrdId.js} +198 -247
  51. package/dist/packem_shared/{GlobalDataBrowser-BTEmGrph.js → GlobalDataBrowser-BkTPLzAY.js} +37 -66
  52. package/dist/packem_shared/HomePanel-D1Q9LZgK.js +14 -0
  53. package/dist/packem_shared/{OpenRpcReferencePanel-vbcYbv3V.js → OpenRpcReferencePanel-Dno-hfDb.js} +2 -1
  54. package/dist/packem_shared/{ScheduledJobs-CabfKbyM.js → ScheduledJobs-Ctw4jYtU.js} +163 -60
  55. package/dist/packem_shared/Studio-lJhzDAze.js +16 -0
  56. package/dist/packem_shared/{StudioApp-CHOZA-z-.js → StudioApp-DiMkupvZ.js} +276 -11
  57. package/dist/packem_shared/{advisor-view-CGcfMiPq.js → advisor-view-BX8OhG0w.js} +6 -6
  58. package/dist/packem_shared/alert-CdAET2K_.js +68 -0
  59. package/dist/packem_shared/{app.d-CCmwDEVs.d.ts → app.d-CNLRTrWw.d.ts} +1 -1
  60. package/dist/packem_shared/{bar-chart-CzJAgqkp.js → bar-chart-DSwcWIRy.js} +5 -4
  61. package/dist/packem_shared/browser-storage-BTrX4y3B.js +215 -0
  62. package/dist/packem_shared/{cf-links-2cktDedA.js → cf-links-BZfRdxSE.js} +1 -1
  63. package/dist/packem_shared/{data-grid-B5CaV3wS.js → data-grid-CdXztApG.js} +1 -1
  64. package/dist/packem_shared/data-view-params-Cd6yRVbv.js +96 -0
  65. package/dist/packem_shared/error-alert-CXjqyGw9.js +114 -0
  66. package/dist/packem_shared/{grid-features-CzUfqgsM.js → grid-features-BF-KBDFz.js} +131 -163
  67. package/dist/packem_shared/home-panel-TFcRf9Ui.js +1889 -0
  68. package/dist/packem_shared/{internal-rXJEAhXS.js → internal-CYcbqMjX.js} +44 -3
  69. package/dist/packem_shared/modal-shell-hyaJvIJ6.js +100 -0
  70. package/dist/packem_shared/{reference-view-B4E49Lip.js → reference-view-DUiJcILV.js} +6 -45
  71. package/dist/packem_shared/scroll-area-DLhcy-ml.js +93 -0
  72. package/dist/packem_shared/select-UkNYCT3s.js +273 -0
  73. package/dist/packem_shared/skeleton-CGhL0p20.js +45 -0
  74. package/dist/packem_shared/{sparkline-10dG-_f0.js → sparkline-BnA1kC9X.js} +1 -1
  75. package/dist/packem_shared/studio-Dh9UlaF_.js +4015 -0
  76. package/dist/packem_shared/{table-_RzNvy3R.js → table-DsCa9Qp9.js} +1 -1
  77. package/dist/packem_shared/{table-list-sidebar-Bg7uzbvC.js → table-list-sidebar-UVIXQJdU.js} +1 -1
  78. package/dist/packem_shared/use-admin-query-CfHYWx5n.js +106 -0
  79. package/dist/packem_shared/use-async-submit-DJQiPc-_.js +91 -0
  80. package/dist/standalone/chunk-25AYY4H7.js +2 -0
  81. package/dist/standalone/chunk-2ANAF4ZM.js +1 -0
  82. package/dist/standalone/chunk-2K47A3P6.js +1 -0
  83. package/dist/standalone/chunk-2NGUNNGW.js +1 -0
  84. package/dist/standalone/chunk-3CJW6NWG.js +4 -0
  85. package/dist/standalone/chunk-3OA7PECS.js +6 -0
  86. package/dist/standalone/chunk-3OIHOXVV.js +1 -0
  87. package/dist/standalone/chunk-447TAUFD.js +1 -0
  88. package/dist/standalone/chunk-4QHKBC77.js +1 -0
  89. package/dist/standalone/chunk-5C4TSNE6.js +1 -0
  90. package/dist/standalone/chunk-5OIBXYZM.js +1 -0
  91. package/dist/standalone/chunk-6HSHEMZV.js +76 -0
  92. package/dist/standalone/chunk-6JIZ34MB.js +3 -0
  93. package/dist/standalone/chunk-6VO23MMW.js +4 -0
  94. package/dist/standalone/chunk-7MVSQS7B.js +1 -0
  95. package/dist/standalone/chunk-7TJJXVSE.js +1 -0
  96. package/dist/standalone/chunk-7YXOPTWI.js +1 -0
  97. package/dist/standalone/chunk-AHILM3ZP.js +1 -0
  98. package/dist/standalone/chunk-BGXOXASQ.js +1 -0
  99. package/dist/standalone/chunk-BJGBHGK3.js +1 -0
  100. package/dist/standalone/chunk-BOXSWNXZ.js +1 -0
  101. package/dist/standalone/chunk-BX5MKYOC.js +1 -0
  102. package/dist/standalone/chunk-CKSHCYGC.js +2 -0
  103. package/dist/standalone/chunk-DWDILV2E.js +1 -0
  104. package/dist/standalone/chunk-E75ANNWX.js +19 -0
  105. package/dist/standalone/chunk-EQZQOTJY.js +1 -0
  106. package/dist/standalone/chunk-GTLEWM5Y.js +1 -0
  107. package/dist/standalone/chunk-GTM65MVX.js +1 -0
  108. package/dist/standalone/chunk-GUI5GFFI.js +1 -0
  109. package/dist/standalone/chunk-HN6KJXYQ.js +1 -0
  110. package/dist/standalone/chunk-HV7G6DFP.js +5 -0
  111. package/dist/standalone/chunk-HYDJNCGW.js +1 -0
  112. package/dist/standalone/chunk-HZK5RQHG.js +1 -0
  113. package/dist/standalone/chunk-IN2SYVJB.js +1 -0
  114. package/dist/standalone/chunk-IOANPSJN.js +1 -0
  115. package/dist/standalone/chunk-ISDZPW3V.js +1 -0
  116. package/dist/standalone/chunk-IXDH4GL5.js +1 -0
  117. package/dist/standalone/chunk-J6J54MBP.js +1 -0
  118. package/dist/standalone/chunk-J73VHFCL.js +1 -0
  119. package/dist/standalone/chunk-JHKMUTIF.js +13 -0
  120. package/dist/standalone/chunk-JPRH6DPK.js +1 -0
  121. package/dist/standalone/chunk-JSEXCW5Q.js +1 -0
  122. package/dist/standalone/chunk-KA5YB3VP.js +1 -0
  123. package/dist/standalone/chunk-KBB75WNT.js +1 -0
  124. package/dist/standalone/chunk-KEGAWN6Y.js +1 -0
  125. package/dist/standalone/chunk-KJJ3WM6H.js +4 -0
  126. package/dist/standalone/chunk-KQV4NGH3.js +1 -0
  127. package/dist/standalone/chunk-KSKXW5PX.js +1 -0
  128. package/dist/standalone/chunk-KUH4P5F5.js +1 -0
  129. package/dist/standalone/chunk-KYJPPVGB.js +1 -0
  130. package/dist/standalone/chunk-KZ6INM5M.js +1 -0
  131. package/dist/standalone/chunk-L2TJVSDQ.js +1 -0
  132. package/dist/standalone/chunk-L7SK4ZZD.js +1 -0
  133. package/dist/standalone/chunk-LAK5VSPI.js +1 -0
  134. package/dist/standalone/chunk-LBN7LPVK.js +1 -0
  135. package/dist/standalone/chunk-LNZIB2MD.js +1 -0
  136. package/dist/standalone/chunk-MJWVMKQ4.js +6 -0
  137. package/dist/standalone/chunk-MLZYX5CQ.js +1 -0
  138. package/dist/standalone/chunk-N2X2OO4V.js +1 -0
  139. package/dist/standalone/chunk-NGKITPQP.js +13 -0
  140. package/dist/standalone/chunk-O3NAGRTR.js +1 -0
  141. package/dist/standalone/chunk-OZACQNKG.js +1 -0
  142. package/dist/standalone/chunk-PNDNXS5Z.js +1 -0
  143. package/dist/standalone/chunk-Q7DMUTUE.js +1 -0
  144. package/dist/standalone/chunk-QAFAJBAW.js +1 -0
  145. package/dist/standalone/chunk-QBAT52GB.js +1 -0
  146. package/dist/standalone/chunk-RHZ4M2NZ.js +1 -0
  147. package/dist/standalone/chunk-RRCPZMC2.js +22 -0
  148. package/dist/standalone/chunk-SEU5V7I6.js +1 -0
  149. package/dist/standalone/chunk-TAD43CG5.js +1 -0
  150. package/dist/standalone/chunk-TBMYIZIO.js +1 -0
  151. package/dist/standalone/chunk-TDZ44E5I.js +4 -0
  152. package/dist/standalone/chunk-THNBTMUF.js +1 -0
  153. package/dist/standalone/chunk-TIQISBGK.js +1 -0
  154. package/dist/standalone/chunk-TMYVNQ66.js +1 -0
  155. package/dist/standalone/chunk-TQ36RWOP.js +1 -0
  156. package/dist/standalone/chunk-UGUEC6BC.js +1 -0
  157. package/dist/standalone/chunk-UJB2LEI4.js +4 -0
  158. package/dist/standalone/chunk-UK64ZSUW.js +1 -0
  159. package/dist/standalone/chunk-UKDJ4H7I.js +1 -0
  160. package/dist/standalone/chunk-VLXV72QE.js +1 -0
  161. package/dist/standalone/chunk-VON7JUPG.js +1 -0
  162. package/dist/standalone/chunk-W3JK4YWR.js +1 -0
  163. package/dist/standalone/chunk-W3SHEIAL.js +3 -0
  164. package/dist/standalone/chunk-WI7GWFEG.js +1 -0
  165. package/dist/standalone/chunk-WIHXMNUY.js +1 -0
  166. package/dist/standalone/chunk-WLDVXVI2.js +1 -0
  167. package/dist/standalone/chunk-XLXNLJ4N.js +1 -0
  168. package/dist/standalone/chunk-XNJNSCLM.js +1 -0
  169. package/dist/standalone/chunk-YAECF5LW.js +1 -0
  170. package/dist/standalone/chunk-YBGC4PPD.js +1 -0
  171. package/dist/standalone/chunk-YJAPWSDC.js +4 -0
  172. package/dist/standalone/chunk-ZEJB6DXU.js +8 -0
  173. package/dist/standalone/chunk-ZFNBPAIZ.js +1 -0
  174. package/dist/standalone/chunk-ZHVTQ37P.js +1 -0
  175. package/dist/standalone/chunk-ZIGWVHCS.js +1 -0
  176. package/dist/standalone/chunk-ZPP2KOR4.js +1 -0
  177. package/dist/standalone/chunk-ZPUO7FNI.js +1 -0
  178. package/dist/standalone/studio.js +104 -246
  179. package/dist/styles.css +2 -2
  180. package/package.json +15 -13
  181. package/dist/packem_shared/HomePanel-Cw16stjq.js +0 -1273
  182. package/dist/packem_shared/SettingsPanel-C0uLRf5P.js +0 -176
  183. package/dist/packem_shared/SqlEditorPanel-CguV7otm.js +0 -13
  184. package/dist/packem_shared/Studio-DFWAlcuf.js +0 -33
  185. package/dist/packem_shared/studio-Bj8psK1c.js +0 -10303
  186. package/dist/packem_shared/use-live-admin-Dq6g3daN.js +0 -73
  187. package/dist/packem_shared/use-live-shard-seed-Cuk3dnH0.js +0 -76
@@ -1,18 +1,19 @@
1
1
  import { c } from 'react/compiler-runtime';
2
2
  import { useLunora } from '@lunora/react';
3
3
  import { useNavigate } from '@tanstack/react-router';
4
- import { useState, useEffect, useMemo } from 'react';
5
- import { ShardInput } from './ShardInput-gx_DZXXn.js';
6
- import { B as Button } from './button-BhsN2uZH.js';
7
- import { useT } from './DEFAULT_LOCALE-CiX4W7Kr.js';
8
- import { ADMIN_FUNCTIONS } from './ADMIN_FUNCTIONS-DmBqMZ-z.js';
9
- import { f as fireAndForget, c as callOptions, e as errorMessage, a as adminRef } from './internal-rXJEAhXS.js';
10
- import { r as recordShard } from './shard-history-DyebH1R5.js';
11
- import { u as useLiveShardSeed } from './use-live-shard-seed-Cuk3dnH0.js';
12
- import { a as advisoryRow, A as AdvisorView } from './advisor-view-CGcfMiPq.js';
13
- import { ConfirmButton } from './ConfirmButton-C2eVi2Qv.js';
4
+ import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
5
+ import { ShardInput } from '../packem_shared/ShardInput-gx_DZXXn.js';
6
+ import { B as Button } from '../packem_shared/button-BhsN2uZH.js';
7
+ import { u as useAdminQuery } from '../packem_shared/use-admin-query-CfHYWx5n.js';
8
+ import useDebounced from '../packem_shared/useDebounced-Dxncpg6z.js';
9
+ import { useT } from '../packem_shared/DEFAULT_LOCALE-CiX4W7Kr.js';
10
+ import { ADMIN_FUNCTIONS } from '../packem_shared/ADMIN_FUNCTIONS-BHHJi3Gb.js';
11
+ import { f as fireAndForget, c as callOptions, a as adminRef } from '../packem_shared/internal-CYcbqMjX.js';
12
+ import { r as recordShard } from '../packem_shared/shard-history-DyebH1R5.js';
13
+ import { a as advisoryRow, A as AdvisorView } from '../packem_shared/advisor-view-BX8OhG0w.js';
14
+ import { ConfirmButton } from '../packem_shared/ConfirmButton-C2eVi2Qv.js';
14
15
  import { jsxDEV } from 'react/jsx-dev-runtime';
15
- import { deriveInsights } from './DEFAULT_INSIGHT_THRESHOLDS-DjF0h-gA.js';
16
+ import { deriveInsights } from '../packem_shared/DEFAULT_INSIGHT_THRESHOLDS-DjF0h-gA.js';
16
17
  import { runAdvisor, RUNTIME_LINTS } from '@lunora/advisor';
17
18
 
18
19
  const hasIndexMetadata = (metadata) => {
@@ -185,9 +186,6 @@ const deriveRuntimeAdvisories = (inputs) => {
185
186
  return visible.map((finding) => advisoryRow(finding));
186
187
  };
187
188
 
188
- const GET_ADVISORIES = adminRef(ADMIN_FUNCTIONS.getAdvisories);
189
- const GET_FUNCTION_STATS = adminRef(ADMIN_FUNCTIONS.getFunctionStats);
190
- const GET_METRICS = adminRef(ADMIN_FUNCTIONS.getMetrics);
191
189
  const LIST_TABLES = adminRef(ADMIN_FUNCTIONS.listTables);
192
190
  const LIST_TABLE_INDEXES = adminRef(ADMIN_FUNCTIONS.listTableIndexes);
193
191
  const percent = (rate) => `${(rate * 100).toFixed(1)}%`;
@@ -286,46 +284,41 @@ const InsightsPanel = ({
286
284
  const navigate = useNavigate();
287
285
  const t = useT();
288
286
  const [shardKey, setShardKey] = useState(initialShardKey ?? "");
289
- const [metrics, setMetrics] = useState(null);
290
- const [functions, setFunctions] = useState(null);
291
- const [advisories, setAdvisories] = useState(null);
292
- const [indexHits, setIndexHits] = useState(null);
293
287
  const [declaredIndexes, setDeclaredIndexes] = useState(null);
294
288
  const [shardTraffic, setShardTraffic] = useState(null);
295
- const [error, setError] = useState(null);
289
+ const debouncedShard = useDebounced(shardKey.trim(), 400);
290
+ const latestEnumeratedShard = useRef("");
291
+ const metricsQuery = useAdminQuery(ADMIN_FUNCTIONS.getMetrics, {}, {
292
+ live: true,
293
+ shardKey: debouncedShard
294
+ });
295
+ const functionsQuery = useAdminQuery(ADMIN_FUNCTIONS.getFunctionStats, {}, {
296
+ live: true,
297
+ shardKey: debouncedShard
298
+ });
299
+ const advisoriesQuery = useAdminQuery(ADMIN_FUNCTIONS.getAdvisories, {}, {
300
+ live: true,
301
+ shardKey: debouncedShard
302
+ });
303
+ const metrics = metricsQuery.data ?? null;
304
+ const functions = functionsQuery.data?.functions ?? null;
305
+ const advisories = advisoriesQuery.data?.advisories ?? null;
306
+ const indexHits = metricsQuery.data?.indexHits ?? null;
307
+ const error = metricsQuery.error !== null && functionsQuery.error !== null ? metricsQuery.error : null;
296
308
  const fanShardTraffic = loadShardTraffic ?? ((table) => client.shardTraffic(table));
297
- const refresh = async (shard) => {
298
- const [snapshot, stats, advisorySnapshot] = await Promise.allSettled([client.query(GET_METRICS, {}, callOptions(shard)), client.query(GET_FUNCTION_STATS, {}, callOptions(shard)), client.query(GET_ADVISORIES, {}, callOptions(shard))]);
299
- if (snapshot.status === "rejected" && stats.status === "rejected") {
300
- setError(errorMessage(snapshot.reason));
301
- } else {
302
- setError(null);
303
- recordShard(shard);
304
- }
305
- setMetrics(snapshot.status === "fulfilled" ? snapshot.value : null);
306
- setFunctions(stats.status === "fulfilled" ? stats.value.functions : null);
307
- setAdvisories(advisorySnapshot.status === "fulfilled" ? advisorySnapshot.value.advisories : null);
308
- setIndexHits(snapshot.status === "fulfilled" ? snapshot.value.indexHits ?? null : null);
309
- let tableNames = [];
310
- try {
311
- const tables = await client.query(LIST_TABLES, {}, callOptions(shard));
312
- tableNames = tables.map((table_0) => table_0.name);
313
- const indexResults = await Promise.allSettled(tables.map(async (table_1) => [table_1.name, await client.query(LIST_TABLE_INDEXES, {
314
- table: table_1.name
315
- }, callOptions(shard))]));
316
- const declared = [];
317
- for (const result of indexResults) {
318
- if (result.status === "fulfilled") {
319
- const [name, payload] = result.value;
320
- declared.push(...declaredIndexesFor(name, payload.indexes));
321
- }
309
+ const loadShardTrafficFeed = async (tableNames, shard) => {
310
+ const seedTable = tableNames[0];
311
+ if (seedTable === void 0 || seedTable === "") {
312
+ if (latestEnumeratedShard.current === shard) {
313
+ setShardTraffic(null);
322
314
  }
323
- setDeclaredIndexes(declared);
324
- } catch {
325
- setDeclaredIndexes(null);
315
+ return;
326
316
  }
327
317
  try {
328
- const traffic = await fanShardTraffic(tableNames[0] ?? "");
318
+ const traffic = await fanShardTraffic(seedTable);
319
+ if (latestEnumeratedShard.current !== shard) {
320
+ return;
321
+ }
329
322
  const byShard = /* @__PURE__ */ new Map();
330
323
  for (const entry of traffic.shards) {
331
324
  if (!byShard.has(entry.shardKey)) {
@@ -337,31 +330,76 @@ const InsightsPanel = ({
337
330
  }
338
331
  setShardTraffic([...byShard.values()]);
339
332
  } catch {
340
- setShardTraffic(null);
333
+ if (latestEnumeratedShard.current === shard) {
334
+ setShardTraffic(null);
335
+ }
341
336
  }
342
337
  };
343
- useLiveShardSeed(shardKey, refresh);
338
+ const enumerateShard = useCallback(
339
+ async (shard) => {
340
+ latestEnumeratedShard.current = shard;
341
+ let tableNames = [];
342
+ try {
343
+ const tables = await client.query(LIST_TABLES, {}, callOptions(shard));
344
+ if (latestEnumeratedShard.current !== shard) {
345
+ return;
346
+ }
347
+ recordShard(shard);
348
+ tableNames = tables.map((table) => table.name);
349
+ const indexResults = await Promise.allSettled(tables.map(async (table) => [table.name, await client.query(LIST_TABLE_INDEXES, {
350
+ table: table.name
351
+ }, callOptions(shard))]));
352
+ if (latestEnumeratedShard.current !== shard) {
353
+ return;
354
+ }
355
+ const declared = [];
356
+ for (const result of indexResults) {
357
+ if (result.status === "fulfilled") {
358
+ const [name, payload] = result.value;
359
+ declared.push(...declaredIndexesFor(name, payload.indexes));
360
+ }
361
+ }
362
+ setDeclaredIndexes(declared);
363
+ } catch {
364
+ if (latestEnumeratedShard.current === shard) {
365
+ setDeclaredIndexes(null);
366
+ }
367
+ }
368
+ await loadShardTrafficFeed(tableNames, shard);
369
+ },
370
+ // `fanShardTraffic`/`loadShardTrafficFeed` are render-fresh closures; the
371
+ // enumeration only needs to re-run on a shard change (or a manual visibility
372
+ // refresh), so they're intentionally excluded from the cache key.
373
+ // eslint-disable-next-line react-hooks/exhaustive-deps
374
+ [client]
375
+ );
376
+ useEffect(() => {
377
+ fireAndForget(enumerateShard(debouncedShard));
378
+ }, [debouncedShard, enumerateShard]);
344
379
  useEffect(() => {
345
380
  const onVisible = () => {
346
381
  if (document.visibilityState === "visible") {
347
- fireAndForget(refresh(shardKey));
382
+ metricsQuery.refetch();
383
+ functionsQuery.refetch();
384
+ advisoriesQuery.refetch();
385
+ fireAndForget(enumerateShard(debouncedShard));
348
386
  }
349
387
  };
350
388
  document.addEventListener("visibilitychange", onVisible);
351
389
  return () => {
352
390
  document.removeEventListener("visibilitychange", onVisible);
353
391
  };
354
- }, [refresh, shardKey]);
355
- const jumpToSchemaIndex = (table_2) => {
392
+ }, [advisoriesQuery, debouncedShard, enumerateShard, functionsQuery, metricsQuery]);
393
+ const jumpToSchemaIndex = useCallback((table) => {
356
394
  fireAndForget(navigate({
357
395
  search: {
358
- table: table_2
396
+ table
359
397
  },
360
398
  to: "/schema"
361
399
  }));
362
- };
400
+ }, [navigate]);
363
401
  const insights = deriveInsights(metrics, functions);
364
- const missingIndexTables = new Set(insights.filter((insight) => insight.kind === "missing-index").flatMap((insight_0) => insight_0.tables ?? []));
402
+ const missingIndexTables = new Set(insights.filter((insight) => insight.kind === "missing-index").flatMap((insight) => insight.tables ?? []));
365
403
  const runtimeRows = deriveRuntimeAdvisories({
366
404
  declaredIndexes: declaredIndexes ?? [],
367
405
  functions,
@@ -370,18 +408,18 @@ const InsightsPanel = ({
370
408
  suppressHotScanTables: missingIndexTables
371
409
  });
372
410
  const rows = useMemo(() => {
373
- const insightRows = insights.map((insight_1) => {
374
- const tables_0 = insight_1.kind === "missing-index" ? insight_1.tables ?? [] : [];
411
+ const insightRows = insights.map((insight) => {
412
+ const tables = insight.kind === "missing-index" ? insight.tables ?? [] : [];
375
413
  return {
376
- action: tables_0.length > 0 ? tables_0.map((table_3) => /* @__PURE__ */ jsxDEV(AddIndexButton, {
414
+ action: tables.length > 0 ? tables.map((table) => /* @__PURE__ */ jsxDEV(AddIndexButton, {
377
415
  onJump: jumpToSchemaIndex,
378
- table: table_3
379
- }, table_3, false)) : void 0,
380
- description: insight_1.message === void 0 ? insightDetail(t, insight_1) : `${insightDetail(t, insight_1)} — ${insight_1.message}`,
381
- entity: insight_1.fn,
382
- issueType: insightTitle(t, insight_1),
383
- key: `${insight_1.kind}:${insight_1.fn ?? ""}`,
384
- level: insight_1.severity
416
+ table
417
+ }, table, false)) : void 0,
418
+ description: insight.message === void 0 ? insightDetail(t, insight) : `${insightDetail(t, insight)} — ${insight.message}`,
419
+ entity: insight.fn,
420
+ issueType: insightTitle(t, insight),
421
+ key: `${insight.kind}:${insight.fn ?? ""}`,
422
+ level: insight.severity
385
423
  };
386
424
  });
387
425
  const indexAdvisoryLints = /* @__PURE__ */ new Set(["unindexed_foreign_key", "unindexed_relation_target"]);
@@ -389,16 +427,16 @@ const InsightsPanel = ({
389
427
  const base = advisoryRow(finding);
390
428
  if (indexAdvisoryLints.has(finding.name) && hasIndexMetadata(finding.metadata)) {
391
429
  const {
392
- table: table_4,
430
+ table,
393
431
  suggestedIndex
394
432
  } = finding.metadata;
395
- const testId = `in-apply-index-${table_4}-${suggestedIndex.name}`;
433
+ const testId = `in-apply-index-${table}-${suggestedIndex.name}`;
396
434
  return {
397
435
  ...base,
398
436
  action: /* @__PURE__ */ jsxDEV(ApplyIndexButton, {
399
437
  fields: suggestedIndex.fields,
400
438
  indexName: suggestedIndex.name,
401
- table: table_4,
439
+ table,
402
440
  testId
403
441
  }, void 0, false)
404
442
  };
@@ -414,6 +452,7 @@ const InsightsPanel = ({
414
452
  }, void 0, false);
415
453
  return /* @__PURE__ */ jsxDEV(AdvisorView, {
416
454
  error,
455
+ errorSource: error === null ? void 0 : metricsQuery.errorSource,
417
456
  rows,
418
457
  testId: "lunora-insights",
419
458
  toolbar
@@ -1,21 +1,20 @@
1
1
  import { c } from 'react/compiler-runtime';
2
- import { useLunora } from '@lunora/react';
3
2
  import { useVirtualizer } from '@tanstack/react-virtual';
4
- import { useState, useMemo, useRef } from 'react';
5
- import { L as LiveError } from './live-status-FZ0psC1z.js';
6
- import { ShardInput } from './ShardInput-gx_DZXXn.js';
7
- import { B as Badge } from './badge-B2PKA1-5.js';
8
- import { E as EmptyState } from './empty-state-DY_oe0k6.js';
9
- import { I as Input } from './input-XH4r1Pt1.js';
10
- import { u as useLiveAdmin } from './use-live-admin-Dq6g3daN.js';
11
- import { useT } from './DEFAULT_LOCALE-CiX4W7Kr.js';
12
- import { ADMIN_FUNCTIONS } from './ADMIN_FUNCTIONS-DmBqMZ-z.js';
13
- import { C as CLOUDFLARE_OBSERVABILITY_URL } from './cf-links-2cktDedA.js';
14
- import { c as callOptions, e as errorMessage, a as adminRef } from './internal-rXJEAhXS.js';
15
- import { r as recordShard } from './shard-history-DyebH1R5.js';
16
- import { c as cn } from './utils-B05Dmz_H.js';
17
- import { f as flooredRectObserver } from './virtual-rect-CVMUskSm.js';
18
- import { u as useLiveShardSeed } from './use-live-shard-seed-Cuk3dnH0.js';
3
+ import { useState, useEffect, useMemo, useRef } from 'react';
4
+ import { E as ErrorAlert } from '../packem_shared/error-alert-CXjqyGw9.js';
5
+ import { L as LiveError } from '../packem_shared/live-status-FZ0psC1z.js';
6
+ import { ShardInput } from '../packem_shared/ShardInput-gx_DZXXn.js';
7
+ import { B as Badge } from '../packem_shared/badge-B2PKA1-5.js';
8
+ import { E as EmptyState } from '../packem_shared/empty-state-DY_oe0k6.js';
9
+ import { I as Input } from '../packem_shared/input-XH4r1Pt1.js';
10
+ import { u as useAdminQuery } from '../packem_shared/use-admin-query-CfHYWx5n.js';
11
+ import useDebounced from '../packem_shared/useDebounced-Dxncpg6z.js';
12
+ import { useT } from '../packem_shared/DEFAULT_LOCALE-CiX4W7Kr.js';
13
+ import { ADMIN_FUNCTIONS } from '../packem_shared/ADMIN_FUNCTIONS-BHHJi3Gb.js';
14
+ import { a as CLOUDFLARE_OBSERVABILITY_URL } from '../packem_shared/cf-links-BZfRdxSE.js';
15
+ import { r as recordShard } from '../packem_shared/shard-history-DyebH1R5.js';
16
+ import { c as cn } from '../packem_shared/utils-B05Dmz_H.js';
17
+ import { f as flooredRectObserver } from '../packem_shared/virtual-rect-CVMUskSm.js';
19
18
  import { jsxDEV } from 'react/jsx-dev-runtime';
20
19
 
21
20
  const SCROLL_HEIGHT = 400;
@@ -316,8 +315,6 @@ const RequestRow = (t0) => {
316
315
  }
317
316
  return t17;
318
317
  };
319
- const GET_LOGS = adminRef(ADMIN_FUNCTIONS.getLogs);
320
- const GET_REQUEST_LOG = adminRef(ADMIN_FUNCTIONS.getRequestLog);
321
318
  const entriesOf = (result) => {
322
319
  const {
323
320
  entries
@@ -488,13 +485,9 @@ const SummaryBucketRow = (t0) => {
488
485
  const LogsPanel = ({
489
486
  initialShardKey
490
487
  }) => {
491
- const client = useLunora();
492
488
  const t = useT();
493
489
  const [view, setView] = useState("requests");
494
490
  const [shardKey, setShardKey] = useState(initialShardKey ?? "");
495
- const [entries, setEntries] = useState([]);
496
- const [requests, setRequests] = useState([]);
497
- const [error, setError] = useState(null);
498
491
  const [search, setSearch] = useState("");
499
492
  const [levelFilter, setLevelFilter] = useState(() => /* @__PURE__ */ new Set());
500
493
  const [pathFilter, setPathFilter] = useState("");
@@ -504,43 +497,37 @@ const LogsPanel = ({
504
497
  const [userIdFilter, setUserIdFilter] = useState("");
505
498
  const [tableFilter, setTableFilter] = useState("");
506
499
  const [outcomeFilter, setOutcomeFilter] = useState("all");
507
- const [liveError, setLiveError] = useState(void 0);
500
+ const debouncedShard = useDebounced(shardKey.trim(), 400);
508
501
  const requestQuery = buildRequestQuery({
509
502
  functionPathPrefix: pathPrefix,
510
503
  outcome: outcomeFilter,
511
504
  tableTouched: tableFilter,
512
505
  userId: userIdFilter
513
506
  });
514
- const refresh = async (shard) => {
515
- setError(null);
516
- try {
517
- if (view === "requests") {
518
- const result = await client.query(GET_REQUEST_LOG, requestQuery, callOptions(shard));
519
- recordShard(shard);
520
- setRequests(entriesOf(result));
521
- } else {
522
- const result_0 = await client.query(GET_LOGS, {}, callOptions(shard));
523
- recordShard(shard);
524
- setEntries(entriesOf(result_0));
525
- }
526
- } catch (error_) {
527
- setEntries([]);
528
- setRequests([]);
529
- setError(errorMessage(error_));
530
- throw error_;
507
+ const requestsQuery = useAdminQuery(ADMIN_FUNCTIONS.getRequestLog, requestQuery, {
508
+ enabled: view === "requests",
509
+ live: true,
510
+ shardKey: debouncedShard
511
+ });
512
+ const errorsQuery = useAdminQuery(ADMIN_FUNCTIONS.getLogs, {}, {
513
+ enabled: view === "errors",
514
+ live: true,
515
+ shardKey: debouncedShard
516
+ });
517
+ const activeQuery = view === "requests" ? requestsQuery : errorsQuery;
518
+ const {
519
+ error,
520
+ errorSource,
521
+ isLoading: activeLoading,
522
+ liveError
523
+ } = activeQuery;
524
+ const entries = entriesOf(errorsQuery.data);
525
+ const requests = entriesOf(requestsQuery.data);
526
+ useEffect(() => {
527
+ if (activeQuery.data !== void 0) {
528
+ recordShard(debouncedShard);
531
529
  }
532
- };
533
- const committedShard = useLiveShardSeed(shardKey, refresh, [view, requestQuery]);
534
- useLiveAdmin(ADMIN_FUNCTIONS.getRequestLog, requestQuery, committedShard ?? "", (result_1) => {
535
- setError(null);
536
- setLiveError(void 0);
537
- setRequests(entriesOf(result_1));
538
- }, view === "requests" && committedShard !== void 0, setLiveError);
539
- useLiveAdmin(ADMIN_FUNCTIONS.getLogs, {}, committedShard ?? "", (result_2) => {
540
- setError(null);
541
- setLiveError(void 0);
542
- setEntries(entriesOf(result_2));
543
- }, view === "errors" && committedShard !== void 0, setLiveError);
530
+ }, [activeQuery.data, debouncedShard]);
544
531
  const filtered = filterLogs(entries, {
545
532
  levels: levelFilter,
546
533
  now: Date.now(),
@@ -556,10 +543,13 @@ const LogsPanel = ({
556
543
  return "error";
557
544
  }
558
545
  if (activeCount === 0) {
546
+ if (activeLoading) {
547
+ return summaryVisible ? "summary" : "list";
548
+ }
559
549
  return "empty";
560
550
  }
561
551
  return summaryVisible ? "summary" : "list";
562
- }, [activeCount, error, summaryVisible]);
552
+ }, [activeCount, activeLoading, error, summaryVisible]);
563
553
  const scrollRef = useRef(null);
564
554
  const virtualizer = useVirtualizer({
565
555
  count: activeCount,
@@ -755,11 +745,9 @@ const LogsPanel = ({
755
745
  children: t("error")
756
746
  }, void 0, false)]
757
747
  }, void 0, true)]
758
- }, void 0, true), readout === "error" && /* @__PURE__ */ jsxDEV("p", {
759
- className: "text-sm text-destructive",
760
- "data-testid": "lg-error",
761
- role: "alert",
762
- children: error
748
+ }, void 0, true), readout === "error" && /* @__PURE__ */ jsxDEV(ErrorAlert, {
749
+ error: errorSource,
750
+ testId: "lg-error"
763
751
  }, void 0, false), readout === "empty" && /* @__PURE__ */ jsxDEV(EmptyState, {
764
752
  description: t("Function and request logs for this shard show up here as your app handles traffic."),
765
753
  icon: /* @__PURE__ */ jsxDEV("svg", {
@@ -1,19 +1,19 @@
1
- 'use client';
2
1
  import { useLunora } from '@lunora/react';
3
- import { useState, useEffect, useMemo } from 'react';
4
- import { B as Badge } from './badge-B2PKA1-5.js';
5
- import { B as Button } from './button-BhsN2uZH.js';
6
- import { E as EmptyState } from './empty-state-DY_oe0k6.js';
7
- import { I as Input } from './input-XH4r1Pt1.js';
8
- import { c } from 'react/compiler-runtime';
9
- import { ScrollArea as ScrollArea$1 } from '@base-ui/react/scroll-area';
10
- import { c as cn } from './utils-B05Dmz_H.js';
11
- import { jsxDEV, Fragment } from 'react/jsx-dev-runtime';
2
+ import { useState, useMemo } from 'react';
3
+ import { E as ErrorAlert } from '../packem_shared/error-alert-CXjqyGw9.js';
4
+ import { B as Badge } from '../packem_shared/badge-B2PKA1-5.js';
5
+ import { B as Button } from '../packem_shared/button-BhsN2uZH.js';
6
+ import { E as EmptyState } from '../packem_shared/empty-state-DY_oe0k6.js';
7
+ import { I as Input } from '../packem_shared/input-XH4r1Pt1.js';
8
+ import { S as ScrollArea } from '../packem_shared/scroll-area-DLhcy-ml.js';
12
9
  import { Separator as Separator$1 } from '@base-ui/react/separator';
13
- import { useAutoRefresh } from './DEFAULT_AUTO_REFRESH_MS-Vxwaxx51.js';
14
- import { useT } from './DEFAULT_LOCALE-CiX4W7Kr.js';
15
- import { ADMIN_FUNCTIONS } from './ADMIN_FUNCTIONS-DmBqMZ-z.js';
16
- import { f as fireAndForget, b as formatTimestamp, c as callOptions, e as errorMessage, g as copyToClipboard, a as adminRef } from './internal-rXJEAhXS.js';
10
+ import { c as cn } from '../packem_shared/utils-B05Dmz_H.js';
11
+ import { jsxDEV, Fragment } from 'react/jsx-dev-runtime';
12
+ import { u as useAdminQuery } from '../packem_shared/use-admin-query-CfHYWx5n.js';
13
+ import { useAutoRefresh } from '../packem_shared/DEFAULT_AUTO_REFRESH_MS-Vxwaxx51.js';
14
+ import { useT } from '../packem_shared/DEFAULT_LOCALE-CiX4W7Kr.js';
15
+ import { ADMIN_FUNCTIONS } from '../packem_shared/ADMIN_FUNCTIONS-BHHJi3Gb.js';
16
+ import { i as formatTimestamp, f as fireAndForget, g as copyToClipboard, c as callOptions, e as errorMessage, a as adminRef } from '../packem_shared/internal-CYcbqMjX.js';
17
17
 
18
18
  function Separator({
19
19
  className,
@@ -28,93 +28,6 @@ function Separator({
28
28
  }, void 0, false);
29
29
  }
30
30
 
31
- function ScrollArea(t0) {
32
- const $ = c(14);
33
- let children;
34
- let className;
35
- let props;
36
- if ($[0] !== t0) {
37
- ({
38
- className,
39
- children,
40
- ...props
41
- } = t0);
42
- $[0] = t0;
43
- $[1] = children;
44
- $[2] = className;
45
- $[3] = props;
46
- } else {
47
- children = $[1];
48
- className = $[2];
49
- props = $[3];
50
- }
51
- let t1;
52
- if ($[4] !== className) {
53
- t1 = cn("relative", className);
54
- $[4] = className;
55
- $[5] = t1;
56
- } else {
57
- t1 = $[5];
58
- }
59
- let t2;
60
- if ($[6] !== children) {
61
- t2 = /* @__PURE__ */ jsxDEV(ScrollArea$1.Viewport, {
62
- "data-slot": "scroll-area-viewport",
63
- className: "size-full rounded-[inherit] transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1",
64
- children
65
- }, void 0, false);
66
- $[6] = children;
67
- $[7] = t2;
68
- } else {
69
- t2 = $[7];
70
- }
71
- let t3;
72
- let t4;
73
- if ($[8] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel")) {
74
- t3 = /* @__PURE__ */ jsxDEV(ScrollBar, {}, void 0, false);
75
- t4 = /* @__PURE__ */ jsxDEV(ScrollArea$1.Corner, {}, void 0, false);
76
- $[8] = t3;
77
- $[9] = t4;
78
- } else {
79
- t3 = $[8];
80
- t4 = $[9];
81
- }
82
- let t5;
83
- if ($[10] !== props || $[11] !== t1 || $[12] !== t2) {
84
- t5 = /* @__PURE__ */ jsxDEV(ScrollArea$1.Root, {
85
- "data-slot": "scroll-area",
86
- className: t1,
87
- ...props,
88
- children: [t2, t3, t4]
89
- }, void 0, true);
90
- $[10] = props;
91
- $[11] = t1;
92
- $[12] = t2;
93
- $[13] = t5;
94
- } else {
95
- t5 = $[13];
96
- }
97
- return t5;
98
- }
99
- function ScrollBar({
100
- className,
101
- orientation = "vertical",
102
- ...props
103
- }) {
104
- return /* @__PURE__ */ jsxDEV(ScrollArea$1.Scrollbar, {
105
- "data-slot": "scroll-area-scrollbar",
106
- "data-orientation": orientation,
107
- orientation,
108
- className: cn("flex touch-none p-px transition-colors select-none data-horizontal:h-2.5 data-horizontal:flex-col data-horizontal:border-t data-horizontal:border-t-transparent data-vertical:h-full data-vertical:w-2.5 data-vertical:border-s data-vertical:border-s-transparent", className),
109
- ...props,
110
- children: /* @__PURE__ */ jsxDEV(ScrollArea$1.Thumb, {
111
- "data-slot": "scroll-area-thumb",
112
- className: "relative flex-1 rounded-md bg-border"
113
- }, void 0, false)
114
- }, void 0, false);
115
- }
116
-
117
- const GET_CAPTURED_MAIL = adminRef(ADMIN_FUNCTIONS.getCapturedMail);
118
31
  const CLEAR_CAPTURED_MAIL = adminRef(ADMIN_FUNCTIONS.clearCapturedMail);
119
32
  const SEND_TEST_MAIL = adminRef(ADMIN_FUNCTIONS.sendTestMail);
120
33
  const LINK_PATTERN = /https?:\/\/[^\s"'<>)]+/i;
@@ -144,49 +57,44 @@ const MailPanel = ({
144
57
  }) => {
145
58
  const client = useLunora();
146
59
  const t = useT();
147
- const [entries, setEntries] = useState([]);
148
- const [error, setError] = useState(null);
60
+ const {
61
+ data,
62
+ error: readError,
63
+ errorSource: readErrorSource,
64
+ isLoading,
65
+ refetch
66
+ } = useAdminQuery(ADMIN_FUNCTIONS.getCapturedMail, {
67
+ limit
68
+ });
69
+ const [actionError, setActionError] = useState(null);
149
70
  const [selectedId, setSelectedId] = useState(null);
150
71
  const [tab, setTab] = useState("html");
151
72
  const [filter, setFilter] = useState("");
152
- const refresh = async () => {
153
- setError(null);
154
- try {
155
- const next = await client.query(GET_CAPTURED_MAIL, {
156
- limit
157
- }, callOptions(""));
158
- setEntries(next.entries);
159
- } catch (error_) {
160
- setEntries([]);
161
- setError(errorMessage(error_));
162
- }
163
- };
73
+ const entries = useMemo(() => data?.entries ?? [], [data]);
74
+ const error = readError ?? actionError;
75
+ const errorSource = readError === null ? actionError : readErrorSource;
164
76
  const clearInbox = async () => {
165
- setError(null);
77
+ setActionError(null);
166
78
  try {
167
79
  await client.query(CLEAR_CAPTURED_MAIL, {}, callOptions(""));
168
80
  setSelectedId(null);
169
- await refresh();
170
- } catch (error__0) {
171
- setError(errorMessage(error__0));
81
+ refetch();
82
+ } catch (error_) {
83
+ setActionError(errorMessage(error_));
172
84
  }
173
85
  };
174
86
  const sendTest = async () => {
175
- setError(null);
87
+ setActionError(null);
176
88
  try {
177
89
  await client.query(SEND_TEST_MAIL, {}, callOptions(""));
178
- await refresh();
179
- } catch (error__1) {
180
- setError(errorMessage(error__1));
90
+ refetch();
91
+ } catch (error__0) {
92
+ setActionError(errorMessage(error__0));
181
93
  }
182
94
  };
183
- useEffect(() => {
184
- fireAndForget(refresh());
185
- }, [refresh]);
186
- const reload = () => {
187
- fireAndForget(refresh());
188
- };
189
- useAutoRefresh(reload, true);
95
+ useAutoRefresh(() => {
96
+ refetch();
97
+ }, true);
190
98
  const onClear = () => {
191
99
  fireAndForget(clearInbox());
192
100
  };
@@ -205,9 +113,9 @@ const MailPanel = ({
205
113
  }
206
114
  };
207
115
  const onSelectTab = (event_1) => {
208
- const next_0 = event_1.currentTarget.dataset["tab"];
209
- if (next_0 === "headers" || next_0 === "html" || next_0 === "text") {
210
- setTab(next_0);
116
+ const next = event_1.currentTarget.dataset["tab"];
117
+ if (next === "headers" || next === "html" || next === "text") {
118
+ setTab(next);
211
119
  }
212
120
  };
213
121
  const tabTitle = (value) => {
@@ -271,12 +179,10 @@ const MailPanel = ({
271
179
  count: entries.length
272
180
  })
273
181
  }, void 0, false)]
274
- }, void 0, true), error !== null && /* @__PURE__ */ jsxDEV("p", {
275
- className: "text-sm text-destructive",
276
- "data-testid": "mail-error",
277
- role: "alert",
278
- children: error
279
- }, void 0, false), error === null && entries.length === 0 && /* @__PURE__ */ jsxDEV(EmptyState, {
182
+ }, void 0, true), error !== null && /* @__PURE__ */ jsxDEV(ErrorAlert, {
183
+ error: errorSource,
184
+ testId: "mail-error"
185
+ }, void 0, false), error === null && !isLoading && entries.length === 0 && /* @__PURE__ */ jsxDEV(EmptyState, {
280
186
  description: t("Email your app sends in dev is captured here — nothing is delivered."),
281
187
  icon: /* @__PURE__ */ jsxDEV("svg", {
282
188
  "aria-hidden": "true",