@open-mercato/core 0.6.2-develop.3330.1.8ad2b3b84c → 0.6.2-develop.3366.1.4692954e44

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 (102) hide show
  1. package/.turbo/turbo-build.log +2 -2
  2. package/dist/generated/entities/sync_excel_upload/index.js +37 -0
  3. package/dist/generated/entities/sync_excel_upload/index.js.map +7 -0
  4. package/dist/generated/entities.ids.generated.js +4 -0
  5. package/dist/generated/entities.ids.generated.js.map +2 -2
  6. package/dist/generated/entity-fields-registry.js +19 -0
  7. package/dist/generated/entity-fields-registry.js.map +2 -2
  8. package/dist/modules/customers/search.js +3 -2
  9. package/dist/modules/customers/search.js.map +2 -2
  10. package/dist/modules/data_sync/api/runs/[id]/cancel.js +16 -0
  11. package/dist/modules/data_sync/api/runs/[id]/cancel.js.map +2 -2
  12. package/dist/modules/data_sync/di.js +2 -1
  13. package/dist/modules/data_sync/di.js.map +2 -2
  14. package/dist/modules/data_sync/lib/sync-engine.js +178 -54
  15. package/dist/modules/data_sync/lib/sync-engine.js.map +2 -2
  16. package/dist/modules/data_sync/lib/sync-run-service.js +23 -0
  17. package/dist/modules/data_sync/lib/sync-run-service.js.map +3 -3
  18. package/dist/modules/integrations/backend/integrations/[id]/page.js +241 -55
  19. package/dist/modules/integrations/backend/integrations/[id]/page.js.map +3 -3
  20. package/dist/modules/sync_excel/acl.js +10 -0
  21. package/dist/modules/sync_excel/acl.js.map +7 -0
  22. package/dist/modules/sync_excel/api/import/route.js +164 -0
  23. package/dist/modules/sync_excel/api/import/route.js.map +7 -0
  24. package/dist/modules/sync_excel/api/preview/route.js +84 -0
  25. package/dist/modules/sync_excel/api/preview/route.js.map +7 -0
  26. package/dist/modules/sync_excel/api/upload/route.js +131 -0
  27. package/dist/modules/sync_excel/api/upload/route.js.map +7 -0
  28. package/dist/modules/sync_excel/data/entities.js +79 -0
  29. package/dist/modules/sync_excel/data/entities.js.map +7 -0
  30. package/dist/modules/sync_excel/data/validators.js +58 -0
  31. package/dist/modules/sync_excel/data/validators.js.map +7 -0
  32. package/dist/modules/sync_excel/di.js +11 -0
  33. package/dist/modules/sync_excel/di.js.map +7 -0
  34. package/dist/modules/sync_excel/index.js +11 -0
  35. package/dist/modules/sync_excel/index.js.map +7 -0
  36. package/dist/modules/sync_excel/integration.js +36 -0
  37. package/dist/modules/sync_excel/integration.js.map +7 -0
  38. package/dist/modules/sync_excel/lib/adapters/customers.js +852 -0
  39. package/dist/modules/sync_excel/lib/adapters/customers.js.map +7 -0
  40. package/dist/modules/sync_excel/lib/column-detector.js +77 -0
  41. package/dist/modules/sync_excel/lib/column-detector.js.map +7 -0
  42. package/dist/modules/sync_excel/lib/mapping.js +16 -0
  43. package/dist/modules/sync_excel/lib/mapping.js.map +7 -0
  44. package/dist/modules/sync_excel/lib/parser.js +125 -0
  45. package/dist/modules/sync_excel/lib/parser.js.map +7 -0
  46. package/dist/modules/sync_excel/lib/scope.js +44 -0
  47. package/dist/modules/sync_excel/lib/scope.js.map +7 -0
  48. package/dist/modules/sync_excel/lib/upload-storage.js +63 -0
  49. package/dist/modules/sync_excel/lib/upload-storage.js.map +7 -0
  50. package/dist/modules/sync_excel/migrations/Migration20260329181120_sync_excel.js +11 -0
  51. package/dist/modules/sync_excel/migrations/Migration20260329181120_sync_excel.js.map +7 -0
  52. package/dist/modules/sync_excel/setup.js +19 -0
  53. package/dist/modules/sync_excel/setup.js.map +7 -0
  54. package/dist/modules/sync_excel/widgets/injection/upload-config/target-options.js +293 -0
  55. package/dist/modules/sync_excel/widgets/injection/upload-config/target-options.js.map +7 -0
  56. package/dist/modules/sync_excel/widgets/injection/upload-config/widget.client.js +934 -0
  57. package/dist/modules/sync_excel/widgets/injection/upload-config/widget.client.js.map +7 -0
  58. package/dist/modules/sync_excel/widgets/injection/upload-config/widget.js +15 -0
  59. package/dist/modules/sync_excel/widgets/injection/upload-config/widget.js.map +7 -0
  60. package/dist/modules/sync_excel/widgets/injection-table.js +17 -0
  61. package/dist/modules/sync_excel/widgets/injection-table.js.map +7 -0
  62. package/generated/entities/sync_excel_upload/index.ts +17 -0
  63. package/generated/entities.ids.generated.ts +4 -0
  64. package/generated/entity-fields-registry.ts +19 -0
  65. package/package.json +7 -7
  66. package/src/modules/customers/search.ts +3 -2
  67. package/src/modules/data_sync/api/runs/[id]/cancel.ts +18 -0
  68. package/src/modules/data_sync/di.ts +4 -1
  69. package/src/modules/data_sync/lib/adapter.ts +15 -0
  70. package/src/modules/data_sync/lib/sync-engine.ts +205 -52
  71. package/src/modules/data_sync/lib/sync-run-service.ts +24 -0
  72. package/src/modules/integrations/backend/integrations/[id]/page.tsx +220 -15
  73. package/src/modules/integrations/i18n/de.json +9 -0
  74. package/src/modules/integrations/i18n/en.json +9 -0
  75. package/src/modules/integrations/i18n/es.json +9 -0
  76. package/src/modules/integrations/i18n/pl.json +9 -0
  77. package/src/modules/sync_excel/acl.ts +6 -0
  78. package/src/modules/sync_excel/api/import/route.ts +182 -0
  79. package/src/modules/sync_excel/api/preview/route.ts +89 -0
  80. package/src/modules/sync_excel/api/upload/route.ts +144 -0
  81. package/src/modules/sync_excel/data/entities.ts +61 -0
  82. package/src/modules/sync_excel/data/validators.ts +58 -0
  83. package/src/modules/sync_excel/di.ts +9 -0
  84. package/src/modules/sync_excel/i18n/de.json +107 -0
  85. package/src/modules/sync_excel/i18n/en.json +107 -0
  86. package/src/modules/sync_excel/i18n/es.json +107 -0
  87. package/src/modules/sync_excel/i18n/pl.json +107 -0
  88. package/src/modules/sync_excel/index.ts +7 -0
  89. package/src/modules/sync_excel/integration.ts +31 -0
  90. package/src/modules/sync_excel/lib/adapters/customers.ts +1097 -0
  91. package/src/modules/sync_excel/lib/column-detector.ts +91 -0
  92. package/src/modules/sync_excel/lib/mapping.ts +19 -0
  93. package/src/modules/sync_excel/lib/parser.ts +165 -0
  94. package/src/modules/sync_excel/lib/scope.ts +63 -0
  95. package/src/modules/sync_excel/lib/upload-storage.ts +79 -0
  96. package/src/modules/sync_excel/migrations/.snapshot-open-mercato.json +199 -0
  97. package/src/modules/sync_excel/migrations/Migration20260329181120_sync_excel.ts +10 -0
  98. package/src/modules/sync_excel/setup.ts +20 -0
  99. package/src/modules/sync_excel/widgets/injection/upload-config/target-options.ts +351 -0
  100. package/src/modules/sync_excel/widgets/injection/upload-config/widget.client.tsx +1224 -0
  101. package/src/modules/sync_excel/widgets/injection/upload-config/widget.ts +30 -0
  102. package/src/modules/sync_excel/widgets/injection-table.ts +15 -0
@@ -47,6 +47,11 @@ const UNSUPPORTED_CREDENTIAL_FIELD_TYPES = /* @__PURE__ */ new Set(["oauth", "ss
47
47
  function isEditableCredentialField(field) {
48
48
  return !UNSUPPORTED_CREDENTIAL_FIELD_TYPES.has(field.type);
49
49
  }
50
+ const LOG_LEVEL_STYLES = {
51
+ info: "bg-blue-100 text-blue-800",
52
+ warn: "bg-yellow-100 text-yellow-800",
53
+ error: "bg-red-100 text-red-800"
54
+ };
50
55
  const HEALTH_STATUS_STYLES = {
51
56
  healthy: "bg-green-100 text-green-800",
52
57
  degraded: "bg-yellow-100 text-yellow-800",
@@ -59,6 +64,66 @@ const HEALTH_STATUS_ICONS = {
59
64
  unhealthy: XCircle,
60
65
  unconfigured: AlertTriangle
61
66
  };
67
+ function formatRunStatusLabel(status, t) {
68
+ switch (status) {
69
+ case "pending":
70
+ return t("integrations.detail.runActivity.status.pending", "Pending");
71
+ case "running":
72
+ return t("integrations.detail.runActivity.status.running", "Running");
73
+ case "completed":
74
+ return t("integrations.detail.runActivity.status.completed", "Completed");
75
+ case "failed":
76
+ return t("integrations.detail.runActivity.status.failed", "Failed");
77
+ case "cancelled":
78
+ return t("integrations.detail.runActivity.status.cancelled", "Cancelled");
79
+ default:
80
+ return status;
81
+ }
82
+ }
83
+ function RunActivityStrip({
84
+ run,
85
+ refreshedAt,
86
+ isRefreshing,
87
+ onRefresh,
88
+ t
89
+ }) {
90
+ if (!run) return null;
91
+ const progress = typeof run.progressJob?.progressPercent === "number" ? run.progressJob.progressPercent : 0;
92
+ const processed = typeof run.progressJob?.processedCount === "number" ? run.progressJob.processedCount : 0;
93
+ const total = typeof run.progressJob?.totalCount === "number" ? run.progressJob.totalCount : null;
94
+ const statusClass = run.status === "completed" ? "border-emerald-500/30 bg-emerald-500/10 text-emerald-700 dark:text-emerald-300" : run.status === "failed" ? "border-red-500/30 bg-red-500/10 text-red-700 dark:text-red-300" : run.status === "cancelled" ? "border-zinc-500/30 bg-zinc-500/10 text-zinc-700 dark:text-zinc-300" : "border-blue-500/30 bg-blue-500/10 text-blue-700 dark:text-blue-300";
95
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 rounded-lg border bg-muted/20 px-4 py-3 text-sm", children: [
96
+ /* @__PURE__ */ jsxs(Badge, { variant: "outline", className: cn("gap-1.5", statusClass), children: [
97
+ /* @__PURE__ */ jsx(RefreshCw, { className: cn("h-3.5 w-3.5", run.status === "running" ? "animate-spin" : "") }),
98
+ formatRunStatusLabel(run.status, t)
99
+ ] }),
100
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
101
+ t("integrations.detail.runActivity.processed", "Processed"),
102
+ ": ",
103
+ /* @__PURE__ */ jsxs("span", { className: "font-medium text-foreground", children: [
104
+ processed,
105
+ total !== null ? ` / ${total}` : ""
106
+ ] })
107
+ ] }),
108
+ /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
109
+ t("integrations.detail.runActivity.progress", "Progress"),
110
+ ": ",
111
+ /* @__PURE__ */ jsxs("span", { className: "font-medium text-foreground", children: [
112
+ progress,
113
+ "%"
114
+ ] })
115
+ ] }),
116
+ refreshedAt ? /* @__PURE__ */ jsxs("span", { className: "text-muted-foreground", children: [
117
+ t("integrations.detail.runActivity.lastRefreshed", "Last refreshed"),
118
+ ": ",
119
+ new Date(refreshedAt).toLocaleTimeString()
120
+ ] }) : null,
121
+ /* @__PURE__ */ jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "ml-auto", onClick: onRefresh, disabled: isRefreshing, children: [
122
+ isRefreshing ? /* @__PURE__ */ jsx(Spinner, { className: "mr-2 h-4 w-4" }) : /* @__PURE__ */ jsx(RefreshCw, { className: "mr-2 h-4 w-4" }),
123
+ t("integrations.detail.runActivity.refresh", "Refresh")
124
+ ] })
125
+ ] });
126
+ }
62
127
  function DetailLogSparkline({ counts, className }) {
63
128
  const max = Math.max(1, ...counts);
64
129
  const w = 120;
@@ -217,6 +282,9 @@ function IntegrationDetailPage({ params }) {
217
282
  const [isCheckingHealth, setIsCheckingHealth] = React.useState(false);
218
283
  const [isTogglingState, setIsTogglingState] = React.useState(false);
219
284
  const [latestHealthResult, setLatestHealthResult] = React.useState(null);
285
+ const [activeRunDetail, setActiveRunDetail] = React.useState(null);
286
+ const [activeRunRefreshedAt, setActiveRunRefreshedAt] = React.useState(null);
287
+ const [isRefreshingRunActivity, setIsRefreshingRunActivity] = React.useState(false);
220
288
  const [activeTab, setActiveTab] = React.useState("credentials");
221
289
  const credentialsFormId = React.useId();
222
290
  const resolveCurrentIntegrationId = React.useCallback(() => {
@@ -297,6 +365,35 @@ function IntegrationDetailPage({ params }) {
297
365
  const refreshLogs = React.useCallback(async () => {
298
366
  await loadLogs();
299
367
  }, [loadLogs]);
368
+ const refreshHealthSnapshot = React.useCallback(async () => {
369
+ await loadDetail();
370
+ }, [loadDetail]);
371
+ const runIdFromUrl = searchParams?.get("runId") ?? null;
372
+ const refreshRunActivity = React.useCallback(async (options) => {
373
+ if (!runIdFromUrl) {
374
+ setActiveRunDetail(null);
375
+ setActiveRunRefreshedAt(null);
376
+ return null;
377
+ }
378
+ if (options?.showLoading) setIsRefreshingRunActivity(true);
379
+ try {
380
+ const call = await apiCall(
381
+ `/api/data_sync/runs/${encodeURIComponent(runIdFromUrl)}`,
382
+ void 0,
383
+ { fallback: null }
384
+ );
385
+ await loadLogs();
386
+ await loadDetail();
387
+ if (call.ok && call.result) {
388
+ setActiveRunDetail(call.result);
389
+ setActiveRunRefreshedAt((/* @__PURE__ */ new Date()).toISOString());
390
+ return call.result;
391
+ }
392
+ return null;
393
+ } finally {
394
+ if (options?.showLoading) setIsRefreshingRunActivity(false);
395
+ }
396
+ }, [loadDetail, loadLogs, runIdFromUrl]);
300
397
  const injectionContext = React.useMemo(
301
398
  () => ({
302
399
  formId: mutationContextId,
@@ -313,6 +410,7 @@ function IntegrationDetailPage({ params }) {
313
410
  setActiveTab,
314
411
  refreshDetail,
315
412
  refreshLogs,
413
+ refreshHealthSnapshot,
316
414
  retryLastMutation
317
415
  }),
318
416
  [
@@ -324,6 +422,7 @@ function IntegrationDetailPage({ params }) {
324
422
  latestHealthResult,
325
423
  mutationContextId,
326
424
  refreshDetail,
425
+ refreshHealthSnapshot,
327
426
  refreshLogs,
328
427
  retryLastMutation
329
428
  ]
@@ -571,8 +670,12 @@ function IntegrationDetailPage({ params }) {
571
670
  });
572
671
  }), [editableCredentialFields, t]);
573
672
  const latestHealthLog = React.useMemo(() => logs.find(isHealthLog) ?? null, [logs]);
574
- const healthMessage = latestHealthResult?.message ?? (typeof latestHealthLog?.payload?.message === "string" ? latestHealthLog.payload.message : null);
575
- const healthDetailsSource = latestHealthResult?.details ?? extractHealthDetails(latestHealthLog?.payload);
673
+ const latestOperationalLog = React.useMemo(
674
+ () => logs.find((log) => typeof log.payload?.operationalStatus === "string" || typeof log.payload?.summary === "string") ?? null,
675
+ [logs]
676
+ );
677
+ const healthMessage = latestHealthResult?.message ?? (typeof latestHealthLog?.payload?.message === "string" ? latestHealthLog.payload.message : typeof latestOperationalLog?.payload?.summary === "string" ? latestOperationalLog.payload.summary : null);
678
+ const healthDetailsSource = latestHealthResult?.details ?? extractHealthDetails(latestHealthLog?.payload ?? latestOperationalLog?.payload);
576
679
  const healthDetails = latestHealthLog?.code ? { ...healthDetailsSource, code: latestHealthLog.code } : healthDetailsSource;
577
680
  const healthDetailEntries = Object.entries(healthDetails);
578
681
  const resolvedIntegration = detail?.integration ?? null;
@@ -622,8 +725,37 @@ function IntegrationDetailPage({ params }) {
622
725
  setActiveTab(nextTab);
623
726
  if (!currentIntegrationId) return;
624
727
  const basePath = `/backend/integrations/${encodeURIComponent(currentIntegrationId)}`;
625
- router.replace(nextTab === "credentials" ? basePath : `${basePath}?tab=${encodeURIComponent(nextTab)}`);
626
- }, [resolveCurrentIntegrationId, router, visibleTabIds]);
728
+ const params2 = new URLSearchParams(searchParams?.toString() ?? "");
729
+ if (nextTab === "credentials") params2.delete("tab");
730
+ else params2.set("tab", nextTab);
731
+ const query = params2.toString();
732
+ router.replace(query ? `${basePath}?${query}` : basePath);
733
+ }, [resolveCurrentIntegrationId, router, searchParams, visibleTabIds]);
734
+ React.useEffect(() => {
735
+ if (!runIdFromUrl) {
736
+ setActiveRunDetail(null);
737
+ setActiveRunRefreshedAt(null);
738
+ return;
739
+ }
740
+ if (activeTab !== "logs" && activeTab !== "health") return;
741
+ let cancelled = false;
742
+ let timeoutId = null;
743
+ const poll = async () => {
744
+ const detail2 = await refreshRunActivity();
745
+ if (cancelled) return;
746
+ const status = detail2?.status ?? null;
747
+ if (status === "pending" || status === "running") {
748
+ timeoutId = setTimeout(() => {
749
+ void poll();
750
+ }, 4e3);
751
+ }
752
+ };
753
+ void poll();
754
+ return () => {
755
+ cancelled = true;
756
+ if (timeoutId) clearTimeout(timeoutId);
757
+ };
758
+ }, [activeTab, refreshRunActivity, runIdFromUrl]);
627
759
  if (isLoading) return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(LoadingMessage, { label: t("integrations.detail.title") }) }) });
628
760
  if (error || !detail || !resolvedIntegration || !resolvedState) {
629
761
  return /* @__PURE__ */ jsx(Page, { children: /* @__PURE__ */ jsx(PageBody, { children: /* @__PURE__ */ jsx(ErrorMessage, { label: error ?? t("integrations.detail.loadError") }) }) });
@@ -855,67 +987,121 @@ function IntegrationDetailPage({ params }) {
855
987
  isEnabled: resolvedState.isEnabled
856
988
  }
857
989
  ) }) : null,
858
- showHealthTab ? /* @__PURE__ */ jsx(TabsContent, { value: "health", className: "mt-0 space-y-4", children: /* @__PURE__ */ jsxs(Card, { className: "gap-4 py-4", children: [
859
- /* @__PURE__ */ jsx(CardHeader, { className: "px-5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
860
- /* @__PURE__ */ jsx(CardTitle, { children: t("integrations.detail.health.title") }),
990
+ showHealthTab ? /* @__PURE__ */ jsxs(TabsContent, { value: "health", className: "mt-0 space-y-4", children: [
991
+ /* @__PURE__ */ jsx(
992
+ RunActivityStrip,
993
+ {
994
+ run: activeRunDetail,
995
+ refreshedAt: activeRunRefreshedAt,
996
+ isRefreshing: isRefreshingRunActivity,
997
+ onRefresh: () => void refreshRunActivity({ showLoading: true }),
998
+ t
999
+ }
1000
+ ),
1001
+ /* @__PURE__ */ jsxs(Card, { className: "gap-4 py-4", children: [
1002
+ /* @__PURE__ */ jsx(CardHeader, { className: "px-5", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1003
+ /* @__PURE__ */ jsx(CardTitle, { children: t("integrations.detail.health.title") }),
1004
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
1005
+ /* @__PURE__ */ jsxs(
1006
+ Button,
1007
+ {
1008
+ type: "button",
1009
+ variant: "outline",
1010
+ size: "sm",
1011
+ onClick: () => void refreshRunActivity({ showLoading: true }),
1012
+ disabled: isRefreshingRunActivity || !runIdFromUrl,
1013
+ children: [
1014
+ isRefreshingRunActivity ? /* @__PURE__ */ jsx(Spinner, { className: "mr-2 h-4 w-4" }) : /* @__PURE__ */ jsx(RefreshCw, { className: "mr-2 h-4 w-4" }),
1015
+ t("integrations.detail.runActivity.refresh", "Refresh")
1016
+ ]
1017
+ }
1018
+ ),
1019
+ /* @__PURE__ */ jsxs(
1020
+ Button,
1021
+ {
1022
+ type: "button",
1023
+ variant: "outline",
1024
+ size: "sm",
1025
+ onClick: () => void handleHealthCheck(),
1026
+ disabled: isCheckingHealth,
1027
+ children: [
1028
+ isCheckingHealth ? /* @__PURE__ */ jsx(Spinner, { className: "mr-2 h-4 w-4" }) : /* @__PURE__ */ jsx(Zap, { className: "mr-2 h-4 w-4" }),
1029
+ isCheckingHealth ? t("integrations.detail.health.checking") : t("integrations.detail.health.check")
1030
+ ]
1031
+ }
1032
+ )
1033
+ ] })
1034
+ ] }) }),
1035
+ /* @__PURE__ */ jsxs(CardContent, { className: "space-y-3 px-5", children: [
1036
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 rounded-lg border bg-muted/20 px-4 py-3", children: [
1037
+ displayHealthStatus ? /* @__PURE__ */ jsxs(Badge, { className: `gap-1.5 ${HEALTH_STATUS_STYLES[displayHealthStatus] ?? ""}`, children: [
1038
+ HealthStatusIcon ? /* @__PURE__ */ jsx(HealthStatusIcon, { className: "h-3.5 w-3.5" }) : null,
1039
+ t(`integrations.detail.health.${displayHealthStatus}`)
1040
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
1041
+ /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4" }),
1042
+ /* @__PURE__ */ jsx("span", { children: t("integrations.detail.health.unknown") })
1043
+ ] }),
1044
+ healthStatusDescription ? /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 text-sm text-muted-foreground", children: healthStatusDescription }) : null,
1045
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground md:ml-auto", children: resolvedState.lastHealthCheckedAt ? t("integrations.detail.health.lastChecked", { date: new Date(resolvedState.lastHealthCheckedAt).toLocaleString() }) : t("integrations.detail.health.neverChecked") })
1046
+ ] }),
1047
+ healthMessage || healthDetailEntries.length > 0 ? /* @__PURE__ */ jsxs("div", { className: `grid gap-3 ${healthMessage && healthDetailEntries.length > 0 ? "xl:grid-cols-[minmax(0,1.25fr)_minmax(0,1fr)]" : ""}`, children: [
1048
+ healthMessage ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border px-4 py-3", children: [
1049
+ /* @__PURE__ */ jsx("p", { className: "text-overline font-medium uppercase tracking-widest text-muted-foreground", children: t("integrations.detail.health.lastResult", "Last result") }),
1050
+ /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm", children: healthMessage })
1051
+ ] }) : null,
1052
+ healthDetailEntries.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border px-4 py-3", children: [
1053
+ /* @__PURE__ */ jsx("p", { className: "text-overline font-medium uppercase tracking-widest text-muted-foreground", children: t("integrations.detail.health.details", "Details") }),
1054
+ /* @__PURE__ */ jsx("dl", { className: "mt-2 grid gap-x-6 gap-y-2 sm:grid-cols-2", children: healthDetailEntries.map(([key, value]) => /* @__PURE__ */ jsxs("div", { children: [
1055
+ /* @__PURE__ */ jsx("dt", { className: "text-xs font-medium text-muted-foreground", children: formatLogDetailLabel(key) }),
1056
+ /* @__PURE__ */ jsx("dd", { className: "mt-0.5 text-sm", children: formatHealthValue(value) })
1057
+ ] }, key)) })
1058
+ ] }) : null
1059
+ ] }) : null
1060
+ ] })
1061
+ ] })
1062
+ ] }) : null,
1063
+ showLogsTab ? /* @__PURE__ */ jsxs(TabsContent, { value: "logs", className: "mt-0 space-y-4", children: [
1064
+ /* @__PURE__ */ jsx(
1065
+ RunActivityStrip,
1066
+ {
1067
+ run: activeRunDetail,
1068
+ refreshedAt: activeRunRefreshedAt,
1069
+ isRefreshing: isRefreshingRunActivity,
1070
+ onRefresh: () => void refreshRunActivity({ showLoading: true }),
1071
+ t
1072
+ }
1073
+ ),
1074
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3", children: [
1075
+ /* @__PURE__ */ jsx("div", { className: "inline-flex", children: /* @__PURE__ */ jsxs(
1076
+ Select,
1077
+ {
1078
+ value: logLevel || void 0,
1079
+ onValueChange: (value) => setLogLevel(value ?? ""),
1080
+ children: [
1081
+ /* @__PURE__ */ jsx(SelectTrigger, { size: "lg", className: "min-w-40", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("integrations.detail.logs.level.all") }) }),
1082
+ /* @__PURE__ */ jsxs(SelectContent, { children: [
1083
+ /* @__PURE__ */ jsx(SelectItem, { value: "info", children: t("integrations.detail.logs.level.info") }),
1084
+ /* @__PURE__ */ jsx(SelectItem, { value: "warn", children: t("integrations.detail.logs.level.warn") }),
1085
+ /* @__PURE__ */ jsx(SelectItem, { value: "error", children: t("integrations.detail.logs.level.error") })
1086
+ ] })
1087
+ ]
1088
+ }
1089
+ ) }),
861
1090
  /* @__PURE__ */ jsxs(
862
1091
  Button,
863
1092
  {
864
1093
  type: "button",
865
1094
  variant: "outline",
866
1095
  size: "sm",
867
- onClick: () => void handleHealthCheck(),
868
- disabled: isCheckingHealth,
1096
+ onClick: () => void refreshRunActivity({ showLoading: true }),
1097
+ disabled: isRefreshingRunActivity || !runIdFromUrl,
869
1098
  children: [
870
- isCheckingHealth ? /* @__PURE__ */ jsx(Spinner, { className: "mr-2 h-4 w-4" }) : /* @__PURE__ */ jsx(Zap, { className: "mr-2 h-4 w-4" }),
871
- isCheckingHealth ? t("integrations.detail.health.checking") : t("integrations.detail.health.check")
1099
+ isRefreshingRunActivity ? /* @__PURE__ */ jsx(Spinner, { className: "mr-2 h-4 w-4" }) : /* @__PURE__ */ jsx(RefreshCw, { className: "mr-2 h-4 w-4" }),
1100
+ t("integrations.detail.runActivity.refresh", "Refresh")
872
1101
  ]
873
1102
  }
874
1103
  )
875
- ] }) }),
876
- /* @__PURE__ */ jsxs(CardContent, { className: "space-y-3 px-5", children: [
877
- /* @__PURE__ */ jsxs("div", { className: "flex flex-wrap items-center gap-3 rounded-lg border bg-muted/20 px-4 py-3", children: [
878
- displayHealthStatus ? /* @__PURE__ */ jsxs(Badge, { className: `gap-1.5 ${HEALTH_STATUS_STYLES[displayHealthStatus] ?? ""}`, children: [
879
- HealthStatusIcon ? /* @__PURE__ */ jsx(HealthStatusIcon, { className: "h-3.5 w-3.5" }) : null,
880
- t(`integrations.detail.health.${displayHealthStatus}`)
881
- ] }) : /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 text-sm text-muted-foreground", children: [
882
- /* @__PURE__ */ jsx(AlertTriangle, { className: "h-4 w-4" }),
883
- /* @__PURE__ */ jsx("span", { children: t("integrations.detail.health.unknown") })
884
- ] }),
885
- healthStatusDescription ? /* @__PURE__ */ jsx("p", { className: "min-w-0 flex-1 text-sm text-muted-foreground", children: healthStatusDescription }) : null,
886
- /* @__PURE__ */ jsx("p", { className: "text-xs text-muted-foreground md:ml-auto", children: resolvedState.lastHealthCheckedAt ? t("integrations.detail.health.lastChecked", { date: new Date(resolvedState.lastHealthCheckedAt).toLocaleString() }) : t("integrations.detail.health.neverChecked") })
887
- ] }),
888
- healthMessage || healthDetailEntries.length > 0 ? /* @__PURE__ */ jsxs("div", { className: `grid gap-3 ${healthMessage && healthDetailEntries.length > 0 ? "xl:grid-cols-[minmax(0,1.25fr)_minmax(0,1fr)]" : ""}`, children: [
889
- healthMessage ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border px-4 py-3", children: [
890
- /* @__PURE__ */ jsx("p", { className: "text-overline font-medium uppercase tracking-widest text-muted-foreground", children: t("integrations.detail.health.lastResult", "Last result") }),
891
- /* @__PURE__ */ jsx("p", { className: "mt-1.5 text-sm", children: healthMessage })
892
- ] }) : null,
893
- healthDetailEntries.length > 0 ? /* @__PURE__ */ jsxs("div", { className: "rounded-lg border px-4 py-3", children: [
894
- /* @__PURE__ */ jsx("p", { className: "text-overline font-medium uppercase tracking-widest text-muted-foreground", children: t("integrations.detail.health.details", "Details") }),
895
- /* @__PURE__ */ jsx("dl", { className: "mt-2 grid gap-x-6 gap-y-2 sm:grid-cols-2", children: healthDetailEntries.map(([key, value]) => /* @__PURE__ */ jsxs("div", { children: [
896
- /* @__PURE__ */ jsx("dt", { className: "text-xs font-medium text-muted-foreground", children: formatLogDetailLabel(key) }),
897
- /* @__PURE__ */ jsx("dd", { className: "mt-0.5 text-sm", children: formatHealthValue(value) })
898
- ] }, key)) })
899
- ] }) : null
900
- ] }) : null
901
- ] })
902
- ] }) }) : null,
903
- showLogsTab ? /* @__PURE__ */ jsxs(TabsContent, { value: "logs", className: "mt-0 space-y-4", children: [
904
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-3", children: /* @__PURE__ */ jsx("div", { className: "inline-flex", children: /* @__PURE__ */ jsxs(
905
- Select,
906
- {
907
- value: logLevel || void 0,
908
- onValueChange: (value) => setLogLevel(value ?? ""),
909
- children: [
910
- /* @__PURE__ */ jsx(SelectTrigger, { size: "lg", className: "min-w-40", children: /* @__PURE__ */ jsx(SelectValue, { placeholder: t("integrations.detail.logs.level.all") }) }),
911
- /* @__PURE__ */ jsxs(SelectContent, { children: [
912
- /* @__PURE__ */ jsx(SelectItem, { value: "info", children: t("integrations.detail.logs.level.info") }),
913
- /* @__PURE__ */ jsx(SelectItem, { value: "warn", children: t("integrations.detail.logs.level.warn") }),
914
- /* @__PURE__ */ jsx(SelectItem, { value: "error", children: t("integrations.detail.logs.level.error") })
915
- ] })
916
- ]
917
- }
918
- ) }) }),
1104
+ ] }),
919
1105
  isLoadingLogs ? /* @__PURE__ */ jsx("div", { className: "flex justify-center py-8", children: /* @__PURE__ */ jsx(Spinner, {}) }) : /* @__PURE__ */ jsx(
920
1106
  LogList,
921
1107
  {