@koda-plus/medusa-plugin-subiekt-nexo 0.2.0 → 0.3.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.
Files changed (112) hide show
  1. package/.medusa/server/src/admin/index.js +2027 -1225
  2. package/.medusa/server/src/admin/index.mjs +2030 -1228
  3. package/.medusa/server/src/api/admin/subiekt/check/route.d.ts +9 -0
  4. package/.medusa/server/src/api/admin/subiekt/documents/route.d.ts +8 -0
  5. package/.medusa/server/src/api/admin/subiekt/helpers.d.ts +23 -0
  6. package/.medusa/server/src/api/admin/subiekt/helpers.js +4 -4
  7. package/.medusa/server/src/api/admin/subiekt/orders/[id]/check/route.d.ts +10 -0
  8. package/.medusa/server/src/api/admin/subiekt/orders/[id]/check/route.js +33 -0
  9. package/.medusa/server/src/api/admin/subiekt/orders/[id]/documents/route.d.ts +12 -0
  10. package/.medusa/server/src/api/admin/subiekt/orders/[id]/link/route.d.ts +10 -0
  11. package/.medusa/server/src/api/admin/subiekt/orders/[id]/link/route.js +40 -0
  12. package/.medusa/server/src/api/admin/subiekt/orders/[id]/route.d.ts +3 -0
  13. package/.medusa/server/src/api/admin/subiekt/orders/[id]/send/route.d.ts +8 -0
  14. package/.medusa/server/src/api/admin/subiekt/products/release/route.d.ts +9 -0
  15. package/.medusa/server/src/api/admin/subiekt/products/route.d.ts +9 -0
  16. package/.medusa/server/src/api/admin/subiekt/route.d.ts +8 -0
  17. package/.medusa/server/src/api/admin/subiekt/runs/route.d.ts +3 -0
  18. package/.medusa/server/src/api/admin/subiekt/sync/route.d.ts +9 -0
  19. package/.medusa/server/src/api/admin/subiekt/sync/route.js +6 -4
  20. package/.medusa/server/src/api/admin/subiekt/tasks/[id]/retry/route.d.ts +9 -0
  21. package/.medusa/server/src/api/admin/subiekt/tasks/route.d.ts +8 -0
  22. package/.medusa/server/src/api/admin/subiekt/writers/route.d.ts +9 -0
  23. package/.medusa/server/src/api/hooks/subiekt/route.d.ts +11 -0
  24. package/.medusa/server/src/api/middlewares.d.ts +6 -0
  25. package/.medusa/server/src/jobs/subiekt-catch-up.d.ts +12 -0
  26. package/.medusa/server/src/jobs/subiekt-catch-up.js +26 -0
  27. package/.medusa/server/src/jobs/subiekt-process-tasks.d.ts +12 -0
  28. package/.medusa/server/src/jobs/subiekt-pull-events.d.ts +12 -0
  29. package/.medusa/server/src/jobs/subiekt-sync-products.d.ts +11 -0
  30. package/.medusa/server/src/jobs/subiekt-sync-stock.d.ts +11 -0
  31. package/.medusa/server/src/modules/subiekt/index.d.ts +113 -0
  32. package/.medusa/server/src/modules/subiekt/lib/backoff.d.ts +23 -0
  33. package/.medusa/server/src/modules/subiekt/lib/bridge-client.d.ts +86 -0
  34. package/.medusa/server/src/modules/subiekt/lib/capabilities.d.ts +24 -0
  35. package/.medusa/server/src/modules/subiekt/lib/catch-up.d.ts +47 -0
  36. package/.medusa/server/src/modules/subiekt/lib/catch-up.js +79 -0
  37. package/.medusa/server/src/modules/subiekt/lib/constants.d.ts +111 -0
  38. package/.medusa/server/src/modules/subiekt/lib/constants.js +15 -3
  39. package/.medusa/server/src/modules/subiekt/lib/contract.d.ts +560 -0
  40. package/.medusa/server/src/modules/subiekt/lib/demo.d.ts +95 -0
  41. package/.medusa/server/src/modules/subiekt/lib/demo.js +1 -1
  42. package/.medusa/server/src/modules/subiekt/lib/diagnostics.d.ts +15 -0
  43. package/.medusa/server/src/modules/subiekt/lib/documents.d.ts +35 -0
  44. package/.medusa/server/src/modules/subiekt/lib/dto.d.ts +81 -0
  45. package/.medusa/server/src/modules/subiekt/lib/guide.d.ts +19 -0
  46. package/.medusa/server/src/modules/subiekt/lib/kit-contract.d.ts +186 -0
  47. package/.medusa/server/src/modules/subiekt/lib/kit-contract.js +144 -0
  48. package/.medusa/server/src/modules/subiekt/lib/kit-guards.d.ts +12 -0
  49. package/.medusa/server/src/modules/subiekt/lib/kit-guards.js +90 -0
  50. package/.medusa/server/src/modules/subiekt/lib/kit-meta.d.ts +8 -0
  51. package/.medusa/server/src/modules/subiekt/lib/kit-meta.js +13 -0
  52. package/.medusa/server/src/modules/subiekt/lib/kit-routes.d.ts +156 -0
  53. package/.medusa/server/src/modules/subiekt/lib/kit-routes.js +409 -0
  54. package/.medusa/server/src/modules/subiekt/lib/nip.d.ts +44 -0
  55. package/.medusa/server/src/modules/subiekt/lib/numbers.d.ts +9 -0
  56. package/.medusa/server/src/modules/subiekt/lib/options.d.ts +133 -0
  57. package/.medusa/server/src/modules/subiekt/lib/options.js +4 -3
  58. package/.medusa/server/src/modules/subiekt/lib/order-payload.d.ts +137 -0
  59. package/.medusa/server/src/modules/subiekt/lib/order-payload.js +24 -12
  60. package/.medusa/server/src/modules/subiekt/lib/payment.d.ts +54 -0
  61. package/.medusa/server/src/modules/subiekt/lib/products.d.ts +121 -0
  62. package/.medusa/server/src/modules/subiekt/lib/reconcile.d.ts +47 -0
  63. package/.medusa/server/src/modules/subiekt/lib/reconcile.js +83 -0
  64. package/.medusa/server/src/modules/subiekt/lib/signature.d.ts +53 -0
  65. package/.medusa/server/src/modules/subiekt/lib/stock.d.ts +83 -0
  66. package/.medusa/server/src/modules/subiekt/lib/writers.d.ts +29 -0
  67. package/.medusa/server/src/modules/subiekt/migrations/Migration20261004180000.d.ts +9 -0
  68. package/.medusa/server/src/modules/subiekt/migrations/Migration20261006120000.d.ts +11 -0
  69. package/.medusa/server/src/modules/subiekt/models/subiekt-catalog-change.d.ts +36 -0
  70. package/.medusa/server/src/modules/subiekt/models/subiekt-catalog-quarantine.d.ts +17 -0
  71. package/.medusa/server/src/modules/subiekt/models/subiekt-connection.d.ts +25 -0
  72. package/.medusa/server/src/modules/subiekt/models/subiekt-document.d.ts +31 -0
  73. package/.medusa/server/src/modules/subiekt/models/subiekt-sync-run.d.ts +19 -0
  74. package/.medusa/server/src/modules/subiekt/models/subiekt-task.d.ts +39 -0
  75. package/.medusa/server/src/modules/subiekt/models/subiekt-writer.d.ts +17 -0
  76. package/.medusa/server/src/modules/subiekt/service.d.ts +133 -0
  77. package/.medusa/server/src/subscribers/subiekt-fulfillment-created.d.ts +13 -0
  78. package/.medusa/server/src/subscribers/subiekt-order-canceled.d.ts +9 -0
  79. package/.medusa/server/src/subscribers/subiekt-order-placed.d.ts +18 -0
  80. package/.medusa/server/src/subscribers/subiekt-order-placed.js +8 -13
  81. package/.medusa/server/src/subscribers/subiekt-payment-captured.d.ts +11 -0
  82. package/.medusa/server/src/workflows/index.d.ts +20 -0
  83. package/.medusa/server/src/workflows/subiekt/cancel-order-in-subiekt.d.ts +13 -0
  84. package/.medusa/server/src/workflows/subiekt/catalog.d.ts +89 -0
  85. package/.medusa/server/src/workflows/subiekt/catch-up.d.ts +45 -0
  86. package/.medusa/server/src/workflows/subiekt/catch-up.js +163 -0
  87. package/.medusa/server/src/workflows/subiekt/check-subiekt-connection.d.ts +8 -0
  88. package/.medusa/server/src/workflows/subiekt/create-subiekt-wz.d.ts +14 -0
  89. package/.medusa/server/src/workflows/subiekt/events.d.ts +30 -0
  90. package/.medusa/server/src/workflows/subiekt/health.d.ts +20 -0
  91. package/.medusa/server/src/workflows/subiekt/issue-subiekt-document.d.ts +23 -0
  92. package/.medusa/server/src/workflows/subiekt/orders.d.ts +70 -0
  93. package/.medusa/server/src/workflows/subiekt/process-subiekt-tasks.d.ts +8 -0
  94. package/.medusa/server/src/workflows/subiekt/pull-subiekt-events.d.ts +8 -0
  95. package/.medusa/server/src/workflows/subiekt/queue.d.ts +34 -0
  96. package/.medusa/server/src/workflows/subiekt/reconcile-order.d.ts +26 -0
  97. package/.medusa/server/src/workflows/subiekt/reconcile-order.js +95 -0
  98. package/.medusa/server/src/workflows/subiekt/runtime.d.ts +52 -0
  99. package/.medusa/server/src/workflows/subiekt/runtime.js +38 -1
  100. package/.medusa/server/src/workflows/subiekt/sales-documents.d.ts +35 -0
  101. package/.medusa/server/src/workflows/subiekt/send-order-to-subiekt.d.ts +45 -0
  102. package/.medusa/server/src/workflows/subiekt/stock-plan.d.ts +17 -0
  103. package/.medusa/server/src/workflows/subiekt/sync-subiekt-products.d.ts +17 -0
  104. package/.medusa/server/src/workflows/subiekt/sync-subiekt-stock.d.ts +23 -0
  105. package/.medusa/server/src/workflows/subiekt/tasks.d.ts +43 -0
  106. package/.medusa/server/src/workflows/subiekt/writers.d.ts +18 -0
  107. package/CHANGELOG.md +55 -0
  108. package/README.md +66 -19
  109. package/contract/examples/events.response.json +1 -1
  110. package/contract/openapi.yaml +1 -1
  111. package/package.json +30 -2
  112. package/.medusa/server/src/modules/subiekt/lib/references.js +0 -135
@@ -3,14 +3,15 @@ var __defProp = Object.defineProperty;
3
3
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
4
4
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  const jsxRuntime = require("react/jsx-runtime");
6
+ const react = require("react");
6
7
  const reactI18next = require("react-i18next");
7
8
  const adminSdk = require("@medusajs/admin-sdk");
9
+ const icons = require("@medusajs/icons");
8
10
  const ui = require("@medusajs/ui");
9
11
  const reactQuery = require("@tanstack/react-query");
10
12
  const reactRouterDom = require("react-router-dom");
11
- const icons = require("@medusajs/icons");
12
- const react = require("react");
13
- function backendUrl() {
13
+ const reactDom = require("react-dom");
14
+ function backendUrl$1() {
14
15
  try {
15
16
  if (typeof __BACKEND_URL__ !== "undefined" && __BACKEND_URL__) return String(__BACKEND_URL__).replace(/\/+$/, "");
16
17
  } catch {
@@ -27,7 +28,7 @@ class SubiektRequestError extends Error {
27
28
  }
28
29
  async function subiektFetch(path, init) {
29
30
  const hasBody = (init == null ? void 0 : init.body) !== void 0;
30
- const res = await fetch(`${backendUrl()}${path}`, {
31
+ const res = await fetch(`${backendUrl$1()}${path}`, {
31
32
  method: (init == null ? void 0 : init.method) ?? "GET",
32
33
  credentials: "include",
33
34
  headers: { Accept: "application/json", ...hasBody ? { "Content-Type": "application/json" } : {} },
@@ -82,6 +83,7 @@ function useSubiektTasks(filter, q, offset, limit, poll) {
82
83
  function useSubiektDocuments(kind, q, offset, limit, poll) {
83
84
  const params = new URLSearchParams({ limit: String(limit), offset: String(offset) });
84
85
  if (kind && kind !== "all") params.set("kind", kind);
86
+ if (q) params.set("q", q);
85
87
  return reactQuery.useQuery({
86
88
  queryKey: subiektKeys.documents(kind, q, offset, limit),
87
89
  queryFn: () => subiektFetch(`/admin/subiekt/documents?${params.toString()}`),
@@ -166,502 +168,240 @@ function useSubiektSendOrder(orderId) {
166
168
  onSuccess: () => client.invalidateQueries({ queryKey: subiektKeys.order(orderId) })
167
169
  });
168
170
  }
169
- function fmtDateTime(value, lang) {
170
- if (!value) return "";
171
- const d = new Date(value);
172
- if (!Number.isFinite(d.getTime())) return "";
171
+ function useSubiektOrderCheck(orderId) {
172
+ return reactQuery.useMutation({
173
+ mutationFn: () => subiektFetch(`/admin/subiekt/orders/${encodeURIComponent(orderId)}/check`, { method: "POST", body: {} })
174
+ });
175
+ }
176
+ function useSubiektLinkDocument(orderId) {
177
+ const client = reactQuery.useQueryClient();
178
+ return reactQuery.useMutation({
179
+ mutationFn: (body) => subiektFetch(`/admin/subiekt/orders/${encodeURIComponent(orderId)}/link`, { method: "POST", body }),
180
+ onSuccess: () => client.invalidateQueries({ queryKey: subiektKeys.all })
181
+ });
182
+ }
183
+ function backendUrl() {
173
184
  try {
174
- return new Intl.DateTimeFormat(lang, { dateStyle: "medium", timeStyle: "short" }).format(d);
185
+ if (typeof __BACKEND_URL__ !== "undefined" && __BACKEND_URL__ && __BACKEND_URL__ !== "/") return String(__BACKEND_URL__).replace(/\/+$/, "");
175
186
  } catch {
176
- return d.toISOString().slice(0, 16).replace("T", " ");
177
187
  }
188
+ return "";
178
189
  }
179
- function fmtDuration(ms) {
180
- if (!Number.isFinite(ms) || ms <= 0) return "0 s";
181
- return ms < 1e4 ? `${(ms / 1e3).toFixed(1)} s` : `${Math.round(ms / 1e3)} s`;
182
- }
183
- function fmtNumber(value, lang) {
184
- const n = typeof value === "number" ? value : Number(value);
185
- if (!Number.isFinite(n)) return "0";
190
+ function authHeaders() {
191
+ let type = "session";
186
192
  try {
187
- return new Intl.NumberFormat(lang).format(n);
193
+ if (typeof __AUTH_TYPE__ !== "undefined" && __AUTH_TYPE__) type = String(__AUTH_TYPE__);
188
194
  } catch {
189
- return String(n);
190
195
  }
196
+ if (type !== "jwt") return {};
197
+ let key = "medusa_auth_token";
198
+ try {
199
+ if (typeof __JWT_TOKEN_STORAGE_KEY__ !== "undefined" && __JWT_TOKEN_STORAGE_KEY__) key = String(__JWT_TOKEN_STORAGE_KEY__);
200
+ } catch {
201
+ }
202
+ let token = null;
203
+ try {
204
+ token = window.localStorage.getItem(key) ?? window.sessionStorage.getItem(key);
205
+ } catch {
206
+ token = null;
207
+ }
208
+ return token ? { Authorization: `Bearer ${token}` } : {};
191
209
  }
192
- const TASK_TONE = {
193
- waiting: "purple",
194
- pending: "blue",
195
- running: "blue",
196
- unknown: "orange",
197
- succeeded: "green",
198
- failed: "red",
199
- canceled: "grey"
200
- };
201
- function TaskStatusBadge({ status }) {
202
- const { t } = reactI18next.useTranslation("subiekt");
203
- return /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: TASK_TONE[status] ?? "grey", children: t(`tasks.statuses.${status}`) });
204
- }
205
- const RUN_TONE = { success: "green", partial: "orange", error: "red", skipped: "grey" };
206
- function RunStatusBadge({ status }) {
207
- const { t } = reactI18next.useTranslation("subiekt");
208
- return /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: RUN_TONE[status] ?? "grey", children: t(`runs.statuses.${status}`) });
209
- }
210
- function DocumentStatusBadge({ status }) {
211
- const { t } = reactI18next.useTranslation("subiekt");
212
- const tone = status === "canceled" ? "grey" : status === "completed" ? "green" : "blue";
213
- return /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: tone, children: t(`documents.statuses.${status}`, { defaultValue: status }) });
214
- }
215
- const CATALOG_TONE = {
216
- planned: "blue",
217
- applied: "green",
218
- simulated: "purple",
219
- over_cap: "grey",
220
- stale: "orange",
221
- failed: "red",
222
- quarantined: "red",
223
- skipped: "grey"
224
- };
225
- function CatalogStatusBadge({ status }) {
226
- const { t } = reactI18next.useTranslation("subiekt");
227
- return /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: CATALOG_TONE[status] ?? "grey", children: t(`products.statuses.${status}`, { defaultValue: status }) });
228
- }
229
- function SampleList({ label, items }) {
230
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
231
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: label }),
232
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", className: "font-mono", children: item }, item)) })
233
- ] });
234
- }
235
- function RichText({ text }) {
236
- const parts = text.split("`");
237
- return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts.map(
238
- (part, i) => i % 2 === 1 ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "txt-compact-xsmall rounded border border-ui-border-base bg-ui-bg-subtle px-1 font-mono text-ui-fg-base", children: part }, i) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: part }, i)
239
- ) });
210
+ class KitRequestError extends Error {
211
+ constructor(status, message, code, body) {
212
+ super(message);
213
+ __publicField(this, "status");
214
+ __publicField(this, "code");
215
+ __publicField(this, "body");
216
+ this.name = "KitRequestError";
217
+ this.status = status;
218
+ this.code = code;
219
+ this.body = body;
220
+ }
240
221
  }
241
- function connectionState(s) {
242
- var _a;
243
- if (!s) return { key: "unknown", tone: "grey" };
244
- if (s.mode === "demo") return { key: "demo", tone: "purple" };
245
- if (!s.configured) return { key: "notConfigured", tone: "orange" };
246
- if (!s.connection.checkedAt && !s.connection.lastErrorAt) return { key: "unknown", tone: "grey" };
247
- if (!s.connection.reachable) return { key: "unreachable", tone: "red" };
248
- if (s.connection.health && !((_a = s.connection.health.subiekt) == null ? void 0 : _a.connected)) return { key: "subiektDown", tone: "orange" };
249
- return { key: "connected", tone: "green" };
222
+ function kitRequestInit(init = {}) {
223
+ const method = init.method ?? "GET";
224
+ const write = method !== "GET";
225
+ const hasBody = init.body !== void 0;
226
+ return {
227
+ method,
228
+ credentials: "include",
229
+ signal: init.signal,
230
+ headers: {
231
+ Accept: "application/json",
232
+ ...write ? { "Content-Type": "application/json", "x-koda-request": "1" } : {},
233
+ ...authHeaders(),
234
+ ...init.headers ?? {}
235
+ },
236
+ body: write ? JSON.stringify(hasBody ? init.body : {}) : void 0
237
+ };
250
238
  }
251
- function ConnectionBadge({ status }) {
252
- const { t } = reactI18next.useTranslation("subiekt");
253
- const state = connectionState(status);
254
- return /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: state.tone, children: t(`mode.${state.key}`) });
239
+ async function kitFetch(path, init = {}) {
240
+ const res = await fetch(`${backendUrl()}${path}`, kitRequestInit(init));
241
+ const text = await res.text();
242
+ let json = null;
243
+ try {
244
+ json = text ? JSON.parse(text) : null;
245
+ } catch {
246
+ json = null;
247
+ }
248
+ if (!res.ok) {
249
+ const body = json && typeof json === "object" ? json : {};
250
+ throw new KitRequestError(res.status, typeof body.message === "string" ? body.message : `HTTP ${res.status}`, typeof body.code === "string" ? body.code : null, json);
251
+ }
252
+ return json;
255
253
  }
256
- function StatTile({ label, value, tone }) {
257
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1 px-6 py-4", children: [
258
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: label }),
259
- /* @__PURE__ */ jsxRuntime.jsx(
260
- ui.Text,
261
- {
262
- size: "xlarge",
263
- weight: "plus",
264
- leading: "compact",
265
- className: ui.clx("tabular-nums", tone === "attention" ? "text-ui-tag-red-text" : tone === "muted" ? "text-ui-fg-muted" : "text-ui-fg-base"),
266
- children: value
267
- }
268
- )
254
+ function WidgetFrame({ embedded, header, children, className }) {
255
+ if (embedded) return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.clx("divide-y divide-ui-border-base", className), children });
256
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: ui.clx("divide-y p-0", className), children: [
257
+ header,
258
+ children
269
259
  ] });
270
260
  }
271
- function Field({ label, children }) {
272
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[minmax(120px,1fr)_2fr] items-start gap-x-4 px-6 py-2", children: [
273
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: label }),
274
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small text-ui-fg-base min-w-0 break-words", children })
261
+ function KitLoading({ label, className }) {
262
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "status", "aria-live": "polite", className: ui.clx("flex min-h-[8rem] flex-col items-center justify-center gap-y-2 px-6 py-8", className), children: [
263
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "size-5 animate-spin rounded-full border-2 border-ui-border-base border-t-ui-fg-interactive" }),
264
+ label ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small text-ui-fg-subtle", children: label }) : null
275
265
  ] });
276
266
  }
277
- function FilterPills({ value, options, onChange }) {
278
- return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", children: options.map((o) => /* @__PURE__ */ jsxRuntime.jsxs(
279
- "button",
280
- {
281
- type: "button",
282
- onClick: () => onChange(o.value),
283
- className: ui.clx(
284
- "txt-compact-small-plus rounded-full border px-3 py-1 transition-colors",
285
- value === o.value ? "border-ui-border-interactive bg-ui-bg-highlight text-ui-fg-interactive" : "border-ui-border-base text-ui-fg-subtle hover:bg-ui-bg-base-hover"
286
- ),
287
- children: [
288
- o.label,
289
- typeof o.count === "number" && o.count > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", className: "ml-2", children: o.count }) : null
290
- ]
291
- },
292
- o.value
293
- )) });
267
+ function KitSkeletonRows({ cols, rows = 6 }) {
268
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: Array.from({ length: rows }, (_, r) => /* @__PURE__ */ jsxRuntime.jsx("tr", { "aria-hidden": true, className: "border-b border-ui-border-base last:border-b-0", children: Array.from({ length: cols }, (_2, c) => /* @__PURE__ */ jsxRuntime.jsx("td", { className: "px-6 py-3.5", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "block h-3 animate-pulse rounded bg-ui-bg-component", style: { width: `${45 + (r * 7 + c * 13) % 45}%` } }) }, c)) }, r)) });
294
269
  }
295
- function Pager({ offset, limit, count, onChange }) {
296
- const { t } = reactI18next.useTranslation("subiekt");
297
- if (count <= limit) return null;
298
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-3", children: [
299
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle tabular-nums", children: t("tasks.page", { from: offset + 1, to: Math.min(offset + limit, count), count }) }),
300
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-2", children: [
301
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", disabled: offset === 0, onClick: () => onChange(Math.max(0, offset - limit)), children: t("tasks.prev") }),
302
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", disabled: offset + limit >= count, onClick: () => onChange(offset + limit), children: t("tasks.next") })
303
- ] })
304
- ] });
270
+ const KIT_META = {
271
+ pkg: "@koda-plus/medusa-plugin-subiekt-nexo",
272
+ version: "0.3.0"
273
+ };
274
+ const NBSP = " ";
275
+ const NBHY = "‑";
276
+ const SHORT = /(^|[\s("„])(oraz|albo|lub|ale|że|bo|czy|gdy|aby|by|więc|jak|na|do|za|ze|we|od|po|to|[aiouwze])[ \t]+/gi;
277
+ function nb(text) {
278
+ let out = text;
279
+ for (let k = 0; k < 2; k++) out = out.replace(SHORT, `$1$2${NBSP}`);
280
+ out = out.replace(/(\d) (?=\d{3}\b)/g, `$1${NBSP}`);
281
+ out = out.replace(/\b([eE])-(?=mail)/g, `$1${NBHY}`);
282
+ return out.replace(/(\d) (zł|€|Kč|EUR|USD|PLN|CZK|mln|tys\.|cm|mm|m²|%)/g, `$1${NBSP}$2`);
305
283
  }
306
- const num = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
307
- function runSummary(run, t) {
308
- const s = run.stats ?? {};
309
- if (run.status === "error" || run.status === "skipped" || !run.stats) return run.message ?? "";
310
- if (run.kind === "stock") {
311
- const changes = num(s.toUpdate) + num(s.toCreate);
312
- return t(run.dryRun ? "runs.summary.stockDry" : "runs.summary.stock", { changes, unchanged: num(s.unchanged) });
313
- }
314
- if (run.kind === "tasks") {
315
- const vars = { succeeded: num(s.succeeded), retry: num(s.retry), failed: num(s.failed) };
316
- return t(vars.retry || vars.failed ? "runs.summary.tasksIssues" : "runs.summary.tasks", vars);
317
- }
318
- if (run.kind === "events") return num(s.read) > 0 ? t("runs.summary.events", { applied: num(s.applied) }) : t("runs.summary.eventsNone");
319
- if (run.kind === "health" && run.status === "success") return t("runs.summary.health");
320
- if (run.kind === "products") {
321
- const applied = num(s.applied) + num(s.simulated);
322
- return t(run.dryRun ? "runs.summary.productsPlan" : "runs.summary.productsApplied", {
323
- prices: num(s.priceChanges),
324
- creates: num(s.toCreate),
325
- applied,
326
- failed: num(s.failed)
327
- });
284
+ function typeset(value) {
285
+ if (typeof value === "string") return nb(value);
286
+ if (Array.isArray(value)) return value.map((v) => typeset(v));
287
+ if (value && typeof value === "object") {
288
+ return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, typeset(v)]));
328
289
  }
329
- return run.message ?? "";
290
+ return value;
330
291
  }
331
- function fmtMoney(value, currency, lang) {
332
- if (typeof value !== "number" || !Number.isFinite(value)) return "-";
333
- try {
334
- return new Intl.NumberFormat(lang, { style: "currency", currency: currency.toUpperCase() }).format(value);
335
- } catch {
336
- return `${value.toFixed(2)} ${currency.toUpperCase()}`;
337
- }
292
+ function usePageNav(tabs) {
293
+ const [params, setParams] = reactRouterDom.useSearchParams();
294
+ const raw = params.get("view");
295
+ const view = raw === "guide" || raw === "settings" ? raw : "panel";
296
+ const asked = params.get("tab") ?? "";
297
+ const tab = tabs.includes(asked) ? asked : tabs[0];
298
+ const go = (next, nextTab) => {
299
+ const p = new URLSearchParams(params);
300
+ if (next === "panel") p.delete("view");
301
+ else p.set("view", next);
302
+ if (next === "settings") p.set("tab", nextTab ?? tab);
303
+ else p.delete("tab");
304
+ setParams(p, { replace: true });
305
+ };
306
+ return { view, tab, go };
338
307
  }
339
- function fmtMs(ms) {
340
- if (typeof ms !== "number" || !Number.isFinite(ms)) return "-";
341
- const abs = Math.abs(ms);
342
- return abs < 1e3 ? `${Math.round(ms)} ms` : `${(ms / 1e3).toFixed(abs < 1e4 ? 1 : 0)} s`;
308
+ const VIEWS = ["panel", "guide", "settings"];
309
+ const VIEW_ICON = { panel: /* @__PURE__ */ jsxRuntime.jsx(icons.ChartBar, {}), guide: /* @__PURE__ */ jsxRuntime.jsx(icons.BookOpen, {}), settings: /* @__PURE__ */ jsxRuntime.jsx(icons.CogSixTooth, {}) };
310
+ function PageTabs({ value, onChange, labels }) {
311
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", className: "flex flex-wrap items-center gap-1", children: VIEWS.map((v) => {
312
+ const on = v === value;
313
+ return /* @__PURE__ */ jsxRuntime.jsxs(
314
+ "button",
315
+ {
316
+ type: "button",
317
+ role: "tab",
318
+ "aria-selected": on,
319
+ onClick: () => onChange(v),
320
+ className: ui.clx(
321
+ "txt-compact-small-plus inline-flex items-center gap-x-1.5 rounded-md px-2.5 py-1.5 outline-none transition-fg focus-visible:shadow-borders-focus",
322
+ on ? "bg-ui-bg-base text-ui-fg-base shadow-borders-base" : "text-ui-fg-subtle hover:bg-ui-bg-base-hover hover:text-ui-fg-base"
323
+ ),
324
+ children: [
325
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("flex", on ? "text-ui-fg-interactive" : "text-ui-fg-muted"), children: VIEW_ICON[v] }),
326
+ labels[v]
327
+ ]
328
+ },
329
+ v
330
+ );
331
+ }) });
343
332
  }
344
- function resolveText(value, lang) {
345
- if (!value) return void 0;
346
- if (typeof value === "string") return value;
347
- const pl2 = lang.toLowerCase().startsWith("pl");
348
- return (pl2 ? value.pl ?? value.en : value.en ?? value.pl) || void 0;
349
- }
350
- const PL_GENITIVE = ["stycznia", "lutego", "marca", "kwietnia", "maja", "czerwca", "lipca", "sierpnia", "września", "października", "listopada", "grudnia"];
351
- function monthYear(since, lang) {
352
- const m = /^(\d{4})-(\d{2})$/.exec(since);
353
- if (!m) return since;
354
- const year = Number(m[1]);
355
- const month = Number(m[2]);
356
- if (lang.toLowerCase().startsWith("pl")) return `${PL_GENITIVE[month - 1] ?? m[2]} ${year}`;
357
- try {
358
- return new Intl.DateTimeFormat(lang, { month: "long", year: "numeric", timeZone: "UTC" }).format(new Date(Date.UTC(year, month - 1, 15)));
359
- } catch {
360
- return since;
361
- }
333
+ const POINT_TONE = {
334
+ grey: "border-ui-border-base bg-ui-bg-subtle text-ui-fg-subtle",
335
+ green: "border-ui-tag-green-border bg-ui-tag-green-bg text-ui-tag-green-text",
336
+ orange: "border-ui-tag-orange-border bg-ui-tag-orange-bg text-ui-tag-orange-text",
337
+ red: "border-ui-tag-red-border bg-ui-tag-red-bg text-ui-tag-red-text",
338
+ blue: "border-ui-tag-blue-border bg-ui-tag-blue-bg text-ui-tag-blue-text"
339
+ };
340
+ function KeyPoints({ items, label, className }) {
341
+ const shown = items.filter((p) => Boolean(p));
342
+ if (!shown.length) return null;
343
+ return /* @__PURE__ */ jsxRuntime.jsx("ul", { "aria-label": label, title: label, className: ui.clx("flex min-w-0 flex-nowrap items-center gap-1.5 overflow-x-auto [scrollbar-width:none] [&::-webkit-scrollbar]:hidden", className), children: shown.map((p, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { title: p.title, className: ui.clx("txt-compact-xsmall-plus inline-flex shrink-0 items-center gap-1 whitespace-nowrap rounded-full border px-2 py-0.5", POINT_TONE[p.tone ?? "grey"]), children: [
344
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "flex shrink-0 [&_svg]:size-3.5", children: p.icon }),
345
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: p.text })
346
+ ] }, i)) });
362
347
  }
363
- function referencesFor(list, lang) {
364
- return (list ?? []).map((r) => ({
365
- name: r.name,
366
- url: r.url,
367
- icon: r.icon,
368
- description: resolveText(r.description, lang),
369
- since: r.since,
370
- metrics: r.metrics.map((m) => ({ label: resolveText(m.label, lang) ?? "", value: m.value })).filter((m) => m.label),
371
- links: r.links.map((l) => ({ label: resolveText(l.label, lang) ?? l.url, url: l.url })),
372
- review: r.review ? { ...r.review, quote: resolveText(r.review.quote ?? void 0, lang) } : null
373
- }));
348
+ function OtherActions({ items }) {
349
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: items.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: a.loading, disabled: a.disabled, onClick: a.onClick, className: "whitespace-nowrap", children: [
350
+ a.icon,
351
+ a.label
352
+ ] }, a.key)) });
374
353
  }
375
- function fmtRating(value, lang) {
354
+ function isWhiteLabel() {
355
+ var _a;
376
356
  try {
377
- return new Intl.NumberFormat(lang, { minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(value);
357
+ return Boolean((_a = globalThis.__KODA_KIT__) == null ? void 0 : _a.whiteLabel);
378
358
  } catch {
379
- return value.toFixed(1);
359
+ return false;
380
360
  }
381
361
  }
382
- function MedusaMark({ className }) {
383
- return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 36 38", fill: "none", "aria-hidden": true, className, children: /* @__PURE__ */ jsxRuntime.jsx(
384
- "path",
385
- {
386
- d: "M30.85 6.16832L22.2453 1.21782C19.4299 -0.405941 15.9801 -0.405941 13.1648 1.21782L4.52043 6.16832C1.74473 7.79208 0 10.802 0 14.0099V23.9505C0 27.198 1.74473 30.1683 4.52043 31.7921L13.1251 36.7822C15.9405 38.4059 19.3903 38.4059 22.2056 36.7822L30.8103 31.7921C33.6257 30.1683 35.3307 27.198 35.3307 23.9505V14.0099C35.41 10.802 33.6653 7.79208 30.85 6.16832ZM17.6852 27.8317C12.8079 27.8317 8.8426 23.8713 8.8426 19C8.8426 14.1287 12.8079 10.1683 17.6852 10.1683C22.5625 10.1683 26.5674 14.1287 26.5674 19C26.5674 23.8713 22.6022 27.8317 17.6852 27.8317Z",
387
- fill: "currentColor"
388
- }
389
- ) });
390
- }
391
- function StoreColumn({ label, hint }) {
392
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-x-1.5", title: hint, children: [
393
- /* @__PURE__ */ jsxRuntime.jsx(MedusaMark, { className: "h-3.5 w-3.5 text-ui-fg-muted" }),
394
- label
395
- ] });
396
- }
397
- function StoreLink({ to, title, mono, monoTitle, action }) {
398
- return /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to, className: "group flex items-center gap-x-2.5", title: action, children: [
399
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-ui-bg-component shadow-borders-base transition-fg group-hover:bg-ui-bg-component-hover", children: /* @__PURE__ */ jsxRuntime.jsx(MedusaMark, { className: "h-4 w-4 text-ui-fg-base" }) }),
400
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
401
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus truncate text-ui-fg-base group-hover:text-ui-fg-interactive", children: title }),
402
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-x-1.5", children: [
403
- mono ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-ui-fg-muted txt-compact-xsmall", title: monoTitle, children: mono }) : null,
404
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "txt-compact-xsmall-plus inline-flex shrink-0 items-center gap-x-0.5 text-ui-fg-interactive", children: [
405
- action,
406
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightMini, {})
407
- ] })
408
- ] })
409
- ] })
410
- ] });
411
- }
412
- function StoreUnlinked({ label, hint, mono }) {
413
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-y-1", title: hint, children: [
414
- /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "orange", children: label }),
415
- mono ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-muted txt-compact-xsmall", children: mono }) : null
416
- ] });
417
- }
418
- function StoreOrderCell({ orderId, displayId }) {
419
- const { t } = reactI18next.useTranslation("subiekt");
420
- if (!orderId) return /* @__PURE__ */ jsxRuntime.jsx(StoreUnlinked, { label: t("store.noOrder"), hint: t("store.noOrderHint") });
421
- return /* @__PURE__ */ jsxRuntime.jsx(
422
- StoreLink,
423
- {
424
- to: `/orders/${orderId}`,
425
- title: displayId ? `#${displayId}` : orderId,
426
- mono: displayId ? orderId : null,
427
- monoTitle: orderId,
428
- action: t("store.openOrder")
429
- }
430
- );
431
- }
432
- function SubiektIcon({ width = 15, height = 15, ...props }) {
433
- return /* @__PURE__ */ jsxRuntime.jsxs(
434
- "svg",
435
- {
436
- width,
437
- height,
438
- viewBox: "0 0 192 192",
439
- fill: "none",
440
- xmlns: "http://www.w3.org/2000/svg",
441
- "aria-hidden": "true",
442
- ...props,
443
- children: [
444
- /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "192", height: "192", rx: "40", fill: "#0071B8" }),
445
- /* @__PURE__ */ jsxRuntime.jsx(
446
- "path",
447
- {
448
- fill: "#FFFFFF",
449
- d: "M38.4 134.71L38.4 123.08Q40.4 124.84 43.19 126.25 45.98 127.66 49.06 128.63 52.15 129.6 55.26 130.13 58.37 130.66 61.02 130.66 70.12 130.66 74.62 127.28 79.11 123.9 79.11 117.56 79.11 114.15 77.61 111.63 76.12 109.1 73.47 107.02 70.83 104.93 67.21 103.02 63.6 101.11 59.43 99 55.03 96.76 51.21 94.47 47.39 92.18 44.57 89.42 41.75 86.66 40.13 83.16 38.52 79.67 38.52 74.97 38.52 69.21 41.04 64.95 43.57 60.69 47.68 57.93 51.79 55.17 57.05 53.82 62.31 52.47 67.77 52.47 80.23 52.47 85.93 55.47L85.93 66.57Q78.46 61.4 66.77 61.4 63.54 61.4 60.31 62.07 57.08 62.75 54.56 64.28 52.03 65.8 50.44 68.21 48.86 70.62 48.86 74.09 48.86 77.32 50.06 79.67 51.27 82.02 53.62 83.96 55.97 85.9 59.34 87.72 62.72 89.54 67.13 91.71 71.65 93.94 75.7 96.41 79.76 98.88 82.81 101.87 85.87 104.87 87.66 108.51 89.45 112.15 89.45 116.85 89.45 123.08 87.01 127.4 84.57 131.72 80.43 134.42 76.29 137.12 70.89 138.33 65.48 139.53 59.49 139.53 57.49 139.53 54.56 139.21 51.62 138.88 48.56 138.27 45.51 137.65 42.78 136.74 40.04 135.83 38.4 134.71M153.6 77.96L153.6 138.12 143.97 138.12 143.97 128.6 143.73 128.6Q137.74 139.53 125.17 139.53 103.67 139.53 103.67 113.92L103.67 77.96 113.24 77.96 113.24 112.39Q113.24 131.42 127.81 131.42 134.86 131.42 139.41 126.22 143.97 121.03 143.97 112.63L143.97 77.96"
450
- }
451
- )
452
- ]
453
- }
454
- );
455
- }
456
- const SubiektOrderWidget = ({ data }) => {
457
- var _a, _b, _c, _d;
458
- const { t, i18n } = reactI18next.useTranslation("subiekt");
459
- const lang = i18n.language || "en";
460
- const q = useSubiektOrder(data.id);
461
- const send = useSubiektSendOrder(data.id);
462
- const issue = useSubiektIssueDocument(data.id);
463
- const retry = useSubiektRetry();
464
- const documents = ((_a = q.data) == null ? void 0 : _a.documents) ?? [];
465
- const tasks = ((_b = q.data) == null ? void 0 : _b.tasks) ?? [];
466
- const sales = (_c = q.data) == null ? void 0 : _c.salesDocument;
467
- const create = tasks.find((task) => task.kind === "order.create");
468
- const documentTask = tasks.find((task) => task.kind === "order.document");
469
- const hasZk = documents.some((d) => d.kind === "ZK" && d.status !== "canceled");
470
- const hasSales = documents.some((d) => (d.kind === "FS" || d.kind === "PA") && d.status !== "canceled");
471
- const busy = (create == null ? void 0 : create.status) === "pending" || (create == null ? void 0 : create.status) === "running";
472
- const documentBusy = documentTask ? ["pending", "running", "unknown"].includes(documentTask.status) : false;
473
- const canceled = data.status === "canceled";
474
- const offerIssue = Boolean(sales && sales.option !== "none" && sales.supported && hasZk && !hasSales && !documentBusy && !canceled);
475
- const onSend = async () => {
476
- try {
477
- await send.mutateAsync();
478
- ui.toast.success(t("widget.sent"));
479
- } catch (err) {
480
- ui.toast.error(t("toast.error", { error: errorMessage(err) }));
481
- }
482
- };
483
- const onIssue = async (kind) => {
484
- try {
485
- await issue.mutateAsync(kind);
486
- ui.toast.success(t("widget.issued"));
487
- } catch (err) {
488
- ui.toast.error(t("toast.error", { error: errorMessage(err) }));
489
- }
490
- };
491
- const onRetry = async (id) => {
492
- try {
493
- await retry.mutateAsync(id);
494
- ui.toast.success(t("toast.retried"));
495
- void q.refetch();
496
- } catch (err) {
497
- ui.toast.error(t("toast.error", { error: errorMessage(err) }));
498
- }
499
- };
500
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
501
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
502
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
503
- /* @__PURE__ */ jsxRuntime.jsx(SubiektIcon, { width: 18, height: 18, className: "shrink-0" }),
504
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("widget.title") }),
505
- ((_d = q.data) == null ? void 0 : _d.mode) === "demo" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "purple", children: t("widget.demo") }) : null
506
- ] }),
507
- /* @__PURE__ */ jsxRuntime.jsx("a", { href: "/app/subiekt", className: "txt-compact-small text-ui-fg-interactive hover:text-ui-fg-interactive-hover", children: t("widget.more") })
508
- ] }),
509
- q.isLoading ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
510
- documents.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: documents.map((d) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
511
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [
512
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "font-mono", children: d.number }),
513
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
514
- fmtDateTime(d.issuedAt, lang),
515
- ", ",
516
- t(`documents.sources.${d.source}`, { defaultValue: d.source })
517
- ] }),
518
- d.kind === "FS" && d.status !== "canceled" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: d.ksefNumber ? "break-all font-mono text-ui-fg-subtle" : "text-ui-fg-muted", children: d.ksefNumber ? t("widget.ksef", { number: d.ksefNumber }) : t("widget.ksefWaiting") }) : null
519
- ] }),
520
- /* @__PURE__ */ jsxRuntime.jsx(DocumentStatusBadge, { status: d.status })
521
- ] }, d.id)) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: (create == null ? void 0 : create.status) === "waiting" ? t("widget.waiting") : t("widget.none") }) }),
522
- tasks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: tasks.map((task) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
523
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
524
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: task.kind === "order.document" && (task.documentKind === "fs" || task.documentKind === "pa") ? t(`tasks.documentKinds.${task.documentKind}`) : t(`tasks.kinds.${task.kind}`) }),
525
- /* @__PURE__ */ jsxRuntime.jsx(TaskStatusBadge, { status: task.status })
526
- ] }),
527
- task.buyer ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: task.buyer.source === "retail" ? t("tasks.buyer.retail") : t(`tasks.buyer.${task.buyer.source}`, { name: task.buyer.name ?? task.buyer.symbol ?? "?", nip: task.buyer.nip ?? "?" }) }) : null,
528
- task.warnings.map((w) => /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: w }, w)),
529
- task.lastError && task.status !== "succeeded" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: task.status === "failed" ? "text-ui-tag-red-text" : "text-ui-fg-muted", children: task.lastError }) : null,
530
- task.status === "unknown" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: t("tasks.unknownHint") }) : null,
531
- task.manualAction ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: t("tasks.manual") }) : null,
532
- task.status === "failed" ? /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", isLoading: retry.isPending && retry.variables === task.id, onClick: () => onRetry(task.id), children: t("actions.retry") }) }) : null
533
- ] }, task.id)) }) : null,
534
- !hasZk && !busy && !canceled && (create == null ? void 0 : create.status) !== "failed" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", isLoading: send.isPending, onClick: onSend, children: t("widget.send") }) }) : null,
535
- offerIssue && sales ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: [
536
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: sales.writerActive ? t("widget.autoOn", { after: sales.after.toUpperCase() }) : t("widget.autoOff") }),
537
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
538
- sales.option === "fs" || sales.option === "auto" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", isLoading: issue.isPending && issue.variables === "fs", onClick: () => onIssue("fs"), children: t("widget.issueFs") }) : null,
539
- sales.option === "pa" || sales.option === "auto" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", isLoading: issue.isPending && issue.variables === "pa", onClick: () => onIssue("pa"), children: t("widget.issuePa") }) : null
540
- ] })
541
- ] }) : null
542
- ] })
543
- ] });
544
- };
545
- adminSdk.defineWidgetConfig({
546
- zone: "order.details.side.after"
547
- });
548
- const NBSP = " ";
549
- const NBHY = "‑";
550
- const SHORT = /(^|[\s("„])(oraz|albo|lub|ale|że|bo|czy|gdy|aby|by|więc|jak|na|do|za|ze|we|od|po|to|[aiouwze])[ \t]+/gi;
551
- function nb(text) {
552
- let out = text;
553
- for (let k = 0; k < 2; k++) out = out.replace(SHORT, `$1$2${NBSP}`);
554
- out = out.replace(/(\d) (?=\d{3}\b)/g, `$1${NBSP}`);
555
- out = out.replace(/\b([eE])-(?=mail)/g, `$1${NBHY}`);
556
- return out.replace(/(\d) (zł|€|Kč|EUR|USD|PLN|CZK|mln|tys\.|cm|mm|m²|%)/g, `$1${NBSP}$2`);
557
- }
558
- function typeset(value) {
559
- if (typeof value === "string") return nb(value);
560
- if (Array.isArray(value)) return value.map((v) => typeset(v));
561
- if (value && typeof value === "object") {
562
- return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, typeset(v)]));
563
- }
564
- return value;
565
- }
566
- function usePageNav(tabs) {
567
- const [params, setParams] = reactRouterDom.useSearchParams();
568
- const raw = params.get("view");
569
- const view = raw === "guide" || raw === "settings" ? raw : "panel";
570
- const asked = params.get("tab") ?? "";
571
- const tab = tabs.includes(asked) ? asked : tabs[0];
572
- const go = (next, nextTab) => {
573
- const p = new URLSearchParams(params);
574
- if (next === "panel") p.delete("view");
575
- else p.set("view", next);
576
- if (next === "settings") p.set("tab", nextTab ?? tab);
577
- else p.delete("tab");
578
- setParams(p, { replace: true });
579
- };
580
- return { view, tab, go };
581
- }
582
- const VIEWS = ["panel", "guide", "settings"];
583
- const VIEW_ICON = { panel: /* @__PURE__ */ jsxRuntime.jsx(icons.ChartBar, {}), guide: /* @__PURE__ */ jsxRuntime.jsx(icons.BookOpen, {}), settings: /* @__PURE__ */ jsxRuntime.jsx(icons.CogSixTooth, {}) };
584
- function PageTabs({ value, onChange, labels }) {
585
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", className: "flex flex-wrap items-center gap-1", children: VIEWS.map((v) => {
586
- const on = v === value;
587
- return /* @__PURE__ */ jsxRuntime.jsxs(
588
- "button",
589
- {
590
- type: "button",
591
- role: "tab",
592
- "aria-selected": on,
593
- onClick: () => onChange(v),
594
- className: ui.clx(
595
- "txt-compact-small-plus inline-flex items-center gap-x-1.5 rounded-md px-2.5 py-1.5 outline-none transition-fg focus-visible:shadow-borders-focus",
596
- on ? "bg-ui-bg-base text-ui-fg-base shadow-borders-base" : "text-ui-fg-subtle hover:bg-ui-bg-base-hover hover:text-ui-fg-base"
597
- ),
598
- children: [
599
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("flex", on ? "text-ui-fg-interactive" : "text-ui-fg-muted"), children: VIEW_ICON[v] }),
600
- labels[v]
601
- ]
602
- },
603
- v
604
- );
605
- }) });
606
- }
607
- function OtherActions({ items, label }) {
608
- if (items.length === 1) {
609
- const a = items[0];
610
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: a.loading, disabled: a.disabled, onClick: a.onClick, children: [
611
- a.icon,
612
- a.label
613
- ] });
614
- }
615
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
616
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", children: [
617
- label,
618
- /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronDownMini, {})
619
- ] }) }),
620
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Content, { align: "end", children: items.map((a) => /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Item, { disabled: a.disabled || a.loading, onClick: a.onClick, className: "gap-x-2", children: [
621
- a.icon,
622
- a.label
623
- ] }, a.key)) })
624
- ] });
625
- }
626
- function IntegrationHeader({
627
- icon,
628
- title,
629
- by,
630
- badges,
631
- description,
632
- social,
633
- help,
634
- view,
635
- onView,
636
- labels,
637
- primary,
638
- actions = []
639
- }) {
640
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
641
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 pb-5 pt-5", children: [
642
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between", children: [
643
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2.5 gap-y-1.5", children: [
644
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0", children: icon }),
645
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: title }),
646
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: by }),
647
- badges ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-wrap items-center gap-1.5", children: badges }) : null
648
- ] }),
649
- help ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0", children: help }) : null
650
- ] }),
651
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-3xl text-ui-fg-subtle", children: description }),
652
- social ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2 pt-0.5", children: social }) : null
653
- ] }),
654
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-t border-ui-border-base bg-ui-bg-subtle px-6 py-2.5 md:flex-row md:items-center md:justify-between", children: [
655
- /* @__PURE__ */ jsxRuntime.jsx(PageTabs, { value: view, onChange: onView, labels }),
656
- primary || actions.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
657
- actions.length ? /* @__PURE__ */ jsxRuntime.jsx(OtherActions, { items: actions, label: labels.more }) : null,
658
- primary ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "primary", isLoading: primary.loading, disabled: primary.disabled, onClick: primary.onClick, children: [
659
- primary.icon,
660
- primary.label
661
- ] }) : null
662
- ] }) : null
663
- ] })
664
- ] });
362
+ function IntegrationHeader({
363
+ icon,
364
+ title,
365
+ badges,
366
+ featured,
367
+ description,
368
+ points,
369
+ social,
370
+ help,
371
+ view,
372
+ onView,
373
+ labels,
374
+ primary,
375
+ actions = []
376
+ }) {
377
+ const plain2 = isWhiteLabel();
378
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
379
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 pb-5 pt-5", children: [
380
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between", children: [
381
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2.5 gap-y-1.5", children: [
382
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0", children: icon }),
383
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: title }),
384
+ featured && !plain2 || badges ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-wrap items-center gap-1.5", children: [
385
+ featured && !plain2 ? /* @__PURE__ */ jsxRuntime.jsx(FeaturedBadge, { url: featured.url, labels: featured.labels }) : null,
386
+ badges
387
+ ] }) : null
388
+ ] }),
389
+ help && !plain2 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0", children: help }) : null
390
+ ] }),
391
+ points && points.some(Boolean) ? /* @__PURE__ */ jsxRuntime.jsx(KeyPoints, { items: points, label: description }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-3xl text-ui-fg-subtle", children: description }),
392
+ social && !plain2 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2 pt-0.5", children: social }) : null
393
+ ] }),
394
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 border-t border-ui-border-base bg-ui-bg-subtle px-6 py-2.5 md:flex-row md:items-center md:justify-between", children: [
395
+ /* @__PURE__ */ jsxRuntime.jsx(PageTabs, { value: view, onChange: onView, labels }),
396
+ primary || actions.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
397
+ actions.length ? /* @__PURE__ */ jsxRuntime.jsx(OtherActions, { items: actions, label: labels.more }) : null,
398
+ primary ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "primary", isLoading: primary.loading, disabled: primary.disabled, onClick: primary.onClick, children: [
399
+ primary.icon,
400
+ primary.label
401
+ ] }) : null
402
+ ] }) : null
403
+ ] })
404
+ ] });
665
405
  }
666
406
  function ModeBadge({ color, label, title, children }) {
667
407
  if (!children) return /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color, children: label });
@@ -676,130 +416,31 @@ function ModeBadge({ color, label, title, children }) {
676
416
  ] })
677
417
  ] });
678
418
  }
679
- const host = (url) => {
680
- try {
681
- return new URL(url).host.replace(/^www\./, "");
682
- } catch {
683
- return url;
684
- }
685
- };
686
- const STAR = "M10 1.5l2.6 5.3 5.9.9-4.25 4.1 1 5.85L10 14.9l-5.25 2.75 1-5.85L1.5 7.7l5.9-.9L10 1.5z";
687
- function Stars({ rating, scale = 5, size = 12 }) {
688
- const fill = Math.max(0, Math.min(1, rating / (scale || 5))) * 100;
689
- const row = (color) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex gap-x-px", style: { color }, children: [0, 1, 2, 3, 4].map((i) => /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 20 20", "aria-hidden": true, children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: STAR, fill: "currentColor" }) }, i)) });
690
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex shrink-0", "aria-hidden": true, children: [
691
- row("var(--fg-disabled)"),
692
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-y-0 left-0 overflow-hidden", style: { width: `${fill}%` }, children: row("#F5A524") })
693
- ] });
694
- }
695
- function SourceMark({ review, height = 10 }) {
696
- if (!review.icon) {
697
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: review.source });
698
- }
699
- return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "inline-flex shrink-0 items-center rounded-full bg-white px-2 py-1 shadow-borders-base", children: /* @__PURE__ */ jsxRuntime.jsx("img", { src: review.icon, alt: review.source, style: { height, width: "auto" } }) });
700
- }
701
- function StoreIcon({ reference, size }) {
702
- const box = { width: size, height: size };
703
- return reference.icon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: reference.icon, alt: "", width: size, height: size, style: box, className: "shrink-0 rounded-md bg-white object-contain shadow-borders-base" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { style: box, className: "txt-compact-xsmall-plus flex shrink-0 items-center justify-center rounded-md bg-ui-bg-base text-ui-fg-base shadow-borders-base", children: reference.name.slice(0, 1).toUpperCase() });
704
- }
705
- function meanRating(items) {
706
- const reviews = items.map((r) => r.review).filter((r) => Boolean(r));
707
- if (reviews.length === 0) return null;
708
- const value = reviews.reduce((sum, r) => sum + r.rating / (r.scale || 5) * 5, 0) / reviews.length;
709
- return { value: Math.round(value * 10) / 10, first: reviews[0] };
710
- }
711
- function ReferencesBadge({ items, labels }) {
712
- if (items.length === 0) return null;
713
- const mean = meanRating(items);
714
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
715
- /* @__PURE__ */ jsxRuntime.jsx(ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
716
- "button",
717
- {
718
- type: "button",
719
- className: "inline-flex h-9 max-w-full items-center gap-x-3 rounded-full border border-ui-border-base bg-ui-bg-component py-1 pl-1.5 pr-3 outline-none transition-fg hover:bg-ui-bg-component-hover focus-visible:shadow-borders-focus",
720
- children: [
721
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center", children: items.slice(0, 3).map((r, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("rounded-md", i > 0 && "-ml-2"), children: /* @__PURE__ */ jsxRuntime.jsx(StoreIcon, { reference: r, size: 24 }) }, r.url)) }),
722
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus truncate text-ui-fg-base", children: labels.count }),
723
- mean ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-x-2 border-l border-ui-border-base pl-3", children: [
724
- /* @__PURE__ */ jsxRuntime.jsx(Stars, { rating: mean.value, size: 13 }),
725
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus tabular-nums text-ui-fg-base", children: labels.rating(mean.value) }),
726
- /* @__PURE__ */ jsxRuntime.jsx(SourceMark, { review: mean.first, height: 10 })
727
- ] }) : null,
728
- /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronDownMini, { className: "-ml-1 shrink-0 text-ui-fg-muted" })
729
- ]
730
- }
731
- ) }),
732
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover.Content, { align: "start", sideOffset: 8, className: "w-[min(460px,calc(100vw-32px))] p-0", children: [
733
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-0.5 border-b border-ui-border-base px-4 py-3", children: [
734
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "text-ui-fg-base", children: labels.title }),
735
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: labels.subtitle })
736
- ] }),
737
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex max-h-[60vh] flex-col divide-y divide-ui-border-base overflow-y-auto", children: items.map((r) => {
738
- var _a, _b;
739
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-col gap-y-2 px-4 py-3", children: [
740
- /* @__PURE__ */ jsxRuntime.jsxs("a", { href: r.url, target: "_blank", rel: "noreferrer", className: "group flex items-center gap-x-3", children: [
741
- /* @__PURE__ */ jsxRuntime.jsx(StoreIcon, { reference: r, size: 32 }),
742
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
743
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "truncate text-ui-fg-base", children: r.name }),
744
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "truncate text-ui-fg-interactive group-hover:text-ui-fg-interactive-hover", children: host(r.url) })
745
- ] }),
746
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "ml-auto shrink-0 text-ui-fg-muted group-hover:text-ui-fg-interactive" })
747
- ] }),
748
- r.review ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
749
- /* @__PURE__ */ jsxRuntime.jsx(Stars, { rating: r.review.rating, scale: r.review.scale }),
750
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-xsmall-plus tabular-nums text-ui-fg-base", children: labels.rating(r.review.rating / (r.review.scale || 5) * 5) }),
751
- /* @__PURE__ */ jsxRuntime.jsx(SourceMark, { review: r.review }),
752
- r.review.url ? /* @__PURE__ */ jsxRuntime.jsxs("a", { href: r.review.url, target: "_blank", rel: "noreferrer", className: "txt-compact-xsmall-plus inline-flex items-center gap-x-0.5 text-ui-fg-interactive hover:text-ui-fg-interactive-hover", children: [
753
- labels.review,
754
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "h-3.5 w-3.5" })
755
- ] }) : null
756
- ] }) : null,
757
- ((_a = r.review) == null ? void 0 : _a.quote) ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "border-l-2 border-ui-border-strong pl-2 italic text-ui-fg-subtle", children: [
758
- nb(r.review.quote),
759
- r.review.author ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "not-italic text-ui-fg-muted", children: [
760
- " ",
761
- r.review.author
762
- ] }) : null
763
- ] }) : null,
764
- r.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: nb(r.description) }) : null,
765
- ((_b = r.metrics) == null ? void 0 : _b.length) || r.since ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-1.5", children: [
766
- (r.metrics ?? []).map((m) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "green", children: [
767
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: m.value }),
768
- " ",
769
- m.label
770
- ] }, m.label)),
771
- r.since ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: labels.since(r.since) }) : null
772
- ] }) : null,
773
- (r.links ?? []).length ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-x-3 gap-y-1", children: (r.links ?? []).map((l) => /* @__PURE__ */ jsxRuntime.jsxs("a", { href: l.url, target: "_blank", rel: "noreferrer", className: "txt-compact-xsmall-plus inline-flex items-center gap-x-0.5 text-ui-fg-interactive hover:text-ui-fg-interactive-hover", children: [
774
- l.label,
775
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "h-3.5 w-3.5" })
776
- ] }, l.url)) }) : null
777
- ] }, r.url);
778
- }) })
779
- ] })
780
- ] });
419
+ function FeaturedBadge({ url, labels }) {
420
+ return /* @__PURE__ */ jsxRuntime.jsx(
421
+ "a",
422
+ {
423
+ href: url,
424
+ target: "_blank",
425
+ rel: "noopener noreferrer",
426
+ title: labels.title,
427
+ "aria-label": `${labels.badge}. ${labels.title}`,
428
+ className: "inline-flex rounded-full outline-none transition-fg hover:opacity-80 focus-visible:shadow-borders-focus",
429
+ children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", rounded: "full", color: "green", className: "cursor-pointer gap-x-1", children: [
430
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Medusa, { className: "h-3 w-3" }),
431
+ labels.badge,
432
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "h-3 w-3 opacity-70" })
433
+ ] })
434
+ }
435
+ );
781
436
  }
782
- const KODA_DISCORD = "https://discord.gg/WzUUKYzu8";
437
+ const KODA_DISCORD = "https://koda.plus/discord";
783
438
  const KODA_EMAIL = "hello@koda.plus";
784
439
  const KODA_DEMO = "https://medusa.koda.plus";
785
440
  const plain = (text) => text.split(NBSP).join(" ");
786
- function communityLabels(t, integration) {
441
+ function communityLabels(t, _integration) {
787
442
  const k = (key, options) => t(`community.${key}`, options);
788
443
  return {
789
- addStore: {
790
- button: k("addStore.button"),
791
- title: k("addStore.title"),
792
- text: k("addStore.text"),
793
- name: k("addStore.name"),
794
- url: k("addStore.url"),
795
- note: k("addStore.note"),
796
- send: k("addStore.send"),
797
- copy: k("addStore.copy"),
798
- copied: k("addStore.copied"),
799
- hint: k("addStore.hint", { email: KODA_EMAIL }),
800
- subject: k("addStore.subject", { integration }),
801
- greeting: k("addStore.greeting", { integration })
802
- },
803
444
  prompt: {
804
445
  button: k("prompt.button"),
805
446
  title: k("prompt.title"),
@@ -808,87 +449,23 @@ function communityLabels(t, integration) {
808
449
  copied: k("prompt.copied"),
809
450
  failed: k("prompt.failed")
810
451
  },
811
- discord: { button: k("discord.button"), title: k("discord.title") }
452
+ discord: { button: k("discord.button"), title: k("discord.title") },
453
+ featured: { badge: k("featured.badge"), title: k("featured.title") }
812
454
  };
813
455
  }
814
- function AddStoreButton({ labels }) {
815
- const [name, setName] = react.useState("");
816
- const [url, setUrl] = react.useState("");
817
- const [note, setNote] = react.useState("");
818
- const ready = name.trim() !== "" && url.trim() !== "";
819
- const subject = plain(labels.subject);
820
- const body = plain(
821
- [labels.greeting, "", `${labels.name}: ${name.trim()}`, `${labels.url}: ${url.trim()}`, ...note.trim() ? ["", note.trim()] : []].join("\n")
822
- );
823
- const send = () => {
824
- window.location.href = `mailto:${KODA_EMAIL}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
825
- };
826
- const copy = async () => {
827
- try {
828
- await navigator.clipboard.writeText(`${KODA_EMAIL}
829
- ${subject}
830
-
831
- ${body}`);
832
- ui.toast.success(labels.copied);
833
- } catch {
834
- ui.toast.error(KODA_EMAIL);
835
- }
836
- };
837
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
838
- /* @__PURE__ */ jsxRuntime.jsx(ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
839
- "button",
840
- {
841
- type: "button",
842
- className: "txt-compact-small-plus inline-flex h-9 items-center gap-x-1.5 rounded-full px-3 text-ui-fg-subtle outline-none transition-fg hover:bg-ui-bg-base-hover hover:text-ui-fg-base focus-visible:shadow-borders-focus",
843
- children: [
844
- /* @__PURE__ */ jsxRuntime.jsx(icons.PlusMini, {}),
845
- labels.button
846
- ]
847
- }
848
- ) }),
849
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover.Content, { align: "start", sideOffset: 8, className: "w-[min(420px,calc(100vw-32px))] p-0", children: [
850
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1 border-b border-ui-border-base px-4 py-3", children: [
851
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "text-ui-fg-base", children: labels.title }),
852
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: labels.text })
853
- ] }),
854
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-4 py-4", children: [
855
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1.5", children: [
856
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "xsmall", weight: "plus", htmlFor: "koda-add-store-name", children: labels.name }),
857
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { id: "koda-add-store-name", size: "small", value: name, onChange: (e) => setName(e.target.value) })
858
- ] }),
859
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1.5", children: [
860
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "xsmall", weight: "plus", htmlFor: "koda-add-store-url", children: labels.url }),
861
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { id: "koda-add-store-url", size: "small", type: "url", placeholder: "https://", value: url, onChange: (e) => setUrl(e.target.value) })
862
- ] }),
863
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1.5", children: [
864
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "xsmall", weight: "plus", htmlFor: "koda-add-store-note", children: labels.note }),
865
- /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { id: "koda-add-store-note", rows: 3, value: note, onChange: (e) => setNote(e.target.value) })
866
- ] })
867
- ] }),
868
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 border-t border-ui-border-base px-4 py-3", children: [
869
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: labels.hint }),
870
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [
871
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", disabled: !ready, onClick: () => void copy(), children: [
872
- /* @__PURE__ */ jsxRuntime.jsx(icons.SquareTwoStack, {}),
873
- labels.copy
874
- ] }),
875
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "primary", disabled: !ready, onClick: send, children: [
876
- /* @__PURE__ */ jsxRuntime.jsx(icons.PaperPlane, {}),
877
- labels.send
878
- ] })
879
- ] })
880
- ] })
881
- ] })
882
- ] });
883
- }
884
456
  function envNames(code) {
885
457
  const names = /* @__PURE__ */ new Set();
886
458
  for (const m of code.matchAll(/process\.env\.([A-Z][A-Z0-9_]*)/g)) names.add(m[1]);
887
459
  for (const m of code.matchAll(/^([A-Z][A-Z0-9_]*)=/gm)) names.add(m[1]);
888
460
  return [...names];
889
461
  }
462
+ function pinnedPackage(spec) {
463
+ const version = spec.version ?? (spec.pkg === KIT_META.pkg ? KIT_META.version : null);
464
+ return version && /^\d+\.\d+\.\d+(-[0-9A-Za-z.-]+)?$/.test(version) ? `${spec.pkg}@${version}` : spec.pkg;
465
+ }
890
466
  function buildSetupPrompt(spec, lang) {
891
467
  const code = (text) => "`" + text + "`";
468
+ const pinned = pinnedPackage(spec);
892
469
  const env = envNames(`${spec.config}
893
470
  ${spec.demo}`).map(code).join(", ");
894
471
  const needs = spec.needs.map((n) => `- ${plain(n)}`);
@@ -909,16 +486,16 @@ ${spec.demo}`).map(code).join(", ");
909
486
  "",
910
487
  "## Kroki",
911
488
  "1. Zanim cokolwiek zmienisz, sprawdź projekt: Medusa 2.12 albo nowsza (tego wymagają strony i tłumaczenia panelu we wtyczce), menedżer pakietów projektu i medusa-config.ts. Jeśli coś blokuje instalację, zatrzymaj się i napisz mi, co.",
912
- `2. Zainstaluj wtyczkę menedżerem pakietów projektu, na przykład ${code(`npm install ${spec.pkg}`)}. Jeśli rejestr jej nie znajduje, zatrzymaj się i daj mi znać: dostęp daje Koda Plus (${KODA_EMAIL}, Discord ${KODA_DISCORD}).`,
489
+ `2. Zainstaluj wtyczkę w tej wersji menedżerem pakietów projektu, na przykład ${code(`npm install ${pinned}`)}. Potem sprawdź pochodzenie paczki: ${code(`npm view ${spec.pkg} dist-tags.latest`)} i ${code("npm audit signatures")}. Jeśli rejestr jej nie znajduje albo podpisy się nie zgadzają, zatrzymaj się i daj mi znać: pomaga Koda Plus (${KODA_EMAIL}, Discord ${KODA_DISCORD}).`,
913
490
  "3. Zarejestruj wtyczkę w medusa-config.ts, nie ruszając tego, co już tam jest. Użyj konfiguracji z Przewodnika wdrożenia:",
914
491
  "",
915
492
  ...config2,
916
493
  "",
917
- `4. Dodaj do opcji przełącznik trybu demo, tak jak w sklepie demo: ${code(spec.demo)}. Dopóki kluczy nie ma w .env, moduł pracuje na przykładowych danych i nie łączy się z ${service}.`,
494
+ `4. Dodaj do opcji przełącznik trybu demo, tak jak w sklepie demo: ${code(spec.demo)}. Tryb demo działa tylko po jawnym włączeniu: wtedy moduł pracuje na przykładowych danych i nie łączy się z ${service}; bez niego i bez kluczy mówi „nieskonfigurowane” i nic nie robi.`,
918
495
  `5. Wpisz zmienne do .env i do środowiska hostingu, nigdy do kodu ani do gita: ${env}. Jeśli nie podałem Ci wartości, zostaw ją pustą i wypisz mi ją na końcu.`,
919
- `6. Uruchom migracje bazy (${code("npx medusa db:migrate")}), potem sklep, i otwórz ${spec.route} w panelu admina. Sprawdź, czy Panel, Przewodnik wdrożenia i Ustawienia otwierają się bez błędów w konsoli przeglądarki i w logu serwera.`,
920
- `7. Nie włączaj żadnego zapisu, czyli niczego, co zmienia dane w ${service} albo w sklepie. Każdy zapis uzbraja człowiek w Ustawieniach, po próbie na sucho; opcje tylko na to pozwalają.`,
921
- `8. Dopisz sekcję o tej integracji do notatek projektu dla agentów AI (CLAUDE.md albo AGENTS.md, zależnie od tego, czego używa projekt; jeśli nie ma żadnego, załóż CLAUDE.md): pakiet i jego wersja, gdzie są jego opcje w medusa-config.ts, zmienne środowiskowe, przełącznik demo, to, że zapisy uzbraja człowiek w Ustawieniach, że wdrożenie krok po kroku jest w panelu w Przewodniku wdrożenia, że pomoc jest na Discordzie (${KODA_DISCORD}) i że wtyczka zmienia się aktualizacją pakietu, nigdy edycją node_modules.`,
496
+ spec.migrations === false ? `6. Uruchom sklep i otwórz ${spec.route} w panelu admina (ta wtyczka nie ma własnych tabel, migracje nie są potrzebne). Sprawdź, czy Panel, Przewodnik wdrożenia i Ustawienia otwierają się bez błędów w konsoli przeglądarki i w logu serwera.` : `6. Uruchom migracje bazy (${code("npx medusa db:migrate")}), potem sklep, i otwórz ${spec.route} w panelu admina. Sprawdź, czy Panel, Przewodnik wdrożenia i Ustawienia otwierają się bez błędów w konsoli przeglądarki i w logu serwera.`,
497
+ spec.readOnly ? `7. Ta integracja tylko czyta z ${service}: nie ma zapisów do uzbrajania. Użyj klucza tylko do odczytu, jeśli ${service} go oferuje.` : `7. Nie włączaj żadnego zapisu, czyli niczego, co zmienia dane w ${service} albo w sklepie. Każdy zapis uzbraja człowiek w Ustawieniach, po próbie na sucho; opcje tylko na to pozwalają.`,
498
+ `8. Zaproponuj sekcję o tej integracji do notatek projektu dla agentów AI (CLAUDE.md albo AGENTS.md, zależnie od tego, czego używa projekt; jeśli nie ma żadnego, zaproponuj CLAUDE.md) i pokaż mi jej treść, zanim ją zapiszesz: pakiet i jego wersja, gdzie są jego opcje w medusa-config.ts, zmienne środowiskowe, przełącznik demo, to, że zapisy uzbraja człowiek w Ustawieniach, że wdrożenie krok po kroku jest w panelu w Przewodniku wdrożenia, że pomoc jest na Discordzie (${KODA_DISCORD}) i że wtyczka zmienia się aktualizacją pakietu, nigdy edycją node_modules.`,
922
499
  "",
923
500
  "Na koniec napisz mi, co zmieniłeś i co zostało po mojej stronie: konta i klucze, pierwsze połączenie w Ustawieniach i uzbrojenie zapisów."
924
501
  ].join("\n");
@@ -936,16 +513,16 @@ ${spec.demo}`).map(code).join(", ");
936
513
  "",
937
514
  "## Steps",
938
515
  "1. Before you change anything, check the project: Medusa 2.12 or newer (the plugin's admin pages and translations need it), the project's package manager and medusa-config.ts. If something blocks the install, stop and tell me what.",
939
- `2. Install the plugin with the project's package manager, for example ${code(`npm install ${spec.pkg}`)}. If the registry cannot find it, stop and tell me: Koda Plus gives access (${KODA_EMAIL}, Discord ${KODA_DISCORD}).`,
516
+ `2. Install this version of the plugin with the project's package manager, for example ${code(`npm install ${pinned}`)}. Then check where the package comes from: ${code(`npm view ${spec.pkg} dist-tags.latest`)} and ${code("npm audit signatures")}. If the registry cannot find it or the signatures do not verify, stop and tell me: Koda Plus helps (${KODA_EMAIL}, Discord ${KODA_DISCORD}).`,
940
517
  "3. Register the plugin in medusa-config.ts without touching what is already there. Use the setup from the Setup guide:",
941
518
  "",
942
519
  ...config2,
943
520
  "",
944
- `4. Add the demo switch to the options, as the demo store has it: ${code(spec.demo)}. Until the keys are in .env, the module works on sample data and never calls ${service}.`,
521
+ `4. Add the demo switch to the options, as the demo store has it: ${code(spec.demo)}. Demo mode runs only when switched on: then the module works on sample data and never calls ${service}; without it and without keys it says "Not configured" and does nothing.`,
945
522
  `5. Put the variables in .env and in the hosting's environment, never in code or in git: ${env}. If I did not give you a value, leave it empty and list it for me at the end.`,
946
- `6. Run the database migrations (${code("npx medusa db:migrate")}), then the store, and open ${spec.route} in the admin. Check that the Panel, the Setup guide and Settings open with no errors in the browser console or the server log.`,
947
- `7. Do not turn on any writer, that is anything that changes data in ${service} or in the store. A person arms each writer in Settings, after a dry run; the options only allow it.`,
948
- `8. Add a section about this integration to the project's notes for AI agents (CLAUDE.md or AGENTS.md, whichever the project uses; if neither exists, create CLAUDE.md): the package and its version, where its options sit in medusa-config.ts, the environment variables, the demo switch, that a person arms writers in Settings, that the step by step setup is in the admin under Setup guide, that help is on Discord (${KODA_DISCORD}), and that the plugin changes through package updates, never through edits in node_modules.`,
523
+ spec.migrations === false ? `6. Start the store and open ${spec.route} in the admin (this plugin has no tables of its own, no migrations needed). Check that the Panel, the Setup guide and Settings open with no errors in the browser console or the server log.` : `6. Run the database migrations (${code("npx medusa db:migrate")}), then the store, and open ${spec.route} in the admin. Check that the Panel, the Setup guide and Settings open with no errors in the browser console or the server log.`,
524
+ spec.readOnly ? `7. This integration only reads from ${service}: there are no writers to arm. Use a read-only key if ${service} offers one.` : `7. Do not turn on any writer, that is anything that changes data in ${service} or in the store. A person arms each writer in Settings, after a dry run; the options only allow it.`,
525
+ `8. Propose a section about this integration for the project's notes for AI agents (CLAUDE.md or AGENTS.md, whichever the project uses; if neither exists, propose CLAUDE.md) and show me its text before you save it: the package and its version, where its options sit in medusa-config.ts, the environment variables, the demo switch, that a person arms writers in Settings, that the step by step setup is in the admin under Setup guide, that help is on Discord (${KODA_DISCORD}), and that the plugin changes through package updates, never through edits in node_modules.`,
949
526
  "",
950
527
  "When you are done, tell me what you changed and what is left for me: accounts and keys, the first connection in Settings and arming the writers."
951
528
  ].join("\n");
@@ -962,7 +539,7 @@ function PromptButton({ spec, lang, labels }) {
962
539
  }
963
540
  };
964
541
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
965
- /* @__PURE__ */ jsxRuntime.jsx(ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", onClick: () => void copy(), children: [
542
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", onClick: () => setState("idle"), children: [
966
543
  /* @__PURE__ */ jsxRuntime.jsx(icons.Sparkles, {}),
967
544
  labels.button
968
545
  ] }) }),
@@ -1046,56 +623,6 @@ function SettingsView({
1046
623
  children
1047
624
  ] });
1048
625
  }
1049
- function References({ items, title, subtitle, openLabel, sinceLabel, reviewLabel, ratingLabel }) {
1050
- if (items.length === 0) return null;
1051
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1052
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1 px-6 py-4", children: [
1053
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: title }),
1054
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: subtitle })
1055
- ] }),
1056
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-3 px-6 py-4 md:grid-cols-2 xl:grid-cols-3", children: items.map((r) => {
1057
- var _a;
1058
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 rounded-lg border border-ui-border-base bg-ui-bg-component px-4 py-3", children: [
1059
- /* @__PURE__ */ jsxRuntime.jsxs("a", { href: r.url, target: "_blank", rel: "noreferrer", className: "group flex items-center gap-x-3", children: [
1060
- r.icon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: r.icon, alt: "", width: 36, height: 36, className: "h-9 w-9 shrink-0 rounded-md bg-white object-contain shadow-borders-base" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-medium-plus flex h-9 w-9 shrink-0 items-center justify-center rounded-md bg-ui-bg-base text-ui-fg-base shadow-borders-base", children: r.name.slice(0, 1).toUpperCase() }),
1061
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
1062
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "truncate text-ui-fg-base", children: r.name }),
1063
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "truncate text-ui-fg-interactive group-hover:text-ui-fg-interactive-hover", children: host(r.url) })
1064
- ] }),
1065
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "ml-auto shrink-0 text-ui-fg-muted group-hover:text-ui-fg-interactive" })
1066
- ] }),
1067
- r.review ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
1068
- /* @__PURE__ */ jsxRuntime.jsx(Stars, { rating: r.review.rating, scale: r.review.scale }),
1069
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-xsmall-plus tabular-nums text-ui-fg-base", children: (ratingLabel ?? ((v) => v.toFixed(1)))(r.review.rating / (r.review.scale || 5) * 5) }),
1070
- /* @__PURE__ */ jsxRuntime.jsx(SourceMark, { review: r.review }),
1071
- r.review.url && reviewLabel ? /* @__PURE__ */ jsxRuntime.jsxs("a", { href: r.review.url, target: "_blank", rel: "noreferrer", className: "txt-compact-xsmall-plus inline-flex items-center gap-x-0.5 text-ui-fg-interactive hover:text-ui-fg-interactive-hover", children: [
1072
- reviewLabel,
1073
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "h-3.5 w-3.5" })
1074
- ] }) : null
1075
- ] }) : null,
1076
- r.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: nb(r.description) }) : null,
1077
- ((_a = r.metrics) == null ? void 0 : _a.length) || r.since ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
1078
- (r.metrics ?? []).map((m) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "green", children: [
1079
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: m.value }),
1080
- " ",
1081
- m.label
1082
- ] }, m.label)),
1083
- r.since ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: sinceLabel(r.since) }) : null
1084
- ] }) : null,
1085
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-auto flex flex-col gap-y-1 border-t border-ui-border-base pt-2", children: [
1086
- (r.links ?? []).map((l) => /* @__PURE__ */ jsxRuntime.jsxs("a", { href: l.url, target: "_blank", rel: "noreferrer", className: "txt-compact-small inline-flex w-fit items-center gap-x-1 text-ui-fg-interactive hover:text-ui-fg-interactive-hover", children: [
1087
- l.label,
1088
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "shrink-0" })
1089
- ] }, l.url)),
1090
- /* @__PURE__ */ jsxRuntime.jsxs("a", { href: r.url, target: "_blank", rel: "noreferrer", className: "txt-compact-small-plus inline-flex w-fit items-center gap-x-1 text-ui-fg-interactive hover:text-ui-fg-interactive-hover", children: [
1091
- openLabel,
1092
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "shrink-0" })
1093
- ] })
1094
- ] })
1095
- ] }, r.url);
1096
- }) })
1097
- ] });
1098
- }
1099
626
  function GuideIntro({ title, text, time, needs, needsLabel, timeLabel }) {
1100
627
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1101
628
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: [
@@ -1261,6 +788,830 @@ function GuideFaq({ title, items }) {
1261
788
  ] }, it.q))
1262
789
  ] });
1263
790
  }
791
+ const TEXT$1 = {
792
+ en: {
793
+ search: "Search",
794
+ empty: "Nothing here yet",
795
+ now: "Now",
796
+ next: "In a moment",
797
+ counted: "Done",
798
+ stopped: "Stopped",
799
+ queued: "Waiting for a free slot on the server",
800
+ ready: "Ready",
801
+ error: "Error",
802
+ pctDone: "done",
803
+ pctError: "error",
804
+ pctQueued: "queued",
805
+ pctRunning: "working",
806
+ running: (time) => `running ${time}`,
807
+ left: (time) => `about ${time} left`,
808
+ clean: "no errors",
809
+ of: "of",
810
+ waiting: "waiting",
811
+ log: "Log",
812
+ retry: "Try again"
813
+ },
814
+ pl: {
815
+ search: "Szukaj",
816
+ empty: "Na razie pusto",
817
+ now: "Teraz",
818
+ next: "Za chwilę",
819
+ counted: "Gotowe",
820
+ stopped: "Przerwane",
821
+ queued: "Czekam na wolne miejsce na serwerze",
822
+ ready: "Gotowe",
823
+ error: "Błąd",
824
+ pctDone: "gotowe",
825
+ pctError: "błąd",
826
+ pctQueued: "w kolejce",
827
+ pctRunning: "liczę",
828
+ running: (time) => `trwa ${time}`,
829
+ left: (time) => nb(`zostało ok. ${time}`),
830
+ clean: "bez błędów",
831
+ of: "z",
832
+ waiting: "czeka",
833
+ log: "Przebieg",
834
+ retry: "Spróbuj ponownie"
835
+ }
836
+ };
837
+ function useKitText() {
838
+ const { i18n } = reactI18next.useTranslation();
839
+ const pl2 = String((i18n == null ? void 0 : i18n.language) ?? "en").startsWith("pl");
840
+ return { text: pl2 ? TEXT$1.pl : TEXT$1.en, locale: pl2 ? "pl-PL" : "en-GB" };
841
+ }
842
+ const DOT = {
843
+ green: "bg-ui-tag-green-icon",
844
+ orange: "bg-ui-tag-orange-icon",
845
+ red: "bg-ui-tag-red-icon",
846
+ blue: "bg-ui-tag-blue-icon",
847
+ grey: "bg-ui-tag-neutral-icon",
848
+ purple: "bg-ui-tag-purple-icon"
849
+ };
850
+ const ICON = {
851
+ green: "text-ui-tag-green-icon",
852
+ orange: "text-ui-tag-orange-icon",
853
+ red: "text-ui-tag-red-icon",
854
+ blue: "text-ui-tag-blue-icon",
855
+ grey: "text-ui-fg-muted",
856
+ purple: "text-ui-tag-purple-icon"
857
+ };
858
+ function ToneBadge({ tone = "grey", children, icon, dot = false, title, size = "2xsmall" }) {
859
+ if (dot) {
860
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { title, className: "txt-compact-small inline-flex items-center gap-x-1.5 whitespace-nowrap text-ui-fg-subtle", children: [
861
+ /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: ui.clx("size-1.5 shrink-0 rounded-full", DOT[tone]) }),
862
+ children
863
+ ] });
864
+ }
865
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size, color: tone, title, className: "whitespace-nowrap", children: icon ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-x-1 [&_svg]:size-3 [&_svg]:shrink-0", children: [
866
+ icon,
867
+ children
868
+ ] }) : children });
869
+ }
870
+ function FilterBar({ children, className }) {
871
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.clx("flex flex-wrap items-center gap-2 bg-ui-bg-subtle px-6 py-2.5", className), children });
872
+ }
873
+ function FilterButton({
874
+ icon,
875
+ label,
876
+ count,
877
+ active,
878
+ attention,
879
+ onClick,
880
+ title,
881
+ disabled
882
+ }) {
883
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: active ? "primary" : "secondary", "aria-pressed": active, onClick, title, disabled, className: "shrink-0 gap-x-1.5 whitespace-nowrap [&_svg]:size-4", children: [
884
+ icon,
885
+ label,
886
+ typeof count === "number" ? /* @__PURE__ */ jsxRuntime.jsx(
887
+ "span",
888
+ {
889
+ className: ui.clx(
890
+ "txt-compact-xsmall-plus rounded-full px-1.5 tabular-nums",
891
+ active ? "bg-white/20" : attention && count > 0 ? "bg-ui-tag-orange-bg text-ui-tag-orange-text" : "bg-ui-bg-component text-ui-fg-muted"
892
+ ),
893
+ children: count
894
+ }
895
+ ) : null
896
+ ] });
897
+ }
898
+ function FilterDivider() {
899
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "mx-1 h-4 w-px shrink-0 bg-ui-border-base" });
900
+ }
901
+ function useDebouncedValue(value, ms = 300) {
902
+ const [out, setOut] = react.useState(value);
903
+ react.useEffect(() => {
904
+ const t = setTimeout(() => setOut(value), ms);
905
+ return () => clearTimeout(t);
906
+ }, [value, ms]);
907
+ return out;
908
+ }
909
+ function SearchInput({ value, onChange, placeholder, className, autoFocus, label }) {
910
+ const { text } = useKitText();
911
+ return /* @__PURE__ */ jsxRuntime.jsx(
912
+ ui.Input,
913
+ {
914
+ size: "small",
915
+ type: "search",
916
+ autoFocus,
917
+ "aria-label": label ?? placeholder ?? text.search,
918
+ placeholder: placeholder ?? text.search,
919
+ value,
920
+ onChange: (e) => onChange(e.target.value),
921
+ className: ui.clx("w-full sm:w-64", className)
922
+ }
923
+ );
924
+ }
925
+ function RowActions({ actions, className }) {
926
+ const shown = actions.filter((a) => !a.hidden);
927
+ if (!shown.length) return null;
928
+ const stop = (e) => e.stopPropagation();
929
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("inline-flex items-center justify-end gap-0.5", className), onClick: stop, children: shown.map((a) => {
930
+ const icon = a.loading ? /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, { className: "animate-spin" }) : a.icon;
931
+ const tone = a.danger ? "text-ui-tag-red-icon" : "text-ui-fg-subtle";
932
+ if (a.href && !a.disabled) {
933
+ return /* @__PURE__ */ jsxRuntime.jsx(
934
+ "a",
935
+ {
936
+ href: a.href,
937
+ title: a.label,
938
+ "aria-label": a.label,
939
+ ...a.external ? { target: "_blank", rel: "noreferrer" } : {},
940
+ className: ui.clx("inline-flex size-7 items-center justify-center rounded-md outline-none transition-fg hover:bg-ui-bg-base-hover focus-visible:shadow-borders-focus", tone),
941
+ children: icon
942
+ },
943
+ a.key
944
+ );
945
+ }
946
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", variant: "transparent", title: a.label, "aria-label": a.label, disabled: a.disabled || a.loading, onClick: () => {
947
+ var _a;
948
+ return (_a = a.onClick) == null ? void 0 : _a.call(a);
949
+ }, className: tone, children: icon }, a.key);
950
+ }) });
951
+ }
952
+ function EmptyState({ icon, title, points, action, compact = false, className }) {
953
+ const { text } = useKitText();
954
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.clx("flex flex-col items-center justify-center gap-y-2 px-6 text-center", compact ? "py-5" : "py-10", className), children: [
955
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex size-9 items-center justify-center rounded-lg border border-ui-border-base bg-ui-bg-component text-ui-fg-muted shadow-elevation-card-rest [&_svg]:size-5", children: icon }) : null,
956
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "text-ui-fg-subtle", children: title ?? text.empty }),
957
+ points ? /* @__PURE__ */ jsxRuntime.jsx(KeyPoints, { items: points, className: "max-w-full justify-center" }) : null,
958
+ action ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-1", children: action }) : null
959
+ ] });
960
+ }
961
+ function EmptyTableRow({ cols, ...props }) {
962
+ return /* @__PURE__ */ jsxRuntime.jsx("tr", { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: cols, children: /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { compact: true, ...props }) }) });
963
+ }
964
+ function Section({
965
+ id,
966
+ icon,
967
+ title,
968
+ badges,
969
+ points,
970
+ pointsLabel,
971
+ description,
972
+ actions,
973
+ children,
974
+ className
975
+ }) {
976
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { id, className: ui.clx("scroll-mt-4 divide-y p-0", className), children: [
977
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-start justify-between gap-3 px-6 py-4", children: [
978
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-y-1.5", children: [
979
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2 gap-y-1", children: [
980
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 text-ui-fg-subtle [&_svg]:size-[18px]", children: icon }) : null,
981
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: title }),
982
+ badges ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-wrap items-center gap-1.5", children: badges }) : null
983
+ ] }),
984
+ points ? /* @__PURE__ */ jsxRuntime.jsx(KeyPoints, { items: points, label: pointsLabel }) : null,
985
+ description ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-small min-w-0 text-ui-fg-subtle", children: description }) : null
986
+ ] }),
987
+ actions ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", children: actions }) : null
988
+ ] }),
989
+ children
990
+ ] });
991
+ }
992
+ const GRID = {
993
+ 2: "md:grid-cols-2",
994
+ 3: "md:grid-cols-3",
995
+ 4: "md:grid-cols-4",
996
+ 5: "md:grid-cols-3 xl:grid-cols-5",
997
+ 6: "md:grid-cols-3 xl:grid-cols-6",
998
+ 7: "md:grid-cols-4 xl:grid-cols-7"
999
+ };
1000
+ function StatTiles({ children, columns = 4, className }) {
1001
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: ui.clx("grid grid-cols-2 gap-3 px-6 py-4", GRID[columns], className), children });
1002
+ }
1003
+ function StatTile({
1004
+ label,
1005
+ value,
1006
+ hint,
1007
+ tone = "grey",
1008
+ icon,
1009
+ active = false,
1010
+ onClick,
1011
+ title
1012
+ }) {
1013
+ const body = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1014
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-x-2", children: [
1015
+ icon ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("flex shrink-0 [&_svg]:size-3.5", ICON[tone]), children: icon }) : /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: ui.clx("size-1.5 shrink-0 rounded-full", DOT[tone]) }),
1016
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "truncate text-ui-fg-subtle", children: label })
1017
+ ] }),
1018
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-xlarge-plus max-w-full break-words tabular-nums text-ui-fg-base", children: value }),
1019
+ hint ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: hint }) : null
1020
+ ] });
1021
+ const cls = ui.clx(
1022
+ "flex h-full min-w-0 flex-col items-start gap-y-1 rounded-lg border px-4 py-3 text-left transition-fg",
1023
+ active ? "border-ui-border-interactive bg-ui-bg-base shadow-borders-interactive-with-active" : "border-ui-border-base bg-ui-bg-subtle"
1024
+ );
1025
+ return onClick ? /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-pressed": active, title, onClick, className: ui.clx(cls, !active && "hover:bg-ui-bg-base-hover"), children: body }) : /* @__PURE__ */ jsxRuntime.jsx("div", { title, className: cls, children: body });
1026
+ }
1027
+ function runFromSteps(steps, startedAt, log = []) {
1028
+ var _a;
1029
+ const all = Object.values(steps);
1030
+ const status = all.some((s) => s.status === "error") ? "error" : all.some((s) => s.status === "running") ? "running" : all.length && all.every((s) => s.status === "done") ? "done" : all.some((s) => s.status === "done") ? "running" : "queued";
1031
+ return {
1032
+ status,
1033
+ started_at: new Date(startedAt).toISOString(),
1034
+ finished_at: status === "done" || status === "error" ? (/* @__PURE__ */ new Date()).toISOString() : null,
1035
+ steps,
1036
+ log,
1037
+ error: ((_a = all.find((s) => s.status === "error")) == null ? void 0 : _a.note) ?? null
1038
+ };
1039
+ }
1040
+ function formatDuration(ms) {
1041
+ const s = Math.max(0, Math.round(ms / 1e3));
1042
+ return s >= 60 ? `${Math.floor(s / 60)} min ${String(s % 60).padStart(2, "0")} s` : `${s} s`;
1043
+ }
1044
+ const GRID_STAGES = {
1045
+ 3: "grid-cols-3",
1046
+ 4: "grid-cols-2 sm:grid-cols-4",
1047
+ 5: "grid-cols-3 lg:grid-cols-5",
1048
+ 6: "grid-cols-3 lg:grid-cols-6"
1049
+ };
1050
+ function StagedLoader({ run, stages, doneTitle, columns = 6, onRetry }) {
1051
+ const { text, locale } = useKitText();
1052
+ const [openLog, setOpenLog] = react.useState(false);
1053
+ const [now, setNow] = react.useState(Date.now());
1054
+ const live = run.status === "running" || run.status === "queued";
1055
+ react.useEffect(() => {
1056
+ if (!live) return;
1057
+ const t = setInterval(() => setNow(Date.now()), 500);
1058
+ return () => clearInterval(t);
1059
+ }, [live]);
1060
+ const share = (key) => {
1061
+ const s = run.steps[key] ?? { status: "queued" };
1062
+ if (s.status === "done" || s.status === "error") return 1;
1063
+ if (s.status === "running") return s.total ? Math.min(1, (s.done ?? 0) / s.total) : 0.3;
1064
+ return 0;
1065
+ };
1066
+ const weights = stages.reduce((sum, e) => sum + e.weight, 0) || 1;
1067
+ const pct = Math.round(stages.reduce((sum, e) => sum + e.weight * share(e.key), 0) / weights * 100);
1068
+ const start = new Date(run.started_at).getTime();
1069
+ const end = run.finished_at ? new Date(run.finished_at).getTime() : now;
1070
+ const elapsed = Math.max(0, end - start);
1071
+ const left = run.status === "running" && pct >= 5 && pct < 100 ? elapsed * (100 - pct) / pct : null;
1072
+ const current = stages.find((e) => {
1073
+ var _a;
1074
+ return ((_a = run.steps[e.key]) == null ? void 0 : _a.status) === "running";
1075
+ });
1076
+ const cs = current ? run.steps[current.key] : null;
1077
+ const log = run.log ?? [];
1078
+ const number = (n) => new Intl.NumberFormat(locale).format(n);
1079
+ const R = 46;
1080
+ const C = 2 * Math.PI * R;
1081
+ const ring = run.status === "error" ? "var(--tag-red-icon)" : run.status === "done" ? "var(--tag-green-icon)" : "var(--fg-interactive)";
1082
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "status", "aria-live": "polite", className: "flex flex-col gap-y-4 px-6 py-5", children: [
1083
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-6 rounded-xl border border-ui-border-base bg-ui-bg-subtle p-5 sm:flex-row", children: [
1084
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative size-32 shrink-0", children: [
1085
+ /* @__PURE__ */ jsxRuntime.jsxs("svg", { viewBox: "0 0 110 110", className: "size-32 -rotate-90", "aria-hidden": true, children: [
1086
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "55", cy: "55", r: R, fill: "none", stroke: "var(--border-base)", strokeWidth: "9" }),
1087
+ /* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "55", cy: "55", r: R, fill: "none", stroke: ring, strokeWidth: "9", strokeLinecap: "round", strokeDasharray: C, strokeDashoffset: C * (1 - pct / 100), style: { transition: "stroke-dashoffset .6s ease" } })
1088
+ ] }),
1089
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute inset-0 flex flex-col items-center justify-center", children: [
1090
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "txt-xlarge-plus tabular-nums text-ui-fg-base", children: [
1091
+ pct,
1092
+ "%"
1093
+ ] }),
1094
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-xsmall text-ui-fg-muted", children: run.status === "done" ? text.pctDone : run.status === "error" ? text.pctError : run.status === "queued" ? text.pctQueued : text.pctRunning })
1095
+ ] })
1096
+ ] }),
1097
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-1 flex-col gap-y-2", children: [
1098
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "uppercase tracking-wide text-ui-fg-muted", children: run.status === "running" ? text.now : run.status === "queued" ? text.next : run.status === "done" ? text.counted : text.stopped }),
1099
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-2 [&_svg]:size-5", children: [
1100
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("flex shrink-0", run.status === "error" ? "text-ui-tag-red-icon" : run.status === "done" ? "text-ui-tag-green-icon" : "text-ui-fg-interactive"), children: current ? current.icon : run.status === "error" ? /* @__PURE__ */ jsxRuntime.jsx(icons.XCircleSolid, {}) : run.status === "queued" ? /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircleSolid, {}) }),
1101
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "large", weight: "plus", className: "truncate", children: current ? current.name : run.status === "done" ? doneTitle ?? text.ready : run.status === "queued" ? text.queued : run.error ?? text.error })
1102
+ ] }),
1103
+ (cs == null ? void 0 : cs.total) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
1104
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-2 overflow-hidden rounded-full bg-ui-bg-component", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-full rounded-full bg-ui-fg-interactive transition-all", style: { width: `${Math.min(100, Math.round((cs.done ?? 0) / cs.total * 100))}%` } }) }),
1105
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "tabular-nums text-ui-fg-subtle", children: [
1106
+ number(cs.done ?? 0),
1107
+ " ",
1108
+ text.of,
1109
+ " ",
1110
+ number(cs.total),
1111
+ cs.note ? `, ${cs.note}` : ""
1112
+ ] })
1113
+ ] }) : (cs == null ? void 0 : cs.note) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: cs.note }) : null,
1114
+ /* @__PURE__ */ jsxRuntime.jsx(
1115
+ KeyPoints,
1116
+ {
1117
+ items: [
1118
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), text: text.running(formatDuration(elapsed)) },
1119
+ left !== null && { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Sparkles, {}), text: text.left(formatDuration(left)), tone: "blue" },
1120
+ run.status === "done" && { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircleSolid, {}), text: text.clean, tone: "green" }
1121
+ ]
1122
+ }
1123
+ )
1124
+ ] })
1125
+ ] }),
1126
+ /* @__PURE__ */ jsxRuntime.jsx("ol", { className: ui.clx("grid gap-2", GRID_STAGES[columns]), children: stages.map((e) => {
1127
+ const s = run.steps[e.key] ?? { status: "queued" };
1128
+ const p = s.total ? Math.min(100, Math.round((s.done ?? 0) / s.total * 100)) : s.status === "done" ? 100 : 0;
1129
+ return /* @__PURE__ */ jsxRuntime.jsxs(
1130
+ "li",
1131
+ {
1132
+ className: ui.clx(
1133
+ "relative flex min-w-0 flex-col gap-1 overflow-hidden rounded-lg border px-3 py-2.5",
1134
+ s.status === "running" ? "border-ui-border-interactive bg-ui-bg-highlight shadow-borders-interactive-with-active" : s.status === "done" ? "border-ui-tag-green-border bg-ui-tag-green-bg" : s.status === "error" ? "border-ui-tag-red-border bg-ui-tag-red-bg" : "border-ui-border-base bg-ui-bg-base opacity-70"
1135
+ ),
1136
+ children: [
1137
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center justify-between gap-1", children: [
1138
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("flex [&_svg]:size-4", s.status === "running" ? "text-ui-fg-interactive" : s.status === "done" ? "text-ui-tag-green-icon" : s.status === "error" ? "text-ui-tag-red-icon" : "text-ui-fg-muted"), children: e.icon }),
1139
+ s.status === "done" ? /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircleSolid, { className: "size-4 text-ui-tag-green-icon" }) : s.status === "running" ? /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, { className: "size-4 animate-spin text-ui-fg-interactive" }) : s.status === "error" ? /* @__PURE__ */ jsxRuntime.jsx(icons.XCircleSolid, { className: "size-4 text-ui-tag-red-icon" }) : null
1140
+ ] }),
1141
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "truncate", children: e.short }),
1142
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "truncate tabular-nums text-ui-fg-subtle", children: s.total ? `${number(s.done ?? 0)} / ${number(s.total)}` : s.done !== void 0 ? number(s.done) : s.status === "queued" ? text.waiting : s.note ?? "" }),
1143
+ s.status === "running" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-x-0 bottom-0 h-0.5 bg-ui-fg-interactive transition-all", style: { width: `${p}%` } }) : null
1144
+ ]
1145
+ },
1146
+ e.key
1147
+ );
1148
+ }) }),
1149
+ log.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "rounded-lg border border-ui-border-base", children: [
1150
+ /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", "aria-expanded": openLog, onClick: () => setOpenLog((v) => !v), className: "flex w-full items-center justify-between rounded-lg px-3 py-2 text-left hover:bg-ui-bg-base-hover", children: [
1151
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", weight: "plus", className: "uppercase tracking-wide text-ui-fg-muted", children: [
1152
+ text.log,
1153
+ " (",
1154
+ log.length,
1155
+ ")"
1156
+ ] }),
1157
+ /* @__PURE__ */ jsxRuntime.jsx(icons.TriangleRightMini, { className: ui.clx("text-ui-fg-muted transition-transform", openLog && "rotate-90") })
1158
+ ] }),
1159
+ openLog ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-xsmall flex max-h-56 flex-col gap-y-0.5 overflow-y-auto rounded-b-lg border-t border-ui-border-base bg-ui-bg-subtle px-3 py-2 font-mono text-ui-fg-subtle", children: log.map((l, i) => /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1160
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-muted", children: new Date(l.at).toLocaleTimeString(locale) }),
1161
+ " ",
1162
+ l.text
1163
+ ] }, i)) }) : null
1164
+ ] }) : null,
1165
+ run.status === "error" && (run.error || onRetry) ? /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "error", label: text.error, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-wrap items-center justify-between gap-2", children: [
1166
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: run.error }),
1167
+ onRetry ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", onClick: onRetry, children: [
1168
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
1169
+ text.retry
1170
+ ] }) : null
1171
+ ] }) }) : null
1172
+ ] });
1173
+ }
1174
+ const TILE = '<rect width="192" height="192" rx="40" fill="#FFFFFF"/><rect x="0.75" y="0.75" width="190.5" height="190.5" rx="39.25" fill="none" stroke="#000000" stroke-opacity="0.1" stroke-width="1.5"/><image href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKkAAAAsCAYAAAAeqJhEAAAACXBIWXMAAAPoAAAD6AG1e1JrAAAgAElEQVR4nO29d3jV55UuulS2urTpYBvHNT5JPONknHPTnjkZnySTMkl8M3dOZjJzfU9zzjMTD+4GJLR7UwNjx3biJLjbFIEAUSXUtbWrGh1swGCatrTrr375773P+rYASdg4U5zJKX+sRwjQ/pXv/da31rvetURCCJpppmleNUXNUVoI+kAIimaMtzrSAi+OXoZv8BwebT+M2q4jaAidxNunk+hKCZzIia+mhCDD1EkxVMrxV2GQKsxZ1/h9mXwGPUspXacLuqDTilh8PC0eOJowHjyTFTUfaIIu6jnK6DqZ+r/utQ0zN8uEUGeY8Xt9B4ZhkK7rNCUEnVKV5QdTxiPHTPGdw5p46JQilk9lDdIyuX+TNfpd7LqHUfUcCU2Qqms0IQS1n7yMv30jiJqnN6Gitgs1jn6U2LpR5u5HibMXZY5elNt7UV3fjfu8PRK844nMk7lskhQtS1kzR4o5QVlhUE6YpDNgzU/wocxrz6PrKqlGhkaEaPjRxlFUPbkV1fb9KHfuR6VjP/5kXSe6E/pvU2aOVKGSKgzSTYOE+U+/R3Pa5PeGSQYDVc+QMKc3gGaQaWqkiCwpDFyDv/+kN69JqhDTANVpIKke+9Kzu7DEtwfzAvuwwL8Nn/Jvgat/DKf1xGJeI753fnbjDxWkum5QLqfRRVOlzg8y+O4vOjGvdhOqfUEUNxxDiSOMQlsQFncEhc4wyB1CoSuEImcIFmcIhc4+lNoOYPmanVjRFsRhw3wokbhMQs0vkjRjGqif8IOZpk66kaOkoZP7wCHMW9mKsrpulDgGUeAeRLFzEKUrd+CRtigSQpAmFFLNfz5IZ75HwzQpKwRNqFOUEwrlDIWyelqCWFEEmYb4vYE0Z5ikmXmH88O1WzHP3o0la4exqLEfVQ0jWNhyCJ917sTusxr+oEGaB6hOmqbTRVPQ+vgZLF+zGWW2/bC4e1HoHECBM4wCVwxkD6PYHUORIwpyR0GuKApcURQyUP09KHQNotwfRVltN+7z7MKWoxdxUWikaxqJnC6BmvvEjzuDTKGQbmRo0jDpH9rGULRqH4pccRQ4YyB3DOSKodQbxddf2I8PFE16uX8RSHUzvwFNgxRTp1xGpTNpreZgIvvIySnt/gspnSZNQUmhU87Ufn+e1BSkihydE4K+6GnH/Jb3UNV4CIubI5i3LgxLyzCW+trx88Pv/2GD9ErMougavTQ0ik/V7UZpwyGQM4ZizyjKAsMSfGQflF602BZEpSOCAlfek1ocIRQ7h0DuMIo8cZCzH8XeLhR7BzB/TRsCPWO4fAWoqi6P/k8SoEJoZIoc6UaaErk0/bctwyio7UYRPw9vLrmporC4Q/jK2jYkOQzR9X8ZSDWThG7Iz8gIndw97+IeXxusvv1Y2tSLT3l34QfPbkPofLYjo/+ePKnJpxaDNEvv6eKuf+/djkr/CKpbDqE6MIAlDd2oXn8YtzYfwLqR43+4IDWFSZohKKNq9Mrhi1i88h2UuWIodo6jyDGMAmcURa5BFLn6UenuBTn6YfGNotwxikJXBMXuIRS7+mDx9KHQ3Q9yB2UYwECo9DOIg1iyZjPeOHIGuqmQqZuUM9VP7IFM0yDD0EgVmrxOylDooc0xFNu6YXEMyee5YsWuEP50/T5c4uPe0CVwfnfw5DeayQtqZihlXEmQUrTt/Swq7QdQ6hxCoTcM8g+gyhdEhbMXD77egwmO/a+CQf8EF9iUIOVk7aQu7r+3uQ/zvBFUBUZhbYjD2hhEVWMECwO9+PnYqU8MpIapys/j+DhjsvPIv19d18gQ+ST9hiA1hEGaEMSZ3n1Pv455dT0oqOsB2XpAclHZ+4RR6uhDgTuG4uY4qDkCCkRAnj4UBaIobzmCIv84yD2aP0oZpI4+FNl7QPY4PtUYx9+/tiP/EkydhJr4Xw6k/A4NvqaWoEDXGCrt3SjlGN4TBfmDKK4PosIdw+2rXsd5Tkz/NwKpaRoyDufPVYwsCZElTeRkrH7lvd/onZNuqJTSBT3VEYd1xT5Y1kRQZO8E2Q6g0BOWIC21DaPa1oMl9h4sr9+Mr6zfji82bcOXG1pxX9Me1Kxsg9U5II/SAlc+oSJPHCXOMIqdw1i6cgeeHziIjMjvHKFl/pcDKYNBNwxKKpMUGDqOSlsfSh1RFHpiIF8YJc4QyBbC7c5WvK+L0v+dQKqrE3LdJw1B55nSZDpQ6IuZEhOaLkOtK+/9w949ZXIpSpiCPut+HZWroihwRED2faD6XhAfV64RVNRGcbe3F6/Gz4I505SZJlVXKKtm6aIQ1DlhYMXWMG627UeFswfkHgJ5j6Hadwjz7P34m9eCOC3E4pSellmv4F31SYFUGJKn1YRGigSpSg9tisFi60GxfVAmeVes2BXGn67fL0HKlJvBO57td2IfzBkgzUlPms5kKCdyVN97CNV2pufCMiQq8odQyiePN4a7/TtxjpMZw5gGg/E7Xsu8es1/CkiNGSD9bHMfrBKkI6hpiGFewxCqGqISpM9/QiBlRuOcqdMroeP4Xksb7rO/ic87NuJLja2o3z+OE2nxVU16WmZjrr3X2SA1cjSeE08uWbMHFlcvipyDKGSPY+ed34dKbw8+79uGoYzoS5iKXHRN12WSoGgapXSNLhs6nddN2vneJP440IoqVy9KXGFYVu7Cf94cxwWmXoQxy2YWDf41EwgGKZsudNJNjdKmTn/3ThQljl4U2ftkrHzFilxRfP25LlwWBmUV9u7GHPvdr8vPpPE7MVRy9Y6joJavxeHPQZArjmJ7F8gbwt3123F52nNzkiZPlo+47rV3Y340SM05NuezeBMxSE8Y4qt3t/Si2hdGtX8EVQ0xLPCHJVgXNPRh/fjpfzWQ8iaX62AYlDNNaj2RwL2eNixaO4IFTQO4Y30Pbn92FHc3d6B+WxRcABJajlT9I0CaMExqO5XFAi9n5JFZIGVvU7HiTWw8PAEmugVTNZqe5wJlIJwhzciSoeXIUFVKaSoFp4zwz97uxXfWvgNXz0GcEOKrDADmRmfaHwJIi10RPPBcJybY6+ZSkludbdff50ffMx/1XF3T6J3x97D46R1Y7A6jyhVFmS2IIv9Byc1+/xddmPodQHqluGJI5sW8aobxcff0u4PU2hCWXxcG+vDC6I1BOnf9rnvvM+9DrkH+CE8Kg/z97+NPXohj8c+PY8naQdy2th9LGmJYui6MP3u2R25aoedIlZ70+vCHMkJQc88IKuz7UOwYmAXSYs8hLHn0bRxNiQd15Vq8drWyIjT5oXxMGoYgTXJygtJCpylDpaSmUEpR5FF4w4f6NwKpxRnGN9bvQ0IopOWmZCw724yPtOvu2RA0qbFHVeh9U5R+9zdxzH+6DVZbD6rtPbA+tRX3erfjnaPMchg3BOnMUqaua6Tpmaumz7kv/oyZ9k8BaXVTGJWNMSz29+EXwzcGqTrnJJz73me9H1OfLo3rNCF0Wt19GJ97LojFzx7G7S0RLGsJ4ya+bssg7vXuwlkZzyvTIZByPUinDJ1su4Mote1DiYsTiwEU28ModIRA9iHc/MyrOG6KB0xTIUNT5eKxS5YufRpghozLTOnemZvjB9RNvvD038n/f610KGkHQ5CqaaQz8a2rlFWVfJWIy5P8Vb7wa2XO2abKjcGLwC9DNXQS0xkk6wQUISjHG0bXKGPo9Hdvx1DCG9AWnBWTWtwx/Nmze5EWWRJakgQ/20xTctOVMkFCyQPR4MxcM0llzzYNMrlpDUFpQ+TLv7pK5zWDgpeT4T0XJ7Dj/Dn0nUpcOJszKSl44yjy3vhUkicU6xt0/ixebJVysjAgSNMMShsGKUqCNHOKckaChJ6lnJKjFIdeIklJ+ayazJaz04mSwhtUKCQMZTpxUuioLh68tXEP5jeMocofRXVjDBUNEdQEgpjfEMKvR9+bA1JeW87G82vGSSgnebqe/0yN75GdgZaRToH/nOP/x2EPA1TjcDBDl3SFVg+ex13rBrDsxZNYFhjBrc0x3NRyCLc0B/E533YZowt1Uq6ZJsvmbLy2+VI1JZQcbXkvgSr7PpTLbL4fFlsEhY4wLL4YFq3ehP6keVrVpkjVmONiovzajv8om+txZgI07z0ylFUnKWkkKGtOkqlMkKmnKZNLk2Jo0tPIn/1QkDIgc2QaGdL1ZP6zsgwylbLpiySMtHx5vAHynjQGi2MQhbbZ2X2Rewj/8ZcHcJ4LDSJFWVOZZVwunRIGMYhzZppy5hSljSnKcP1deurZIE3lNMow7yyfMU2TuazcwGoyQ2k1S4KrWsoUpZWU3KAGg5Q3G28yPUdKNkG6PkUiqVIyLeg9Ie569eApuPpP4v9+cS8+X/cO/sT/Nh7eNYyXDyYRS4gNWa5iTU1KgYjO5WeO6zhUESrpIp/QMUiP6OLHywPtWNB4CFUcizbGUd4QhdU/iHmNketAmmcrOMTIU0ZCpEnNTZKiZCmbVSR4snqOclqKhMiRoaekFzR4UwtB2ewUpXIJ4nhzxYFzuGvdEBavZ2CO4daWGJasHcPNzRHc09AhPalhpCTA+Z5NXg9TkSBnr01pLU3hKdE+b/UOlDi6Z4GUM9OKuj346bYYmDpgwpoXj73XPwekvKBXjiVFF3QpK2gsIWpjCWXDobT+8AlF/+pllevNej7bZi88TfzODRUMI0tTQpUKrXhavNQzKZT+hHE6Pqm/xHXqtJqWYEkJnX6yMSbDmAL7HArK3o8vvxjEqyez6LioY8cZZZbtuiDQc1Eoh6bEw+dVQQnTpER6ivRckkwtOxukJi8Mg1vIhTmXydJwTjy7KyXQnhM4aogHPzD5vjRStays7vFxKI9+9tgiRxNKkjjJ3PbuFP7y1x2oWvVLFLtfQ0ljO8rWh0EtoyBPFOWNw7DU96Dsic34o8Y22INn5GmXZq1AlgGf38g5of6LQJoPY1KU1pJ0Jp2uOZQRD3dcMLH3nIquKRMH0gJdCYEjmvjxlKQWU/LalzRBsUR6Q8eFLHpyQvn2xiO4tSWKhWvHcfO6GG5aF8GStXEsbYnjluYoNicEui4JHJgQGEgYx7omdIwL8eQFkz24TqSbaTojRM2ylVtR5e2ZDdI1fSh1h1H25DtoHDyJhJmVxwwLFuTx+k8A6RWAsodk++m2cSxbsQkL6najvG4bSh5/E19buxFdZxNIc4mWQwFmET4EpPwSU0qGhiaNvu8/146Fde0otXWjyrYHVSv34QfPdeBwUn8oY+o0KXT6602xfFl3Dk8qy7iBIMjeiVJfH0o8PbOsuGkAVL8TxWtascDbjofeHkT7uRyY57uimLoK0ukF5rj8vUzmrr96M4IFq1tR5uhBiTuI4tq9+IJ3F3YfvwjV0ChnsNfNJxdpRaWJbJqiWfHWT94ZwmLHTlR746B6rtoNo8gZRrkrhEpnP6rdQ6gIHESx7wiKHDHMC8RgtXfjs+42/Po9Had0ZfmVTJ81BP9ckMqf402lTNERxfjxip3jWLp6M6rcPVjaMoBlTR2Y3xTCfOcBfNq+HTtPppDITko54PrBE7jPvxXLXPtx57PDuLmxD4ubYrjpuSNYuHYQS9eHsGRdBItaRrGg5RhuahrALf4QljQfxh1r41je1Is/btiChr2jyBoaSbDxsfafntsEi2sIpW4m74OgNf0o8YdBnggK3WEsrt+Jx3f04aQq7ld1lSbUlKzFp0SGFD1NQtGnY6HpI9rMe0+5I+VD66QpOqVSSXp9+AxK6jtQ6BtAAZcNHUFplU0H8ZWW3TLb4ziTj3T9Q6kggy6nUvRft46B7L2weIZQ7GRvGQat3I9FDWN44sBhpFXOLgX97WtRlNT3osA1G6SFjhgK7XmxCXuomUlV3sKzrMITQtnqXXhwQw8GLueOqZyJZi8Rf00JRZaW00qGXhg+i1JbF0rsIRS5Iij0Dslrl3ji+JaMgZkF4DCCk60MGcoU9V4WU/f6OlBe14kiT/SaeWMoaxhGqS+KUk8Q5W6uXAVRwaecK4YyrgL6QijxDqLKFcRj20+BeW8OhRLMNshwSZcx6W3N3aj0hVDhG0ZFQwyV7giqG8NY5ArjV2PvI83/V0nJUIFLtzkzR2dyyZqH3hzCPH8Y1Y3DqGgaRWnzOMrXHZex7CJfP5atG8czu04hJzJ0UlHv/2xDB6zr+jG/JYaFTcewqGUEi1uGZxgnTcNY0nIQS9ceweKW8au2qGUMN62LY9naGL7q34aYkt5Ahq7LDH/XmUlUP/UOKuwxlK4OwVI7AIujHwVuLn/GYXENYN4arpjshLf/KMaT2pMTuTTpHKMoDNZprlDk6RsOfmeDVCNDF5TTVFrd2jkLpAVcjXEEUeiK4uYVL+KSeWOQmtNB+oO/7pEbaSZIi539qHCG8Zcb9oALBx8H0iJHPK/u8sRQ4I7ONtfwLCv2xlDii2G+Yx++4NyM1hNTuCQ9vSKz+pyaD/S9vUeuA2mJjzd7DPfWvYWLuklZLUeamaEM611V0fD1QBsWuQdQztfwDF61UvcgKpwRVHgiKPeHUeIPoZilk96IvJ8y1wiKPSNyA1Q5w7jpma2o3x6TNJduqjLxYZDykXxbc9cNQZoSLFQXZOo5MnMX6WRauf8nbwxikbsHNU1DsDYNYX5DGAv9USxtiKK8+Rhqmkaw3LML7eeSUMQEHZpMP3yPfS+sLTFYW0awqHkYi1pm2+KWuATqknVhLH02NA3avC1pieGmtcOwrjuEe7x78yCVCY0p6ANVoe+/2Ap6ZrusNLFQpNAdQoEzAnJF5PfldYOwMJdq68Ktnl78dHMM0YTxVlpNkakn8rEkC3pFRmbH8niXR4hBOTVLui5oUs3Qyh3dc0DKlS2mvGK49fGXMfGxntSUIP3hy10o8gRngdTiHYLFNogvBzYg83EgZV2CcxiF7jgKvDFZwpxl7tlG3mlpopePyTBuqduCtosmpjLsfdKUy2UoqeTI1n30OpDKCp57GHev3iirdqx1zWYuEicN3/x1CFZbByxS/zCMYs/gVSvyDMqyKgXCKGgMoTAwhCJ/EEW+CIp87ElZ5DOOEvcoqlyDWMjey7YXre/lkMomKKfnVWGHVfHQx4GUj3tmRtjDH05rD/3k1QGUOw6gsmkUNU0DmNc4iAWBISzyh3FTwxBqAnHc6d6DDUcSUpM7mT5Lh5PqQ59bsws1TaMobzmMhU0xLGxmi1+1ayCNYOmz4VkgXdYyimUtI5j33HHc5pkBUqEyt5ihkBAdX2raA+uanuk6dwwFjiiKHT0odnaAmoZAjgjK3eModgyi0h5EWe3b+M4v92HrCQNZQyfFzJAhJvP0B6t9OHvVmfNTJJfK2e8T22d7Ut4U7KGYFrp71au4ZHz8cZ8xTPr+Lw6AXAOzj3tnP8o8Efxf/t+ACxUfC1LXCIo8wyj0xa8HqTc4y4jjWls3ygMsSYyh0juALzVuxPsptTSVOiufOaVpVNd97ENA2oMC7xg+bWuT2aySnSQG0ZZ3NVTU7847hoajea/um2H+GCz+GCqdYcyr60cli7W9QZR6Iij1xFDm7UWxZzjvST0HUOjtR0HjYXxj7W4kNM6+mRZU6ZAiHv7Ux4GUY+3JszSiiIYvrt0jw4fKwBAWNvRiUSCIeQ0cy8ZQ2RRHWWMYd/r34a3DCXB7Tp6GVOhI0vzxF93tkuIqaTmBhQ2jEqgLZtjilui1477l6KzjflnLESxqiGPZC0fxR/62PEiZV+QMigPUtK5SMKGH77NvQ7XtAGr8I6A1g3kg1fei1B5GqT2EEtsALLZekJclfIOosA3CuqYX32jeif4zqdPSg5lZmtQUyd1JTpCV71qeElq5s1+ClFw9IA/HayEUuOMo9Pbhtkc3ylo6B/3CyMmY+frsXpdZ9F+81IFi9qSuoEwiiLsDPHy/IXx3/WZMMhUiTPqrVwZl4mGxh2fFnKWBOCoDYVjq2bP3oMrZN8uK67rlcWbxRVHoDqLIM4AiTy8KWeztjqPINYDy+k44Of7NcbgzSQk1SfUHDqGYVWDOQRTxaeSJSIljgT2Gu1zbwYmqSJn0vjJZ+o3n2mXla6ZxGELeQyh39eDmurfweMcpdE4JdCYE9icFWoYv4wtrO1D89FbM9w2i0D+MMk8Xinz9IGcQZc0juKV2H147mUZOpIjfw/GU+sBi7z5UBYKo8EdR7h9Gjeswij39sDpCeOXQB1JCGLqc6/hqS4cEc2XTMGr8w5jvDWF+w7BM4qyNw1jaHMF9LfvQevISmEHI5jIy32AajfOJpo6DuNOxF4vcQ1geCGFhQxyL1w5jyfo4lnCWv44/Iwpr0zg+FejB8sYIbl83hGVrB/Dv1sbwqaZ+3OVow8odIUwJjWSiw0cyZ5uKrlM6laPBtDb67xtaUV63X3o4XpBibxyl9lGU2OOw2COw2LllJN+GIfWmniFU+kZR/cQu1LaP41TGWK5Mx49pJUuGyJGiapQyNHpmR98nBtIi9yAKvSH86Bc7wV6UPff/8+ogytwhKTmcBVJnBPc/F0PDyBSeOzKJnx9PzrI1/Rfwww0RWFe2ocbHMeqolCtanBGUuKMokbHmMBY99jpOZ8XiNHOtQiFb5/HrQMpFkkJnXIKU6Tw9o1I0J95asGY7CrkdZ4ZV+cZR7ozitlUbsf2iQFomowoZaoKUyVPL02qCjgvxwMO7RzCvbrfUBhR4hkABDl96pK53kSuKb7x4AOwskqago2nlwcWe2SCd5z8GqyeM+c4OPHvwA3TkBD4T2IWFjTHU+NnLDqPaN4wabxDVDTFQ4DiqvDF8s2krIudTrUk9TYp2iRSW3cm1Viilp+iyIWj7ySx+cySNZ48m8LVXjmFJUwhLnj+IhU0RLODYtDkEa/MwPr9uEIF4As+PT6BlfAIvjU3iV0cS2HsuJZ2MpKCu8I6yBMfKeU2htNAoksi1PtQ6gOpnXkeVfQAVtjAsLJRgYQaDwRmU4CzgI9DNfUMDKOIs2D4Ky6pOfL1lB4IpEU7kEiS0SdJNrpSolNRVenp77ycG0mLngATGQ691yuQhJUz60WscS3MP1myQFnmH8J0N3bjI0sHclDwWZ5l6mTKmQnvOm7jftQ0V9iGZYLEnZTAVuYMoCYyjZvUevB27AG4NUYVC9fvf/VCQFrmGcbd7By5OJzU7LgrUODry/z7DyDaE8tV7EQi+j4tCnT6FWKWlUiajkGCKTs3RsaT6nS827kaFfwQlAU7+QigJhFHoG0S1axifbtyPi5msBNDBnPrIMm/nLJAWemOwuoZh9ffi7/afw71NezEvMITShmGU+aOo8kRR5YujKhBCjS+IBe5+PLBuP2KXsxvyzYUcKrIOIV9GzVchuVqXlnFwLjkhS+QrOi9hifsArC1jWMRHfiPLBAcxvzmKP38pinPME+uKFESbhkqKlqSMYeQVc7oxpxGPyWXmM1X2rCoxWNpO6/hMoBPk64HFPijlbVypKXb3SVUPcRlVJj688KOocEdRae+Tx+Jy5y5wG3RCdkoyRZOjpGnQyrYulNRzPMnJBJcqhyQNVOjpw+2PbfodQJqnb773UieKPUMSpLJ3ibN7R7/Uif73t/ukJ2WBw4MMUg93C8wGKQPtWy/1yh2rmNp0We+a8TUUNS298UlF3L+0fhfIx4nkEMgflSqxYncc8119+NmbfDRxf5NKq/eflMwInzKcfBIzJO5BWJzDuMOzQ1JsipGhl8cuY6G36zqQFvnisDyxEd0Z8VtDTJGpTlFGyVJKS5MipkgYE9Kr8uf8963DmOdmGi4kmY6CxjgKA2FUOEO4yb0HZ7MGJTWdxrJK7RWQlvkiKOcT0hNEmWMY1U0xWJ29qHENYj4LtN29KG1ibxpDlS+CMn8Q8zwd+OHLPYilxYZJjQsRXB6frpbJyqBJmsodsnnqMc0gzmmUMgU90n4Cd7UEUdk8inkNESxojMHaFMTC5gh+8HIEF5mB0Jhbn5Y+yjxJk5uRe8c+VCiQb8rjnqQ0pbSc5Nha4u/jT9ceQM1TW1EqifFBFPlHZYOeFKTYgih2sIo/IkErvczTA7jb9TpGL2VdWV2llMhSQhe0snUPSuu7Qa4+kHsABa6g7Kcq8PTijsc3S09zY5CakjT+7ktdsLiHpEfPdwSEpYiEQfrTTQN5T2rq9OCrHEvyRpjjST1D+PMXOzElr8Gl0XzJ9oqpZl7hpWgqJQ2N/sP6A1LQXV7fL70Vg7zYOSr55XtWvSYTRwb30x3HUMptNk6+r3zvF/mCKLHFcLN3u7yvrJ6llvBplHu6rzvuCxxhVNdux8YJgVgiu2FsIlsbT2RfikxlWwenkqPhiWR7+HKmvTOl4OHBBKpc+1HUEENpYxRFgRAKfTGUOgdwk7cbh7PioYSu06GM+vAtgS5U+jnpi6DMO4QK70FU+MbyiZQ/hnLuspi2skAMlXzkB4Io52SnuQ8hTXRkWVXPJ+6NhD7TnpVBxtTkf9k2huWBXlQxSJvD0oPOawnLrP/bLw5INoeTzrwKSrtOePQRJcdpoOqMZpWEkSHFTNIpTSzfcmIKD/y8C9W1O1FV3y2zTLL1ojwwOB0GTJsrhApHDPO9XfjpG70yDpsSOZpSdXqidd//FCDVTJVMncuYBqVMg/72dY69o6hcw6FO/yyQVj7cJCmvKV2jp/ccuSFIma5hHe/TO0Io8XRdD1JvBLRmLyprt+EW23YsqNuK+Wu2wlrPX3dgce0OLFm9A/Pqd6DI0YmK5jgKfGGUNYRng9TTjYMZ8ciUadLBtPLIzT4m82MocsckA5IH6Oj01zGZU1yxCt+I/L/VgXC+DBuI4uXYZQjBJeF/Y5DOBCoLmll6x4IFnUUWOYWymkYfGIJ2n0rhh+u3wfrUFswLjKKgjnug+iXguIWkkDPpZ7pQ0HAS1ifeQNuZi7isp+WCP9Xe8z8FSJn+4sZBTRfE1ZiH3jqAgsZRlNZHJB87E6Q1K54D168nGaS7D2wbVYgAABnsSURBVN8QpFJbIHL00K93oIhpozkglZ/LHKmbe6Ty3Kk01zCK3KMo8o5IIp8567JACEWePknwF/pCs0C6zN2Fg2nxCIc946nckzd5e1Dpi6PIHUeZJ4YKGZ+GpRdlb1rti1w1Bmgl/50/gnJ+5ucO4guubTgixI91KSr5NwbpTNJc2rQ6XNbiuReIkyzDII4lXhv/AEtXbsK8psMo4jJq/T4QL6AzgkJW57tDqKnvxg9e7pflOpaUPba1G6W2zjw36OJ+fuZfh1Hg6ccdj7V+LEj5XhKmQd/+RQeKfHmQMufJiREndFwc+IctQ7LixF7kh6/wgg9KemZWTOoaxPd+1SNBarCqao5GdJYWwTTp4U0hyVuy7raQW7fZ67ljqHAGUfXkC0iZGiWESav2HkWZjTcfJ1os1InO9qQsnBAa/eff7EaJJ1/Vm2kc8xdxDO0Oo8DDgItcNWIv6+dGyCioIYrCQAgF/hDIx9l9GGXuMZT6jqDEFcVCRzdiqtjACc5wOvfscm+fLKNaPGN5kHpCqPCEUc4xKidK7iEs9B9Hoe0Aqji58cRR7h9BpZ+ZkEHMax7Cit6TOJ+4ICuI6lVFm3Y1npQlcSNfadQMVTqT/2/bMdwc6EN1S54zZa2AtTmERS1xfP/lsDxZpArsamfBHD3pjUF6A2Er6xx1TfY4HZgS+Iq3DeVrOkF2XkAuN+ZByslDlW0At9VulrQUB/9PbuudBmnoXwBSnf58Bkg5u2cyv8jJhP0Qftb68SAtuAJS8fEgZfvpJvaI/Gx90yCNXgPpUy8gbVwB6TGU118BKb+H2IeAVKf/smEPSjwD14GUCyZs3G9WwJtdFh7yVuqIyTCq0hlDlSuOakdsllm9YZT5w6gK9GCRuw2HhHhY5Ewamkz1Lff2yAqVxTsiQcpHfpk3KpOoChkGhFG+7iAq14dQwJx4YBSlAeZKB2BtiMC6NoZ7vFtwNGM8aCjMMuSTJ9lXdgWk056UBSrqNEgf2noMywJ9qGrh9pEYrI1hWJumQfqrPEjNfy2QXqemZw2hkaGUmqOTWfP+z9paUcxyOFscZdKTMr3EBYAwrLVbEUtoGyaNHD3e2vN/QHoDkBZ7x1DiGZEt0BV85DP3O21cYeMQSRoXLmR4dc2YIiOOIb0HcEfTbpzQ01/VswaFM7n2W/09KGM2xBtHmZepKhanxFDONJOXaaEYFjk24nPP78E8TxiWhrg89q2+fpR6emTl7CZPJ1bvPgiuMElhOGt25w67mAPSn2w9isWBXpS1DMPKJP4nCdK5JkuW7BVy+djjqe0xlKzpRpE9itL6AQlS9jY8ZMJSvwtbDr0Pls490fp/POkNPanc6H2w1HeifM1elDv3XTWLfQ+K7LtRZN+DYsdeWGyzrdC+B1bbHnwpsBfNg5dwUUzJboK+ZPrCzd5OlHkGZQWNs3sKxPPVKt8IqjwjWG5rw55DlxHTxYY7nXth9fXJooDVy9l+P8qax2S36b2uHTiYyj6SYfWbqVGWqScWw0/rjCUdNQOkf731CBYFelDSEkdNU+SfA1J21fk5Rkycyn/g7E32z0zHHFf+fc4Pc0VJnTYWMrwych4lazpk9ljk6JIDzAr52LcPyzjnpfgx5IwcrdrRAeLjnnuO+MjnWMs2hCLnOO58/GV53HMjF7dv8DEy15tz8jUhDPr2LzunOVv+2eluAtZhOkL4H60RMM/JScMPfr0fVB9CmT80W09q78P3XgthSsoKP2T0IXsIoVJGZyW6oJ9u4lbtYRCP6vFGYeFwxs087QDKH38FWTVHXMZbvfMwSuz5455BZ+FrsVLJ1ofl7k5c4t4rkaHHtg6gxNkz657YLIE4ljh3Y8eFNIYm033hS+n20ESuYyih9Q1OqKODl5Wr1n8xdzo4oYbDk0Z7LCU2RJPKW0ez6oOXuMwtNMpKlXuaBib1Y4u9HSjz9KGEY1pvFIX+uIxt59vjuMOzHe2nM8gkVSndfKI9igXOTlid3G4ygJIGTrRiUlizwBvE6v3jOMexaJY53/RsTypzD4PU6dGhD6zvQ03LAMobYrJ1paYhBCsDNhDBj94MSz5bdi3IkFKZ7lO7NqVQIl5jpp9rsFpa9qeklKwECbfn8sVkP5HsVZqziDw2R87fzJJqZGnToYuoqtsHYrDwoDOmaSRIR0Cr9uOl4feQ1HV6ZtcgCus7pbcocOS7UskWRIl7HHc8/boUFefDCe7buZ514ECd25C/84vOfLlTgjQor0U2PhLD+IfWCKaYoTAF/eDlfShmIbe9d7Yy3x3EX/ymHxNcdzZSHyLeFtNktSq//+uX9qPUH0SBd0AWMnj4RaFnCGXOAVhXPA9OhrjC8vTO8RuClJvTmG90dx9GuWv2PcnN44pg8ZqdOK6KB7LcIKhOEmfUmp7Nm5a5aip3ILAmVcbULLEzyciqpGdTpCkpWaQwjTQFJ/XwdSD1xKQQZKmnF+6Rc7goWGuRoEvqeRpNJF3L12yTiSInVdW+QVT5h2QSVeGP43bXXowmNZdQGStzjnup7DdJk9VLQV/y74C1hWWHXCBgkUoY1maOTWP43q/78omTliMWu7N8kWcR5BmWK540p5ExlZAoPpYU39k4eha7TlyWVREWD/CxxI1xrKa/3tOwsiknSe+U0Mhz4Distj6p/LGwst3N1ShWUY1KsfDOs1PIaio92noAxWs6UVzPo3hCUmnFQpZS5whuq23F6KTqysrBYYq8h5lqf+Zv09mE1EfevvINFNvy3qzI1YtCexQFNtZhhrF6/yGkdIWSqk5/8+YAyuzcjNc/R08axJ8+1yU3Rf5ZZieGOR4+lkpIjSzTJF8OtMMS6EIhdzB4Y3KMDjMZlfYBfMX3DpLcU6QLerR95IYgnZTNgll65WgS1UzbzQWpM4KqVbsxnBTP8uAJRc1STtMoK1Vl002O08YNgXnjxjdulGOHwb1BPKgiSxrHjXqaQgm9Y4lnNkgLuEbvCWORvwOvHz0FbgCckkDJNzf+445RlPh6UOaLoiIwhHJ/UCZlpX5+9j481X4Yk+yt0/qHg1RXpVb5z5/vQE2gHxXuMdT4BmDlI58lfC3D+Pr6PXnBjaZSSuEjPyl70/JtRtMgTQqFJoVC3cncbz+z6nlUOCKYX9eBbza1YiyRquUWh9xHgpRdPcvhDHo3p9x7v2srrO4RUG03SrzdeZDK4WejuMm2A+8Kca+amaTfHHoflmmQslCl2BVHRWAYJbYo5j/6FvacnQBnybK9VcvOafHlqo5J3RP6b2sefUuGCOwRi9xdEqQV3ihKPCE0hFkfyUp5nf5++xjKbTFYA3OOVU8cCx97Az2nJ5W0cj17oYoUaUaSLgmTdpz6APNWbwXZd6GYq032uJxQwiCttg/gf2wJ4rI5JevZK3bFbwhSPt54HGPbBQEr6x7mgLTEMYQyWx+e2T4kF1A3UqSJrOzpl2HQhxjXvHWef8DvTDIj+WG+3DgpuI8tobfPBSk1szqMOw46sOPkZST0BKkZ/iyFMuIS7U9ouMO9TyrsqYHLrcwEBFHt6cOCln65pnsSCejK9SCVHcPcBSwE/bdtB+XAkPmBE7B6eiVIa7iKtXYUX25qw5hi1PKJleO4VEzJVnQJ0ulQj9KGSVuOTeEzru1YwKSwexBl9iAq6w/g06s24u2jU7K2zYKIa9wp94KnKZlKUEYYNJgTo9/6+R7U2LpkSZTV8aVMYtsOgFYOwdoQwjfXb5U1Wj4Sz+REzcJVW0D1QyhrPJ7n/zg2ZWG1vQNfq98sx/KktfNk6vn4hLsIWUzNYotTplj+vV/sRXn9PnmEsLyN6Sduw7Z4h7Hc14G9UwLsrTK6Sr8+eCYfA9uGUOgZQKkUosRAjhhq7P34j0275PUSPHSXj1GDp5nwCZGhy6ZGb4xO4LMr3pLTA+Xz2bn7lEnxPlDzMCqe2Yld7yalsj2rKPTo3hNzQMpzXYflZOxP+fswpfGmT9GIojUsqm2TM6IKAwdlmMS0WKEsOYcw/6m3Eeg/i3PT2bKi8OjM6WHE06bzWkjjrgCecWDIRj/ONXh8jTyRDJUiCbN1oXs/Sr08W2FICswpEEKFO4IK5x7sOpsG857co8VhDr9vHkC8av9RlDt7UBxgbQDX/COo9EZQ2sC0Xh9+tucQJgUPoEvlPbkk8qfbs+UwYYM8A6exeF0Q5Y3HMd8XRGVjH6qaRjHPF8Uyx168fjQh6cJcaoqyRo4mdT4JePOp+W7RwxnzoS+5NsPq6EVhbQ9K6g7AYhuCxTmOQlcc9Nhb+NYL27Bh9DR6PsgqsYzYcMgUD4+qwrXvfQP/2BpH9VNbZLsFS/ryk0EGpNSsojGOgjVDmO/YjNcOnkS+rzojk6yvN7Si4Jl9IHsURXaOXYekQKTE3ovFT7bjuy370Tsppo6a4sHzhia7KLnF98C5Kfwlx6JPvAOq65NAmwlSpk7uWbkBhxXjIe7hVwyFjgrx4C11b6CQr+MO5UHKuk1/XKrbFzj344u+zVgbOoy337uM/ZM69lxK46Xxi/ha8xaUr9qJEv/JPB/LugQnV5pioPoDKPMN4gvuVrA8TZECEEE/23/0Q0Aak015t/u7ZaKWySXoA9Ogv3ltABVrOlHKwh3/CAqYwGeBNfOd3j7U1O/AnStfwV/9ag9WbAvisd0jWLHrmtW2D2P1zjhW74xh1Y4Y6rYdhKt9DG/G35Mbjwf3mkqWwhN6+0LXPnm/XJH7SJDKxkIOsTTSNJNG08L1Wec2VPg58WSxyTRQm+KoaBzFnWtaMTAljsnp1QrPQ+DqZN6xcJbPbcp7zmdhrX0H1YEjsHpCmBcYhDUwimr/QVT7R7HM3or/tKETtgPD8PbG8ULkOLaeuCwTaCnV23c2gaW1O1DgjMteGktdTIKGu0aLbD0ocfVKjWJ5fResq7fCsuINFK/YAGvtRlTUtaHa0YtqzziK7GOyGlLoYuophIL6mIwzFzkj+M7azTjLfeBGfmdxPfyNkdNY7NiPAk8chfZuFDuCKGbAOoKyxFrDR/eKbVjy9C/wrZd78MWWbbjXtw3WR17BAgZHwwjIM5wPJ2aA1PpUO16InUPa4NIdD2pI0wXToNodHBP1SWKdPXcxc4qc2Hm4VBpCpasfVidftxuV9ftRXrcbS32dsspCjgGUeEYl5ytlhUyt2YNyQy31dGNd8Jis2+tmRvYUPdp+6Prj3hZBuaMLd/q6kJDJKM8YSNJAQj9W/ehbsuOT6gdlhYkrWUy6lzAv6umHpT6EYh6j6RuUJcwad+SqVbpHpVW4RlDuZNndCOaxOPmJjVh54F1ZctQVhWIJY8Mi9z4ZV1rczIIMfwRI+bTiEIu9dL6NfdXuYVSx4/FFUOqPwBLgsi1XysJY4urAj98IyXlf6QxL9JT8EDaZdPLMfoPeU9S77rK9ihpXHJWuqKxm1TD/GhhGZcuYLEwsaRlDzdoQFq0bxPKGIdzp2I8nNkXz3aKxqeyGT/s7UOQcQWU9E739KHQeyGfJ9ZG8SS8QR7nrEEqd4yh1jqLSM45SGwORJXZMywxJ4W0p1+KdIZQ6RlHijuEzdR2IJsy3EhpP4strBLmsekY1az7j3ipldjztrtQWkslNgY09CivTD4Kch6SivdjN3nlIdrBy4xnVcSVnRMr7WDoowebsg8U2gD9r2QNu39WVJGVzPAdTkRlubErdcJOzVSqAONMv94ZRwgokDk0aRqVHLnOPo8xzUOo+qZ7LmUyPBUGr92OeowskgT2EQh+XK6OwegbxzZ/3yyycGRG+VsZgvvgwStlrs97WPd1C4hxCmbsb/87PUj2NFM7Wc0nJIz7e9z5qntiK6sDhvHDbFUGNndtzelDo6ZelVQsr7pk14UqZM3LVWH/AfV7cC8UmxSlceXIP4Av+NpyVjXU6hRNG+1LnLjndz8ISPS6PermJMYaq+u3Yey4NRYKUmR7lart2NnuRhrKi71P+LlQ5IyhvHpatIyWNQZQ2RlDt6sQt9jbsv6RjSucRORyWTXcMT49n55Gf/7g9jvk8GyswIsUrVl8IVm8/aloiqOJ+Kc8QFnhCsK4dRjGT/utH8EfO1yQbJDWJgYFjWLqmHeVrorDYx1G4OiTHjctf5DDDpAxvhlmmvxbZWdjBwOyDxTEgZ9FXOgZgXbUJrccVTKjmdTMoedfuu5jBzas3wVLPi8hlQGYGeuRLL3QPXTN7DIUOnoI3nclf0aBK7xmDxT2MKnc/Pu9ox8ClzDGOoTmBYeosK5MIVbZQ/PLgKSyt3y4BX9IwDosnKj2KrK3LwRGxWcbH+kxjXrRUquZjqLL14NP2VinsnsqmZeysGAYldIOe2HEY5fZBmQDxc8kSLHfD+iO4L9CKCzw/1eDMW5WLeFiIh/5+Sww1q/bC4uOQKS5lj2XeEZBMpvITt2W8yr9MY6ZiisU8vBEYqF6m37jUfFj2qN3ua8chXTzMmXrfJf3CrbXbZbMftz9XOPtQzt604Qgqn3gH7aemkO/2vTbMQ466UVNyAMej+45gmZ1le+OoahhDmZ+VUqOo8o6i2jOKv3s9jHfTyr0cKjApP5PK47wglhQbPufaiuqmYVS6RmANRKTIpKYxCmvDGKyBMdT4R1HZEMOyxhjKfHHcWbsJlzUes6OnJbf3fOQUrE+8I4+NUv9RFNRze0hefX/F8kfdNWOwcG2+hD0hC6L5GPWOosg+hFvdbXjndBKciaeYu5szJHVK0l4p2v6+gjvrd8PqHUYBV6o8XO8fmHXdPEgj8s/F/Kt53AdQ7OqZbsnIN9PxQIXWox9gUjMom+NiBB9zVyZ4qJTOTVFCaPRy+D0sWv0GKrwxFNcNo6ief56b3TgRmqNEkp76mrEghsUl8+2d+LNnd6MvaV64wLylepl0/oUVOvOfgp5py59KZUyP8WBhGZNGUegbxddaOmQiytw0Z7HS66gavW9qpY/tDGHB49uktynxsFcdR4FnFIVOHv0emwZo+IYg5UIK2Q/C6g7jltVvIpYTG5jliCfES7evbMuLT1i04u6ZFqscwqKnt6B3wpiaCdIrQhHNYPYnS6OGcN32+JuwNo2g1H4INT7mTCMoCQyjqGEct9q2YSQnGmTiNmOtJUh5uovQadvRC7jLuRvzvUGpwCpvDKGGVf9NQVQ3DqKqcRCVjf1YwOPb1x3BLbZtuKxpRIaukJlLSk8zlNL7/uKFPahY3S7bHqieQRi7ahZHcJaxyIIXr8wWQ8WaKKrdEcxbvQv/7xsDCKWMjozC/U3J/KCIOdPz5PhuOcVDUM/pS8rXfVuxkKsvDgYCJ1PXrNDVLQsD0pPKHnn2bEGU2bphrduPP/FtQ9vpS2AFPVcumJLJqnlSmL0Bv3g5D4BbGoRK+04m8B8admJB3U4ZJ5a4+FliMhQo8oSvGh+LM616zW7cbdsMd8coTmjiqwmVj8YcpbOTkh/VTJOSuSR59oyh2taNCnuvHJRW7AyilHuPbJ346w394NE/POuIB4BJwtowSTFy0mO9Mvo+vuTeBOvjbaiyc8x5ZUjEEIq83PEwdGOQytr8KKz1+/DtX3bI5COrTdBoQnF9zr4R5d5xWNyH821AfvamUdyzaiNCl5Ids0Aqh89xm45KqsItKFla1c4SxJ0otTNnOoyyQFxWoiyNMSxf9TbGUqJWrvV0MeaKycKDnpGhzbbR9/H1dbsxf802qdJf3DCCysYIKhrCKA+EUMo9UOxJG0dwR91GXNYVmiNy1uWo6HXB9/Bp+xbMr+uEdU0Q5av7UeWIosTeg0rPICo9+aSB7JxY8S986EdNfafUG249lcT5JHuX/JicjxrvzSVXpkiYf1V0g87pguxdI1iw6jdYzFSUjcuOLLwdRaGHZ+93wbKmT/YZlbtHUebYh3n/8DwaDxzF8ankAxz35McG5mOqqzaniqSLKUqYOTqp6fe/dvQS7mvcgaKn3ga5u2FxRaTEjY2b7cqaYiiu3YnSFS/jNtvr8PXEEVfFS7K9RfKAV06I/DgbjjFTxiQd0nMP39OyF5ZntqKQhxG7D8sk8tOebXh75AzyPzs7/JFrYPAgXp34Nwu+MnYBX1u3FYvqXkPxyp0or+tCDfeZMYPinWG+UTlB2uLhZsNeVHNS4u7DPbWvo3NChSYHiZk0oQt6YmsINSteQ6U/DouHJ5JEYH20DY+/NYz3hSi9kU4jkdPopBD3/82bgyh+dAOquf+JEzcni9uH8KPnN0thuxTJzxkyd23EEntZnY4b4oEXY2fxx842VD/RhoXOISziokIgJoUoS927cfOTr+L5wRPg9zR7dpOcvaRQQtPpaEp/sPXoGTzyzj7cvuplWO07YeU257oOafznxata8dlnfoXa1h4MfDB17OL0jCYuZ+o8Ue4Gc9CvCovlyEZVNuulRI5Om2Lx1vc+wI9/sx032d5GlWM7qtx9KFvZDuuTW7F89U7815f34vnoMVkcmOKRizyYQOHJdUnZrCYplCs2B6Qqc3eGRpNqlia0nJQaxjPipQ0Hz8HVM47VuyN4pj0Ex4FRrA+ewPZ3JzCWVmo5dp/iiSMqlymn5GIY+pXP5RFDTMFkSFdTNKFoxG0bb8dO4lfRU3g+fAavjZ1F+HKyXf4ayxyXMa+fpXXFWWSyE5TSM/J0O6nq9/OMqK7zKrYfS+DNsUt4deziVfvlwUv41fh5vDJ2Bq+PvovXRt/Fb6LHwe9xIn3xqgQxqZt0UTMpeC4dfiV+Fm/ET2ND5F0Ez2ph9nBTmdOLbywoSsrMn4HYfW7yt5sOfYAtRy5g6/HLaDuZwKmcWJ5TFTLkbxT56LVmp8QjLKeMjKziHcvq3wklREfX+Ry2n7yMHScuYM+pBOKT5kuTqirfx/8PIAwWEixjLzMAAAAASUVORK5CYII=" x="24.00" y="77.25" width="144" height="37.49"/>';
1175
+ function SubiektIcon({ width = 15, height = 15, ...props }) {
1176
+ return /* @__PURE__ */ jsxRuntime.jsx(
1177
+ "svg",
1178
+ {
1179
+ width,
1180
+ height,
1181
+ viewBox: "0 0 192 192",
1182
+ fill: "none",
1183
+ xmlns: "http://www.w3.org/2000/svg",
1184
+ "aria-hidden": "true",
1185
+ ...props,
1186
+ dangerouslySetInnerHTML: { __html: TILE }
1187
+ }
1188
+ );
1189
+ }
1190
+ function fmtDateTime(value, lang) {
1191
+ if (!value) return "";
1192
+ const d = new Date(value);
1193
+ if (!Number.isFinite(d.getTime())) return "";
1194
+ try {
1195
+ return new Intl.DateTimeFormat(lang, { dateStyle: "medium", timeStyle: "short" }).format(d);
1196
+ } catch {
1197
+ return d.toISOString().slice(0, 16).replace("T", " ");
1198
+ }
1199
+ }
1200
+ function fmtDuration(ms) {
1201
+ if (!Number.isFinite(ms) || ms <= 0) return "0 s";
1202
+ return ms < 1e4 ? `${(ms / 1e3).toFixed(1)} s` : `${Math.round(ms / 1e3)} s`;
1203
+ }
1204
+ function fmtNumber(value, lang) {
1205
+ const n = typeof value === "number" ? value : Number(value);
1206
+ if (!Number.isFinite(n)) return "0";
1207
+ try {
1208
+ return new Intl.NumberFormat(lang).format(n);
1209
+ } catch {
1210
+ return String(n);
1211
+ }
1212
+ }
1213
+ const TASK_TONE = {
1214
+ waiting: "grey",
1215
+ pending: "blue",
1216
+ running: "blue",
1217
+ unknown: "orange",
1218
+ succeeded: "green",
1219
+ failed: "red",
1220
+ canceled: "grey"
1221
+ };
1222
+ function taskTone(status) {
1223
+ return TASK_TONE[status] ?? "grey";
1224
+ }
1225
+ function TaskStatusBadge({ status, dot = false }) {
1226
+ const { t } = reactI18next.useTranslation("subiekt");
1227
+ return /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: taskTone(status), dot, children: t(`tasks.statuses.${status}`) });
1228
+ }
1229
+ const RUN_TONE = { success: "green", partial: "orange", error: "red", skipped: "grey" };
1230
+ function RunStatusBadge({ status, dot = false }) {
1231
+ const { t } = reactI18next.useTranslation("subiekt");
1232
+ return /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: RUN_TONE[status] ?? "grey", dot, children: t(`runs.statuses.${status}`) });
1233
+ }
1234
+ function DocumentStatusBadge({ status, dot = false }) {
1235
+ const { t } = reactI18next.useTranslation("subiekt");
1236
+ const tone = status === "canceled" ? "grey" : status === "completed" ? "green" : "blue";
1237
+ return /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone, dot, children: t(`documents.statuses.${status}`, { defaultValue: status }) });
1238
+ }
1239
+ const CATALOG_TONE = {
1240
+ planned: "blue",
1241
+ applied: "green",
1242
+ simulated: "blue",
1243
+ over_cap: "grey",
1244
+ stale: "orange",
1245
+ failed: "red",
1246
+ quarantined: "red",
1247
+ skipped: "grey"
1248
+ };
1249
+ function CatalogStatusBadge({ status, dot = false }) {
1250
+ const { t } = reactI18next.useTranslation("subiekt");
1251
+ return /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: CATALOG_TONE[status] ?? "grey", dot, children: t(`products.statuses.${status}`, { defaultValue: status }) });
1252
+ }
1253
+ function SampleList({ label, items }) {
1254
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1255
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: label }),
1256
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: items.map((item) => /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono", children: item }) }, item)) })
1257
+ ] });
1258
+ }
1259
+ function RichText({ text }) {
1260
+ const parts = text.split("`");
1261
+ return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: parts.map(
1262
+ (part, i) => i % 2 === 1 ? /* @__PURE__ */ jsxRuntime.jsx("code", { className: "txt-compact-xsmall rounded border border-ui-border-base bg-ui-bg-subtle px-1 font-mono text-ui-fg-base", children: part }, i) : /* @__PURE__ */ jsxRuntime.jsx("span", { children: part }, i)
1263
+ ) });
1264
+ }
1265
+ function connectionState(s) {
1266
+ var _a;
1267
+ if (!s) return { key: "unknown", tone: "grey" };
1268
+ if (s.mode === "demo") return { key: "demo", tone: "blue" };
1269
+ if (!s.configured) return { key: "notConfigured", tone: "orange" };
1270
+ if (!s.connection.checkedAt && !s.connection.lastErrorAt) return { key: "unknown", tone: "grey" };
1271
+ if (!s.connection.reachable) return { key: "unreachable", tone: "red" };
1272
+ if (s.connection.health && !((_a = s.connection.health.subiekt) == null ? void 0 : _a.connected)) return { key: "subiektDown", tone: "orange" };
1273
+ return { key: "connected", tone: "green" };
1274
+ }
1275
+ function ConnectionBadge({ status }) {
1276
+ const { t } = reactI18next.useTranslation("subiekt");
1277
+ const state = connectionState(status);
1278
+ return /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: state.tone, children: t(`mode.${state.key}`) });
1279
+ }
1280
+ function Field({ label, children }) {
1281
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-[minmax(120px,1fr)_2fr] items-start gap-x-4 px-6 py-2", children: [
1282
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: label }),
1283
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-compact-small text-ui-fg-base min-w-0 break-words", children })
1284
+ ] });
1285
+ }
1286
+ function Pager({ offset, limit, count, onChange }) {
1287
+ const { t } = reactI18next.useTranslation("subiekt");
1288
+ if (count <= limit) return null;
1289
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-3", children: [
1290
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle tabular-nums", children: t("tasks.page", { from: offset + 1, to: Math.min(offset + limit, count), count }) }),
1291
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-x-2", children: [
1292
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", disabled: offset === 0, onClick: () => onChange(Math.max(0, offset - limit)), children: t("tasks.prev") }),
1293
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", disabled: offset + limit >= count, onClick: () => onChange(offset + limit), children: t("tasks.next") })
1294
+ ] })
1295
+ ] });
1296
+ }
1297
+ const num$1 = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
1298
+ function runSummary(run, t) {
1299
+ const s = run.stats ?? {};
1300
+ if (run.status === "error" || run.status === "skipped" || !run.stats) return run.message ?? "";
1301
+ if (run.kind === "stock") {
1302
+ const changes = num$1(s.toUpdate) + num$1(s.toCreate);
1303
+ return t(run.dryRun ? "runs.summary.stockDry" : "runs.summary.stock", { changes, unchanged: num$1(s.unchanged) });
1304
+ }
1305
+ if (run.kind === "tasks") {
1306
+ const vars = { succeeded: num$1(s.succeeded), retry: num$1(s.retry), failed: num$1(s.failed) };
1307
+ return t(vars.retry || vars.failed ? "runs.summary.tasksIssues" : "runs.summary.tasks", vars);
1308
+ }
1309
+ if (run.kind === "events") return num$1(s.read) > 0 ? t("runs.summary.events", { applied: num$1(s.applied) }) : t("runs.summary.eventsNone");
1310
+ if (run.kind === "health" && run.status === "success") return t("runs.summary.health");
1311
+ if (run.kind === "products") {
1312
+ const applied = num$1(s.applied) + num$1(s.simulated);
1313
+ return t(run.dryRun ? "runs.summary.productsPlan" : "runs.summary.productsApplied", {
1314
+ prices: num$1(s.priceChanges),
1315
+ creates: num$1(s.toCreate),
1316
+ applied,
1317
+ failed: num$1(s.failed)
1318
+ });
1319
+ }
1320
+ if (run.kind === "catchup") {
1321
+ const vars = { queued: num$1(s.queued) + num$1(s.waiting), released: num$1(s.released), errors: num$1(s.errors) };
1322
+ return t(vars.errors ? "runs.summary.catchupErrors" : "runs.summary.catchup", vars);
1323
+ }
1324
+ return run.message ?? "";
1325
+ }
1326
+ function fmtMoney(value, currency, lang) {
1327
+ if (typeof value !== "number" || !Number.isFinite(value)) return "-";
1328
+ try {
1329
+ return new Intl.NumberFormat(lang, { style: "currency", currency: currency.toUpperCase() }).format(value);
1330
+ } catch {
1331
+ return `${value.toFixed(2)} ${currency.toUpperCase()}`;
1332
+ }
1333
+ }
1334
+ function fmtMs(ms) {
1335
+ if (typeof ms !== "number" || !Number.isFinite(ms)) return "-";
1336
+ const abs = Math.abs(ms);
1337
+ return abs < 1e3 ? `${Math.round(ms)} ms` : `${(ms / 1e3).toFixed(abs < 1e4 ? 1 : 0)} s`;
1338
+ }
1339
+ function MedusaMark({ className }) {
1340
+ return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 36 38", fill: "none", "aria-hidden": true, className, children: /* @__PURE__ */ jsxRuntime.jsx(
1341
+ "path",
1342
+ {
1343
+ d: "M30.85 6.16832L22.2453 1.21782C19.4299 -0.405941 15.9801 -0.405941 13.1648 1.21782L4.52043 6.16832C1.74473 7.79208 0 10.802 0 14.0099V23.9505C0 27.198 1.74473 30.1683 4.52043 31.7921L13.1251 36.7822C15.9405 38.4059 19.3903 38.4059 22.2056 36.7822L30.8103 31.7921C33.6257 30.1683 35.3307 27.198 35.3307 23.9505V14.0099C35.41 10.802 33.6653 7.79208 30.85 6.16832ZM17.6852 27.8317C12.8079 27.8317 8.8426 23.8713 8.8426 19C8.8426 14.1287 12.8079 10.1683 17.6852 10.1683C22.5625 10.1683 26.5674 14.1287 26.5674 19C26.5674 23.8713 22.6022 27.8317 17.6852 27.8317Z",
1344
+ fill: "currentColor"
1345
+ }
1346
+ ) });
1347
+ }
1348
+ function StoreColumn({ label, hint }) {
1349
+ return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-x-1.5", title: hint, children: [
1350
+ /* @__PURE__ */ jsxRuntime.jsx(MedusaMark, { className: "h-3.5 w-3.5 text-ui-fg-muted" }),
1351
+ label
1352
+ ] });
1353
+ }
1354
+ function StoreLink({ to, title, mono, monoTitle, action }) {
1355
+ return /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to, className: "group flex items-center gap-x-2.5", title: action, children: [
1356
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-ui-bg-component shadow-borders-base transition-fg group-hover:bg-ui-bg-component-hover", children: /* @__PURE__ */ jsxRuntime.jsx(MedusaMark, { className: "h-4 w-4 text-ui-fg-base" }) }),
1357
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
1358
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus truncate text-ui-fg-base group-hover:text-ui-fg-interactive", children: title }),
1359
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-x-1.5", children: [
1360
+ mono ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-ui-fg-muted txt-compact-xsmall", title: monoTitle, children: mono }) : null,
1361
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "txt-compact-xsmall-plus inline-flex shrink-0 items-center gap-x-0.5 text-ui-fg-interactive", children: [
1362
+ action,
1363
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightMini, {})
1364
+ ] })
1365
+ ] })
1366
+ ] })
1367
+ ] });
1368
+ }
1369
+ function StoreUnlinked({ label, hint, mono }) {
1370
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-y-1", title: hint, children: [
1371
+ /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: "orange", children: label }),
1372
+ mono ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-muted txt-compact-xsmall", children: mono }) : null
1373
+ ] });
1374
+ }
1375
+ function StoreOrderCell({ orderId, displayId }) {
1376
+ const { t } = reactI18next.useTranslation("subiekt");
1377
+ if (!orderId) return /* @__PURE__ */ jsxRuntime.jsx(StoreUnlinked, { label: t("store.noOrder"), hint: t("store.noOrderHint") });
1378
+ return /* @__PURE__ */ jsxRuntime.jsx(
1379
+ StoreLink,
1380
+ {
1381
+ to: `/orders/${orderId}`,
1382
+ title: displayId ? `#${displayId}` : orderId,
1383
+ mono: displayId ? orderId : null,
1384
+ monoTitle: orderId,
1385
+ action: t("store.openOrder")
1386
+ }
1387
+ );
1388
+ }
1389
+ const BUSY = /* @__PURE__ */ new Set(["pending", "running", "unknown"]);
1390
+ function taskRun(task, hasDocument) {
1391
+ const s = task.status;
1392
+ const queue = s === "pending" && task.attempts === 0 ? { status: "running" } : { status: "done" };
1393
+ const bridge = s === "pending" && task.attempts === 0 ? { status: "queued" } : s === "failed" ? { status: "error", note: task.lastError ?? void 0 } : s === "succeeded" ? { status: "done" } : { status: "running", note: task.lastError ?? void 0 };
1394
+ const document2 = s === "succeeded" ? hasDocument ? { status: "done" } : { status: "running" } : { status: "queued" };
1395
+ return runFromSteps({ queue, bridge, document: document2 }, task.updatedAt ?? task.createdAt ?? Date.now());
1396
+ }
1397
+ function DocumentLine({ d, lang }) {
1398
+ const { t } = reactI18next.useTranslation("subiekt");
1399
+ const meta = [
1400
+ fmtDateTime(d.issuedAt, lang),
1401
+ t(`documents.sources.${d.source}`, { defaultValue: d.source }),
1402
+ d.warehouse ? t("widget.warehouse", { warehouse: d.warehouse }) : null
1403
+ ].filter(Boolean);
1404
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
1405
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [
1406
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t(`widget.kinds.${d.kind}`, { defaultValue: d.kind }) }),
1407
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "break-all font-mono", children: d.number }),
1408
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: meta.join(", ") }),
1409
+ d.related.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("widget.related", { numbers: d.related.map((r) => r.number).join(", ") }) }) : null,
1410
+ d.kind === "ZK" && d.status === "completed" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("widget.zkCompleted") }) : null,
1411
+ d.kind === "FS" && d.status !== "canceled" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: d.ksefNumber ? "break-all font-mono text-ui-fg-subtle" : "text-ui-fg-muted", children: d.ksefNumber ? t("widget.ksef", { number: d.ksefNumber }) : t("widget.ksefWaiting") }) : null
1412
+ ] }),
1413
+ /* @__PURE__ */ jsxRuntime.jsx(DocumentStatusBadge, { status: d.status })
1414
+ ] });
1415
+ }
1416
+ const ENTRY_TONE = { missing: "orange", status_differs: "orange", same: "green", only_local: "grey" };
1417
+ function CheckResult({
1418
+ result,
1419
+ lang,
1420
+ linking,
1421
+ onLink
1422
+ }) {
1423
+ const { t } = reactI18next.useTranslation("subiekt");
1424
+ const status = (v) => t(`documents.statuses.${v ?? "open"}`, { defaultValue: v ?? "" });
1425
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
1426
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
1427
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: t("widget.check.title") }),
1428
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("widget.check.at", { time: fmtDateTime(result.checkedAt, lang) }) })
1429
+ ] }),
1430
+ result.entries.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("widget.check.nothing") }) : result.entries.map((e) => {
1431
+ const key = `${e.kind}|${e.number}`;
1432
+ const where = e.state === "only_local" ? t("widget.check.notReported") : [t("widget.check.inSubiekt", { status: status(e.remoteStatus) }), e.issuedAt ? fmtDateTime(e.issuedAt, lang) : null].filter(Boolean).join(", ");
1433
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1434
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
1435
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [
1436
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "break-all font-mono", children: e.number }),
1437
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: where })
1438
+ ] }),
1439
+ /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: ENTRY_TONE[e.state], children: e.state === "status_differs" ? t("widget.check.states.status_differs", { status: status(e.localStatus) }) : t(`widget.check.states.${e.state}`) })
1440
+ ] }),
1441
+ e.kind === "ZK" && e.remoteStatus === "completed" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("widget.zkCompleted") }) : null,
1442
+ e.remoteStatus === "canceled" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("widget.check.canceledThere") }) : null,
1443
+ e.state === "missing" || e.state === "status_differs" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1444
+ /* @__PURE__ */ jsxRuntime.jsx("div", { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: linking === key, onClick: () => onLink(e), children: [
1445
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Link, {}),
1446
+ e.state === "missing" ? t("widget.check.link") : t("widget.check.update")
1447
+ ] }) }),
1448
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: e.state === "missing" ? t("widget.check.linkHint") : t("widget.check.updateHint") })
1449
+ ] }) : null
1450
+ ] }, key);
1451
+ })
1452
+ ] });
1453
+ }
1454
+ const SubiektOrderWidget = ({ data }) => {
1455
+ var _a, _b, _c, _d;
1456
+ const { t, i18n } = reactI18next.useTranslation("subiekt");
1457
+ const lang = i18n.language || "en";
1458
+ const q = useSubiektOrder(data.id);
1459
+ const send = useSubiektSendOrder(data.id);
1460
+ const issue = useSubiektIssueDocument(data.id);
1461
+ const retry = useSubiektRetry();
1462
+ const check = useSubiektOrderCheck(data.id);
1463
+ const link = useSubiektLinkDocument(data.id);
1464
+ const [checked, setChecked] = react.useState(null);
1465
+ const documents = ((_a = q.data) == null ? void 0 : _a.documents) ?? [];
1466
+ const tasks = ((_b = q.data) == null ? void 0 : _b.tasks) ?? [];
1467
+ const sales = (_c = q.data) == null ? void 0 : _c.salesDocument;
1468
+ const create = tasks.find((task) => task.kind === "order.create");
1469
+ const documentTask = tasks.find((task) => task.kind === "order.document");
1470
+ const hasZk = documents.some((d) => d.kind === "ZK" && d.status !== "canceled");
1471
+ const hasSales = documents.some((d) => (d.kind === "FS" || d.kind === "PA") && d.status !== "canceled");
1472
+ const busy = (create == null ? void 0 : create.status) === "pending" || (create == null ? void 0 : create.status) === "running";
1473
+ const documentBusy = documentTask ? BUSY.has(documentTask.status) : false;
1474
+ const canceled = data.status === "canceled";
1475
+ const offerIssue = Boolean(sales && sales.option !== "none" && sales.supported && hasZk && !hasSales && !documentBusy && !canceled);
1476
+ const inFlight = tasks.find((task) => (task.kind === "order.create" || task.kind === "order.document") && BUSY.has(task.status));
1477
+ const failed = tasks.some((task) => task.status === "failed");
1478
+ const state = failed ? { tone: "red", key: "attention" } : inFlight ? { tone: "blue", key: "sending" } : hasZk ? { tone: "green", key: "inSubiekt" } : (create == null ? void 0 : create.status) === "waiting" ? { tone: "grey", key: "waiting" } : { tone: "grey", key: "notSent" };
1479
+ const onSend = async () => {
1480
+ try {
1481
+ await send.mutateAsync();
1482
+ ui.toast.success(t("widget.sent"));
1483
+ } catch (err) {
1484
+ ui.toast.error(t("toast.error", { error: errorMessage(err) }));
1485
+ }
1486
+ };
1487
+ const onIssue = async (kind) => {
1488
+ try {
1489
+ await issue.mutateAsync(kind);
1490
+ ui.toast.success(t("widget.issued"));
1491
+ } catch (err) {
1492
+ ui.toast.error(t("toast.error", { error: errorMessage(err) }));
1493
+ }
1494
+ };
1495
+ const onCheck = async () => {
1496
+ try {
1497
+ setChecked(await check.mutateAsync());
1498
+ } catch (err) {
1499
+ ui.toast.error(t("toast.error", { error: errorMessage(err) }));
1500
+ }
1501
+ };
1502
+ const onLink = async (e) => {
1503
+ try {
1504
+ const r = await link.mutateAsync({ kind: e.kind, number: e.number });
1505
+ setChecked(r.check);
1506
+ ui.toast.success(e.state === "missing" ? t("widget.check.linked", { number: e.number }) : t("widget.check.updated", { number: e.number }));
1507
+ } catch (err) {
1508
+ ui.toast.error(t("toast.error", { error: errorMessage(err) }));
1509
+ }
1510
+ };
1511
+ const onRetry = async (id) => {
1512
+ try {
1513
+ await retry.mutateAsync(id);
1514
+ ui.toast.success(t("toast.retried"));
1515
+ void q.refetch();
1516
+ } catch (err) {
1517
+ ui.toast.error(t("toast.error", { error: errorMessage(err) }));
1518
+ }
1519
+ };
1520
+ const header = /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2 px-6 py-4", children: [
1521
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-2", children: [
1522
+ /* @__PURE__ */ jsxRuntime.jsx(SubiektIcon, { width: 18, height: 18, className: "shrink-0" }),
1523
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("widget.title") }),
1524
+ q.data ? /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: state.tone, children: t(`widget.state.${state.key}`) }) : null,
1525
+ ((_d = q.data) == null ? void 0 : _d.mode) === "demo" ? /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: "blue", children: t("widget.demo") }) : null
1526
+ ] }),
1527
+ /* @__PURE__ */ jsxRuntime.jsxs(
1528
+ "a",
1529
+ {
1530
+ href: `/app/subiekt?q=${encodeURIComponent(String(data.display_id ?? data.id))}`,
1531
+ className: "txt-compact-small inline-flex shrink-0 items-center gap-x-1 text-ui-fg-interactive hover:text-ui-fg-interactive-hover",
1532
+ children: [
1533
+ t("widget.more"),
1534
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, {})
1535
+ ]
1536
+ }
1537
+ )
1538
+ ] });
1539
+ const sendingDocument = (inFlight == null ? void 0 : inFlight.kind) === "order.document";
1540
+ const inFlightHasDocument = sendingDocument ? hasSales : hasZk;
1541
+ return /* @__PURE__ */ jsxRuntime.jsx(WidgetFrame, { header, children: q.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(KitLoading, { className: "min-h-0 py-6" }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1542
+ inFlight ? /* @__PURE__ */ jsxRuntime.jsx(
1543
+ StagedLoader,
1544
+ {
1545
+ run: taskRun(inFlight, inFlightHasDocument),
1546
+ columns: 3,
1547
+ doneTitle: t("widget.run.done"),
1548
+ stages: [
1549
+ { key: "queue", name: t("widget.run.queue"), short: t("widget.run.queueShort"), icon: /* @__PURE__ */ jsxRuntime.jsx(icons.QueueList, {}), weight: 20 },
1550
+ { key: "bridge", name: t("widget.run.bridge"), short: t("widget.run.bridgeShort"), icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ServerStack, {}), weight: 60 },
1551
+ {
1552
+ key: "document",
1553
+ name: t("widget.run.document"),
1554
+ short: t("widget.run.documentShort"),
1555
+ icon: sendingDocument ? /* @__PURE__ */ jsxRuntime.jsx(icons.Receipt, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.DocumentText, {}),
1556
+ weight: 20
1557
+ }
1558
+ ]
1559
+ }
1560
+ ) : null,
1561
+ documents.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: documents.map((d) => /* @__PURE__ */ jsxRuntime.jsx(DocumentLine, { d, lang }, d.id)) }) : inFlight ? null : /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { compact: true, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.DocumentText, {}), title: (create == null ? void 0 : create.status) === "waiting" ? t("widget.waiting") : t("widget.none") }),
1562
+ tasks.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: tasks.map((task) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1563
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
1564
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: task.kind === "order.document" && (task.documentKind === "fs" || task.documentKind === "pa") ? t(`tasks.documentKinds.${task.documentKind}`) : t(`tasks.kinds.${task.kind}`) }),
1565
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex items-center gap-x-1", children: [
1566
+ /* @__PURE__ */ jsxRuntime.jsx(TaskStatusBadge, { status: task.status }),
1567
+ task.status === "failed" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: retry.isPending && retry.variables === task.id, onClick: () => onRetry(task.id), children: [
1568
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
1569
+ t("actions.retry")
1570
+ ] }) : null
1571
+ ] })
1572
+ ] }),
1573
+ task.buyer ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: task.buyer.source === "retail" ? t("tasks.buyer.retail") : t(`tasks.buyer.${task.buyer.source}`, { name: task.buyer.name ?? task.buyer.symbol ?? "?", nip: task.buyer.nip ?? "?" }) }) : null,
1574
+ task.warnings.map((w) => /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: w }, w)),
1575
+ task.lastError && task.status !== "succeeded" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: task.status === "failed" ? "text-ui-tag-red-text" : "text-ui-fg-muted", children: task.lastError }) : null,
1576
+ task.status === "unknown" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: t("tasks.unknownHint") }) : null,
1577
+ task.manualAction ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: t("tasks.manual") }) : null
1578
+ ] }, task.id)) }) : null,
1579
+ checked ? /* @__PURE__ */ jsxRuntime.jsx(
1580
+ CheckResult,
1581
+ {
1582
+ result: checked,
1583
+ lang,
1584
+ linking: link.isPending && link.variables ? `${link.variables.kind}|${link.variables.number}` : null,
1585
+ onLink: (e) => void onLink(e)
1586
+ }
1587
+ ) : null,
1588
+ !inFlight || !hasZk && !busy && !canceled && (create == null ? void 0 : create.status) !== "failed" || offerIssue && sales ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: [
1589
+ offerIssue && sales ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: sales.writerActive ? t("widget.autoOn", { after: sales.after.toUpperCase() }) : t("widget.autoOff") }) : null,
1590
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
1591
+ !hasZk && !busy && !canceled && (create == null ? void 0 : create.status) !== "failed" ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: send.isPending, onClick: onSend, children: [
1592
+ /* @__PURE__ */ jsxRuntime.jsx(icons.PaperPlane, {}),
1593
+ t("widget.send")
1594
+ ] }) : null,
1595
+ offerIssue && sales && (sales.option === "fs" || sales.option === "auto") ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: issue.isPending && issue.variables === "fs", onClick: () => onIssue("fs"), children: [
1596
+ /* @__PURE__ */ jsxRuntime.jsx(icons.DocumentText, {}),
1597
+ t("widget.issueFs")
1598
+ ] }) : null,
1599
+ offerIssue && sales && (sales.option === "pa" || sales.option === "auto") ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: issue.isPending && issue.variables === "pa", onClick: () => onIssue("pa"), children: [
1600
+ /* @__PURE__ */ jsxRuntime.jsx(icons.Receipt, {}),
1601
+ t("widget.issuePa")
1602
+ ] }) : null,
1603
+ !inFlight ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: check.isPending, onClick: () => void onCheck(), children: [
1604
+ /* @__PURE__ */ jsxRuntime.jsx(icons.MagnifyingGlass, {}),
1605
+ checked ? t("widget.check.again") : t("widget.check.button")
1606
+ ] }) : null
1607
+ ] }),
1608
+ !checked && !inFlight && (failed || !hasZk && !canceled) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("widget.check.hint") }) : null
1609
+ ] }) : null
1610
+ ] }) });
1611
+ };
1612
+ adminSdk.defineWidgetConfig({
1613
+ zone: "order.details.side.after"
1614
+ });
1264
1615
  const CLOCK_SKEW_WARN_SECONDS = 60;
1265
1616
  const CLOCK_SKEW_LIMIT_SECONDS = 300;
1266
1617
  function skewLevel(skewMs) {
@@ -1376,7 +1727,7 @@ function usePromptSpec() {
1376
1727
  needs: Array.isArray(needs) ? needs : [],
1377
1728
  config: `// medusa-config.ts, in plugins: [ ... ]
1378
1729
  ${MEDUSA_CODE}`,
1379
- demo: 'demo: process.env.SUBIEKT_DEMO === "true" || !process.env.SUBIEKT_BRIDGE_URL,'
1730
+ demo: 'demo: process.env.SUBIEKT_DEMO === "true",'
1380
1731
  };
1381
1732
  }, [t]);
1382
1733
  }
@@ -1388,7 +1739,7 @@ maxProductsPerRun: 20,`;
1388
1739
  const DOCUMENTS_CODE = `salesDocument: "auto",
1389
1740
  salesDocumentAfter: "wz",
1390
1741
  createContractors: true,`;
1391
- function GuideView({ status, lang }) {
1742
+ function GuideView({ status }) {
1392
1743
  const { t } = reactI18next.useTranslation("subiekt");
1393
1744
  function list(key) {
1394
1745
  const value = t(key, { returnObjects: true });
@@ -1421,7 +1772,6 @@ function GuideView({ status, lang }) {
1421
1772
  q: item.q,
1422
1773
  a: (item.a ?? []).map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("p", { children: /* @__PURE__ */ jsxRuntime.jsx(RichText, { text: p }) }, i))
1423
1774
  }));
1424
- const references = referencesFor(s.references, lang);
1425
1775
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3", children: [
1426
1776
  /* @__PURE__ */ jsxRuntime.jsx(
1427
1777
  GuideIntro,
@@ -1465,31 +1815,249 @@ function GuideView({ status, lang }) {
1465
1815
  }))
1466
1816
  }
1467
1817
  ),
1468
- /* @__PURE__ */ jsxRuntime.jsx(GuideFaq, { title: t("guide.faq.title"), items: faq }),
1469
- /* @__PURE__ */ jsxRuntime.jsx(
1470
- References,
1471
- {
1472
- items: references,
1473
- title: t("references.title"),
1474
- subtitle: t("references.subtitle"),
1475
- openLabel: t("references.open"),
1476
- sinceLabel: (since) => t("references.since", { date: monthYear(since, lang) }),
1477
- reviewLabel: t("references.review"),
1478
- ratingLabel: (value) => fmtRating(value, lang)
1479
- }
1480
- )
1818
+ /* @__PURE__ */ jsxRuntime.jsx(GuideFaq, { title: t("guide.faq.title"), items: faq })
1481
1819
  ] });
1482
1820
  }
1483
- const PAGE_SIZE$1 = 15;
1484
- function SectionHeader({ title, subtitle, children }) {
1485
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 px-6 py-4 md:flex-row md:items-start md:justify-between", children: [
1486
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1487
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: title }),
1488
- subtitle ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-2xl text-ui-fg-subtle", children: subtitle }) : null
1821
+ const FIELDS = [
1822
+ "id",
1823
+ "currency_code",
1824
+ "items.id",
1825
+ "items.title",
1826
+ "items.product_title",
1827
+ "items.variant_title",
1828
+ "items.thumbnail",
1829
+ "items.quantity",
1830
+ "items.unit_price",
1831
+ "items.variant_sku",
1832
+ "items.variant_barcode",
1833
+ /* Totals come from the order module. Their relations in FULL (.*): with partial fields
1834
+ (e.g. adjustments.code alone) the module computes from incomplete rows. */
1835
+ "total",
1836
+ "shipping_total",
1837
+ "discount_total",
1838
+ "items.tax_lines.*",
1839
+ "items.adjustments.*",
1840
+ "shipping_methods.*",
1841
+ "shipping_methods.tax_lines.*",
1842
+ "shipping_methods.adjustments.*"
1843
+ ].join(",");
1844
+ const TEXT = {
1845
+ en: { productsLine: "Products (before discount)", shippingLine: "Shipping (after its discount)", free: "free", discountLine: "Discount", codesLine: "Discount, codes", button: "View", show: "Show products", title: "Products", ofOrder: "of order", lines: "lines", pcs: "pcs", components: "components", close: "Close", showParts: "Show components", hideParts: "Hide components", empty: "This order has no items." },
1846
+ pl: { productsLine: "Produkty (przed rabatem)", shippingLine: "Dostawa (po rabacie na dostawę)", free: "gratis", discountLine: "Rabat", codesLine: "Rabat, kupony", button: "Zobacz", show: "Pokaż produkty", title: "Produkty", ofOrder: "zamówienia", lines: "poz.", pcs: "szt.", components: "składników", close: "Zamknij", showParts: "Pokaż składniki", hideParts: "Ukryj składniki", empty: "Zamówienie nie ma pozycji." }
1847
+ };
1848
+ function useText() {
1849
+ const { i18n } = reactI18next.useTranslation();
1850
+ return String((i18n == null ? void 0 : i18n.language) ?? "en").startsWith("pl") ? TEXT.pl : TEXT.en;
1851
+ }
1852
+ const num = (v) => {
1853
+ const n = typeof v === "number" ? v : typeof v === "string" ? Number(v) : NaN;
1854
+ return Number.isFinite(n) ? n : null;
1855
+ };
1856
+ function amountsOf(o) {
1857
+ const total = num(o.total);
1858
+ const shipping = num(o.shipping_total);
1859
+ const discount = num(o.discount_total) ?? 0;
1860
+ if (total == null || shipping == null) return null;
1861
+ const codes = /* @__PURE__ */ new Set();
1862
+ const adjustments = [...(o.items ?? []).flatMap((it) => it.adjustments ?? []), ...(o.shipping_methods ?? []).flatMap((sm) => sm.adjustments ?? [])];
1863
+ for (const a of adjustments) if (typeof (a == null ? void 0 : a.code) === "string" && a.code.trim()) codes.add(a.code.trim().toUpperCase());
1864
+ const r2 = (n) => Math.round(n * 100) / 100;
1865
+ return { total: r2(total), shipping: r2(shipping), discount: r2(discount), products: r2(total - shipping + discount), codes: [...codes] };
1866
+ }
1867
+ function itemOf(it) {
1868
+ const unitPrice = Number(it.unit_price ?? 0);
1869
+ return {
1870
+ id: it.id,
1871
+ title: it.product_title || it.title || "Product",
1872
+ variant: it.variant_title && it.variant_title !== "Default variant" ? it.variant_title : null,
1873
+ thumbnail: it.thumbnail ?? null,
1874
+ quantity: Number(it.quantity ?? 0),
1875
+ unitPrice,
1876
+ sku: it.variant_sku ?? null,
1877
+ barcode: it.variant_barcode ?? null,
1878
+ component: unitPrice <= 0.05
1879
+ };
1880
+ }
1881
+ async function load(ids) {
1882
+ const out = {};
1883
+ for (let i = 0; i < ids.length; i += 100) {
1884
+ const batch = ids.slice(i, i + 100);
1885
+ const qs = [`fields=${encodeURIComponent(FIELDS)}`, `limit=${batch.length}`, ...batch.map((id) => `id=${encodeURIComponent(id)}`)].join("&");
1886
+ const r = await kitFetch(`/admin/orders?${qs}`);
1887
+ for (const o of r.orders ?? []) {
1888
+ out[o.id] = {
1889
+ currency: String(o.currency_code ?? "usd"),
1890
+ amounts: amountsOf(o),
1891
+ items: (o.items ?? []).map(itemOf)
1892
+ };
1893
+ }
1894
+ }
1895
+ return out;
1896
+ }
1897
+ function useKitOrderProducts(ids) {
1898
+ const unique = [...new Set(ids.filter((x) => typeof x === "string" && x.startsWith("order_")))].sort();
1899
+ return reactQuery.useQuery({
1900
+ queryKey: ["koda-kit-order-products", unique],
1901
+ queryFn: () => load(unique),
1902
+ enabled: unique.length > 0,
1903
+ staleTime: 6e4
1904
+ });
1905
+ }
1906
+ function money(n, currency, lang) {
1907
+ try {
1908
+ return new Intl.NumberFormat(lang, { style: "currency", currency: currency.toUpperCase() }).format(n);
1909
+ } catch {
1910
+ return `${n.toFixed(2)} ${currency.toUpperCase()}`;
1911
+ }
1912
+ }
1913
+ function Thumb({ src, size, title }) {
1914
+ const [broken, setBroken] = react.useState(false);
1915
+ const style = { width: size, height: size };
1916
+ if (!src || broken)
1917
+ return /* @__PURE__ */ jsxRuntime.jsx("span", { style, className: "flex shrink-0 items-center justify-center rounded-lg border border-ui-border-base bg-ui-bg-component text-ui-fg-muted", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntime.jsx("svg", { width: size * 0.5, height: size * 0.5, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" }) }) });
1918
+ return /* @__PURE__ */ jsxRuntime.jsx("img", { src, alt: title, title, style, loading: "lazy", onError: () => setBroken(true), className: "shrink-0 rounded-lg border border-ui-border-base bg-ui-bg-base object-cover" });
1919
+ }
1920
+ function Dialog({ data, displayId, onClose }) {
1921
+ const t = useText();
1922
+ const lang = t === TEXT.pl ? "pl-PL" : "en-GB";
1923
+ const [partsOpen, setPartsOpen] = react.useState(false);
1924
+ react.useEffect(() => {
1925
+ const k = (e) => e.key === "Escape" && onClose();
1926
+ window.addEventListener("keydown", k);
1927
+ return () => window.removeEventListener("keydown", k);
1928
+ }, [onClose]);
1929
+ const main = data.items.filter((p) => !p.component);
1930
+ const parts = data.items.filter((p) => p.component);
1931
+ const pcs = main.reduce((s, p) => s + p.quantity, 0);
1932
+ const value = data.items.reduce((s, p) => s + p.unitPrice * p.quantity, 0);
1933
+ return reactDom.createPortal(
1934
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-black/40 p-4", onClick: onClose, role: "presentation", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { role: "dialog", "aria-modal": "true", "aria-label": `${t.title} ${displayId ? `#${displayId}` : ""}`, className: "flex max-h-[85vh] w-full max-w-2xl flex-col overflow-hidden rounded-xl border border-ui-border-base bg-ui-bg-base shadow-elevation-modal", onClick: (e) => e.stopPropagation(), children: [
1935
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-4 border-b border-ui-border-base px-5 py-4", children: [
1936
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1937
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { weight: "plus", children: [
1938
+ t.title,
1939
+ displayId ? ` ${t.ofOrder} #${displayId}` : ""
1940
+ ] }),
1941
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: [
1942
+ main.length,
1943
+ " ",
1944
+ t.lines,
1945
+ ", ",
1946
+ pcs,
1947
+ " ",
1948
+ t.pcs,
1949
+ parts.length ? `, ${parts.length} ${t.components}` : "",
1950
+ ", ",
1951
+ money(value, data.currency, lang)
1952
+ ] })
1953
+ ] }),
1954
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", onClick: onClose, children: t.close })
1955
+ ] }),
1956
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 overflow-y-auto px-5 py-2", children: [
1957
+ main.map((p) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 border-b border-ui-border-base py-3 last:border-0", children: [
1958
+ /* @__PURE__ */ jsxRuntime.jsx(Thumb, { src: p.thumbnail, size: 48, title: p.title }),
1959
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-w-0 flex-1", children: [
1960
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "truncate", children: p.title }),
1961
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: [p.variant, p.sku ? `SKU ${p.sku}` : null, p.barcode ? `EAN ${p.barcode}` : null].filter(Boolean).join(", ") || "-" })
1962
+ ] }),
1963
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-right", children: [
1964
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", weight: "plus", className: "tabular-nums", children: [
1965
+ p.quantity,
1966
+ " × ",
1967
+ money(p.unitPrice, data.currency, lang)
1968
+ ] }),
1969
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "tabular-nums text-ui-fg-subtle", children: money(p.unitPrice * p.quantity, data.currency, lang) })
1970
+ ] })
1971
+ ] }, p.id)),
1972
+ parts.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-3", children: [
1973
+ /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", className: "txt-small-plus text-ui-fg-interactive", onClick: () => setPartsOpen((v) => !v), children: [
1974
+ partsOpen ? t.hideParts : t.showParts,
1975
+ " (",
1976
+ parts.length,
1977
+ ")"
1978
+ ] }),
1979
+ partsOpen ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-2 grid grid-cols-1 gap-x-4 gap-y-1 sm:grid-cols-2", children: parts.map((p) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: [
1980
+ p.quantity,
1981
+ " × ",
1982
+ p.title,
1983
+ p.variant ? ` (${p.variant})` : ""
1984
+ ] }, p.id)) }) : null
1985
+ ] }) : null,
1986
+ !data.items.length ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "py-6 text-center text-ui-fg-subtle", children: t.empty }) : null
1987
+ ] })
1988
+ ] }) }),
1989
+ document.body
1990
+ );
1991
+ }
1992
+ function KitOpenDialogIcon({ size = 14 }) {
1993
+ return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", children: [
1994
+ /* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "3" }),
1995
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M14 7h3v3" }),
1996
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M17 7l-4 4" }),
1997
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M10 17H7v-3" }),
1998
+ /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 17l4-4" })
1999
+ ] });
2000
+ }
2001
+ const SINGLE = 88;
2002
+ const CARD = 72;
2003
+ const MAX_CARDS = 4;
2004
+ function KitOrderProductsCell({ data, loading, displayId }) {
2005
+ const t = useText();
2006
+ const [open, setOpen] = react.useState(false);
2007
+ if (!data)
2008
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: loading ? "…" : "-" });
2009
+ const main = data.items.filter((p) => !p.component);
2010
+ const pool = main.length ? main : data.items;
2011
+ if (!pool.length)
2012
+ return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: "-" });
2013
+ const shown = pool.slice(0, pool.length > MAX_CARDS ? MAX_CARDS - 1 : MAX_CARDS);
2014
+ const rest = pool.length - shown.length;
2015
+ const size = pool.length === 1 ? SINGLE : CARD;
2016
+ const show = (e) => {
2017
+ e.stopPropagation();
2018
+ e.preventDefault();
2019
+ setOpen(true);
2020
+ };
2021
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-y-2", onClick: (e) => e.stopPropagation(), children: [
2022
+ /* @__PURE__ */ jsxRuntime.jsxs(
2023
+ "button",
2024
+ {
2025
+ type: "button",
2026
+ onClick: show,
2027
+ className: "inline-flex items-center gap-x-1 txt-compact-small-plus text-ui-fg-interactive underline-offset-2 transition-fg hover:text-ui-fg-interactive-hover hover:underline",
2028
+ title: t.show,
2029
+ children: [
2030
+ t.button,
2031
+ /* @__PURE__ */ jsxRuntime.jsx(KitOpenDialogIcon, {})
2032
+ ]
2033
+ }
2034
+ ),
2035
+ /* @__PURE__ */ jsxRuntime.jsxs("button", { type: "button", onClick: show, className: "isolate flex items-center py-1", "aria-label": `${t.title}${displayId ? ` #${displayId}` : ""}: ${pool.length}`, children: [
2036
+ shown.map((p, i) => /* @__PURE__ */ jsxRuntime.jsx(
2037
+ "span",
2038
+ {
2039
+ style: { marginLeft: i ? -40 : 0, zIndex: i + 1 },
2040
+ className: "relative rounded-lg bg-ui-bg-base shadow-elevation-card-rest ring-2 ring-ui-bg-base transition-transform duration-200 ease-out hover:!z-30 hover:scale-[1.15]",
2041
+ children: /* @__PURE__ */ jsxRuntime.jsx(Thumb, { src: p.thumbnail, size, title: `${p.quantity} × ${p.title}${p.variant ? ` (${p.variant})` : ""}` })
2042
+ },
2043
+ p.id
2044
+ )),
2045
+ rest > 0 ? /* @__PURE__ */ jsxRuntime.jsxs(
2046
+ "span",
2047
+ {
2048
+ style: { marginLeft: -40, zIndex: shown.length + 1, width: CARD, height: CARD },
2049
+ className: "relative flex items-center justify-end rounded-lg bg-ui-bg-component pr-3 shadow-elevation-card-rest ring-2 ring-ui-bg-base txt-compact-small-plus text-ui-fg-subtle",
2050
+ children: [
2051
+ "+",
2052
+ rest
2053
+ ]
2054
+ }
2055
+ ) : null
1489
2056
  ] }),
1490
- children ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0 flex-wrap items-center gap-2", children }) : null
2057
+ open ? /* @__PURE__ */ jsxRuntime.jsx(Dialog, { data, displayId: displayId ?? null, onClose: () => setOpen(false) }) : null
1491
2058
  ] });
1492
2059
  }
2060
+ const PAGE_SIZE$1 = 15;
1493
2061
  const LEVEL_TEXT = {
1494
2062
  ok: "text-ui-fg-base",
1495
2063
  warn: "text-ui-tag-orange-text",
@@ -1510,54 +2078,65 @@ function BridgeSection({ status, lang }) {
1510
2078
  const licence = ((_a = h == null ? void 0 : h.subiekt) == null ? void 0 : _a.licence) === "ok" || ((_b = h == null ? void 0 : h.subiekt) == null ? void 0 : _b.licence) === "refused" ? h.subiekt.licence : "unknown";
1511
2079
  const signatureTone = d.signature === "ok" ? LEVEL_TEXT.ok : d.signature === "unknown" ? LEVEL_TEXT.unknown : LEVEL_TEXT.error;
1512
2080
  const rejectedLater = Boolean(d.webhook.rejectedAt && (!d.webhook.lastAt || d.webhook.rejectedAt > d.webhook.lastAt));
1513
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1514
- /* @__PURE__ */ jsxRuntime.jsx(SectionHeader, { title: t("bridge.title"), subtitle: t("bridge.subtitle") }),
1515
- d.legacy ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "warning", label: t("bridge.title"), children: t("bridge.legacy") }) }) : null,
1516
- status.mode === "live" && ((_c = h == null ? void 0 : h.bridge) == null ? void 0 : _c.mode) === "fake" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "warning", label: t("bridge.title"), children: t("bridge.fakeMode") }) }) : null,
1517
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-2", children: [
1518
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.versions"), children: t("bridge.versionsValue", { bridge: ((_d = h == null ? void 0 : h.bridge) == null ? void 0 : _d.version) ?? "?", contract: ((_e = h == null ? void 0 : h.bridge) == null ? void 0 : _e.contract) ?? "?", plugin: status.pluginVersion }) }),
1519
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.sdk"), children: h ? t("bridge.sdkValue", { sdk: ((_f = h.bridge) == null ? void 0 : _f.sdk_version) ?? none, db: ((_g = h.subiekt) == null ? void 0 : _g.database_version) ?? none }) : none }),
1520
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.licence"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: licence === "refused" ? LEVEL_TEXT.error : licence === "ok" ? LEVEL_TEXT.ok : LEVEL_TEXT.unknown, children: t(`bridge.licenceStates.${licence}`) }) }),
1521
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.started"), children: fmtDateTime((_h = h == null ? void 0 : h.bridge) == null ? void 0 : _h.started_at, lang) || none }),
1522
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.latency"), children: fmtMs(d.latencyMs) }),
1523
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.skew"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: LEVEL_TEXT[skew], children: t(`bridge.skewStates.${skew}`, { value: d.clockSkewMs === null ? "" : signedMs(d.clockSkewMs) }) }) }),
1524
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.signature"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: signatureTone, children: t(`bridge.signatureStates.${d.signature}`, { defaultValue: d.signature }) }) }),
1525
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.lastEvent"), children: (h == null ? void 0 : h.events) ? t("bridge.lastEventValue", { id: h.events.last_id, time: fmtDateTime(h.events.last_at, lang) || none }) : none }),
1526
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.queues"), children: (h == null ? void 0 : h.queues) ? t("bridge.queuesValue", { sfera: h.queues.sfera_pending, webhook: h.queues.webhook_pending }) : none }),
1527
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.webhook"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
1528
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: d.webhook.lastAt ? t("bridge.webhookValue", { time: fmtDateTime(d.webhook.lastAt, lang) }) : t("bridge.webhookNever") }),
1529
- rejectedLater ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: LEVEL_TEXT.warn, children: t("bridge.webhookRejected", {
1530
- time: fmtDateTime(d.webhook.rejectedAt, lang),
1531
- reason: t(`bridge.webhookReasons.${d.webhook.rejectReason ?? "missing"}`, { defaultValue: d.webhook.rejectReason ?? "" })
1532
- }) }) : null
1533
- ] }) }),
1534
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.checkedAt"), children: fmtDateTime(d.checkedAt, lang) || t("connection.never") })
1535
- ] }),
1536
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
1537
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1538
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("bridge.capabilities") }),
1539
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: d.capabilities.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: none }) : d.capabilities.map((c) => /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "green", children: t(`bridge.capabilityNames.${c}`, { defaultValue: c }) }, c)) })
1540
- ] }),
1541
- d.missing.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1542
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("bridge.cannot") }),
1543
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-y-1", children: d.missing.map((m) => {
1544
- const hint = m.reason === "bridge_config" ? t(`bridge.capabilityHints.${m.capability}`, { defaultValue: "" }) : "";
1545
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "txt-compact-small flex flex-wrap gap-x-1", children: [
1546
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-base", children: [
1547
- t(`bridge.capabilityNames.${m.capability}`, { defaultValue: m.capability }),
1548
- ":"
1549
- ] }),
1550
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-subtle", children: t(`bridge.reasons.${m.reason}`, { defaultValue: m.reason }) }),
1551
- hint ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-ui-fg-muted", children: [
1552
- "(",
1553
- hint,
1554
- ")"
1555
- ] }) : null
1556
- ] }, m.capability);
1557
- }) })
1558
- ] }) : null
1559
- ] })
1560
- ] });
2081
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2082
+ Section,
2083
+ {
2084
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ComputerDesktop, {}),
2085
+ title: t("bridge.title"),
2086
+ points: [
2087
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), text: t("bridge.points.last") },
2088
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ShieldCheck, {}), text: t("bridge.points.fresh") }
2089
+ ],
2090
+ pointsLabel: t("bridge.subtitle"),
2091
+ children: [
2092
+ d.legacy ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "warning", label: t("bridge.title"), children: t("bridge.legacy") }) }) : null,
2093
+ status.mode === "live" && ((_c = h == null ? void 0 : h.bridge) == null ? void 0 : _c.mode) === "fake" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "warning", label: t("bridge.title"), children: t("bridge.fakeMode") }) }) : null,
2094
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-2", children: [
2095
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.versions"), children: t("bridge.versionsValue", { bridge: ((_d = h == null ? void 0 : h.bridge) == null ? void 0 : _d.version) ?? "?", contract: ((_e = h == null ? void 0 : h.bridge) == null ? void 0 : _e.contract) ?? "?", plugin: status.pluginVersion }) }),
2096
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.sdk"), children: h ? t("bridge.sdkValue", { sdk: ((_f = h.bridge) == null ? void 0 : _f.sdk_version) ?? none, db: ((_g = h.subiekt) == null ? void 0 : _g.database_version) ?? none }) : none }),
2097
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.licence"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: licence === "refused" ? LEVEL_TEXT.error : licence === "ok" ? LEVEL_TEXT.ok : LEVEL_TEXT.unknown, children: t(`bridge.licenceStates.${licence}`) }) }),
2098
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.started"), children: fmtDateTime((_h = h == null ? void 0 : h.bridge) == null ? void 0 : _h.started_at, lang) || none }),
2099
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.latency"), children: fmtMs(d.latencyMs) }),
2100
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.skew"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: LEVEL_TEXT[skew], children: t(`bridge.skewStates.${skew}`, { value: d.clockSkewMs === null ? "" : signedMs(d.clockSkewMs) }) }) }),
2101
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.signature"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: signatureTone, children: t(`bridge.signatureStates.${d.signature}`, { defaultValue: d.signature }) }) }),
2102
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.lastEvent"), children: (h == null ? void 0 : h.events) ? t("bridge.lastEventValue", { id: h.events.last_id, time: fmtDateTime(h.events.last_at, lang) || none }) : none }),
2103
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.queues"), children: (h == null ? void 0 : h.queues) ? t("bridge.queuesValue", { sfera: h.queues.sfera_pending, webhook: h.queues.webhook_pending }) : none }),
2104
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.webhook"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
2105
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: d.webhook.lastAt ? t("bridge.webhookValue", { time: fmtDateTime(d.webhook.lastAt, lang) }) : t("bridge.webhookNever") }),
2106
+ rejectedLater ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: LEVEL_TEXT.warn, children: t("bridge.webhookRejected", {
2107
+ time: fmtDateTime(d.webhook.rejectedAt, lang),
2108
+ reason: t(`bridge.webhookReasons.${d.webhook.rejectReason ?? "missing"}`, { defaultValue: d.webhook.rejectReason ?? "" })
2109
+ }) }) : null
2110
+ ] }) }),
2111
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.checkedAt"), children: fmtDateTime(d.checkedAt, lang) || t("connection.never") })
2112
+ ] }),
2113
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
2114
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
2115
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("bridge.capabilities") }),
2116
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-1", children: d.capabilities.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: none }) : d.capabilities.map((c) => /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: "green", children: t(`bridge.capabilityNames.${c}`, { defaultValue: c }) }, c)) })
2117
+ ] }),
2118
+ d.missing.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
2119
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("bridge.cannot") }),
2120
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-y-1", children: d.missing.map((m) => {
2121
+ const hint = m.reason === "bridge_config" ? t(`bridge.capabilityHints.${m.capability}`, { defaultValue: "" }) : "";
2122
+ return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "txt-compact-small flex flex-wrap gap-x-1", children: [
2123
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-base", children: [
2124
+ t(`bridge.capabilityNames.${m.capability}`, { defaultValue: m.capability }),
2125
+ ":"
2126
+ ] }),
2127
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-subtle", children: t(`bridge.reasons.${m.reason}`, { defaultValue: m.reason }) }),
2128
+ hint ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-ui-fg-muted", children: [
2129
+ "(",
2130
+ hint,
2131
+ ")"
2132
+ ] }) : null
2133
+ ] }, m.capability);
2134
+ }) })
2135
+ ] }) : null
2136
+ ] })
2137
+ ]
2138
+ }
2139
+ );
1561
2140
  }
1562
2141
  const WRITER_ORDER = ["documents", "contractors", "prices", "products"];
1563
2142
  function WriterRow({ writer, status, lang }) {
@@ -1591,15 +2170,14 @@ function WriterRow({ writer, status, lang }) {
1591
2170
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
1592
2171
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
1593
2172
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "text-ui-fg-base", children: name }),
1594
- writer.active ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "green", children: t("writers.active") }) : writer.armed ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "orange", children: t("writers.blocked") }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: t("writers.disarmed") }),
1595
- /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-x-1", children: [
1596
- writer.allowed ? null : /* @__PURE__ */ jsxRuntime.jsx(icons.LockClosedSolid, {}),
2173
+ writer.active ? /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: "green", children: t("writers.active") }) : writer.armed ? /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: "orange", children: t("writers.blocked") }) : /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { children: t("writers.disarmed") }),
2174
+ /* @__PURE__ */ jsxRuntime.jsxs(ToneBadge, { icon: writer.allowed ? void 0 : /* @__PURE__ */ jsxRuntime.jsx(icons.LockClosedSolid, {}), children: [
1597
2175
  t("writers.option", { option: writer.option }),
1598
2176
  " ",
1599
2177
  writer.allowed ? t("writers.allowed") : t("writers.forbidden")
1600
- ] }) })
2178
+ ] })
1601
2179
  ] }),
1602
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-2xl text-ui-fg-subtle", children: description }),
2180
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: description }),
1603
2181
  writer.unsupported ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: t("writers.unsupported") }) : null,
1604
2182
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: writer.changedAt ? t(writer.armed ? "writers.armedBy" : "writers.disarmedBy", { who: writer.changedBy ?? "?", time: fmtDateTime(writer.changedAt, lang) }) : t("writers.never") })
1605
2183
  ] }),
@@ -1609,13 +2187,34 @@ function WriterRow({ writer, status, lang }) {
1609
2187
  function WritersSection({ status, lang }) {
1610
2188
  const { t } = reactI18next.useTranslation("subiekt");
1611
2189
  const writers = WRITER_ORDER.map((k) => status.writers.find((w) => w.key === k)).filter((w) => Boolean(w));
1612
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1613
- /* @__PURE__ */ jsxRuntime.jsx(SectionHeader, { title: t("writers.title"), subtitle: t("writers.subtitle") }),
1614
- status.mode === "demo" ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("writers.demoNote") }) }) : null,
1615
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: writers.map((w) => /* @__PURE__ */ jsxRuntime.jsx(WriterRow, { writer: w, status, lang }, w.key)) })
1616
- ] });
2190
+ return /* @__PURE__ */ jsxRuntime.jsx(
2191
+ Section,
2192
+ {
2193
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.LockClosedSolid, {}),
2194
+ title: t("writers.title"),
2195
+ badges: status.mode === "demo" ? /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: "blue", title: t("writers.demoNote"), children: t("widget.demo") }) : null,
2196
+ points: [
2197
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {}), text: t("writers.points.option") },
2198
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.User, {}), text: t("writers.points.person") },
2199
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.LockClosedSolid, {}), text: t("writers.points.falseWins") }
2200
+ ],
2201
+ pointsLabel: t("writers.subtitle"),
2202
+ children: writers.map((w) => /* @__PURE__ */ jsxRuntime.jsx(WriterRow, { writer: w, status, lang }, w.key))
2203
+ }
2204
+ );
1617
2205
  }
1618
2206
  const STATUS_FILTERS = ["planned", "applied", "simulated", "over_cap", "stale", "failed", "quarantined", "skipped"];
2207
+ const STATUS_ICON = {
2208
+ planned: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}),
2209
+ applied: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, {}),
2210
+ simulated: /* @__PURE__ */ jsxRuntime.jsx(icons.Beaker, {}),
2211
+ over_cap: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLongRight, {}),
2212
+ stale: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
2213
+ failed: /* @__PURE__ */ jsxRuntime.jsx(icons.XCircle, {}),
2214
+ quarantined: /* @__PURE__ */ jsxRuntime.jsx(icons.ExclamationCircle, {}),
2215
+ skipped: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUturnLeft, {})
2216
+ };
2217
+ const STATUS_ATTENTION = /* @__PURE__ */ new Set(["failed", "quarantined", "stale"]);
1619
2218
  function ChangeCell({ change, lang }) {
1620
2219
  const { t } = reactI18next.useTranslation("subiekt");
1621
2220
  if (change.kind === "create") return /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("products.newProduct", { price: fmtMoney(change.to, change.currency, lang) }) });
@@ -1661,7 +2260,7 @@ function ProductsSection({ status, lang, poll, onAction }) {
1661
2260
  const [filter, setFilter] = react.useState("all");
1662
2261
  const [search, setSearch] = react.useState("");
1663
2262
  const [offset, setOffset] = react.useState(0);
1664
- const q = search.trim();
2263
+ const q = useDebouncedValue(search).trim();
1665
2264
  const running = status.running.includes("products");
1666
2265
  const products = useSubiektProducts(kind, filter, q, offset, PAGE_SIZE$1, poll || running);
1667
2266
  const sync = useSubiektSync();
@@ -1710,112 +2309,147 @@ function ProductsSection({ status, lang, poll, onAction }) {
1710
2309
  ["unmatchedVariants", stats.unmatchedVariants, true],
1711
2310
  ["noPrice", stats.noPrice, true]
1712
2311
  ] : [];
1713
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1714
- /* @__PURE__ */ jsxRuntime.jsxs(SectionHeader, { title: t("products.title"), subtitle: t("products.subtitle"), children: [
1715
- (run == null ? void 0 : run.dryRun) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "purple", children: t("stock.dryRun") }) : null,
1716
- run ? /* @__PURE__ */ jsxRuntime.jsx(RunStatusBadge, { status: run.status }) : null,
1717
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", disabled: !ready || !supported || !o.productSyncEnabled || running, isLoading: sync.isPending, onClick: onRead, children: [
1718
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
1719
- running ? t("actions.running") : t("actions.products")
1720
- ] })
1721
- ] }),
1722
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1 px-6 py-3", children: [
1723
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: settings }),
1724
- run ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
1725
- runSummary(run, t),
1726
- " ",
1727
- fmtDateTime(run.startedAt, lang),
1728
- ", ",
1729
- fmtDuration(run.durationMs)
1730
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("products.never") })
1731
- ] }),
1732
- !o.productSyncEnabled ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "info", label: t("products.title"), children: t("products.disabled") }) }) : !supported ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "warning", label: t("products.title"), children: t("products.unsupported") }) }) : null,
1733
- (stats == null ? void 0 : stats.blocked) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "warning", label: t("products.title"), children: t(`products.blocked.${stats.blocked}`) }) }) : null,
1734
- counters.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-4 gap-y-2 px-6 py-4 sm:grid-cols-4", children: counters.map(([key, value, warn]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
1735
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t(`products.counters.${key}`) }),
1736
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: ui.clx("tabular-nums", warn && value ? "text-ui-tag-orange-text" : void 0), children: fmtNumber(value ?? 0, lang) })
1737
- ] }, key)) }) : null,
1738
- (stats == null ? void 0 : stats.samples) && (((_a = stats.samples.conflicts) == null ? void 0 : _a.length) || ((_b = stats.samples.unmatchedVariants) == null ? void 0 : _b.length) || ((_c = stats.samples.noPrice) == null ? void 0 : _c.length)) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
1739
- ((_d = stats.samples.conflicts) == null ? void 0 : _d.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.conflicts"), items: stats.samples.conflicts }) : null,
1740
- ((_e = stats.samples.unmatchedVariants) == null ? void 0 : _e.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.unmatchedVariants"), items: stats.samples.unmatchedVariants }) : null,
1741
- ((_f = stats.samples.noPrice) == null ? void 0 : _f.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.noPrice"), items: stats.samples.noPrice }) : null
1742
- ] }) : null,
1743
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 px-6 py-3", children: [
1744
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
1745
- /* @__PURE__ */ jsxRuntime.jsx(
1746
- FilterPills,
1747
- {
1748
- value: kind,
1749
- onChange: setKind,
1750
- options: [
1751
- { value: "all", label: t("products.statuses.all") },
1752
- { value: "price", label: t("products.kinds.price") },
1753
- { value: "create", label: t("products.kinds.create") }
1754
- ]
1755
- }
1756
- ),
1757
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full md:w-56", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { size: "small", type: "search", placeholder: t("products.search"), value: search, onChange: (e) => setSearch(e.target.value) }) })
2312
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2313
+ Section,
2314
+ {
2315
+ id: "subiekt-products",
2316
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Tag, {}),
2317
+ title: t("products.title"),
2318
+ badges: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2319
+ (run == null ? void 0 : run.dryRun) ? /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: "blue", children: t("stock.dryRun") }) : null,
2320
+ run ? /* @__PURE__ */ jsxRuntime.jsx(RunStatusBadge, { status: run.status }) : null
1758
2321
  ] }),
1759
- /* @__PURE__ */ jsxRuntime.jsx(
1760
- FilterPills,
1761
- {
1762
- value: filter,
1763
- onChange: setFilter,
1764
- options: [
1765
- { value: "all", label: t("products.statuses.all"), count: summary == null ? void 0 : summary.total },
1766
- ...STATUS_FILTERS.filter((s) => ((summary == null ? void 0 : summary[s]) ?? 0) > 0 || s === filter).map((s) => ({ value: s, label: t(`products.statuses.${s}`), count: summary == null ? void 0 : summary[s] }))
1767
- ]
1768
- }
1769
- )
1770
- ] }),
1771
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
1772
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
1773
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.product") }),
1774
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.change") }),
1775
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("products.columns.store"), hint: t("products.matching") }) }),
1776
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.status") }),
1777
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.details") })
1778
- ] }) }),
1779
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: 5, className: "px-6 py-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: products.isLoading ? "" : t("products.empty") }) }) }) : rows.map((c) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { className: "[&_td]:py-2.5", children: [
1780
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[240px]", children: /* @__PURE__ */ jsxRuntime.jsx(SubiektProductCell, { change: c }) }),
1781
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ChangeCell, { change: c, lang }) }),
1782
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[300px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreProductCell, { change: c }) }),
1783
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(CatalogStatusBadge, { status: c.status }) }),
1784
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { className: "max-w-md", children: [
1785
- c.lastError ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: c.status === "failed" || c.status === "quarantined" ? "text-ui-tag-red-text" : "text-ui-fg-subtle", children: c.lastError }) : null,
1786
- c.appliedAt ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: fmtDateTime(c.appliedAt, lang) }) : null
2322
+ points: [
2323
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListBullet, {}), text: t("products.points.plan") },
2324
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.MagnifyingGlass, {}), text: t("products.points.match"), title: t("products.matching") },
2325
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.LockClosedSolid, {}), text: t("products.points.writer") }
2326
+ ],
2327
+ pointsLabel: t("products.subtitle"),
2328
+ actions: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2329
+ /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { value: search, onChange: setSearch, placeholder: t("products.search") }),
2330
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", disabled: !ready || !supported || !o.productSyncEnabled || running, isLoading: sync.isPending, onClick: onRead, children: [
2331
+ /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
2332
+ running ? t("actions.running") : t("actions.products")
1787
2333
  ] })
1788
- ] }, c.id)) })
1789
- ] }) }),
1790
- /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE$1, count: (data == null ? void 0 : data.count) ?? 0, onChange: setOffset }),
1791
- data && data.quarantined.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: [
1792
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: t("products.quarantine") }),
1793
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("products.quarantineHint") }),
1794
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col divide-y", children: data.quarantined.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start justify-between gap-x-4 py-2", children: [
1795
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [
1796
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "font-mono", children: [
1797
- t(`products.kinds.${item.kind}`),
1798
- ": ",
1799
- item.key
1800
- ] }),
1801
- item.lastError ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-red-text", children: item.lastError }) : null
2334
+ ] }),
2335
+ children: [
2336
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1 px-6 py-3", children: [
2337
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: settings }),
2338
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: run ? `${runSummary(run, t)} ${fmtDateTime(run.startedAt, lang)}, ${fmtDuration(run.durationMs)}` : t("products.never") })
1802
2339
  ] }),
1803
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", isLoading: release.isPending && release.variables === item.id, onClick: () => onRelease(item.id), children: t("actions.release") })
1804
- ] }, item.id)) })
1805
- ] }) : null
1806
- ] });
2340
+ !o.productSyncEnabled ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "info", label: t("products.title"), children: t("products.disabled") }) }) : !supported ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "warning", label: t("products.title"), children: t("products.unsupported") }) }) : null,
2341
+ (stats == null ? void 0 : stats.blocked) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "warning", label: t("products.title"), children: t(`products.blocked.${stats.blocked}`) }) }) : null,
2342
+ counters.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(StatTiles, { columns: 4, children: counters.map(([key, value, warn]) => /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t(`products.counters.${key}`), value: fmtNumber(value ?? 0, lang), tone: warn && value ? "orange" : "grey" }, key)) }) : null,
2343
+ (stats == null ? void 0 : stats.samples) && (((_a = stats.samples.conflicts) == null ? void 0 : _a.length) || ((_b = stats.samples.unmatchedVariants) == null ? void 0 : _b.length) || ((_c = stats.samples.noPrice) == null ? void 0 : _c.length)) ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
2344
+ ((_d = stats.samples.conflicts) == null ? void 0 : _d.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.conflicts"), items: stats.samples.conflicts }) : null,
2345
+ ((_e = stats.samples.unmatchedVariants) == null ? void 0 : _e.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.unmatchedVariants"), items: stats.samples.unmatchedVariants }) : null,
2346
+ ((_f = stats.samples.noPrice) == null ? void 0 : _f.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.noPrice"), items: stats.samples.noPrice }) : null
2347
+ ] }) : null,
2348
+ /* @__PURE__ */ jsxRuntime.jsxs(FilterBar, { children: [
2349
+ /* @__PURE__ */ jsxRuntime.jsx(FilterButton, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListBullet, {}), label: t("products.statuses.all"), count: summary == null ? void 0 : summary.total, active: kind === "all" && filter === "all", onClick: () => (setKind("all"), setFilter("all")) }),
2350
+ /* @__PURE__ */ jsxRuntime.jsx(FilterButton, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Tag, {}), label: t("products.kinds.price"), active: kind === "price", onClick: () => setKind(kind === "price" ? "all" : "price") }),
2351
+ /* @__PURE__ */ jsxRuntime.jsx(FilterButton, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}), label: t("products.kinds.create"), active: kind === "create", onClick: () => setKind(kind === "create" ? "all" : "create") }),
2352
+ STATUS_FILTERS.some((st) => ((summary == null ? void 0 : summary[st]) ?? 0) > 0 || st === filter) ? /* @__PURE__ */ jsxRuntime.jsx(FilterDivider, {}) : null,
2353
+ STATUS_FILTERS.filter((st) => ((summary == null ? void 0 : summary[st]) ?? 0) > 0 || st === filter).map((st) => /* @__PURE__ */ jsxRuntime.jsx(
2354
+ FilterButton,
2355
+ {
2356
+ icon: STATUS_ICON[st],
2357
+ label: t(`products.statuses.${st}`),
2358
+ count: summary == null ? void 0 : summary[st],
2359
+ attention: STATUS_ATTENTION.has(st),
2360
+ active: filter === st,
2361
+ onClick: () => setFilter(filter === st ? "all" : st)
2362
+ },
2363
+ st
2364
+ ))
2365
+ ] }),
2366
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2367
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2368
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.product") }),
2369
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.change") }),
2370
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("products.columns.store"), hint: t("products.matching") }) }),
2371
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.status") }),
2372
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.details") })
2373
+ ] }) }),
2374
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: products.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(KitSkeletonRows, { cols: 5, rows: 4 }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyTableRow, { cols: 5, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Tag, {}), title: t("products.empty") }) : rows.map((c) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { className: "[&_td]:py-2.5", children: [
2375
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[240px]", children: /* @__PURE__ */ jsxRuntime.jsx(SubiektProductCell, { change: c }) }),
2376
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ChangeCell, { change: c, lang }) }),
2377
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[300px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreProductCell, { change: c }) }),
2378
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(CatalogStatusBadge, { status: c.status, dot: true }) }),
2379
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { className: "max-w-md", children: [
2380
+ c.lastError ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: c.status === "failed" || c.status === "quarantined" ? "text-ui-tag-red-text" : "text-ui-fg-subtle", children: c.lastError }) : null,
2381
+ c.appliedAt ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: fmtDateTime(c.appliedAt, lang) }) : null
2382
+ ] })
2383
+ ] }, c.id)) })
2384
+ ] }) }),
2385
+ /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE$1, count: (data == null ? void 0 : data.count) ?? 0, onChange: setOffset }),
2386
+ data && data.quarantined.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: [
2387
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-wrap items-center gap-2", children: [
2388
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: t("products.quarantine") }),
2389
+ /* @__PURE__ */ jsxRuntime.jsx(
2390
+ KeyPoints,
2391
+ {
2392
+ items: [
2393
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ExclamationCircle, {}), text: t("products.quarantinePoints.skipped"), tone: "orange" },
2394
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.PencilSquare, {}), text: t("products.quarantinePoints.fix") }
2395
+ ],
2396
+ label: t("products.quarantineHint")
2397
+ }
2398
+ )
2399
+ ] }),
2400
+ /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col divide-y", children: data.quarantined.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-start justify-between gap-x-4 py-2", children: [
2401
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [
2402
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "font-mono", children: [
2403
+ t(`products.kinds.${item.kind}`),
2404
+ ": ",
2405
+ item.key
2406
+ ] }),
2407
+ item.lastError ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-red-text", children: item.lastError }) : null
2408
+ ] }),
2409
+ /* @__PURE__ */ jsxRuntime.jsx(
2410
+ RowActions,
2411
+ {
2412
+ actions: [
2413
+ {
2414
+ key: "release",
2415
+ label: t("actions.release"),
2416
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUturnLeft, {}),
2417
+ loading: release.isPending && release.variables === item.id,
2418
+ onClick: () => void onRelease(item.id)
2419
+ }
2420
+ ]
2421
+ }
2422
+ )
2423
+ ] }, item.id)) })
2424
+ ] }) : null
2425
+ ]
2426
+ }
2427
+ );
1807
2428
  }
1808
2429
  const PAGE_SIZE = 15;
1809
2430
  const SETTINGS_TABS = ["connection", "bridge", "writers", "stock", "runs"];
2431
+ const TASK_FILTERS = ["attention", "open", "done", "all"];
2432
+ function scrollToSection(id) {
2433
+ requestAnimationFrame(() => {
2434
+ var _a;
2435
+ return (_a = document.getElementById(id)) == null ? void 0 : _a.scrollIntoView({ behavior: "smooth", block: "start" });
2436
+ });
2437
+ }
1810
2438
  const SubiektPage = () => {
1811
2439
  const { t, i18n } = reactI18next.useTranslation("subiekt");
1812
2440
  const lang = i18n.language || "en";
1813
2441
  const client = reactQuery.useQueryClient();
1814
2442
  const nav = usePageNav(SETTINGS_TABS);
2443
+ const [params] = reactRouterDom.useSearchParams();
1815
2444
  const [pollUntil, setPollUntil] = react.useState(0);
1816
2445
  const status = useSubiektStatus(pollUntil);
1817
2446
  const s = status.data;
1818
2447
  const polling = ((s == null ? void 0 : s.running.length) ?? 0) > 0 || Date.now() < pollUntil;
2448
+ const asked = params.get("filter") ?? "";
2449
+ const [taskFilter, setTaskFilter] = react.useState(TASK_FILTERS.includes(asked) ? asked : null);
2450
+ const [docKind, setDocKind] = react.useState("all");
2451
+ const initialQuery = (params.get("q") ?? "").slice(0, 80);
2452
+ const filter = taskFilter ?? (s && s.counts.failed > 0 ? "attention" : "all");
1819
2453
  const runKey = JSON.stringify(Object.values((s == null ? void 0 : s.lastRuns) ?? {}).map((r) => (r == null ? void 0 : r.id) ?? ""));
1820
2454
  const seen = react.useRef(void 0);
1821
2455
  react.useEffect(() => {
@@ -1825,32 +2459,45 @@ const SubiektPage = () => {
1825
2459
  seen.current = runKey;
1826
2460
  }, [runKey, client]);
1827
2461
  const poll = () => setPollUntil(Date.now() + 3e4);
2462
+ const toggleTasks = (f) => {
2463
+ setTaskFilter(filter === f ? "all" : f);
2464
+ scrollToSection("subiekt-tasks");
2465
+ };
2466
+ const toggleDocs = (k) => {
2467
+ setDocKind(docKind === k ? "all" : k);
2468
+ scrollToSection("subiekt-documents");
2469
+ };
2470
+ const c = s == null ? void 0 : s.counts;
2471
+ const queued = c ? c.pending + c.running + c.unknown : 0;
1828
2472
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3", children: [
1829
2473
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1830
- /* @__PURE__ */ jsxRuntime.jsx(Header, { status: s, loading: status.isLoading, lang, nav, onAction: poll }),
2474
+ /* @__PURE__ */ jsxRuntime.jsx(Header, { status: s, loading: status.isLoading, fetching: status.isFetching, lang, nav, onAction: poll }),
1831
2475
  status.isError ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.InlineTip, { variant: "error", label: t("title"), children: errorMessage(status.error) }) }) : null,
1832
2476
  s ? /* @__PURE__ */ jsxRuntime.jsx(Warnings, { status: s }) : null,
1833
- s && nav.view === "panel" ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-2 divide-x divide-y md:grid-cols-4 xl:grid-cols-7 xl:divide-y-0", children: [
1834
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.sent24h"), value: fmtNumber(s.counts.succeeded24h, lang) }),
1835
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.waiting"), value: fmtNumber(s.counts.waiting, lang), tone: s.counts.waiting ? void 0 : "muted" }),
2477
+ c && nav.view === "panel" ? /* @__PURE__ */ jsxRuntime.jsxs(StatTiles, { columns: 7, children: [
2478
+ /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.sent24h"), value: fmtNumber(c.succeeded24h, lang), tone: c.succeeded24h ? "green" : "grey", active: filter === "done", onClick: () => toggleTasks("done") }),
2479
+ /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.waiting"), value: fmtNumber(c.waiting, lang), hint: c.waiting ? t("stats.hintWaiting") : void 0 }),
2480
+ /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.queue"), value: fmtNumber(queued, lang), tone: queued ? "blue" : "grey", active: filter === "open", onClick: () => toggleTasks("open") }),
1836
2481
  /* @__PURE__ */ jsxRuntime.jsx(
1837
2482
  StatTile,
1838
2483
  {
1839
- label: t("stats.queue"),
1840
- value: fmtNumber(s.counts.pending + s.counts.running + s.counts.unknown, lang),
1841
- tone: s.counts.pending + s.counts.running + s.counts.unknown ? void 0 : "muted"
2484
+ label: t("stats.attention"),
2485
+ value: fmtNumber(c.failed, lang),
2486
+ tone: c.failed ? "red" : "grey",
2487
+ hint: c.failed ? t("stats.hintAttention") : void 0,
2488
+ active: filter === "attention",
2489
+ onClick: () => toggleTasks("attention")
1842
2490
  }
1843
2491
  ),
1844
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.attention"), value: fmtNumber(s.counts.failed, lang), tone: s.counts.failed ? "attention" : "muted" }),
1845
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.zk"), value: fmtNumber(s.counts.zk, lang) }),
1846
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.wz"), value: fmtNumber(s.counts.wz, lang) }),
1847
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.sales"), value: fmtNumber(s.counts.fs + s.counts.pa, lang), tone: s.counts.fs + s.counts.pa ? void 0 : "muted" })
2492
+ /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.zk"), value: fmtNumber(c.zk, lang), active: docKind === "ZK", onClick: () => toggleDocs("ZK") }),
2493
+ /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.wz"), value: fmtNumber(c.wz, lang), active: docKind === "WZ", onClick: () => toggleDocs("WZ") }),
2494
+ /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.sales"), value: fmtNumber(c.fs + c.pa, lang) })
1848
2495
  ] }) : null
1849
2496
  ] }),
1850
- s && nav.view === "guide" ? /* @__PURE__ */ jsxRuntime.jsx(GuideView, { status: s, lang }) : null,
2497
+ s && nav.view === "guide" ? /* @__PURE__ */ jsxRuntime.jsx(GuideView, { status: s }) : null,
1851
2498
  nav.view === "panel" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1852
- s ? /* @__PURE__ */ jsxRuntime.jsx(TasksSection, { status: s, lang, poll: polling, onAction: poll }) : null,
1853
- /* @__PURE__ */ jsxRuntime.jsx(DocumentsSection, { lang, poll: polling }),
2499
+ s ? /* @__PURE__ */ jsxRuntime.jsx(TasksSection, { status: s, lang, poll: polling, onAction: poll, filter, onFilter: setTaskFilter, initialQuery }) : null,
2500
+ /* @__PURE__ */ jsxRuntime.jsx(DocumentsSection, { lang, poll: polling, kind: docKind, onKind: setDocKind, counts: c, initialQuery }),
1854
2501
  s ? /* @__PURE__ */ jsxRuntime.jsx(ProductsSection, { status: s, lang, poll: polling, onAction: poll }) : null
1855
2502
  ] }) : null,
1856
2503
  nav.view === "settings" ? /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1864,7 +2511,7 @@ const SubiektPage = () => {
1864
2511
  { id: "connection", label: t("settings.tab.connection") },
1865
2512
  { id: "bridge", label: t("settings.tab.bridge") },
1866
2513
  { id: "writers", label: t("settings.tab.writers"), badge: s == null ? void 0 : s.writers.filter((w) => w.active).length, tone: "orange" },
1867
- { id: "stock", label: t("settings.tab.stock"), badge: (s == null ? void 0 : s.options.stockDryRun) ? t("stock.dryRun") : null, tone: "purple" },
2514
+ { id: "stock", label: t("settings.tab.stock"), badge: (s == null ? void 0 : s.options.stockDryRun) ? t("stock.dryRun") : null, tone: "blue" },
1868
2515
  { id: "runs", label: t("settings.tab.runs") }
1869
2516
  ],
1870
2517
  children: [
@@ -1881,17 +2528,18 @@ const SubiektPage = () => {
1881
2528
  function Header({
1882
2529
  status,
1883
2530
  loading,
2531
+ fetching,
1884
2532
  lang,
1885
2533
  nav,
1886
2534
  onAction
1887
2535
  }) {
1888
2536
  const { t } = reactI18next.useTranslation("subiekt");
2537
+ const client = reactQuery.useQueryClient();
1889
2538
  const sync = useSubiektSync();
1890
2539
  const check = useSubiektCheck();
1891
2540
  const ready = Boolean(status && (status.mode === "demo" || status.configured));
1892
2541
  const running = new Set((status == null ? void 0 : status.running) ?? []);
1893
2542
  const state = connectionState(status);
1894
- const references = status ? referencesFor(status.references, lang) : [];
1895
2543
  const promptSpec = usePromptSpec();
1896
2544
  const community = communityLabels((key, options) => t(key, options), `${t("title")} ${t("by")}`);
1897
2545
  const start = async (what) => {
@@ -1915,33 +2563,30 @@ function Header({
1915
2563
  }
1916
2564
  };
1917
2565
  const panel = nav.view !== "guide";
1918
- const checkAction = { key: "check", label: t("actions.check"), loading: check.isPending, disabled: !ready, onClick: () => void onCheck() };
2566
+ const refreshAction = {
2567
+ key: "refresh",
2568
+ label: t("actions.refresh"),
2569
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
2570
+ loading: fetching && !loading,
2571
+ onClick: () => void client.invalidateQueries({ queryKey: subiektKeys.all })
2572
+ };
2573
+ const checkAction = { key: "check", label: t("actions.check"), icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ShieldCheck, {}), loading: check.isPending, disabled: !ready, onClick: () => void onCheck() };
1919
2574
  return /* @__PURE__ */ jsxRuntime.jsx(
1920
2575
  IntegrationHeader,
1921
2576
  {
1922
2577
  icon: /* @__PURE__ */ jsxRuntime.jsx(SubiektIcon, { width: 28, height: 28 }),
1923
2578
  title: t("title"),
1924
- by: t("by"),
2579
+ featured: { url: "https://medusajs.com/integrations/@koda-plusmedusa-plugin-subiekt-nexo", labels: community.featured },
1925
2580
  badges: !loading ? /* @__PURE__ */ jsxRuntime.jsx(ModeBadge, { color: state.tone, label: t(`mode.${state.key}`), title: t("demo.label"), children: (status == null ? void 0 : status.mode) === "demo" ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("demo.text") }) : null }) : null,
1926
2581
  description: t("subtitle"),
1927
- social: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1928
- /* @__PURE__ */ jsxRuntime.jsx(
1929
- ReferencesBadge,
1930
- {
1931
- items: references,
1932
- labels: {
1933
- count: references.length === 1 ? t("references.badgeOne") : t("references.badgeMany", { count: references.length }),
1934
- title: t("references.title"),
1935
- subtitle: t("references.subtitle"),
1936
- open: t("references.open"),
1937
- review: t("references.review"),
1938
- since: (since) => t("references.since", { date: monthYear(since, lang) }),
1939
- rating: (value) => fmtRating(value, lang)
1940
- }
1941
- }
1942
- ),
1943
- /* @__PURE__ */ jsxRuntime.jsx(AddStoreButton, { labels: community.addStore })
1944
- ] }),
2582
+ points: [
2583
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ShoppingCart, {}), text: t("points.orders") },
2584
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArchiveBox, {}), text: t("points.wz") },
2585
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Receipt, {}), text: t("points.sales") },
2586
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CubeSolid, {}), text: t("points.stock") },
2587
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Tag, {}), text: t("points.prices") },
2588
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.LockClosedSolid, {}), text: t("points.safe"), tone: "green" }
2589
+ ],
1945
2590
  help: /* @__PURE__ */ jsxRuntime.jsx(HelpButtons, { spec: promptSpec, lang, labels: community }),
1946
2591
  view: nav.view,
1947
2592
  onView: (v) => nav.go(v),
@@ -1949,19 +2594,21 @@ function Header({
1949
2594
  primary: panel ? {
1950
2595
  key: "stock",
1951
2596
  label: running.has("stock") ? t("actions.running") : t("actions.stock"),
1952
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
2597
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CubeSolid, {}),
1953
2598
  disabled: !ready || running.has("stock"),
1954
2599
  onClick: () => void start("stock")
1955
2600
  } : null,
1956
2601
  actions: panel ? [
2602
+ refreshAction,
1957
2603
  {
1958
2604
  key: "events",
1959
2605
  label: running.has("events") ? t("actions.running") : t("actions.events"),
2606
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownTray, {}),
1960
2607
  disabled: !ready || running.has("events"),
1961
2608
  onClick: () => void start("events")
1962
2609
  },
1963
2610
  checkAction
1964
- ] : [checkAction]
2611
+ ] : [refreshAction, checkAction]
1965
2612
  }
1966
2613
  );
1967
2614
  }
@@ -1977,39 +2624,48 @@ function ConnectionSection({ status, lang }) {
1977
2624
  const { t } = reactI18next.useTranslation("subiekt");
1978
2625
  const c = status.connection;
1979
2626
  const h = c.health;
1980
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1981
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
1982
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("connection.title") }),
1983
- /* @__PURE__ */ jsxRuntime.jsx(ConnectionBadge, { status })
1984
- ] }),
1985
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-2", children: [
1986
- /* @__PURE__ */ jsxRuntime.jsxs(Field, { label: t("connection.bridge"), children: [
1987
- h ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
1988
- (_a = h.bridge) == null ? void 0 : _a.name,
1989
- " ",
1990
- (_b = h.bridge) == null ? void 0 : _b.version,
1991
- " ",
1992
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
1993
- "(",
1994
- t("connection.contract", { version: (_c = h.bridge) == null ? void 0 : _c.contract }),
1995
- ")"
1996
- ] })
1997
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-muted", children: status.bridgeHost ?? t("connection.none") }),
1998
- status.bridgeHost && h ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-muted", children: status.bridgeHost }) : null
1999
- ] }),
2000
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.subiekt"), children: (h == null ? void 0 : h.subiekt) ? [h.subiekt.product, h.subiekt.version].filter(Boolean).join(" ") || t("connection.none") : t("connection.none") }),
2001
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.database"), children: ((_d = h == null ? void 0 : h.subiekt) == null ? void 0 : _d.database) ?? t("connection.none") }),
2002
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.company"), children: ((_e = h == null ? void 0 : h.subiekt) == null ? void 0 : _e.company) ?? t("connection.none") }),
2003
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.warehouse"), children: ((_f = h == null ? void 0 : h.subiekt) == null ? void 0 : _f.warehouse) ?? t("connection.none") }),
2004
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.checkedAt"), children: fmtDateTime(c.checkedAt, lang) || t("connection.never") }),
2005
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.eventsReadAt"), children: fmtDateTime(c.eventsReadAt, lang) || t("connection.never") })
2006
- ] }),
2007
- c.lastError && (!c.reachable || h && !((_g = h.subiekt) == null ? void 0 : _g.connected)) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.InlineTip, { variant: "error", label: t("connection.lastError"), children: [
2008
- c.lastError,
2009
- c.consecutiveFailures > 1 ? ` (${t("connection.failures", { count: c.consecutiveFailures })})` : ""
2010
- ] }) }) : null,
2011
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("connection.schedule") }) })
2012
- ] });
2627
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2628
+ Section,
2629
+ {
2630
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Link, {}),
2631
+ title: t("connection.title"),
2632
+ badges: /* @__PURE__ */ jsxRuntime.jsx(ConnectionBadge, { status }),
2633
+ points: [
2634
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), text: t("connection.points.queue") },
2635
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), text: t("connection.points.documents") },
2636
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), text: t("connection.points.stock") },
2637
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), text: t("connection.points.products") }
2638
+ ],
2639
+ children: [
2640
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-2", children: [
2641
+ /* @__PURE__ */ jsxRuntime.jsxs(Field, { label: t("connection.bridge"), children: [
2642
+ h ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2643
+ (_a = h.bridge) == null ? void 0 : _a.name,
2644
+ " ",
2645
+ (_b = h.bridge) == null ? void 0 : _b.version,
2646
+ " ",
2647
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
2648
+ "(",
2649
+ t("connection.contract", { version: (_c = h.bridge) == null ? void 0 : _c.contract }),
2650
+ ")"
2651
+ ] })
2652
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-muted", children: status.bridgeHost ?? t("connection.none") }),
2653
+ status.bridgeHost && h ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-muted", children: status.bridgeHost }) : null
2654
+ ] }),
2655
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.subiekt"), children: (h == null ? void 0 : h.subiekt) ? [h.subiekt.product, h.subiekt.version].filter(Boolean).join(" ") || t("connection.none") : t("connection.none") }),
2656
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.database"), children: ((_d = h == null ? void 0 : h.subiekt) == null ? void 0 : _d.database) ?? t("connection.none") }),
2657
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.company"), children: ((_e = h == null ? void 0 : h.subiekt) == null ? void 0 : _e.company) ?? t("connection.none") }),
2658
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.warehouse"), children: ((_f = h == null ? void 0 : h.subiekt) == null ? void 0 : _f.warehouse) ?? t("connection.none") }),
2659
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.checkedAt"), children: fmtDateTime(c.checkedAt, lang) || t("connection.never") }),
2660
+ /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.eventsReadAt"), children: fmtDateTime(c.eventsReadAt, lang) || t("connection.never") })
2661
+ ] }),
2662
+ c.lastError && (!c.reachable || h && !((_g = h.subiekt) == null ? void 0 : _g.connected)) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.InlineTip, { variant: "error", label: t("connection.lastError"), children: [
2663
+ c.lastError,
2664
+ c.consecutiveFailures > 1 ? ` (${t("connection.failures", { count: c.consecutiveFailures })})` : ""
2665
+ ] }) }) : null
2666
+ ]
2667
+ }
2668
+ );
2013
2669
  }
2014
2670
  function StockSection({ run, lang }) {
2015
2671
  const { t } = reactI18next.useTranslation("subiekt");
@@ -2025,44 +2681,45 @@ function StockSection({ run, lang }) {
2025
2681
  ["conflicts", stats.conflicts, true]
2026
2682
  ] : [];
2027
2683
  const samples = stats == null ? void 0 : stats.samples;
2028
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2029
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2 px-6 py-4", children: [
2030
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2031
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("stock.title") }),
2032
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("stock.subtitle") })
2033
- ] }),
2034
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-x-2 whitespace-nowrap", children: [
2035
- (run == null ? void 0 : run.dryRun) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "purple", children: t("stock.dryRun") }) : null,
2684
+ return /* @__PURE__ */ jsxRuntime.jsx(
2685
+ Section,
2686
+ {
2687
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CubeSolid, {}),
2688
+ title: t("stock.title"),
2689
+ badges: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2690
+ (run == null ? void 0 : run.dryRun) ? /* @__PURE__ */ jsxRuntime.jsx(ToneBadge, { tone: "blue", children: t("stock.dryRun") }) : null,
2036
2691
  run ? /* @__PURE__ */ jsxRuntime.jsx(RunStatusBadge, { status: run.status }) : null
2037
- ] })
2038
- ] }),
2039
- !run ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: t("stock.never") }) }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2040
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-3", children: [
2041
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: runSummary(run, t) }),
2042
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
2043
- fmtDateTime(run.startedAt, lang),
2044
- ", ",
2045
- fmtDuration(run.durationMs)
2046
- ] })
2047
2692
  ] }),
2048
- counters.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-4 gap-y-2 px-6 py-4 sm:grid-cols-4", children: counters.map(([key, value, warn]) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
2049
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t(`stock.counters.${key}`) }),
2050
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: warn && value ? "text-ui-tag-orange-text tabular-nums" : "tabular-nums", children: fmtNumber(value ?? 0, lang) })
2051
- ] }, key)) }) : null,
2052
- samples ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
2053
- samples.changes && samples.changes.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
2054
- SampleList,
2055
- {
2056
- label: t("stock.samples.changes"),
2057
- items: samples.changes.map((c) => `${c.sku ?? "?"}: ${c.from === null ? "-" : fmtNumber(c.from, lang)} → ${fmtNumber(c.to, lang)}`)
2058
- }
2059
- ) : null,
2060
- samples.unmatchedVariants && samples.unmatchedVariants.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.unmatchedVariants"), items: samples.unmatchedVariants }) : null,
2061
- samples.unmatchedSubiekt && samples.unmatchedSubiekt.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.unmatchedSubiekt"), items: samples.unmatchedSubiekt }) : null,
2062
- samples.conflicts && samples.conflicts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.conflicts"), items: samples.conflicts }) : null
2063
- ] }) : null
2064
- ] })
2065
- ] });
2693
+ points: [
2694
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowLongRight, {}), text: t("stock.points.direction") },
2695
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.MagnifyingGlass, {}), text: t("stock.points.match") }
2696
+ ],
2697
+ pointsLabel: t("stock.subtitle"),
2698
+ children: !run ? /* @__PURE__ */ jsxRuntime.jsx(EmptyState, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CubeSolid, {}), title: t("stock.never"), compact: true }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2699
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-3", children: [
2700
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: runSummary(run, t) }),
2701
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
2702
+ fmtDateTime(run.startedAt, lang),
2703
+ ", ",
2704
+ fmtDuration(run.durationMs)
2705
+ ] })
2706
+ ] }),
2707
+ counters.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(StatTiles, { columns: 4, children: counters.map(([key, value, warn]) => /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t(`stock.counters.${key}`), value: fmtNumber(value ?? 0, lang), tone: warn && value ? "orange" : "grey" }, key)) }) : null,
2708
+ samples ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
2709
+ samples.changes && samples.changes.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
2710
+ SampleList,
2711
+ {
2712
+ label: t("stock.samples.changes"),
2713
+ items: samples.changes.map((ch) => `${ch.sku ?? "?"}: ${ch.from === null ? "-" : fmtNumber(ch.from, lang)} → ${fmtNumber(ch.to, lang)}`)
2714
+ }
2715
+ ) : null,
2716
+ samples.unmatchedVariants && samples.unmatchedVariants.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.unmatchedVariants"), items: samples.unmatchedVariants }) : null,
2717
+ samples.unmatchedSubiekt && samples.unmatchedSubiekt.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.unmatchedSubiekt"), items: samples.unmatchedSubiekt }) : null,
2718
+ samples.conflicts && samples.conflicts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.conflicts"), items: samples.conflicts }) : null
2719
+ ] }) : null
2720
+ ] })
2721
+ }
2722
+ );
2066
2723
  }
2067
2724
  function TaskDetails({ task, lang }) {
2068
2725
  const { t } = reactI18next.useTranslation("subiekt");
@@ -2083,17 +2740,26 @@ function TaskDetails({ task, lang }) {
2083
2740
  (task.status === "pending" || task.status === "unknown") && task.nextAttemptAt && task.attempts > 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("tasks.nextAttempt", { time: fmtDateTime(task.nextAttemptAt, lang) }) }) : null
2084
2741
  ] });
2085
2742
  }
2086
- function TasksSection({ status, lang, poll, onAction }) {
2743
+ function TasksSection({
2744
+ status,
2745
+ lang,
2746
+ poll,
2747
+ onAction,
2748
+ filter,
2749
+ onFilter,
2750
+ initialQuery
2751
+ }) {
2087
2752
  var _a, _b;
2088
2753
  const { t } = reactI18next.useTranslation("subiekt");
2089
- const [filter, setFilter] = react.useState(status.counts.failed > 0 ? "attention" : "all");
2090
- const [search, setSearch] = react.useState("");
2754
+ const [search, setSearch] = react.useState(initialQuery);
2091
2755
  const [offset, setOffset] = react.useState(0);
2092
- const q = search.trim();
2093
- const open = status.counts.waiting + status.counts.pending + status.counts.running + status.counts.unknown;
2094
- const tasks = useSubiektTasks(filter, q, offset, PAGE_SIZE, poll || status.counts.pending + status.counts.running + status.counts.unknown > 0);
2756
+ const q = useDebouncedValue(search).trim();
2757
+ const c = status.counts;
2758
+ const open = c.waiting + c.pending + c.running + c.unknown;
2759
+ const tasks = useSubiektTasks(filter, q, offset, PAGE_SIZE, poll || c.pending + c.running + c.unknown > 0);
2095
2760
  const retry = useSubiektRetry();
2096
2761
  const rows = ((_a = tasks.data) == null ? void 0 : _a.tasks) ?? [];
2762
+ const products = useKitOrderProducts(rows.map((task) => task.orderId));
2097
2763
  react.useEffect(() => setOffset(0), [filter, q]);
2098
2764
  const onRetry = async (task) => {
2099
2765
  try {
@@ -2104,139 +2770,249 @@ function TasksSection({ status, lang, poll, onAction }) {
2104
2770
  ui.toast.error(t("toast.error", { error: errorMessage(err) }));
2105
2771
  }
2106
2772
  };
2107
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2108
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 px-6 py-4 md:flex-row md:items-center md:justify-between", children: [
2109
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2110
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("tasks.title") }),
2111
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-3xl text-ui-fg-subtle", title: t("tasks.technical"), children: t("tasks.subtitle") })
2112
- ] }),
2113
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full md:w-56", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { size: "small", type: "search", placeholder: t("tasks.search"), value: search, onChange: (e) => setSearch(e.target.value) }) })
2114
- ] }),
2115
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
2116
- FilterPills,
2117
- {
2118
- value: filter,
2119
- onChange: setFilter,
2120
- options: [
2121
- { value: "attention", label: t("tasks.filters.attention"), count: status.counts.failed },
2122
- { value: "open", label: t("tasks.filters.open"), count: open },
2123
- { value: "done", label: t("tasks.filters.done") },
2124
- { value: "all", label: t("tasks.filters.all") }
2125
- ]
2126
- }
2127
- ) }),
2128
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2129
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2130
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("tasks.columns.order"), hint: t("store.orderMatching") }) }),
2131
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.operation") }),
2132
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.document") }),
2133
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.status") }),
2134
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: t("tasks.columns.attempts") }),
2135
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.details") }),
2136
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, {})
2137
- ] }) }),
2138
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: 7, className: "px-6 py-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: tasks.isLoading ? "" : t("tasks.empty") }) }) }) : rows.map((task) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { className: "[&_td]:py-2.5", children: [
2139
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[260px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreOrderCell, { orderId: task.orderId, displayId: task.displayId }) }),
2140
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: task.kind === "order.document" && (task.documentKind === "fs" || task.documentKind === "pa") ? t(`tasks.documentKinds.${task.documentKind}`) : t(`tasks.kinds.${task.kind}`) }),
2141
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap font-mono text-xs", children: task.documentNumber ?? "" }),
2142
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(TaskStatusBadge, { status: task.status }) }),
2143
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right tabular-nums", children: task.attempts }),
2144
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-md", children: /* @__PURE__ */ jsxRuntime.jsx(TaskDetails, { task, lang }) }),
2145
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: task.status === "failed" || task.status === "unknown" || task.status === "pending" && task.attempts > 0 || task.status === "waiting" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", isLoading: retry.isPending && retry.variables === task.id, onClick: () => onRetry(task), children: task.status === "waiting" ? t("actions.send") : t("actions.retry") }) : null })
2146
- ] }, task.id)) })
2147
- ] }) }),
2148
- /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE, count: ((_b = tasks.data) == null ? void 0 : _b.count) ?? 0, onChange: setOffset })
2149
- ] });
2773
+ const pick = (f) => onFilter(filter === f && f !== "all" ? "all" : f);
2774
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2775
+ Section,
2776
+ {
2777
+ id: "subiekt-tasks",
2778
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.QueueList, {}),
2779
+ title: t("tasks.title"),
2780
+ points: [
2781
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListBullet, {}), text: t("tasks.points.order") },
2782
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}), text: t("tasks.points.retries") },
2783
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ExclamationCircle, {}), text: t("tasks.points.failed"), tone: c.failed ? "orange" : "grey" }
2784
+ ],
2785
+ pointsLabel: t("tasks.subtitle"),
2786
+ actions: /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { value: search, onChange: setSearch, placeholder: t("tasks.search") }),
2787
+ children: [
2788
+ /* @__PURE__ */ jsxRuntime.jsxs(FilterBar, { children: [
2789
+ /* @__PURE__ */ jsxRuntime.jsx(FilterButton, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListBullet, {}), label: t("tasks.filters.all"), active: filter === "all", onClick: () => pick("all") }),
2790
+ /* @__PURE__ */ jsxRuntime.jsx(FilterDivider, {}),
2791
+ /* @__PURE__ */ jsxRuntime.jsx(FilterButton, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ExclamationCircle, {}), label: t("tasks.filters.attention"), count: c.failed, attention: true, active: filter === "attention", onClick: () => pick("attention") }),
2792
+ /* @__PURE__ */ jsxRuntime.jsx(FilterButton, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), label: t("tasks.filters.open"), count: open, active: filter === "open", onClick: () => pick("open") }),
2793
+ /* @__PURE__ */ jsxRuntime.jsx(FilterButton, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, {}), label: t("tasks.filters.done"), active: filter === "done", onClick: () => pick("done") })
2794
+ ] }),
2795
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2796
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2797
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("tasks.columns.order"), hint: t("store.orderMatching") }) }),
2798
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.products") }),
2799
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.operation") }),
2800
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.document") }),
2801
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.status") }),
2802
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: t("tasks.columns.attempts") }),
2803
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.details") }),
2804
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, {})
2805
+ ] }) }),
2806
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: tasks.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(KitSkeletonRows, { cols: 8, rows: 4 }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyTableRow, { cols: 8, icon: filter === "attention" ? /* @__PURE__ */ jsxRuntime.jsx(icons.CheckCircle, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.QueueList, {}), title: t(`tasks.emptyBy.${filter}`) }) : rows.map((task) => {
2807
+ var _a2;
2808
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { className: "[&_td]:py-2.5", children: [
2809
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[260px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreOrderCell, { orderId: task.orderId, displayId: task.displayId }) }),
2810
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(KitOrderProductsCell, { data: (_a2 = products.data) == null ? void 0 : _a2[task.orderId], loading: products.isLoading, displayId: task.displayId }) }),
2811
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: task.kind === "order.document" && (task.documentKind === "fs" || task.documentKind === "pa") ? t(`tasks.documentKinds.${task.documentKind}`) : t(`tasks.kinds.${task.kind}`) }),
2812
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap font-mono txt-compact-xsmall", children: task.documentNumber ?? "" }),
2813
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(TaskStatusBadge, { status: task.status, dot: true }) }),
2814
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right tabular-nums", children: task.attempts }),
2815
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-md", children: /* @__PURE__ */ jsxRuntime.jsx(TaskDetails, { task, lang }) }),
2816
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right", children: /* @__PURE__ */ jsxRuntime.jsx(
2817
+ RowActions,
2818
+ {
2819
+ actions: [
2820
+ {
2821
+ key: "send",
2822
+ label: task.status === "waiting" ? t("actions.send") : t("actions.retry"),
2823
+ icon: task.status === "waiting" ? /* @__PURE__ */ jsxRuntime.jsx(icons.PaperPlane, {}) : /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
2824
+ loading: retry.isPending && retry.variables === task.id,
2825
+ hidden: !(task.status === "failed" || task.status === "unknown" || task.status === "pending" && task.attempts > 0 || task.status === "waiting"),
2826
+ onClick: () => void onRetry(task)
2827
+ }
2828
+ ]
2829
+ }
2830
+ ) })
2831
+ ] }, task.id);
2832
+ }) })
2833
+ ] }) }),
2834
+ /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE, count: ((_b = tasks.data) == null ? void 0 : _b.count) ?? 0, onChange: setOffset })
2835
+ ]
2836
+ }
2837
+ );
2150
2838
  }
2151
- function DocumentsSection({ lang, poll }) {
2839
+ const DOC_KINDS = [
2840
+ { kind: "ZK", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ShoppingCart, {}), count: (c) => c.zk },
2841
+ { kind: "WZ", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArchiveBox, {}), count: (c) => c.wz },
2842
+ { kind: "FS", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.DocumentText, {}), count: (c) => c.fs },
2843
+ { kind: "PA", icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Receipt, {}), count: (c) => c.pa }
2844
+ ];
2845
+ function DocumentsSection({
2846
+ lang,
2847
+ poll,
2848
+ kind,
2849
+ onKind,
2850
+ counts,
2851
+ initialQuery
2852
+ }) {
2152
2853
  var _a, _b;
2153
2854
  const { t } = reactI18next.useTranslation("subiekt");
2154
- const [kind, setKind] = react.useState("all");
2855
+ const [search, setSearch] = react.useState(initialQuery);
2856
+ const q = useDebouncedValue(search).trim();
2155
2857
  const [offset, setOffset] = react.useState(0);
2156
- const docs = useSubiektDocuments(kind, "", offset, PAGE_SIZE, poll);
2858
+ const docs = useSubiektDocuments(kind, q, offset, PAGE_SIZE, poll);
2157
2859
  const rows = ((_a = docs.data) == null ? void 0 : _a.documents) ?? [];
2158
- react.useEffect(() => setOffset(0), [kind]);
2159
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2160
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 px-6 py-4 md:flex-row md:items-center md:justify-between", children: [
2161
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2162
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("documents.title") }),
2163
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-3xl text-ui-fg-subtle", children: t("documents.subtitle") })
2164
- ] }),
2165
- /* @__PURE__ */ jsxRuntime.jsx(
2166
- FilterPills,
2167
- {
2168
- value: kind,
2169
- onChange: setKind,
2170
- options: ["all", "ZK", "WZ", "FS", "PA"].map((k) => ({ value: k, label: t(`documents.filters.${k}`) }))
2171
- }
2172
- )
2173
- ] }),
2174
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2175
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2176
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.number") }),
2177
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("documents.columns.order"), hint: t("store.orderMatching") }) }),
2178
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.issued") }),
2179
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.source") }),
2180
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.ksef") }),
2181
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.status") })
2182
- ] }) }),
2183
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: 6, className: "px-6 py-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: docs.isLoading ? "" : t("documents.empty") }) }) }) : rows.map((d) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { className: "[&_td]:py-2.5", children: [
2184
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { className: "whitespace-nowrap font-mono text-xs", children: [
2185
- d.number,
2186
- d.related.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
2187
- " ← ",
2188
- d.related.map((r) => r.number).join(", ")
2189
- ] }) : null
2860
+ const products = useKitOrderProducts(rows.map((d) => d.orderId));
2861
+ react.useEffect(() => setOffset(0), [kind, q]);
2862
+ return /* @__PURE__ */ jsxRuntime.jsxs(
2863
+ Section,
2864
+ {
2865
+ id: "subiekt-documents",
2866
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.DocumentText, {}),
2867
+ title: t("documents.title"),
2868
+ points: [
2869
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Link, {}), text: t("documents.points.tag") },
2870
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArchiveBox, {}), text: t("documents.points.warehouse") },
2871
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Receipt, {}), text: t("documents.points.ksef") }
2872
+ ],
2873
+ pointsLabel: t("documents.subtitle"),
2874
+ actions: /* @__PURE__ */ jsxRuntime.jsx(SearchInput, { value: search, onChange: setSearch, placeholder: t("documents.search") }),
2875
+ children: [
2876
+ /* @__PURE__ */ jsxRuntime.jsxs(FilterBar, { children: [
2877
+ /* @__PURE__ */ jsxRuntime.jsx(FilterButton, { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ListBullet, {}), label: t("documents.filters.all"), count: counts == null ? void 0 : counts.documents, active: kind === "all", onClick: () => onKind("all") }),
2878
+ /* @__PURE__ */ jsxRuntime.jsx(FilterDivider, {}),
2879
+ DOC_KINDS.map((d) => /* @__PURE__ */ jsxRuntime.jsx(
2880
+ FilterButton,
2881
+ {
2882
+ icon: d.icon,
2883
+ label: t(`documents.filters.${d.kind}`),
2884
+ count: counts ? d.count(counts) : void 0,
2885
+ active: kind === d.kind,
2886
+ onClick: () => onKind(kind === d.kind ? "all" : d.kind)
2887
+ },
2888
+ d.kind
2889
+ ))
2190
2890
  ] }),
2191
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[260px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreOrderCell, { orderId: d.orderId, displayId: d.displayId }) }),
2192
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: fmtDateTime(d.issuedAt, lang) }),
2193
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: t(`documents.sources.${d.source}`, { defaultValue: d.source }) }),
2194
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap font-mono text-xs", children: d.ksefNumber ? d.ksefNumber : d.kind === "FS" && d.status !== "canceled" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-sans text-ui-fg-muted", children: t("documents.ksefWaiting") }) : "" }),
2195
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatusBadge, { status: d.status }) })
2196
- ] }, d.id)) })
2197
- ] }) }),
2198
- /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE, count: ((_b = docs.data) == null ? void 0 : _b.count) ?? 0, onChange: setOffset })
2199
- ] });
2891
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2892
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2893
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.number") }),
2894
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("documents.columns.order"), hint: t("store.orderMatching") }) }),
2895
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.products") }),
2896
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.issued") }),
2897
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.source") }),
2898
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.ksef") }),
2899
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.status") })
2900
+ ] }) }),
2901
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: docs.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(KitSkeletonRows, { cols: 7, rows: 4 }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyTableRow, { cols: 7, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.DocumentText, {}), title: t("documents.empty") }) : rows.map((d) => {
2902
+ var _a2;
2903
+ return /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { className: "[&_td]:py-2.5", children: [
2904
+ /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { className: "whitespace-nowrap font-mono txt-compact-xsmall", children: [
2905
+ d.number,
2906
+ d.related.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
2907
+ " ← ",
2908
+ d.related.map((r) => r.number).join(", ")
2909
+ ] }) : null
2910
+ ] }),
2911
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[260px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreOrderCell, { orderId: d.orderId, displayId: d.displayId }) }),
2912
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: d.orderId ? /* @__PURE__ */ jsxRuntime.jsx(KitOrderProductsCell, { data: (_a2 = products.data) == null ? void 0 : _a2[d.orderId], loading: products.isLoading, displayId: d.displayId }) : null }),
2913
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: fmtDateTime(d.issuedAt, lang) }),
2914
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: t(`documents.sources.${d.source}`, { defaultValue: d.source }) }),
2915
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap font-mono txt-compact-xsmall", children: d.ksefNumber ? d.ksefNumber : d.kind === "FS" && d.status !== "canceled" ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-sans text-ui-fg-muted", children: t("documents.ksefWaiting") }) : "" }),
2916
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatusBadge, { status: d.status, dot: true }) })
2917
+ ] }, d.id);
2918
+ }) })
2919
+ ] }) }),
2920
+ /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE, count: ((_b = docs.data) == null ? void 0 : _b.count) ?? 0, onChange: setOffset })
2921
+ ]
2922
+ }
2923
+ );
2200
2924
  }
2201
2925
  function RunsSection({ lang, poll }) {
2202
2926
  var _a;
2203
2927
  const { t } = reactI18next.useTranslation("subiekt");
2204
2928
  const runs = useSubiektRuns(poll);
2205
2929
  const rows = ((_a = runs.data) == null ? void 0 : _a.runs) ?? [];
2206
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2207
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("runs.title") }) }),
2208
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2209
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2210
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.kind") }),
2211
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.trigger") }),
2212
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.status") }),
2213
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.message") }),
2214
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.started") }),
2215
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: t("runs.columns.duration") })
2216
- ] }) }),
2217
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Row, { children: /* @__PURE__ */ jsxRuntime.jsx("td", { colSpan: 6, className: "px-6 py-6 text-center", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: runs.isLoading ? "" : t("runs.empty") }) }) }) : rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { className: "[&_td]:py-2.5", children: [
2218
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: t(`runs.kinds.${r.kind}`) }),
2219
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap text-ui-fg-subtle", children: t(`runs.triggers.${r.trigger}`, { defaultValue: r.trigger }) }),
2220
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(RunStatusBadge, { status: r.status }) }),
2221
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-lg", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: runSummary(r, t) }) }),
2222
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: fmtDateTime(r.startedAt, lang) }),
2223
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right tabular-nums", children: fmtDuration(r.durationMs) })
2224
- ] }, r.id)) })
2225
- ] }) })
2226
- ] });
2930
+ return /* @__PURE__ */ jsxRuntime.jsx(
2931
+ Section,
2932
+ {
2933
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}),
2934
+ title: t("runs.title"),
2935
+ points: [
2936
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.BarsArrowDown, {}), text: t("runs.points.newest") },
2937
+ { icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Bolt, {}), text: t("runs.points.jobs") }
2938
+ ],
2939
+ children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2940
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2941
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.kind") }),
2942
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.trigger") }),
2943
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.status") }),
2944
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.message") }),
2945
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.started") }),
2946
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: t("runs.columns.duration") })
2947
+ ] }) }),
2948
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Body, { children: runs.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(KitSkeletonRows, { cols: 6, rows: 4 }) : rows.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(EmptyTableRow, { cols: 6, icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Clock, {}), title: t("runs.empty") }) : rows.map((r) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { className: "[&_td]:py-2.5", children: [
2949
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: t(`runs.kinds.${r.kind}`) }),
2950
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap text-ui-fg-subtle", children: t(`runs.triggers.${r.trigger}`, { defaultValue: r.trigger }) }),
2951
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(RunStatusBadge, { status: r.status, dot: true }) }),
2952
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-lg", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: runSummary(r, t) }) }),
2953
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: fmtDateTime(r.startedAt, lang) }),
2954
+ /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right tabular-nums", children: fmtDuration(r.durationMs) })
2955
+ ] }, r.id)) })
2956
+ ] }) })
2957
+ }
2958
+ );
2227
2959
  }
2228
2960
  const config = adminSdk.defineRouteConfig({
2229
2961
  label: "Subiekt nexo",
2230
2962
  icon: SubiektIcon
2231
2963
  });
2964
+ const communityEn = {
2965
+ prompt: {
2966
+ button: "Copy prompt",
2967
+ title: "Add this integration to your store",
2968
+ text: "Paste it into Claude Code, Cursor or another AI agent opened in your Medusa project. The agent installs this version of the plugin, sets it up like here and shows you its notes before it saves them.",
2969
+ copy: "Copy",
2970
+ copied: "Prompt copied",
2971
+ failed: "Could not copy. Select the text and copy it by hand."
2972
+ },
2973
+ discord: {
2974
+ button: "Help on Discord",
2975
+ title: "Join the Koda Plus server on Discord"
2976
+ },
2977
+ featured: {
2978
+ badge: "Medusa featured integration",
2979
+ title: "Featured in the Medusa integrations catalog. Opens its page there in a new tab."
2980
+ }
2981
+ };
2982
+ const communityPl = {
2983
+ prompt: {
2984
+ button: "Kopiuj prompt",
2985
+ title: "Dodaj tę integrację do swojego sklepu",
2986
+ text: "Wklej go w Claude Code, Cursorze albo innym agencie AI otwartym w projekcie Twojej Medusy. Agent zainstaluje tę wersję wtyczki, ustawi ją tak jak tutaj i pokaże Ci notatki, zanim je zapisze.",
2987
+ copy: "Kopiuj",
2988
+ copied: "Prompt skopiowany",
2989
+ failed: "Nie udało się skopiować. Zaznacz tekst i skopiuj go ręcznie."
2990
+ },
2991
+ discord: {
2992
+ button: "Pomoc na Discordzie",
2993
+ title: "Dołącz do serwera Koda Plus na Discordzie"
2994
+ },
2995
+ featured: {
2996
+ badge: "Wyróżniona przez Medusę",
2997
+ title: "Wyróżniona w katalogu integracji Medusy. Otwiera jej stronę w katalogu w nowej karcie."
2998
+ }
2999
+ };
2232
3000
  const en = {
2233
3001
  title: "Subiekt nexo",
2234
3002
  by: "by Koda Plus",
2235
3003
  subtitle: "Orders become ZK documents in Subiekt nexo PRO, the WZ issued in the warehouse comes back to the order, sales documents carry their KSeF number, and stock and prices flow from Subiekt to Medusa.",
3004
+ points: {
3005
+ orders: "Order becomes a ZK",
3006
+ wz: "WZ back from the warehouse",
3007
+ sales: "Invoices with KSeF numbers",
3008
+ stock: "Stock from Subiekt",
3009
+ prices: "Prices as a plan first",
3010
+ safe: "Writes only once armed"
3011
+ },
2236
3012
  view: { panel: "Panel", guide: "Setup guide" },
2237
3013
  settings: {
2238
3014
  title: "Settings",
2239
- subtitle: "The technical side of the integration: the connection to the bridge and its diagnostics, the writers, the stock sync and the history of background jobs.",
3015
+ subtitle: "The technical side of the integration",
2240
3016
  tab: {
2241
3017
  connection: "Connection",
2242
3018
  bridge: "Bridge",
@@ -2255,6 +3031,7 @@ const en = {
2255
3031
  },
2256
3032
  actions: {
2257
3033
  moreActions: "More actions",
3034
+ refresh: "Refresh",
2258
3035
  check: "Check connection",
2259
3036
  checking: "Checking",
2260
3037
  stock: "Sync stock",
@@ -2286,7 +3063,9 @@ const en = {
2286
3063
  attention: "Need attention",
2287
3064
  zk: "ZK documents",
2288
3065
  wz: "WZ documents",
2289
- sales: "FS and PA"
3066
+ sales: "FS and PA",
3067
+ hintAttention: "Send again below",
3068
+ hintWaiting: "Sent after payment"
2290
3069
  },
2291
3070
  store: {
2292
3071
  openOrder: "Open order",
@@ -2314,11 +3093,12 @@ const en = {
2314
3093
  never: "never",
2315
3094
  none: "none",
2316
3095
  eventsReadAt: "Documents read",
2317
- schedule: "Queue every minute, documents every 2 minutes, stock every 10 minutes, products every hour."
3096
+ points: { queue: "Queue every minute", documents: "Documents every 2 min", stock: "Stock every 10 min", products: "Products every hour" }
2318
3097
  },
2319
3098
  bridge: {
2320
3099
  title: "Bridge",
2321
3100
  subtitle: "What the last check of the bridge said. Click Check connection for a fresh one.",
3101
+ points: { last: "From the last check", fresh: "Check connection reads again" },
2322
3102
  versions: "Versions",
2323
3103
  versionsValue: "bridge {{bridge}}, contract {{contract}}, plugin {{plugin}}",
2324
3104
  sdk: "nexo SDK and database",
@@ -2397,6 +3177,7 @@ const en = {
2397
3177
  writers: {
2398
3178
  title: "Writers",
2399
3179
  subtitle: "Every write added in 0.2.0 needs its option in medusa-config.ts and a person arming it here. An option set to false wins.",
3180
+ points: { option: "Option in medusa-config.ts", person: "Armed here by a person", falseWins: "Option false wins" },
2400
3181
  demoNote: "Demo: armed writers only simulate. Nothing in this store changes.",
2401
3182
  names: {
2402
3183
  prices: "Prices from Subiekt",
@@ -2443,6 +3224,7 @@ const en = {
2443
3224
  products: {
2444
3225
  title: "Products from Subiekt",
2445
3226
  subtitle: "Prices from Subiekt next to the store products they update, and Subiekt products the store does not sell yet. Everything is a plan first: nothing changes until someone switches its writer on in Settings.",
3227
+ points: { plan: "A plan first", match: "EAN first, then SKU", writer: "Changes after arming" },
2446
3228
  matching: "Subiekt products are matched to store variants by EAN first, then by the SKU against the Subiekt symbol. A code used twice is a conflict and is never guessed.",
2447
3229
  matchedKey: "Matched by {{by}}: {{code}}",
2448
3230
  settings: "Prices from {{level}} ({{type}}) to {{target}}, in {{currency}}.",
@@ -2478,10 +3260,11 @@ const en = {
2478
3260
  columns: { product: "Product in Subiekt", change: "Change", store: "Product in the store", matched: "Matched by", status: "Status", details: "Details" },
2479
3261
  matchedBy: { ean: "EAN", sku: "SKU" },
2480
3262
  newProduct: "new, {{price}}",
2481
- empty: "Nothing in this plan.",
3263
+ empty: "Nothing in this plan",
2482
3264
  search: "Symbol, SKU or EAN",
2483
3265
  quarantine: "Quarantined after repeated failures",
2484
3266
  quarantineHint: "The writer skips these until you release them. Fix the cause first (the last error says what failed).",
3267
+ quarantinePoints: { skipped: "Skipped until released", fix: "Fix the cause first" },
2485
3268
  samples: { conflicts: "Conflicts, never guessed", unmatchedVariants: "Variants without a match (SKU)", noPrice: "Without a price in this level" },
2486
3269
  blocked: {
2487
3270
  currency_mismatch: "The price level is in another currency than priceCurrency: nothing was planned.",
@@ -2491,11 +3274,11 @@ const en = {
2491
3274
  tasks: {
2492
3275
  title: "Queue",
2493
3276
  subtitle: "Orders on their way to Subiekt: every ZK, WZ, invoice or receipt the store asked for, and how it went. A send that failed waits here for you, with a Send again button.",
2494
- technical: "Every call Medusa owes the bridge, with retries. A failed task waits for a person.",
3277
+ points: { order: "One row per call", retries: "Retries by itself", failed: "Failed waits for you" },
3278
+ emptyBy: { attention: "Nothing needs attention", open: "Nothing on its way", done: "Nothing sent yet", all: "Queue empty" },
2495
3279
  filters: { attention: "Need attention", open: "Open", done: "Done", all: "All" },
2496
3280
  search: "Order number",
2497
- empty: "Nothing here.",
2498
- columns: { order: "Order in the store", operation: "Operation", status: "Status", attempts: "Attempts", document: "Document in Subiekt", details: "Details", actions: "" },
3281
+ columns: { order: "Order in the store", products: "Products", operation: "Operation", status: "Status", attempts: "Attempts", document: "Document in Subiekt", details: "Details", actions: "" },
2499
3282
  kinds: { "order.create": "Create ZK", "order.cancel": "Cancel ZK", "order.fulfill": "Issue WZ", "order.document": "Issue sales document" },
2500
3283
  documentKinds: { fs: "Issue FS", pa: "Issue PA" },
2501
3284
  statuses: {
@@ -2518,17 +3301,20 @@ const en = {
2518
3301
  documents: {
2519
3302
  title: "Documents",
2520
3303
  subtitle: "What Subiekt issued for your orders: ZK, WZ, invoices and receipts, each next to its order in the store.",
3304
+ points: { tag: "Order tag in the notes", warehouse: "WZ from the warehouse", ksef: "KSeF number on FS" },
3305
+ search: "Document or order number",
2521
3306
  filters: { all: "All", ZK: "ZK", WZ: "WZ", FS: "FS", PA: "PA" },
2522
- empty: "No documents yet.",
2523
- columns: { number: "Number", order: "Order in the store", issued: "Issued", source: "Source", status: "Status", ksef: "KSeF number" },
2524
- sources: { bridge: "Medusa", subiekt: "Warehouse", demo: "Demo" },
3307
+ empty: "No documents yet",
3308
+ columns: { number: "Number", order: "Order in the store", products: "Products", issued: "Issued", source: "Source", status: "Status", ksef: "KSeF number" },
3309
+ sources: { bridge: "Medusa", subiekt: "Warehouse", demo: "Demo", linked: "Linked by hand" },
2525
3310
  statuses: { open: "Open", canceled: "Canceled", completed: "Completed" },
2526
3311
  ksefWaiting: "waiting for KSeF"
2527
3312
  },
2528
3313
  stock: {
2529
3314
  title: "Stock",
2530
3315
  subtitle: "Subiekt to Medusa, by EAN first, then SKU against the product symbol.",
2531
- never: "No stock sync yet.",
3316
+ points: { direction: "Subiekt to Medusa", match: "EAN first, then SKU" },
3317
+ never: "No stock sync yet",
2532
3318
  dryRun: "Dry run",
2533
3319
  counters: {
2534
3320
  subiektProducts: "Products in Subiekt",
@@ -2549,9 +3335,10 @@ const en = {
2549
3335
  },
2550
3336
  runs: {
2551
3337
  title: "History",
2552
- empty: "No runs yet.",
3338
+ empty: "No runs yet",
3339
+ points: { newest: "Newest first", jobs: "Background jobs and clicks" },
2553
3340
  columns: { kind: "Job", trigger: "Trigger", status: "Result", message: "Summary", started: "Started", duration: "Time" },
2554
- kinds: { stock: "Stock", events: "Documents", tasks: "Queue", health: "Connection", products: "Products" },
3341
+ kinds: { stock: "Stock", events: "Documents", tasks: "Queue", health: "Connection", products: "Products", catchup: "Safety net" },
2555
3342
  triggers: { schedule: "Schedule", manual: "Manual", webhook: "Webhook", event: "Event", auto: "Automatic" },
2556
3343
  statuses: { success: "OK", partial: "Partial", error: "Error", skipped: "Skipped" },
2557
3344
  summary: {
@@ -2563,15 +3350,27 @@ const en = {
2563
3350
  eventsNone: "Nothing new.",
2564
3351
  health: "Bridge and Subiekt answer.",
2565
3352
  productsPlan: "Plan: {{prices}} price change(s), {{creates}} new product(s). No writer armed.",
2566
- productsApplied: "{{prices}} price change(s), {{creates}} new product(s) planned, {{applied}} applied, {{failed}} failed."
3353
+ productsApplied: "{{prices}} price change(s), {{creates}} new product(s) planned, {{applied}} applied, {{failed}} failed.",
3354
+ catchup: "{{queued}} order(s) without a ZK task queued, {{released}} released after the payment.",
3355
+ catchupErrors: "{{queued}} order(s) without a ZK task queued, {{released}} released after the payment, {{errors}} error(s)."
2567
3356
  }
2568
3357
  },
2569
3358
  widget: {
2570
3359
  title: "Subiekt nexo",
2571
3360
  demo: "Demo",
2572
3361
  more: "Panel",
2573
- none: "This order has not been sent to Subiekt.",
2574
- waiting: "The ZK will be created when the payment is captured.",
3362
+ none: "Not sent to Subiekt",
3363
+ waiting: "ZK after the payment capture",
3364
+ state: { notSent: "Not sent", waiting: "Waiting for payment", sending: "Sending", attention: "Needs attention", inSubiekt: "In Subiekt" },
3365
+ run: {
3366
+ queue: "Waiting in the Medusa queue",
3367
+ queueShort: "Queue",
3368
+ bridge: "The bridge issues the document",
3369
+ bridgeShort: "Bridge",
3370
+ document: "The number comes back",
3371
+ documentShort: "Number",
3372
+ done: "In Subiekt"
3373
+ },
2575
3374
  send: "Send to Subiekt now",
2576
3375
  sent: "Queued. The ZK appears here in a few seconds.",
2577
3376
  ksef: "KSeF {{number}}",
@@ -2580,7 +3379,29 @@ const en = {
2580
3379
  issuePa: "Issue receipt (PA)",
2581
3380
  issued: "Queued. The document appears here in a few seconds.",
2582
3381
  autoOff: "Automatic sales documents are off: arm the writer on the Subiekt page.",
2583
- autoOn: "The sales document is issued automatically after the {{after}}."
3382
+ autoOn: "The sales document is issued automatically after the {{after}}.",
3383
+ kinds: { ZK: "Order from customer (ZK)", WZ: "Goods issue (WZ)", FS: "Invoice (FS)", PA: "Receipt (PA)" },
3384
+ warehouse: "warehouse {{warehouse}}",
3385
+ related: "From {{numbers}}",
3386
+ zkCompleted: "Realized in Subiekt: the goods were released.",
3387
+ check: {
3388
+ button: "Check in Subiekt",
3389
+ again: "Check again",
3390
+ hint: "No ZK here? Check in Subiekt: if it is already there, link it to the order.",
3391
+ title: "In Subiekt now",
3392
+ at: "checked {{time}}",
3393
+ nothing: "Subiekt has no document for this order.",
3394
+ inSubiekt: "In Subiekt: {{status}}",
3395
+ notReported: "Subiekt does not report it (deleted there, or another database)",
3396
+ canceledThere: "Canceled in Subiekt.",
3397
+ states: { missing: "Not in Medusa", status_differs: "Medusa shows {{status}}", same: "Recorded", only_local: "Only in Medusa" },
3398
+ link: "Link",
3399
+ update: "Update status",
3400
+ linkHint: "Records it in Medusa. Nothing changes in Subiekt, no second document.",
3401
+ updateHint: "Records the status Subiekt shows. Nothing changes in Subiekt.",
3402
+ linked: "{{number}} linked to the order.",
3403
+ updated: "{{number}} updated."
3404
+ }
2584
3405
  },
2585
3406
  toast: {
2586
3407
  started: "Started. Results appear here in a moment.",
@@ -2591,43 +3412,7 @@ const en = {
2591
3412
  released: "Released. The next run tries it again.",
2592
3413
  error: "Something went wrong: {{error}}"
2593
3414
  },
2594
- references: {
2595
- title: "Running in stores built by Koda Plus",
2596
- subtitle: "Live stores implemented by Koda Plus that run on this integration every day.",
2597
- open: "Open the store",
2598
- since: "Since {{date}}",
2599
- badgeOne: "Running in 1 store",
2600
- badgeMany: "Running in {{count}} stores",
2601
- review: "Read the review"
2602
- },
2603
- community: {
2604
- addStore: {
2605
- button: "Add your store",
2606
- title: "Does your store run on this integration?",
2607
- text: "Tell us about it. Once we check it, the store joins this list with a link and its rating.",
2608
- name: "Store name",
2609
- url: "Store address",
2610
- note: "A few words about the setup (optional)",
2611
- send: "Send the request",
2612
- copy: "Copy the text",
2613
- copied: "Request copied, paste it into a mail to hello@koda.plus",
2614
- hint: "Your mail app opens with the message to {{email}} ready to send.",
2615
- subject: "A store for {{integration}}",
2616
- greeting: "Hello, my store runs on {{integration}}. Please add it to the list of stores."
2617
- },
2618
- prompt: {
2619
- button: "Copy prompt",
2620
- title: "Add this integration to your store",
2621
- text: "Paste it into Claude Code, Cursor or another AI agent opened in your Medusa project. The agent installs the plugin, sets it up like here and leaves notes for further work.",
2622
- copy: "Copy again",
2623
- copied: "Prompt copied",
2624
- failed: "Could not copy. Select the text and copy it by hand."
2625
- },
2626
- discord: {
2627
- button: "Help on Discord",
2628
- title: "Join the Koda Plus server on Discord"
2629
- }
2630
- },
3415
+ community: communityEn,
2631
3416
  guide: {
2632
3417
  intro: {
2633
3418
  title: "Connect Medusa to Subiekt nexo PRO",
@@ -2889,10 +3674,18 @@ const pl$1 = {
2889
3674
  title: "Subiekt nexo",
2890
3675
  by: "by Koda Plus",
2891
3676
  subtitle: "Zamówienia trafiają do Subiekta nexo PRO jako dokumenty ZK, WZ wystawione w magazynie wraca do zamówienia, dokumenty sprzedaży dostają numer KSeF, a stany i ceny płyną z Subiekta do Medusy.",
3677
+ points: {
3678
+ orders: "Zamówienie jako ZK",
3679
+ wz: "WZ wraca z magazynu",
3680
+ sales: "Faktury z numerem KSeF",
3681
+ stock: "Stany z Subiekta",
3682
+ prices: "Ceny najpierw jako plan",
3683
+ safe: "Zapis dopiero po włączeniu"
3684
+ },
2892
3685
  view: { panel: "Panel", guide: "Przewodnik wdrożenia" },
2893
3686
  settings: {
2894
3687
  title: "Ustawienia",
2895
- subtitle: "Techniczna strona integracji: połączenie z mostem i jego diagnostyka, przełączniki zapisu, synchronizacja stanów i historia zadań w tle.",
3688
+ subtitle: "Techniczna strona integracji",
2896
3689
  tab: {
2897
3690
  connection: "Połączenie",
2898
3691
  bridge: "Most",
@@ -2911,6 +3704,7 @@ const pl$1 = {
2911
3704
  },
2912
3705
  actions: {
2913
3706
  moreActions: "Więcej akcji",
3707
+ refresh: "Odśwież",
2914
3708
  check: "Sprawdź połączenie",
2915
3709
  checking: "Sprawdzam",
2916
3710
  stock: "Synchronizuj stany",
@@ -2942,7 +3736,9 @@ const pl$1 = {
2942
3736
  attention: "Wymagają uwagi",
2943
3737
  zk: "Dokumenty ZK",
2944
3738
  wz: "Dokumenty WZ",
2945
- sales: "FS i PA"
3739
+ sales: "FS i PA",
3740
+ hintAttention: "Wyślij ponownie niżej",
3741
+ hintWaiting: "Wysyłka po płatności"
2946
3742
  },
2947
3743
  store: {
2948
3744
  openOrder: "Otwórz zamówienie",
@@ -2970,11 +3766,12 @@ const pl$1 = {
2970
3766
  never: "nigdy",
2971
3767
  none: "brak",
2972
3768
  eventsReadAt: "Dokumenty pobrane",
2973
- schedule: "Kolejka co minutę, dokumenty co 2 minuty, stany co 10 minut, produkty co godzinę."
3769
+ points: { queue: "Kolejka co minutę", documents: "Dokumenty co 2 min", stock: "Stany co 10 min", products: "Produkty co godzinę" }
2974
3770
  },
2975
3771
  bridge: {
2976
3772
  title: "Most",
2977
3773
  subtitle: "Co powiedziało ostatnie sprawdzenie mostu. Świeży odczyt daje przycisk Sprawdź połączenie.",
3774
+ points: { last: "Z ostatniego sprawdzenia", fresh: "Sprawdź połączenie czyta od nowa" },
2978
3775
  versions: "Wersje",
2979
3776
  versionsValue: "most {{bridge}}, kontrakt {{contract}}, wtyczka {{plugin}}",
2980
3777
  sdk: "nexo SDK i baza",
@@ -3053,6 +3850,7 @@ const pl$1 = {
3053
3850
  writers: {
3054
3851
  title: "Przełączniki zapisu",
3055
3852
  subtitle: "Każdy zapis dodany w 0.2.0 wymaga swojej opcji w medusa-config.ts i osoby, która włączy go tutaj. Opcja ustawiona na false wygrywa.",
3853
+ points: { option: "Opcja w medusa-config.ts", person: "Włącza tu człowiek", falseWins: "Opcja false wygrywa" },
3056
3854
  demoNote: "Demo: włączone zapisy tylko symulują. W tym sklepie nic się nie zmienia.",
3057
3855
  names: {
3058
3856
  prices: "Ceny z Subiekta",
@@ -3099,6 +3897,7 @@ const pl$1 = {
3099
3897
  products: {
3100
3898
  title: "Produkty z Subiekta",
3101
3899
  subtitle: "Ceny z Subiekta obok produktów w sklepie, które aktualizują, oraz towary z Subiekta, których sklep jeszcze nie sprzedaje. Najpierw wszystko jest planem: nic się nie zmienia, dopóki ktoś nie włączy zapisu w Ustawieniach.",
3900
+ points: { plan: "Najpierw plan", match: "Najpierw EAN, potem SKU", writer: "Zmiany po włączeniu zapisu" },
3102
3901
  matching: "Towary z Subiekta są dopasowywane do wariantów w sklepie najpierw po EAN, potem po SKU porównanym z symbolem w Subiekcie. Kod użyty dwa razy to konflikt i nigdy nie jest zgadywany.",
3103
3902
  matchedKey: "Dopasowane po {{by}}: {{code}}",
3104
3903
  settings: "Ceny z {{level}} ({{type}}) do: {{target}}, w walucie {{currency}}.",
@@ -3134,10 +3933,11 @@ const pl$1 = {
3134
3933
  columns: { product: "Towar w Subiekcie", change: "Zmiana", store: "Produkt w sklepie", matched: "Dopasowanie", status: "Status", details: "Szczegóły" },
3135
3934
  matchedBy: { ean: "EAN", sku: "SKU" },
3136
3935
  newProduct: "nowy, {{price}}",
3137
- empty: "Nic w tym planie.",
3936
+ empty: "Nic w tym planie",
3138
3937
  search: "Symbol, SKU albo EAN",
3139
3938
  quarantine: "W kwarantannie po kolejnych błędach",
3140
3939
  quarantineHint: "Zapis pomija te pozycje, dopóki ich nie zwolnisz. Najpierw usuń przyczynę (ostatni błąd mówi, co poszło nie tak).",
3940
+ quarantinePoints: { skipped: "Pomijane do zwolnienia", fix: "Najpierw usuń przyczynę" },
3141
3941
  samples: { conflicts: "Konflikty, nigdy nie zgadujemy", unmatchedVariants: "Warianty bez dopasowania (SKU)", noPrice: "Bez ceny w tym poziomie" },
3142
3942
  blocked: {
3143
3943
  currency_mismatch: "Poziom cen jest w innej walucie niż priceCurrency: nic nie zaplanowano.",
@@ -3147,11 +3947,11 @@ const pl$1 = {
3147
3947
  tasks: {
3148
3948
  title: "Kolejka",
3149
3949
  subtitle: "Zamówienia w drodze do Subiekta: każde ZK, WZ, faktura albo paragon, o które poprosił sklep, i jak poszło. Wysyłka, która się nie udała, czeka tu na Ciebie z przyciskiem Wyślij ponownie.",
3150
- technical: "Każde wywołanie, które Medusa ma do wykonania w moście, z ponowieniami. Nieudane zadanie czeka na człowieka.",
3950
+ points: { order: "Wiersz na każde wywołanie", retries: "Ponawia sama", failed: "Nieudane czeka na Ciebie" },
3951
+ emptyBy: { attention: "Nic nie wymaga uwagi", open: "Nic nie jest w drodze", done: "Jeszcze nic nie wysłano", all: "Kolejka pusta" },
3151
3952
  filters: { attention: "Wymagają uwagi", open: "Otwarte", done: "Zakończone", all: "Wszystkie" },
3152
3953
  search: "Numer zamówienia",
3153
- empty: "Nic tu nie ma.",
3154
- columns: { order: "Zamówienie w sklepie", operation: "Operacja", status: "Status", attempts: "Próby", document: "Dokument w Subiekcie", details: "Szczegóły", actions: "" },
3954
+ columns: { order: "Zamówienie w sklepie", products: "Produkty", operation: "Operacja", status: "Status", attempts: "Próby", document: "Dokument w Subiekcie", details: "Szczegóły", actions: "" },
3155
3955
  kinds: { "order.create": "Utwórz ZK", "order.cancel": "Anuluj ZK", "order.fulfill": "Wystaw WZ", "order.document": "Wystaw dokument sprzedaży" },
3156
3956
  documentKinds: { fs: "Wystaw FS", pa: "Wystaw PA" },
3157
3957
  statuses: {
@@ -3174,17 +3974,20 @@ const pl$1 = {
3174
3974
  documents: {
3175
3975
  title: "Dokumenty",
3176
3976
  subtitle: "Co Subiekt wystawił do Twoich zamówień: ZK, WZ, faktury i paragony, każdy dokument obok swojego zamówienia w sklepie.",
3977
+ points: { tag: "Znacznik zamówienia w uwagach", warehouse: "WZ z magazynu", ksef: "Numer KSeF na FS" },
3978
+ search: "Numer dokumentu albo zamówienia",
3177
3979
  filters: { all: "Wszystkie", ZK: "ZK", WZ: "WZ", FS: "FS", PA: "PA" },
3178
- empty: "Jeszcze nie ma dokumentów.",
3179
- columns: { number: "Numer", order: "Zamówienie w sklepie", issued: "Wystawiono", source: "Źródło", status: "Status", ksef: "Numer KSeF" },
3180
- sources: { bridge: "Medusa", subiekt: "Magazyn", demo: "Demo" },
3980
+ empty: "Jeszcze bez dokumentów",
3981
+ columns: { number: "Numer", order: "Zamówienie w sklepie", products: "Produkty", issued: "Wystawiono", source: "Źródło", status: "Status", ksef: "Numer KSeF" },
3982
+ sources: { bridge: "Medusa", subiekt: "Magazyn", demo: "Demo", linked: "Połączone ręcznie" },
3181
3983
  statuses: { open: "Otwarty", canceled: "Anulowany", completed: "Zrealizowany" },
3182
3984
  ksefWaiting: "czeka na KSeF"
3183
3985
  },
3184
3986
  stock: {
3185
3987
  title: "Stany",
3186
3988
  subtitle: "Z Subiekta do Medusy, najpierw po EAN, potem po SKU porównanym z symbolem towaru.",
3187
- never: "Synchronizacja stanów jeszcze się nie odbyła.",
3989
+ points: { direction: "Z Subiekta do Medusy", match: "Najpierw EAN, potem SKU" },
3990
+ never: "Stany jeszcze nie synchronizowane",
3188
3991
  dryRun: "Próba na sucho",
3189
3992
  counters: {
3190
3993
  subiektProducts: "Towary w Subiekcie",
@@ -3205,9 +4008,10 @@ const pl$1 = {
3205
4008
  },
3206
4009
  runs: {
3207
4010
  title: "Historia",
3208
- empty: "Jeszcze nic się nie wydarzyło.",
4011
+ empty: "Jeszcze bez uruchomień",
4012
+ points: { newest: "Najnowsze na górze", jobs: "Zadania w tle i kliknięcia" },
3209
4013
  columns: { kind: "Zadanie", trigger: "Wyzwalacz", status: "Wynik", message: "Podsumowanie", started: "Start", duration: "Czas" },
3210
- kinds: { stock: "Stany", events: "Dokumenty", tasks: "Kolejka", health: "Połączenie", products: "Produkty" },
4014
+ kinds: { stock: "Stany", events: "Dokumenty", tasks: "Kolejka", health: "Połączenie", products: "Produkty", catchup: "Siatka bezpieczeństwa" },
3211
4015
  triggers: { schedule: "Harmonogram", manual: "Ręcznie", webhook: "Webhook", event: "Zdarzenie", auto: "Automatycznie" },
3212
4016
  statuses: { success: "OK", partial: "Częściowo", error: "Błąd", skipped: "Pominięto" },
3213
4017
  summary: {
@@ -3219,15 +4023,27 @@ const pl$1 = {
3219
4023
  eventsNone: "Nic nowego.",
3220
4024
  health: "Most i Subiekt odpowiadają.",
3221
4025
  productsPlan: "Plan: zmiany cen {{prices}}, nowe produkty {{creates}}. Żaden zapis nie jest włączony.",
3222
- productsApplied: "Zaplanowane zmiany cen: {{prices}}, nowe produkty: {{creates}}, naniesione: {{applied}}, nieudane: {{failed}}."
4026
+ productsApplied: "Zaplanowane zmiany cen: {{prices}}, nowe produkty: {{creates}}, naniesione: {{applied}}, nieudane: {{failed}}.",
4027
+ catchup: "Zamówienia bez zadania ZK dodane do kolejki: {{queued}}, zwolnione po płatności: {{released}}.",
4028
+ catchupErrors: "Zamówienia bez zadania ZK dodane do kolejki: {{queued}}, zwolnione po płatności: {{released}}, błędy: {{errors}}."
3223
4029
  }
3224
4030
  },
3225
4031
  widget: {
3226
4032
  title: "Subiekt nexo",
3227
4033
  demo: "Demo",
3228
4034
  more: "Panel",
3229
- none: "To zamówienie nie zostało wysłane do Subiekta.",
3230
- waiting: "ZK powstanie po zaksięgowaniu płatności.",
4035
+ none: "Nie wysłano do Subiekta",
4036
+ waiting: "ZK po zaksięgowaniu płatności",
4037
+ state: { notSent: "Nie wysłano", waiting: "Czeka na płatność", sending: "Wysyłka", attention: "Wymaga uwagi", inSubiekt: "W Subiekcie" },
4038
+ run: {
4039
+ queue: "Czeka w kolejce Medusy",
4040
+ queueShort: "Kolejka",
4041
+ bridge: "Most wystawia dokument",
4042
+ bridgeShort: "Most",
4043
+ document: "Numer wraca do Medusy",
4044
+ documentShort: "Numer",
4045
+ done: "W Subiekcie"
4046
+ },
3231
4047
  send: "Wyślij do Subiekta teraz",
3232
4048
  sent: "W kolejce. ZK pojawi się tu za kilka sekund.",
3233
4049
  ksef: "KSeF {{number}}",
@@ -3236,7 +4052,29 @@ const pl$1 = {
3236
4052
  issuePa: "Wystaw paragon (PA)",
3237
4053
  issued: "W kolejce. Dokument pojawi się tu za kilka sekund.",
3238
4054
  autoOff: "Automatyczne dokumenty sprzedaży są wyłączone: włącz zapis na stronie Subiekta.",
3239
- autoOn: "Dokument sprzedaży powstanie automatycznie po {{after}}."
4055
+ autoOn: "Dokument sprzedaży powstanie automatycznie po {{after}}.",
4056
+ kinds: { ZK: "Zamówienie od klienta (ZK)", WZ: "Wydanie zewnętrzne (WZ)", FS: "Faktura (FS)", PA: "Paragon (PA)" },
4057
+ warehouse: "magazyn {{warehouse}}",
4058
+ related: "Na podstawie {{numbers}}",
4059
+ zkCompleted: "Zrealizowane w Subiekcie: towar wydano.",
4060
+ check: {
4061
+ button: "Sprawdź w Subiekcie",
4062
+ again: "Sprawdź ponownie",
4063
+ hint: "Nie ma tu ZK? Sprawdź w Subiekcie: jeśli już tam jest, połącz je z zamówieniem.",
4064
+ title: "W Subiekcie teraz",
4065
+ at: "sprawdzono {{time}}",
4066
+ nothing: "Subiekt nie ma żadnego dokumentu do tego zamówienia.",
4067
+ inSubiekt: "W Subiekcie: {{status}}",
4068
+ notReported: "Subiekt go nie zgłasza (usunięty tam albo inna baza)",
4069
+ canceledThere: "Anulowany w Subiekcie.",
4070
+ states: { missing: "Brak w Medusie", status_differs: "Medusa pokazuje: {{status}}", same: "Zapisany", only_local: "Tylko w Medusie" },
4071
+ link: "Połącz",
4072
+ update: "Zaktualizuj status",
4073
+ linkHint: "Zapisuje go w Medusie. W Subiekcie nic się nie zmienia, drugi dokument nie powstanie.",
4074
+ updateHint: "Zapisuje status, który pokazuje Subiekt. W Subiekcie nic się nie zmienia.",
4075
+ linked: "{{number}} połączony z zamówieniem.",
4076
+ updated: "{{number}} zaktualizowany."
4077
+ }
3240
4078
  },
3241
4079
  toast: {
3242
4080
  started: "Uruchomione. Wynik pojawi się tu za chwilę.",
@@ -3247,43 +4085,7 @@ const pl$1 = {
3247
4085
  released: "Zwolnione. Następny przebieg spróbuje ponownie.",
3248
4086
  error: "Coś poszło nie tak: {{error}}"
3249
4087
  },
3250
- references: {
3251
- title: "Działa w sklepach wdrożonych przez Koda Plus",
3252
- subtitle: "Prawdziwe sklepy z wdrożeniem Koda Plus, które pracują na tej integracji na co dzień.",
3253
- open: "Otwórz sklep",
3254
- since: "Od {{date}}",
3255
- badgeOne: "Działa w 1 sklepie",
3256
- badgeMany: "Działa w {{count}} sklepach",
3257
- review: "Zobacz opinię"
3258
- },
3259
- community: {
3260
- addStore: {
3261
- button: "Dodaj swój sklep",
3262
- title: "Twój sklep działa na tej integracji?",
3263
- text: "Daj nam znać. Po sprawdzeniu dodamy go do tej listy z linkiem i oceną.",
3264
- name: "Nazwa sklepu",
3265
- url: "Adres sklepu",
3266
- note: "Kilka słów o wdrożeniu (opcjonalnie)",
3267
- send: "Wyślij zgłoszenie",
3268
- copy: "Kopiuj treść",
3269
- copied: "Treść skopiowana, wklej ją w mail do hello@koda.plus",
3270
- hint: "Otworzy się Twoja poczta z gotową wiadomością do {{email}}.",
3271
- subject: "Zgłoszenie sklepu: {{integration}}",
3272
- greeting: "Dzień dobry, mój sklep działa na integracji {{integration}}. Proszę o dodanie go do listy sklepów."
3273
- },
3274
- prompt: {
3275
- button: "Kopiuj prompt",
3276
- title: "Dodaj tę integrację do swojego sklepu",
3277
- text: "Wklej go w Claude Code, Cursorze albo innym agencie AI otwartym w projekcie Twojej Medusy. Agent zainstaluje wtyczkę, ustawi ją tak jak tutaj i zostawi notatki do dalszej pracy.",
3278
- copy: "Kopiuj jeszcze raz",
3279
- copied: "Prompt skopiowany",
3280
- failed: "Nie udało się skopiować. Zaznacz tekst i skopiuj go ręcznie."
3281
- },
3282
- discord: {
3283
- button: "Pomoc na Discordzie",
3284
- title: "Dołącz do serwera Koda Plus na Discordzie"
3285
- }
3286
- },
4088
+ community: communityPl,
3287
4089
  guide: {
3288
4090
  intro: {
3289
4091
  title: "Połącz Medusę z Subiektem nexo PRO",