@koda-plus/medusa-plugin-subiekt-nexo 0.2.1 → 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 (43) hide show
  1. package/.medusa/server/src/admin/index.js +1983 -1218
  2. package/.medusa/server/src/admin/index.mjs +1986 -1221
  3. package/.medusa/server/src/api/admin/subiekt/helpers.js +4 -4
  4. package/.medusa/server/src/api/admin/subiekt/orders/[id]/check/route.d.ts +10 -0
  5. package/.medusa/server/src/api/admin/subiekt/orders/[id]/check/route.js +33 -0
  6. package/.medusa/server/src/api/admin/subiekt/orders/[id]/link/route.d.ts +10 -0
  7. package/.medusa/server/src/api/admin/subiekt/orders/[id]/link/route.js +40 -0
  8. package/.medusa/server/src/api/admin/subiekt/sync/route.d.ts +1 -1
  9. package/.medusa/server/src/api/admin/subiekt/sync/route.js +6 -4
  10. package/.medusa/server/src/jobs/subiekt-catch-up.d.ts +12 -0
  11. package/.medusa/server/src/jobs/subiekt-catch-up.js +26 -0
  12. package/.medusa/server/src/modules/subiekt/lib/catch-up.d.ts +47 -0
  13. package/.medusa/server/src/modules/subiekt/lib/catch-up.js +79 -0
  14. package/.medusa/server/src/modules/subiekt/lib/constants.d.ts +13 -1
  15. package/.medusa/server/src/modules/subiekt/lib/constants.js +15 -3
  16. package/.medusa/server/src/modules/subiekt/lib/contract.d.ts +37 -4
  17. package/.medusa/server/src/modules/subiekt/lib/demo.d.ts +1 -1
  18. package/.medusa/server/src/modules/subiekt/lib/demo.js +1 -1
  19. package/.medusa/server/src/modules/subiekt/lib/kit-contract.js +1 -1
  20. package/.medusa/server/src/modules/subiekt/lib/kit-meta.d.ts +2 -2
  21. package/.medusa/server/src/modules/subiekt/lib/kit-meta.js +3 -3
  22. package/.medusa/server/src/modules/subiekt/lib/kit-routes.d.ts +1 -1
  23. package/.medusa/server/src/modules/subiekt/lib/kit-routes.js +2 -2
  24. package/.medusa/server/src/modules/subiekt/lib/options.d.ts +9 -4
  25. package/.medusa/server/src/modules/subiekt/lib/options.js +4 -3
  26. package/.medusa/server/src/modules/subiekt/lib/order-payload.js +24 -12
  27. package/.medusa/server/src/modules/subiekt/lib/reconcile.d.ts +47 -0
  28. package/.medusa/server/src/modules/subiekt/lib/reconcile.js +83 -0
  29. package/.medusa/server/src/subscribers/subiekt-order-placed.d.ts +4 -0
  30. package/.medusa/server/src/subscribers/subiekt-order-placed.js +8 -13
  31. package/.medusa/server/src/workflows/subiekt/catch-up.d.ts +45 -0
  32. package/.medusa/server/src/workflows/subiekt/catch-up.js +163 -0
  33. package/.medusa/server/src/workflows/subiekt/reconcile-order.d.ts +26 -0
  34. package/.medusa/server/src/workflows/subiekt/reconcile-order.js +95 -0
  35. package/.medusa/server/src/workflows/subiekt/runtime.d.ts +9 -0
  36. package/.medusa/server/src/workflows/subiekt/runtime.js +38 -1
  37. package/CHANGELOG.md +39 -0
  38. package/README.md +56 -9
  39. package/contract/examples/events.response.json +1 -1
  40. package/contract/openapi.yaml +1 -1
  41. package/package.json +1 -1
  42. package/.medusa/server/src/modules/subiekt/lib/references.d.ts +0 -76
  43. package/.medusa/server/src/modules/subiekt/lib/references.js +0 -137
@@ -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,493 +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
- function referencesFor(list, lang) {
351
- return (list ?? []).map((r) => ({
352
- name: r.name,
353
- url: r.url ?? void 0,
354
- soon: r.soon,
355
- icon: r.icon,
356
- description: resolveText(r.description, lang),
357
- metrics: r.metrics.map((m) => ({ label: resolveText(m.label, lang) ?? "", value: m.value })).filter((m) => m.label),
358
- links: r.links.map((l) => ({ label: resolveText(l.label, lang) ?? l.url, url: l.url })),
359
- review: r.review ? { ...r.review, quote: resolveText(r.review.quote ?? void 0, lang) } : null
360
- }));
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)) });
347
+ }
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)) });
361
353
  }
362
- function fmtRating(value, lang) {
354
+ function isWhiteLabel() {
355
+ var _a;
363
356
  try {
364
- return new Intl.NumberFormat(lang, { minimumFractionDigits: 1, maximumFractionDigits: 1 }).format(value);
357
+ return Boolean((_a = globalThis.__KODA_KIT__) == null ? void 0 : _a.whiteLabel);
365
358
  } catch {
366
- return value.toFixed(1);
359
+ return false;
367
360
  }
368
361
  }
369
- function MedusaMark({ className }) {
370
- return /* @__PURE__ */ jsxRuntime.jsx("svg", { viewBox: "0 0 36 38", fill: "none", "aria-hidden": true, className, children: /* @__PURE__ */ jsxRuntime.jsx(
371
- "path",
372
- {
373
- 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",
374
- fill: "currentColor"
375
- }
376
- ) });
377
- }
378
- function StoreColumn({ label, hint }) {
379
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-x-1.5", title: hint, children: [
380
- /* @__PURE__ */ jsxRuntime.jsx(MedusaMark, { className: "h-3.5 w-3.5 text-ui-fg-muted" }),
381
- label
382
- ] });
383
- }
384
- function StoreLink({ to, title, mono, monoTitle, action }) {
385
- return /* @__PURE__ */ jsxRuntime.jsxs(reactRouterDom.Link, { to, className: "group flex items-center gap-x-2.5", title: action, children: [
386
- /* @__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" }) }),
387
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
388
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus truncate text-ui-fg-base group-hover:text-ui-fg-interactive", children: title }),
389
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-x-1.5", children: [
390
- mono ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate font-mono text-ui-fg-muted txt-compact-xsmall", title: monoTitle, children: mono }) : null,
391
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "txt-compact-xsmall-plus inline-flex shrink-0 items-center gap-x-0.5 text-ui-fg-interactive", children: [
392
- action,
393
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightMini, {})
394
- ] })
395
- ] })
396
- ] })
397
- ] });
398
- }
399
- function StoreUnlinked({ label, hint, mono }) {
400
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-y-1", title: hint, children: [
401
- /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "orange", children: label }),
402
- mono ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-mono text-ui-fg-muted txt-compact-xsmall", children: mono }) : null
403
- ] });
404
- }
405
- function StoreOrderCell({ orderId, displayId }) {
406
- const { t } = reactI18next.useTranslation("subiekt");
407
- if (!orderId) return /* @__PURE__ */ jsxRuntime.jsx(StoreUnlinked, { label: t("store.noOrder"), hint: t("store.noOrderHint") });
408
- return /* @__PURE__ */ jsxRuntime.jsx(
409
- StoreLink,
410
- {
411
- to: `/orders/${orderId}`,
412
- title: displayId ? `#${displayId}` : orderId,
413
- mono: displayId ? orderId : null,
414
- monoTitle: orderId,
415
- action: t("store.openOrder")
416
- }
417
- );
418
- }
419
- function SubiektIcon({ width = 15, height = 15, ...props }) {
420
- return /* @__PURE__ */ jsxRuntime.jsxs(
421
- "svg",
422
- {
423
- width,
424
- height,
425
- viewBox: "0 0 192 192",
426
- fill: "none",
427
- xmlns: "http://www.w3.org/2000/svg",
428
- "aria-hidden": "true",
429
- ...props,
430
- children: [
431
- /* @__PURE__ */ jsxRuntime.jsx("rect", { width: "192", height: "192", rx: "40", fill: "#0071B8" }),
432
- /* @__PURE__ */ jsxRuntime.jsx(
433
- "path",
434
- {
435
- fill: "#FFFFFF",
436
- 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"
437
- }
438
- )
439
- ]
440
- }
441
- );
442
- }
443
- const SubiektOrderWidget = ({ data }) => {
444
- var _a, _b, _c, _d;
445
- const { t, i18n } = reactI18next.useTranslation("subiekt");
446
- const lang = i18n.language || "en";
447
- const q = useSubiektOrder(data.id);
448
- const send = useSubiektSendOrder(data.id);
449
- const issue = useSubiektIssueDocument(data.id);
450
- const retry = useSubiektRetry();
451
- const documents = ((_a = q.data) == null ? void 0 : _a.documents) ?? [];
452
- const tasks = ((_b = q.data) == null ? void 0 : _b.tasks) ?? [];
453
- const sales = (_c = q.data) == null ? void 0 : _c.salesDocument;
454
- const create = tasks.find((task) => task.kind === "order.create");
455
- const documentTask = tasks.find((task) => task.kind === "order.document");
456
- const hasZk = documents.some((d) => d.kind === "ZK" && d.status !== "canceled");
457
- const hasSales = documents.some((d) => (d.kind === "FS" || d.kind === "PA") && d.status !== "canceled");
458
- const busy = (create == null ? void 0 : create.status) === "pending" || (create == null ? void 0 : create.status) === "running";
459
- const documentBusy = documentTask ? ["pending", "running", "unknown"].includes(documentTask.status) : false;
460
- const canceled = data.status === "canceled";
461
- const offerIssue = Boolean(sales && sales.option !== "none" && sales.supported && hasZk && !hasSales && !documentBusy && !canceled);
462
- const onSend = async () => {
463
- try {
464
- await send.mutateAsync();
465
- ui.toast.success(t("widget.sent"));
466
- } catch (err) {
467
- ui.toast.error(t("toast.error", { error: errorMessage(err) }));
468
- }
469
- };
470
- const onIssue = async (kind) => {
471
- try {
472
- await issue.mutateAsync(kind);
473
- ui.toast.success(t("widget.issued"));
474
- } catch (err) {
475
- ui.toast.error(t("toast.error", { error: errorMessage(err) }));
476
- }
477
- };
478
- const onRetry = async (id) => {
479
- try {
480
- await retry.mutateAsync(id);
481
- ui.toast.success(t("toast.retried"));
482
- void q.refetch();
483
- } catch (err) {
484
- ui.toast.error(t("toast.error", { error: errorMessage(err) }));
485
- }
486
- };
487
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
488
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
489
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
490
- /* @__PURE__ */ jsxRuntime.jsx(SubiektIcon, { width: 18, height: 18, className: "shrink-0" }),
491
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("widget.title") }),
492
- ((_d = q.data) == null ? void 0 : _d.mode) === "demo" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "purple", children: t("widget.demo") }) : null
493
- ] }),
494
- /* @__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") })
495
- ] }),
496
- q.isLoading ? null : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
497
- 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: [
498
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [
499
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "font-mono", children: d.number }),
500
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
501
- fmtDateTime(d.issuedAt, lang),
502
- ", ",
503
- t(`documents.sources.${d.source}`, { defaultValue: d.source })
504
- ] }),
505
- 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
506
- ] }),
507
- /* @__PURE__ */ jsxRuntime.jsx(DocumentStatusBadge, { status: d.status })
508
- ] }, 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") }) }),
509
- 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: [
510
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
511
- /* @__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}`) }),
512
- /* @__PURE__ */ jsxRuntime.jsx(TaskStatusBadge, { status: task.status })
513
- ] }),
514
- 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,
515
- task.warnings.map((w) => /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: w }, w)),
516
- 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,
517
- task.status === "unknown" ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: t("tasks.unknownHint") }) : null,
518
- task.manualAction ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: t("tasks.manual") }) : null,
519
- 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
520
- ] }, task.id)) }) : null,
521
- !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,
522
- offerIssue && sales ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: [
523
- /* @__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") }),
524
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
525
- 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,
526
- 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
527
- ] })
528
- ] }) : null
529
- ] })
530
- ] });
531
- };
532
- adminSdk.defineWidgetConfig({
533
- zone: "order.details.side.after"
534
- });
535
- const KIT_META = {
536
- pkg: "@koda-plus/medusa-plugin-subiekt-nexo",
537
- version: "0.2.1"
538
- };
539
- const NBSP = " ";
540
- const NBHY = "‑";
541
- 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;
542
- function nb(text) {
543
- let out = text;
544
- for (let k = 0; k < 2; k++) out = out.replace(SHORT, `$1$2${NBSP}`);
545
- out = out.replace(/(\d) (?=\d{3}\b)/g, `$1${NBSP}`);
546
- out = out.replace(/\b([eE])-(?=mail)/g, `$1${NBHY}`);
547
- return out.replace(/(\d) (zł|€|Kč|EUR|USD|PLN|CZK|mln|tys\.|cm|mm|m²|%)/g, `$1${NBSP}$2`);
548
- }
549
- function typeset(value) {
550
- if (typeof value === "string") return nb(value);
551
- if (Array.isArray(value)) return value.map((v) => typeset(v));
552
- if (value && typeof value === "object") {
553
- return Object.fromEntries(Object.entries(value).map(([k, v]) => [k, typeset(v)]));
554
- }
555
- return value;
556
- }
557
- function usePageNav(tabs) {
558
- const [params, setParams] = reactRouterDom.useSearchParams();
559
- const raw = params.get("view");
560
- const view = raw === "guide" || raw === "settings" ? raw : "panel";
561
- const asked = params.get("tab") ?? "";
562
- const tab = tabs.includes(asked) ? asked : tabs[0];
563
- const go = (next, nextTab) => {
564
- const p = new URLSearchParams(params);
565
- if (next === "panel") p.delete("view");
566
- else p.set("view", next);
567
- if (next === "settings") p.set("tab", nextTab ?? tab);
568
- else p.delete("tab");
569
- setParams(p, { replace: true });
570
- };
571
- return { view, tab, go };
572
- }
573
- const VIEWS = ["panel", "guide", "settings"];
574
- const VIEW_ICON = { panel: /* @__PURE__ */ jsxRuntime.jsx(icons.ChartBar, {}), guide: /* @__PURE__ */ jsxRuntime.jsx(icons.BookOpen, {}), settings: /* @__PURE__ */ jsxRuntime.jsx(icons.CogSixTooth, {}) };
575
- function PageTabs({ value, onChange, labels }) {
576
- return /* @__PURE__ */ jsxRuntime.jsx("div", { role: "tablist", className: "flex flex-wrap items-center gap-1", children: VIEWS.map((v) => {
577
- const on = v === value;
578
- return /* @__PURE__ */ jsxRuntime.jsxs(
579
- "button",
580
- {
581
- type: "button",
582
- role: "tab",
583
- "aria-selected": on,
584
- onClick: () => onChange(v),
585
- className: ui.clx(
586
- "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",
587
- 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"
588
- ),
589
- children: [
590
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("flex", on ? "text-ui-fg-interactive" : "text-ui-fg-muted"), children: VIEW_ICON[v] }),
591
- labels[v]
592
- ]
593
- },
594
- v
595
- );
596
- }) });
597
- }
598
- function OtherActions({ items, label }) {
599
- if (items.length === 1) {
600
- const a = items[0];
601
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", isLoading: a.loading, disabled: a.disabled, onClick: a.onClick, children: [
602
- a.icon,
603
- a.label
604
- ] });
605
- }
606
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
607
- /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", children: [
608
- label,
609
- /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronDownMini, {})
610
- ] }) }),
611
- /* @__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: [
612
- a.icon,
613
- a.label
614
- ] }, a.key)) })
615
- ] });
616
- }
617
- function IntegrationHeader({
618
- icon,
619
- title,
620
- by,
621
- badges,
622
- description,
623
- social,
624
- help,
625
- view,
626
- onView,
627
- labels,
628
- primary,
629
- actions = []
630
- }) {
631
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
632
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 pb-5 pt-5", children: [
633
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between", children: [
634
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-wrap items-center gap-x-2.5 gap-y-1.5", children: [
635
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0", children: icon }),
636
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h1", children: title }),
637
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: by }),
638
- badges ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex flex-wrap items-center gap-1.5", children: badges }) : null
639
- ] }),
640
- help ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex shrink-0", children: help }) : null
641
- ] }),
642
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-3xl text-ui-fg-subtle", children: description }),
643
- social ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2 pt-0.5", children: social }) : null
644
- ] }),
645
- /* @__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: [
646
- /* @__PURE__ */ jsxRuntime.jsx(PageTabs, { value: view, onChange: onView, labels }),
647
- primary || actions.length ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
648
- actions.length ? /* @__PURE__ */ jsxRuntime.jsx(OtherActions, { items: actions, label: labels.more }) : null,
649
- primary ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "primary", isLoading: primary.loading, disabled: primary.disabled, onClick: primary.onClick, children: [
650
- primary.icon,
651
- primary.label
652
- ] }) : null
653
- ] }) : null
654
- ] })
655
- ] });
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
+ ] });
656
405
  }
657
406
  function ModeBadge({ color, label, title, children }) {
658
407
  if (!children) return /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color, children: label });
@@ -667,149 +416,31 @@ function ModeBadge({ color, label, title, children }) {
667
416
  ] })
668
417
  ] });
669
418
  }
670
- function splitReferences(items) {
671
- return {
672
- live: items.filter((r) => !r.soon && typeof r.url === "string" && r.url !== ""),
673
- soon: items.filter((r) => r.soon === true)
674
- };
675
- }
676
- const host = (url) => {
677
- try {
678
- return new URL(url).host.replace(/^www\./, "");
679
- } catch {
680
- return url;
681
- }
682
- };
683
- 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";
684
- function Stars({ rating, scale = 5, size = 12 }) {
685
- const fill = Math.max(0, Math.min(1, rating / (scale || 5))) * 100;
686
- 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)) });
687
- return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative inline-flex shrink-0", "aria-hidden": true, children: [
688
- row("var(--fg-disabled)"),
689
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute inset-y-0 left-0 overflow-hidden", style: { width: `${fill}%` }, children: row("#F5A524") })
690
- ] });
691
- }
692
- function SourceMark({ review, height = 10 }) {
693
- if (!review.icon) {
694
- return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: review.source });
695
- }
696
- 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" } }) });
697
- }
698
- function StoreIcon({ reference, size }) {
699
- const box = { width: size, height: size };
700
- 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() });
701
- }
702
- function meanRating(items) {
703
- const reviews = items.map((r) => r.review).filter((r) => Boolean(r));
704
- if (reviews.length === 0) return null;
705
- const value = reviews.reduce((sum, r) => sum + r.rating / (r.scale || 5) * 5, 0) / reviews.length;
706
- return { value: Math.round(value * 10) / 10, first: reviews[0] };
707
- }
708
- function ReferencesBadge({ items, labels }) {
709
- const { live, soon } = splitReferences(items);
710
- if (live.length + soon.length === 0) return null;
711
- const mean = meanRating(live);
712
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
713
- /* @__PURE__ */ jsxRuntime.jsx(ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
714
- "button",
715
- {
716
- type: "button",
717
- 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",
718
- children: [
719
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex shrink-0 items-center", children: [...live, ...soon].slice(0, 3).map((r, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { className: ui.clx("rounded-md", i > 0 && "-ml-2", r.soon && "opacity-50"), children: /* @__PURE__ */ jsxRuntime.jsx(StoreIcon, { reference: r, size: 24 }) }, r.url ?? r.name)) }),
720
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-x-1.5", children: [
721
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus truncate text-ui-fg-base", children: labels.count(live.length, soon.length) }),
722
- live.length > 0 && soon.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small shrink-0 text-ui-fg-muted", children: labels.soonMore(soon.length) }) : null
723
- ] }),
724
- mean ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex shrink-0 items-center gap-x-2 border-l border-ui-border-base pl-3", children: [
725
- /* @__PURE__ */ jsxRuntime.jsx(Stars, { rating: mean.value, size: 13 }),
726
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus tabular-nums text-ui-fg-base", children: labels.rating(mean.value) }),
727
- /* @__PURE__ */ jsxRuntime.jsx(SourceMark, { review: mean.first, height: 10 })
728
- ] }) : null,
729
- /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronDownMini, { className: "-ml-1 shrink-0 text-ui-fg-muted" })
730
- ]
731
- }
732
- ) }),
733
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover.Content, { align: "start", sideOffset: 8, className: "w-[min(460px,calc(100vw-32px))] p-0", children: [
734
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-0.5 border-b border-ui-border-base px-4 py-3", children: [
735
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "text-ui-fg-base", children: labels.title }),
736
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: labels.subtitle })
737
- ] }),
738
- /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "flex max-h-[60vh] flex-col divide-y divide-ui-border-base overflow-y-auto", children: [
739
- live.map((r) => {
740
- var _a, _b;
741
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-col gap-y-2 px-4 py-3", children: [
742
- /* @__PURE__ */ jsxRuntime.jsxs("a", { href: r.url, target: "_blank", rel: "noreferrer", className: "group flex items-center gap-x-3", children: [
743
- /* @__PURE__ */ jsxRuntime.jsx(StoreIcon, { reference: r, size: 32 }),
744
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
745
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "truncate text-ui-fg-base", children: r.name }),
746
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "truncate text-ui-fg-interactive group-hover:text-ui-fg-interactive-hover", children: host(r.url) })
747
- ] }),
748
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "ml-auto shrink-0 text-ui-fg-muted group-hover:text-ui-fg-interactive" })
749
- ] }),
750
- r.review ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
751
- /* @__PURE__ */ jsxRuntime.jsx(Stars, { rating: r.review.rating, scale: r.review.scale }),
752
- /* @__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) }),
753
- /* @__PURE__ */ jsxRuntime.jsx(SourceMark, { review: r.review }),
754
- 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: [
755
- labels.review,
756
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "h-3.5 w-3.5" })
757
- ] }) : null
758
- ] }) : null,
759
- ((_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: [
760
- nb(r.review.quote),
761
- r.review.author ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "not-italic text-ui-fg-muted", children: [
762
- " ",
763
- r.review.author
764
- ] }) : null
765
- ] }) : null,
766
- r.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: nb(r.description) }) : null,
767
- ((_b = r.metrics) == null ? void 0 : _b.length) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1.5", children: (r.metrics ?? []).map((m) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "green", children: [
768
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: m.value }),
769
- " ",
770
- m.label
771
- ] }, m.label)) }) : null,
772
- (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: [
773
- l.label,
774
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "h-3.5 w-3.5" })
775
- ] }, l.url)) }) : null
776
- ] }, r.url ?? r.name);
777
- }),
778
- soon.map((r) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-col gap-y-2 px-4 py-3", children: [
779
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
780
- /* @__PURE__ */ jsxRuntime.jsx(StoreIcon, { reference: r, size: 32 }),
781
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-x-2", children: [
782
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "truncate text-ui-fg-base", children: r.name }),
783
- /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "blue", className: "shrink-0", children: labels.soon })
784
- ] })
785
- ] }),
786
- r.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: nb(r.description) }) : null
787
- ] }, r.url ?? r.name))
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" })
788
433
  ] })
789
- ] })
790
- ] });
434
+ }
435
+ );
791
436
  }
792
437
  const KODA_DISCORD = "https://koda.plus/discord";
793
438
  const KODA_EMAIL = "hello@koda.plus";
794
439
  const KODA_DEMO = "https://medusa.koda.plus";
795
440
  const plain = (text) => text.split(NBSP).join(" ");
796
- function communityLabels(t, integration) {
441
+ function communityLabels(t, _integration) {
797
442
  const k = (key, options) => t(`community.${key}`, options);
798
443
  return {
799
- addStore: {
800
- button: k("addStore.button"),
801
- title: k("addStore.title"),
802
- text: k("addStore.text"),
803
- name: k("addStore.name"),
804
- url: k("addStore.url"),
805
- note: k("addStore.note"),
806
- send: k("addStore.send"),
807
- copy: k("addStore.copy"),
808
- copied: k("addStore.copied"),
809
- hint: k("addStore.hint", { email: KODA_EMAIL }),
810
- subject: k("addStore.subject", { integration }),
811
- greeting: k("addStore.greeting", { integration })
812
- },
813
444
  prompt: {
814
445
  button: k("prompt.button"),
815
446
  title: k("prompt.title"),
@@ -818,79 +449,10 @@ function communityLabels(t, integration) {
818
449
  copied: k("prompt.copied"),
819
450
  failed: k("prompt.failed")
820
451
  },
821
- 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") }
822
454
  };
823
455
  }
824
- function AddStoreButton({ labels }) {
825
- const [name, setName] = react.useState("");
826
- const [url, setUrl] = react.useState("");
827
- const [note, setNote] = react.useState("");
828
- const ready = name.trim() !== "" && url.trim() !== "";
829
- const subject = plain(labels.subject);
830
- const body = plain(
831
- [labels.greeting, "", `${labels.name}: ${name.trim()}`, `${labels.url}: ${url.trim()}`, ...note.trim() ? ["", note.trim()] : []].join("\n")
832
- );
833
- const send = () => {
834
- window.location.href = `mailto:${KODA_EMAIL}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
835
- };
836
- const copy = async () => {
837
- try {
838
- await navigator.clipboard.writeText(`${KODA_EMAIL}
839
- ${subject}
840
-
841
- ${body}`);
842
- ui.toast.success(labels.copied);
843
- } catch {
844
- ui.toast.error(KODA_EMAIL);
845
- }
846
- };
847
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
848
- /* @__PURE__ */ jsxRuntime.jsx(ui.Popover.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
849
- "button",
850
- {
851
- type: "button",
852
- 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",
853
- children: [
854
- /* @__PURE__ */ jsxRuntime.jsx(icons.PlusMini, {}),
855
- labels.button
856
- ]
857
- }
858
- ) }),
859
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover.Content, { align: "start", sideOffset: 8, className: "w-[min(420px,calc(100vw-32px))] p-0", children: [
860
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1 border-b border-ui-border-base px-4 py-3", children: [
861
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "text-ui-fg-base", children: labels.title }),
862
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: labels.text })
863
- ] }),
864
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-4 py-4", children: [
865
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1.5", children: [
866
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "xsmall", weight: "plus", htmlFor: "koda-add-store-name", children: labels.name }),
867
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { id: "koda-add-store-name", size: "small", value: name, onChange: (e) => setName(e.target.value) })
868
- ] }),
869
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1.5", children: [
870
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "xsmall", weight: "plus", htmlFor: "koda-add-store-url", children: labels.url }),
871
- /* @__PURE__ */ jsxRuntime.jsx(ui.Input, { id: "koda-add-store-url", size: "small", type: "url", placeholder: "https://", value: url, onChange: (e) => setUrl(e.target.value) })
872
- ] }),
873
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1.5", children: [
874
- /* @__PURE__ */ jsxRuntime.jsx(ui.Label, { size: "xsmall", weight: "plus", htmlFor: "koda-add-store-note", children: labels.note }),
875
- /* @__PURE__ */ jsxRuntime.jsx(ui.Textarea, { id: "koda-add-store-note", rows: 3, value: note, onChange: (e) => setNote(e.target.value) })
876
- ] })
877
- ] }),
878
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 border-t border-ui-border-base px-4 py-3", children: [
879
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: labels.hint }),
880
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center justify-end gap-2", children: [
881
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", disabled: !ready, onClick: () => void copy(), children: [
882
- /* @__PURE__ */ jsxRuntime.jsx(icons.SquareTwoStack, {}),
883
- labels.copy
884
- ] }),
885
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "primary", disabled: !ready, onClick: send, children: [
886
- /* @__PURE__ */ jsxRuntime.jsx(icons.PaperPlane, {}),
887
- labels.send
888
- ] })
889
- ] })
890
- ] })
891
- ] })
892
- ] });
893
- }
894
456
  function envNames(code) {
895
457
  const names = /* @__PURE__ */ new Set();
896
458
  for (const m of code.matchAll(/process\.env\.([A-Z][A-Z0-9_]*)/g)) names.add(m[1]);
@@ -1061,69 +623,6 @@ function SettingsView({
1061
623
  children
1062
624
  ] });
1063
625
  }
1064
- function CardIcon({ reference }) {
1065
- return reference.icon ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: reference.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: reference.name.slice(0, 1).toUpperCase() });
1066
- }
1067
- function References({ items, title, subtitle, openLabel, soonLabel, reviewLabel, ratingLabel }) {
1068
- const { live, soon } = splitReferences(items);
1069
- if (live.length + soon.length === 0) return null;
1070
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1071
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1 px-6 py-4", children: [
1072
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: title }),
1073
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: subtitle })
1074
- ] }),
1075
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-3 px-6 py-4 md:grid-cols-2 xl:grid-cols-3", children: [
1076
- live.map((r) => {
1077
- var _a;
1078
- 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: [
1079
- /* @__PURE__ */ jsxRuntime.jsxs("a", { href: r.url, target: "_blank", rel: "noreferrer", className: "group flex items-center gap-x-3", children: [
1080
- /* @__PURE__ */ jsxRuntime.jsx(CardIcon, { reference: r }),
1081
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
1082
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "truncate text-ui-fg-base", children: r.name }),
1083
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "truncate text-ui-fg-interactive group-hover:text-ui-fg-interactive-hover", children: host(r.url) })
1084
- ] }),
1085
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "ml-auto shrink-0 text-ui-fg-muted group-hover:text-ui-fg-interactive" })
1086
- ] }),
1087
- r.review ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-x-2 gap-y-1", children: [
1088
- /* @__PURE__ */ jsxRuntime.jsx(Stars, { rating: r.review.rating, scale: r.review.scale }),
1089
- /* @__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) }),
1090
- /* @__PURE__ */ jsxRuntime.jsx(SourceMark, { review: r.review }),
1091
- 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: [
1092
- reviewLabel,
1093
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "h-3.5 w-3.5" })
1094
- ] }) : null
1095
- ] }) : null,
1096
- r.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: nb(r.description) }) : null,
1097
- ((_a = r.metrics) == null ? void 0 : _a.length) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-2", children: (r.metrics ?? []).map((m) => /* @__PURE__ */ jsxRuntime.jsxs(ui.Badge, { size: "2xsmall", color: "green", children: [
1098
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "tabular-nums", children: m.value }),
1099
- " ",
1100
- m.label
1101
- ] }, m.label)) }) : null,
1102
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-auto flex flex-col gap-y-1 border-t border-ui-border-base pt-2", children: [
1103
- (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: [
1104
- l.label,
1105
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "shrink-0" })
1106
- ] }, l.url)),
1107
- /* @__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: [
1108
- openLabel,
1109
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, { className: "shrink-0" })
1110
- ] })
1111
- ] })
1112
- ] }, r.url ?? r.name);
1113
- }),
1114
- soon.map((r) => /* @__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: [
1115
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
1116
- /* @__PURE__ */ jsxRuntime.jsx(CardIcon, { reference: r }),
1117
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 items-center gap-x-2", children: [
1118
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "truncate text-ui-fg-base", children: r.name }),
1119
- /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "blue", className: "shrink-0", children: soonLabel })
1120
- ] })
1121
- ] }),
1122
- r.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: nb(r.description) }) : null
1123
- ] }, r.url ?? r.name))
1124
- ] })
1125
- ] });
1126
- }
1127
626
  function GuideIntro({ title, text, time, needs, needsLabel, timeLabel }) {
1128
627
  return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1129
628
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: [
@@ -1285,10 +784,834 @@ function GuideFaq({ title, items }) {
1285
784
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "text-ui-fg-base", children: it.q }),
1286
785
  /* @__PURE__ */ jsxRuntime.jsx(icons.ChevronDownMini, { className: ui.clx("shrink-0 text-ui-fg-muted transition-transform", open === i && "rotate-180") })
1287
786
  ] }),
1288
- open === i ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-small flex max-w-3xl flex-col gap-y-2 pb-4 text-ui-fg-subtle", children: it.a }) : null
1289
- ] }, it.q))
1290
- ] });
1291
- }
787
+ open === i ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "txt-small flex max-w-3xl flex-col gap-y-2 pb-4 text-ui-fg-subtle", children: it.a }) : null
788
+ ] }, it.q))
789
+ ] });
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,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" 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
+ });
1292
1615
  const CLOCK_SKEW_WARN_SECONDS = 60;
1293
1616
  const CLOCK_SKEW_LIMIT_SECONDS = 300;
1294
1617
  function skewLevel(skewMs) {
@@ -1416,7 +1739,7 @@ maxProductsPerRun: 20,`;
1416
1739
  const DOCUMENTS_CODE = `salesDocument: "auto",
1417
1740
  salesDocumentAfter: "wz",
1418
1741
  createContractors: true,`;
1419
- function GuideView({ status, lang }) {
1742
+ function GuideView({ status }) {
1420
1743
  const { t } = reactI18next.useTranslation("subiekt");
1421
1744
  function list(key) {
1422
1745
  const value = t(key, { returnObjects: true });
@@ -1449,7 +1772,6 @@ function GuideView({ status, lang }) {
1449
1772
  q: item.q,
1450
1773
  a: (item.a ?? []).map((p, i) => /* @__PURE__ */ jsxRuntime.jsx("p", { children: /* @__PURE__ */ jsxRuntime.jsx(RichText, { text: p }) }, i))
1451
1774
  }));
1452
- const references = referencesFor(s.references, lang);
1453
1775
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3", children: [
1454
1776
  /* @__PURE__ */ jsxRuntime.jsx(
1455
1777
  GuideIntro,
@@ -1493,31 +1815,249 @@ function GuideView({ status, lang }) {
1493
1815
  }))
1494
1816
  }
1495
1817
  ),
1496
- /* @__PURE__ */ jsxRuntime.jsx(GuideFaq, { title: t("guide.faq.title"), items: faq }),
1497
- /* @__PURE__ */ jsxRuntime.jsx(
1498
- References,
1499
- {
1500
- items: references,
1501
- title: t("references.title"),
1502
- subtitle: t("references.subtitle"),
1503
- openLabel: t("references.open"),
1504
- soonLabel: t("references.soon"),
1505
- reviewLabel: t("references.review"),
1506
- ratingLabel: (value) => fmtRating(value, lang)
1507
- }
1508
- )
1818
+ /* @__PURE__ */ jsxRuntime.jsx(GuideFaq, { title: t("guide.faq.title"), items: faq })
1509
1819
  ] });
1510
1820
  }
1511
- const PAGE_SIZE$1 = 15;
1512
- function SectionHeader({ title, subtitle, children }) {
1513
- 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: [
1514
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1515
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: title }),
1516
- 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
1517
2056
  ] }),
1518
- 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
1519
2058
  ] });
1520
2059
  }
2060
+ const PAGE_SIZE$1 = 15;
1521
2061
  const LEVEL_TEXT = {
1522
2062
  ok: "text-ui-fg-base",
1523
2063
  warn: "text-ui-tag-orange-text",
@@ -1538,54 +2078,65 @@ function BridgeSection({ status, lang }) {
1538
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";
1539
2079
  const signatureTone = d.signature === "ok" ? LEVEL_TEXT.ok : d.signature === "unknown" ? LEVEL_TEXT.unknown : LEVEL_TEXT.error;
1540
2080
  const rejectedLater = Boolean(d.webhook.rejectedAt && (!d.webhook.lastAt || d.webhook.rejectedAt > d.webhook.lastAt));
1541
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1542
- /* @__PURE__ */ jsxRuntime.jsx(SectionHeader, { title: t("bridge.title"), subtitle: t("bridge.subtitle") }),
1543
- 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,
1544
- 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,
1545
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-2", children: [
1546
- /* @__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 }) }),
1547
- /* @__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 }),
1548
- /* @__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}`) }) }),
1549
- /* @__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 }),
1550
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.latency"), children: fmtMs(d.latencyMs) }),
1551
- /* @__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) }) }) }),
1552
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.signature"), children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: signatureTone, children: t(`bridge.signatureStates.${d.signature}`, { defaultValue: d.signature }) }) }),
1553
- /* @__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 }),
1554
- /* @__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 }),
1555
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("bridge.webhook"), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
1556
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: d.webhook.lastAt ? t("bridge.webhookValue", { time: fmtDateTime(d.webhook.lastAt, lang) }) : t("bridge.webhookNever") }),
1557
- rejectedLater ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: LEVEL_TEXT.warn, children: t("bridge.webhookRejected", {
1558
- time: fmtDateTime(d.webhook.rejectedAt, lang),
1559
- reason: t(`bridge.webhookReasons.${d.webhook.rejectReason ?? "missing"}`, { defaultValue: d.webhook.rejectReason ?? "" })
1560
- }) }) : null
1561
- ] }) }),
1562
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.checkedAt"), children: fmtDateTime(d.checkedAt, lang) || t("connection.never") })
1563
- ] }),
1564
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
1565
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1566
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("bridge.capabilities") }),
1567
- /* @__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)) })
1568
- ] }),
1569
- d.missing.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
1570
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t("bridge.cannot") }),
1571
- /* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-y-1", children: d.missing.map((m) => {
1572
- const hint = m.reason === "bridge_config" ? t(`bridge.capabilityHints.${m.capability}`, { defaultValue: "" }) : "";
1573
- return /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "txt-compact-small flex flex-wrap gap-x-1", children: [
1574
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-base", children: [
1575
- t(`bridge.capabilityNames.${m.capability}`, { defaultValue: m.capability }),
1576
- ":"
1577
- ] }),
1578
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-subtle", children: t(`bridge.reasons.${m.reason}`, { defaultValue: m.reason }) }),
1579
- hint ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "font-mono text-ui-fg-muted", children: [
1580
- "(",
1581
- hint,
1582
- ")"
1583
- ] }) : null
1584
- ] }, m.capability);
1585
- }) })
1586
- ] }) : null
1587
- ] })
1588
- ] });
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
+ );
1589
2140
  }
1590
2141
  const WRITER_ORDER = ["documents", "contractors", "prices", "products"];
1591
2142
  function WriterRow({ writer, status, lang }) {
@@ -1619,15 +2170,14 @@ function WriterRow({ writer, status, lang }) {
1619
2170
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col gap-1.5", children: [
1620
2171
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [
1621
2172
  /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", className: "text-ui-fg-base", children: name }),
1622
- 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") }),
1623
- /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-x-1", children: [
1624
- 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: [
1625
2175
  t("writers.option", { option: writer.option }),
1626
2176
  " ",
1627
2177
  writer.allowed ? t("writers.allowed") : t("writers.forbidden")
1628
- ] }) })
2178
+ ] })
1629
2179
  ] }),
1630
- /* @__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 }),
1631
2181
  writer.unsupported ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-tag-orange-text", children: t("writers.unsupported") }) : null,
1632
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") })
1633
2183
  ] }),
@@ -1637,13 +2187,34 @@ function WriterRow({ writer, status, lang }) {
1637
2187
  function WritersSection({ status, lang }) {
1638
2188
  const { t } = reactI18next.useTranslation("subiekt");
1639
2189
  const writers = WRITER_ORDER.map((k) => status.writers.find((w) => w.key === k)).filter((w) => Boolean(w));
1640
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1641
- /* @__PURE__ */ jsxRuntime.jsx(SectionHeader, { title: t("writers.title"), subtitle: t("writers.subtitle") }),
1642
- 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,
1643
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "divide-y", children: writers.map((w) => /* @__PURE__ */ jsxRuntime.jsx(WriterRow, { writer: w, status, lang }, w.key)) })
1644
- ] });
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
+ );
1645
2205
  }
1646
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"]);
1647
2218
  function ChangeCell({ change, lang }) {
1648
2219
  const { t } = reactI18next.useTranslation("subiekt");
1649
2220
  if (change.kind === "create") return /* @__PURE__ */ jsxRuntime.jsx("span", { children: t("products.newProduct", { price: fmtMoney(change.to, change.currency, lang) }) });
@@ -1689,7 +2260,7 @@ function ProductsSection({ status, lang, poll, onAction }) {
1689
2260
  const [filter, setFilter] = react.useState("all");
1690
2261
  const [search, setSearch] = react.useState("");
1691
2262
  const [offset, setOffset] = react.useState(0);
1692
- const q = search.trim();
2263
+ const q = useDebouncedValue(search).trim();
1693
2264
  const running = status.running.includes("products");
1694
2265
  const products = useSubiektProducts(kind, filter, q, offset, PAGE_SIZE$1, poll || running);
1695
2266
  const sync = useSubiektSync();
@@ -1738,112 +2309,147 @@ function ProductsSection({ status, lang, poll, onAction }) {
1738
2309
  ["unmatchedVariants", stats.unmatchedVariants, true],
1739
2310
  ["noPrice", stats.noPrice, true]
1740
2311
  ] : [];
1741
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1742
- /* @__PURE__ */ jsxRuntime.jsxs(SectionHeader, { title: t("products.title"), subtitle: t("products.subtitle"), children: [
1743
- (run == null ? void 0 : run.dryRun) ? /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "purple", children: t("stock.dryRun") }) : null,
1744
- run ? /* @__PURE__ */ jsxRuntime.jsx(RunStatusBadge, { status: run.status }) : null,
1745
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", disabled: !ready || !supported || !o.productSyncEnabled || running, isLoading: sync.isPending, onClick: onRead, children: [
1746
- /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
1747
- running ? t("actions.running") : t("actions.products")
1748
- ] })
1749
- ] }),
1750
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1 px-6 py-3", children: [
1751
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: settings }),
1752
- run ? /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
1753
- runSummary(run, t),
1754
- " ",
1755
- fmtDateTime(run.startedAt, lang),
1756
- ", ",
1757
- fmtDuration(run.durationMs)
1758
- ] }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("products.never") })
1759
- ] }),
1760
- !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,
1761
- (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,
1762
- 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: [
1763
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t(`products.counters.${key}`) }),
1764
- /* @__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) })
1765
- ] }, key)) }) : null,
1766
- (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: [
1767
- ((_d = stats.samples.conflicts) == null ? void 0 : _d.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.conflicts"), items: stats.samples.conflicts }) : null,
1768
- ((_e = stats.samples.unmatchedVariants) == null ? void 0 : _e.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.unmatchedVariants"), items: stats.samples.unmatchedVariants }) : null,
1769
- ((_f = stats.samples.noPrice) == null ? void 0 : _f.length) ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("products.samples.noPrice"), items: stats.samples.noPrice }) : null
1770
- ] }) : null,
1771
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 px-6 py-3", children: [
1772
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 md:flex-row md:items-center md:justify-between", children: [
1773
- /* @__PURE__ */ jsxRuntime.jsx(
1774
- FilterPills,
1775
- {
1776
- value: kind,
1777
- onChange: setKind,
1778
- options: [
1779
- { value: "all", label: t("products.statuses.all") },
1780
- { value: "price", label: t("products.kinds.price") },
1781
- { value: "create", label: t("products.kinds.create") }
1782
- ]
1783
- }
1784
- ),
1785
- /* @__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
1786
2321
  ] }),
1787
- /* @__PURE__ */ jsxRuntime.jsx(
1788
- FilterPills,
1789
- {
1790
- value: filter,
1791
- onChange: setFilter,
1792
- options: [
1793
- { value: "all", label: t("products.statuses.all"), count: summary == null ? void 0 : summary.total },
1794
- ...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] }))
1795
- ]
1796
- }
1797
- )
1798
- ] }),
1799
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
1800
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
1801
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.product") }),
1802
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.change") }),
1803
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("products.columns.store"), hint: t("products.matching") }) }),
1804
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.status") }),
1805
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("products.columns.details") })
1806
- ] }) }),
1807
- /* @__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: [
1808
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[240px]", children: /* @__PURE__ */ jsxRuntime.jsx(SubiektProductCell, { change: c }) }),
1809
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(ChangeCell, { change: c, lang }) }),
1810
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[300px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreProductCell, { change: c }) }),
1811
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(CatalogStatusBadge, { status: c.status }) }),
1812
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { className: "max-w-md", children: [
1813
- 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,
1814
- 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")
1815
2333
  ] })
1816
- ] }, c.id)) })
1817
- ] }) }),
1818
- /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE$1, count: (data == null ? void 0 : data.count) ?? 0, onChange: setOffset }),
1819
- data && data.quarantined.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-2 px-6 py-4", children: [
1820
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", children: t("products.quarantine") }),
1821
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: t("products.quarantineHint") }),
1822
- /* @__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: [
1823
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-w-0 flex-col", children: [
1824
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "small", className: "font-mono", children: [
1825
- t(`products.kinds.${item.kind}`),
1826
- ": ",
1827
- item.key
1828
- ] }),
1829
- 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") })
1830
2339
  ] }),
1831
- /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", isLoading: release.isPending && release.variables === item.id, onClick: () => onRelease(item.id), children: t("actions.release") })
1832
- ] }, item.id)) })
1833
- ] }) : null
1834
- ] });
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
+ );
1835
2428
  }
1836
2429
  const PAGE_SIZE = 15;
1837
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
+ }
1838
2438
  const SubiektPage = () => {
1839
2439
  const { t, i18n } = reactI18next.useTranslation("subiekt");
1840
2440
  const lang = i18n.language || "en";
1841
2441
  const client = reactQuery.useQueryClient();
1842
2442
  const nav = usePageNav(SETTINGS_TABS);
2443
+ const [params] = reactRouterDom.useSearchParams();
1843
2444
  const [pollUntil, setPollUntil] = react.useState(0);
1844
2445
  const status = useSubiektStatus(pollUntil);
1845
2446
  const s = status.data;
1846
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");
1847
2453
  const runKey = JSON.stringify(Object.values((s == null ? void 0 : s.lastRuns) ?? {}).map((r) => (r == null ? void 0 : r.id) ?? ""));
1848
2454
  const seen = react.useRef(void 0);
1849
2455
  react.useEffect(() => {
@@ -1853,32 +2459,45 @@ const SubiektPage = () => {
1853
2459
  seen.current = runKey;
1854
2460
  }, [runKey, client]);
1855
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;
1856
2472
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3", children: [
1857
2473
  /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
1858
- /* @__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 }),
1859
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,
1860
2476
  s ? /* @__PURE__ */ jsxRuntime.jsx(Warnings, { status: s }) : null,
1861
- 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: [
1862
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.sent24h"), value: fmtNumber(s.counts.succeeded24h, lang) }),
1863
- /* @__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") }),
1864
2481
  /* @__PURE__ */ jsxRuntime.jsx(
1865
2482
  StatTile,
1866
2483
  {
1867
- label: t("stats.queue"),
1868
- value: fmtNumber(s.counts.pending + s.counts.running + s.counts.unknown, lang),
1869
- 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")
1870
2490
  }
1871
2491
  ),
1872
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.attention"), value: fmtNumber(s.counts.failed, lang), tone: s.counts.failed ? "attention" : "muted" }),
1873
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.zk"), value: fmtNumber(s.counts.zk, lang) }),
1874
- /* @__PURE__ */ jsxRuntime.jsx(StatTile, { label: t("stats.wz"), value: fmtNumber(s.counts.wz, lang) }),
1875
- /* @__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) })
1876
2495
  ] }) : null
1877
2496
  ] }),
1878
- s && nav.view === "guide" ? /* @__PURE__ */ jsxRuntime.jsx(GuideView, { status: s, lang }) : null,
2497
+ s && nav.view === "guide" ? /* @__PURE__ */ jsxRuntime.jsx(GuideView, { status: s }) : null,
1879
2498
  nav.view === "panel" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1880
- s ? /* @__PURE__ */ jsxRuntime.jsx(TasksSection, { status: s, lang, poll: polling, onAction: poll }) : null,
1881
- /* @__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 }),
1882
2501
  s ? /* @__PURE__ */ jsxRuntime.jsx(ProductsSection, { status: s, lang, poll: polling, onAction: poll }) : null
1883
2502
  ] }) : null,
1884
2503
  nav.view === "settings" ? /* @__PURE__ */ jsxRuntime.jsxs(
@@ -1892,7 +2511,7 @@ const SubiektPage = () => {
1892
2511
  { id: "connection", label: t("settings.tab.connection") },
1893
2512
  { id: "bridge", label: t("settings.tab.bridge") },
1894
2513
  { id: "writers", label: t("settings.tab.writers"), badge: s == null ? void 0 : s.writers.filter((w) => w.active).length, tone: "orange" },
1895
- { 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" },
1896
2515
  { id: "runs", label: t("settings.tab.runs") }
1897
2516
  ],
1898
2517
  children: [
@@ -1909,17 +2528,18 @@ const SubiektPage = () => {
1909
2528
  function Header({
1910
2529
  status,
1911
2530
  loading,
2531
+ fetching,
1912
2532
  lang,
1913
2533
  nav,
1914
2534
  onAction
1915
2535
  }) {
1916
2536
  const { t } = reactI18next.useTranslation("subiekt");
2537
+ const client = reactQuery.useQueryClient();
1917
2538
  const sync = useSubiektSync();
1918
2539
  const check = useSubiektCheck();
1919
2540
  const ready = Boolean(status && (status.mode === "demo" || status.configured));
1920
2541
  const running = new Set((status == null ? void 0 : status.running) ?? []);
1921
2542
  const state = connectionState(status);
1922
- const references = status ? referencesFor(status.references, lang) : [];
1923
2543
  const promptSpec = usePromptSpec();
1924
2544
  const community = communityLabels((key, options) => t(key, options), `${t("title")} ${t("by")}`);
1925
2545
  const start = async (what) => {
@@ -1943,34 +2563,30 @@ function Header({
1943
2563
  }
1944
2564
  };
1945
2565
  const panel = nav.view !== "guide";
1946
- 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() };
1947
2574
  return /* @__PURE__ */ jsxRuntime.jsx(
1948
2575
  IntegrationHeader,
1949
2576
  {
1950
2577
  icon: /* @__PURE__ */ jsxRuntime.jsx(SubiektIcon, { width: 28, height: 28 }),
1951
2578
  title: t("title"),
1952
- by: t("by"),
2579
+ featured: { url: "https://medusajs.com/integrations/@koda-plusmedusa-plugin-subiekt-nexo", labels: community.featured },
1953
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,
1954
2581
  description: t("subtitle"),
1955
- social: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1956
- /* @__PURE__ */ jsxRuntime.jsx(
1957
- ReferencesBadge,
1958
- {
1959
- items: references,
1960
- labels: {
1961
- count: (live, soon) => live > 0 ? live === 1 ? t("references.badgeOne") : t("references.badgeMany", { count: live }) : soon === 1 ? t("references.badgeSoonOne") : t("references.badgeSoonMany", { count: soon }),
1962
- soonMore: (soon) => t("references.soonMore", { count: soon }),
1963
- soon: t("references.soon"),
1964
- title: t("references.title"),
1965
- subtitle: t("references.subtitle"),
1966
- open: t("references.open"),
1967
- review: t("references.review"),
1968
- rating: (value) => fmtRating(value, lang)
1969
- }
1970
- }
1971
- ),
1972
- /* @__PURE__ */ jsxRuntime.jsx(AddStoreButton, { labels: community.addStore })
1973
- ] }),
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
+ ],
1974
2590
  help: /* @__PURE__ */ jsxRuntime.jsx(HelpButtons, { spec: promptSpec, lang, labels: community }),
1975
2591
  view: nav.view,
1976
2592
  onView: (v) => nav.go(v),
@@ -1978,19 +2594,21 @@ function Header({
1978
2594
  primary: panel ? {
1979
2595
  key: "stock",
1980
2596
  label: running.has("stock") ? t("actions.running") : t("actions.stock"),
1981
- icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowPath, {}),
2597
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.CubeSolid, {}),
1982
2598
  disabled: !ready || running.has("stock"),
1983
2599
  onClick: () => void start("stock")
1984
2600
  } : null,
1985
2601
  actions: panel ? [
2602
+ refreshAction,
1986
2603
  {
1987
2604
  key: "events",
1988
2605
  label: running.has("events") ? t("actions.running") : t("actions.events"),
2606
+ icon: /* @__PURE__ */ jsxRuntime.jsx(icons.ArrowDownTray, {}),
1989
2607
  disabled: !ready || running.has("events"),
1990
2608
  onClick: () => void start("events")
1991
2609
  },
1992
2610
  checkAction
1993
- ] : [checkAction]
2611
+ ] : [refreshAction, checkAction]
1994
2612
  }
1995
2613
  );
1996
2614
  }
@@ -2006,39 +2624,48 @@ function ConnectionSection({ status, lang }) {
2006
2624
  const { t } = reactI18next.useTranslation("subiekt");
2007
2625
  const c = status.connection;
2008
2626
  const h = c.health;
2009
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2010
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
2011
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("connection.title") }),
2012
- /* @__PURE__ */ jsxRuntime.jsx(ConnectionBadge, { status })
2013
- ] }),
2014
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "py-2", children: [
2015
- /* @__PURE__ */ jsxRuntime.jsxs(Field, { label: t("connection.bridge"), children: [
2016
- h ? /* @__PURE__ */ jsxRuntime.jsxs("span", { children: [
2017
- (_a = h.bridge) == null ? void 0 : _a.name,
2018
- " ",
2019
- (_b = h.bridge) == null ? void 0 : _b.version,
2020
- " ",
2021
- /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
2022
- "(",
2023
- t("connection.contract", { version: (_c = h.bridge) == null ? void 0 : _c.contract }),
2024
- ")"
2025
- ] })
2026
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-ui-fg-muted", children: status.bridgeHost ?? t("connection.none") }),
2027
- status.bridgeHost && h ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-ui-fg-muted", children: status.bridgeHost }) : null
2028
- ] }),
2029
- /* @__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") }),
2030
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.database"), children: ((_d = h == null ? void 0 : h.subiekt) == null ? void 0 : _d.database) ?? t("connection.none") }),
2031
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.company"), children: ((_e = h == null ? void 0 : h.subiekt) == null ? void 0 : _e.company) ?? t("connection.none") }),
2032
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.warehouse"), children: ((_f = h == null ? void 0 : h.subiekt) == null ? void 0 : _f.warehouse) ?? t("connection.none") }),
2033
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.checkedAt"), children: fmtDateTime(c.checkedAt, lang) || t("connection.never") }),
2034
- /* @__PURE__ */ jsxRuntime.jsx(Field, { label: t("connection.eventsReadAt"), children: fmtDateTime(c.eventsReadAt, lang) || t("connection.never") })
2035
- ] }),
2036
- 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: [
2037
- c.lastError,
2038
- c.consecutiveFailures > 1 ? ` (${t("connection.failures", { count: c.consecutiveFailures })})` : ""
2039
- ] }) }) : null,
2040
- /* @__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") }) })
2041
- ] });
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
+ );
2042
2669
  }
2043
2670
  function StockSection({ run, lang }) {
2044
2671
  const { t } = reactI18next.useTranslation("subiekt");
@@ -2054,44 +2681,45 @@ function StockSection({ run, lang }) {
2054
2681
  ["conflicts", stats.conflicts, true]
2055
2682
  ] : [];
2056
2683
  const samples = stats == null ? void 0 : stats.samples;
2057
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2058
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2 px-6 py-4", children: [
2059
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2060
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("stock.title") }),
2061
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("stock.subtitle") })
2062
- ] }),
2063
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex shrink-0 items-center gap-x-2 whitespace-nowrap", children: [
2064
- (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,
2065
2691
  run ? /* @__PURE__ */ jsxRuntime.jsx(RunStatusBadge, { status: run.status }) : null
2066
- ] })
2067
- ] }),
2068
- !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: [
2069
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-6 py-3", children: [
2070
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: runSummary(run, t) }),
2071
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", className: "text-ui-fg-muted", children: [
2072
- fmtDateTime(run.startedAt, lang),
2073
- ", ",
2074
- fmtDuration(run.durationMs)
2075
- ] })
2076
2692
  ] }),
2077
- 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: [
2078
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", className: "text-ui-fg-subtle", children: t(`stock.counters.${key}`) }),
2079
- /* @__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) })
2080
- ] }, key)) }) : null,
2081
- samples ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
2082
- samples.changes && samples.changes.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
2083
- SampleList,
2084
- {
2085
- label: t("stock.samples.changes"),
2086
- items: samples.changes.map((c) => `${c.sku ?? "?"}: ${c.from === null ? "-" : fmtNumber(c.from, lang)} → ${fmtNumber(c.to, lang)}`)
2087
- }
2088
- ) : null,
2089
- samples.unmatchedVariants && samples.unmatchedVariants.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.unmatchedVariants"), items: samples.unmatchedVariants }) : null,
2090
- samples.unmatchedSubiekt && samples.unmatchedSubiekt.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.unmatchedSubiekt"), items: samples.unmatchedSubiekt }) : null,
2091
- samples.conflicts && samples.conflicts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(SampleList, { label: t("stock.samples.conflicts"), items: samples.conflicts }) : null
2092
- ] }) : null
2093
- ] })
2094
- ] });
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
+ );
2095
2723
  }
2096
2724
  function TaskDetails({ task, lang }) {
2097
2725
  const { t } = reactI18next.useTranslation("subiekt");
@@ -2112,17 +2740,26 @@ function TaskDetails({ task, lang }) {
2112
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
2113
2741
  ] });
2114
2742
  }
2115
- function TasksSection({ status, lang, poll, onAction }) {
2743
+ function TasksSection({
2744
+ status,
2745
+ lang,
2746
+ poll,
2747
+ onAction,
2748
+ filter,
2749
+ onFilter,
2750
+ initialQuery
2751
+ }) {
2116
2752
  var _a, _b;
2117
2753
  const { t } = reactI18next.useTranslation("subiekt");
2118
- const [filter, setFilter] = react.useState(status.counts.failed > 0 ? "attention" : "all");
2119
- const [search, setSearch] = react.useState("");
2754
+ const [search, setSearch] = react.useState(initialQuery);
2120
2755
  const [offset, setOffset] = react.useState(0);
2121
- const q = search.trim();
2122
- const open = status.counts.waiting + status.counts.pending + status.counts.running + status.counts.unknown;
2123
- 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);
2124
2760
  const retry = useSubiektRetry();
2125
2761
  const rows = ((_a = tasks.data) == null ? void 0 : _a.tasks) ?? [];
2762
+ const products = useKitOrderProducts(rows.map((task) => task.orderId));
2126
2763
  react.useEffect(() => setOffset(0), [filter, q]);
2127
2764
  const onRetry = async (task) => {
2128
2765
  try {
@@ -2133,146 +2770,198 @@ function TasksSection({ status, lang, poll, onAction }) {
2133
2770
  ui.toast.error(t("toast.error", { error: errorMessage(err) }));
2134
2771
  }
2135
2772
  };
2136
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2137
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 px-6 py-4 md:flex-row md:items-center md:justify-between", children: [
2138
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2139
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("tasks.title") }),
2140
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-3xl text-ui-fg-subtle", title: t("tasks.technical"), children: t("tasks.subtitle") })
2141
- ] }),
2142
- /* @__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) }) })
2143
- ] }),
2144
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-3", children: /* @__PURE__ */ jsxRuntime.jsx(
2145
- FilterPills,
2146
- {
2147
- value: filter,
2148
- onChange: setFilter,
2149
- options: [
2150
- { value: "attention", label: t("tasks.filters.attention"), count: status.counts.failed },
2151
- { value: "open", label: t("tasks.filters.open"), count: open },
2152
- { value: "done", label: t("tasks.filters.done") },
2153
- { value: "all", label: t("tasks.filters.all") }
2154
- ]
2155
- }
2156
- ) }),
2157
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2158
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2159
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("tasks.columns.order"), hint: t("store.orderMatching") }) }),
2160
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.operation") }),
2161
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.document") }),
2162
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.status") }),
2163
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: t("tasks.columns.attempts") }),
2164
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("tasks.columns.details") }),
2165
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, {})
2166
- ] }) }),
2167
- /* @__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: [
2168
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[260px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreOrderCell, { orderId: task.orderId, displayId: task.displayId }) }),
2169
- /* @__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}`) }),
2170
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap font-mono text-xs", children: task.documentNumber ?? "" }),
2171
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(TaskStatusBadge, { status: task.status }) }),
2172
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right tabular-nums", children: task.attempts }),
2173
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-md", children: /* @__PURE__ */ jsxRuntime.jsx(TaskDetails, { task, lang }) }),
2174
- /* @__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 })
2175
- ] }, task.id)) })
2176
- ] }) }),
2177
- /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE, count: ((_b = tasks.data) == null ? void 0 : _b.count) ?? 0, onChange: setOffset })
2178
- ] });
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
+ );
2179
2838
  }
2180
- 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
+ }) {
2181
2853
  var _a, _b;
2182
2854
  const { t } = reactI18next.useTranslation("subiekt");
2183
- const [kind, setKind] = react.useState("all");
2855
+ const [search, setSearch] = react.useState(initialQuery);
2856
+ const q = useDebouncedValue(search).trim();
2184
2857
  const [offset, setOffset] = react.useState(0);
2185
- const docs = useSubiektDocuments(kind, "", offset, PAGE_SIZE, poll);
2858
+ const docs = useSubiektDocuments(kind, q, offset, PAGE_SIZE, poll);
2186
2859
  const rows = ((_a = docs.data) == null ? void 0 : _a.documents) ?? [];
2187
- react.useEffect(() => setOffset(0), [kind]);
2188
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2189
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3 px-6 py-4 md:flex-row md:items-center md:justify-between", children: [
2190
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
2191
- /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("documents.title") }),
2192
- /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "max-w-3xl text-ui-fg-subtle", children: t("documents.subtitle") })
2193
- ] }),
2194
- /* @__PURE__ */ jsxRuntime.jsx(
2195
- FilterPills,
2196
- {
2197
- value: kind,
2198
- onChange: setKind,
2199
- options: ["all", "ZK", "WZ", "FS", "PA"].map((k) => ({ value: k, label: t(`documents.filters.${k}`) }))
2200
- }
2201
- )
2202
- ] }),
2203
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2204
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2205
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.number") }),
2206
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: /* @__PURE__ */ jsxRuntime.jsx(StoreColumn, { label: t("documents.columns.order"), hint: t("store.orderMatching") }) }),
2207
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.issued") }),
2208
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.source") }),
2209
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.ksef") }),
2210
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("documents.columns.status") })
2211
- ] }) }),
2212
- /* @__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: [
2213
- /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Cell, { className: "whitespace-nowrap font-mono text-xs", children: [
2214
- d.number,
2215
- d.related.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-ui-fg-muted", children: [
2216
- " ← ",
2217
- d.related.map((r) => r.number).join(", ")
2218
- ] }) : 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
+ ))
2219
2890
  ] }),
2220
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-[260px]", children: /* @__PURE__ */ jsxRuntime.jsx(StoreOrderCell, { orderId: d.orderId, displayId: d.displayId }) }),
2221
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: fmtDateTime(d.issuedAt, lang) }),
2222
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: t(`documents.sources.${d.source}`, { defaultValue: d.source }) }),
2223
- /* @__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") }) : "" }),
2224
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatusBadge, { status: d.status }) })
2225
- ] }, d.id)) })
2226
- ] }) }),
2227
- /* @__PURE__ */ jsxRuntime.jsx(Pager, { offset, limit: PAGE_SIZE, count: ((_b = docs.data) == null ? void 0 : _b.count) ?? 0, onChange: setOffset })
2228
- ] });
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
+ );
2229
2924
  }
2230
2925
  function RunsSection({ lang, poll }) {
2231
2926
  var _a;
2232
2927
  const { t } = reactI18next.useTranslation("subiekt");
2233
2928
  const runs = useSubiektRuns(poll);
2234
2929
  const rows = ((_a = runs.data) == null ? void 0 : _a.runs) ?? [];
2235
- return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
2236
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("runs.title") }) }),
2237
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-x-auto", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table, { children: [
2238
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Header, { children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Table.Row, { children: [
2239
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.kind") }),
2240
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.trigger") }),
2241
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.status") }),
2242
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.message") }),
2243
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { children: t("runs.columns.started") }),
2244
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.HeaderCell, { className: "text-right", children: t("runs.columns.duration") })
2245
- ] }) }),
2246
- /* @__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: [
2247
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: t(`runs.kinds.${r.kind}`) }),
2248
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap text-ui-fg-subtle", children: t(`runs.triggers.${r.trigger}`, { defaultValue: r.trigger }) }),
2249
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(RunStatusBadge, { status: r.status }) }),
2250
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "max-w-lg", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", children: runSummary(r, t) }) }),
2251
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "whitespace-nowrap", children: fmtDateTime(r.startedAt, lang) }),
2252
- /* @__PURE__ */ jsxRuntime.jsx(ui.Table.Cell, { className: "text-right tabular-nums", children: fmtDuration(r.durationMs) })
2253
- ] }, r.id)) })
2254
- ] }) })
2255
- ] });
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
+ );
2256
2959
  }
2257
2960
  const config = adminSdk.defineRouteConfig({
2258
2961
  label: "Subiekt nexo",
2259
2962
  icon: SubiektIcon
2260
2963
  });
2261
2964
  const communityEn = {
2262
- addStore: {
2263
- button: "Add your store",
2264
- title: "Does your store run on this integration?",
2265
- text: "Tell us about it. Once we check it, the store joins this list with a link and its rating.",
2266
- name: "Store name",
2267
- url: "Store address",
2268
- note: "A few words about the setup (optional)",
2269
- send: "Send the request",
2270
- copy: "Copy the text",
2271
- copied: "Request copied, paste it into a mail to hello@koda.plus",
2272
- hint: "Your mail app opens with the message to {{email}} ready to send.",
2273
- subject: "A store for {{integration}}",
2274
- greeting: "Hello, my store runs on {{integration}}. Please add it to the list of stores."
2275
- },
2276
2965
  prompt: {
2277
2966
  button: "Copy prompt",
2278
2967
  title: "Add this integration to your store",
@@ -2284,23 +2973,13 @@ const communityEn = {
2284
2973
  discord: {
2285
2974
  button: "Help on Discord",
2286
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."
2287
2980
  }
2288
2981
  };
2289
2982
  const communityPl = {
2290
- addStore: {
2291
- button: "Dodaj swój sklep",
2292
- title: "Twój sklep działa na tej integracji?",
2293
- text: "Daj nam znać. Po sprawdzeniu dodamy go do tej listy z linkiem i oceną.",
2294
- name: "Nazwa sklepu",
2295
- url: "Adres sklepu",
2296
- note: "Kilka słów o wdrożeniu (opcjonalnie)",
2297
- send: "Wyślij zgłoszenie",
2298
- copy: "Kopiuj treść",
2299
- copied: "Treść skopiowana, wklej ją w mail do hello@koda.plus",
2300
- hint: "Otworzy się Twoja poczta z gotową wiadomością do {{email}}.",
2301
- subject: "Zgłoszenie sklepu: {{integration}}",
2302
- greeting: "Dzień dobry, mój sklep działa na integracji {{integration}}. Proszę o dodanie go do listy sklepów."
2303
- },
2304
2983
  prompt: {
2305
2984
  button: "Kopiuj prompt",
2306
2985
  title: "Dodaj tę integrację do swojego sklepu",
@@ -2312,16 +2991,28 @@ const communityPl = {
2312
2991
  discord: {
2313
2992
  button: "Pomoc na Discordzie",
2314
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."
2315
2998
  }
2316
2999
  };
2317
3000
  const en = {
2318
3001
  title: "Subiekt nexo",
2319
3002
  by: "by Koda Plus",
2320
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
+ },
2321
3012
  view: { panel: "Panel", guide: "Setup guide" },
2322
3013
  settings: {
2323
3014
  title: "Settings",
2324
- 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",
2325
3016
  tab: {
2326
3017
  connection: "Connection",
2327
3018
  bridge: "Bridge",
@@ -2340,6 +3031,7 @@ const en = {
2340
3031
  },
2341
3032
  actions: {
2342
3033
  moreActions: "More actions",
3034
+ refresh: "Refresh",
2343
3035
  check: "Check connection",
2344
3036
  checking: "Checking",
2345
3037
  stock: "Sync stock",
@@ -2371,7 +3063,9 @@ const en = {
2371
3063
  attention: "Need attention",
2372
3064
  zk: "ZK documents",
2373
3065
  wz: "WZ documents",
2374
- sales: "FS and PA"
3066
+ sales: "FS and PA",
3067
+ hintAttention: "Send again below",
3068
+ hintWaiting: "Sent after payment"
2375
3069
  },
2376
3070
  store: {
2377
3071
  openOrder: "Open order",
@@ -2399,11 +3093,12 @@ const en = {
2399
3093
  never: "never",
2400
3094
  none: "none",
2401
3095
  eventsReadAt: "Documents read",
2402
- 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" }
2403
3097
  },
2404
3098
  bridge: {
2405
3099
  title: "Bridge",
2406
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" },
2407
3102
  versions: "Versions",
2408
3103
  versionsValue: "bridge {{bridge}}, contract {{contract}}, plugin {{plugin}}",
2409
3104
  sdk: "nexo SDK and database",
@@ -2482,6 +3177,7 @@ const en = {
2482
3177
  writers: {
2483
3178
  title: "Writers",
2484
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" },
2485
3181
  demoNote: "Demo: armed writers only simulate. Nothing in this store changes.",
2486
3182
  names: {
2487
3183
  prices: "Prices from Subiekt",
@@ -2528,6 +3224,7 @@ const en = {
2528
3224
  products: {
2529
3225
  title: "Products from Subiekt",
2530
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" },
2531
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.",
2532
3229
  matchedKey: "Matched by {{by}}: {{code}}",
2533
3230
  settings: "Prices from {{level}} ({{type}}) to {{target}}, in {{currency}}.",
@@ -2563,10 +3260,11 @@ const en = {
2563
3260
  columns: { product: "Product in Subiekt", change: "Change", store: "Product in the store", matched: "Matched by", status: "Status", details: "Details" },
2564
3261
  matchedBy: { ean: "EAN", sku: "SKU" },
2565
3262
  newProduct: "new, {{price}}",
2566
- empty: "Nothing in this plan.",
3263
+ empty: "Nothing in this plan",
2567
3264
  search: "Symbol, SKU or EAN",
2568
3265
  quarantine: "Quarantined after repeated failures",
2569
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" },
2570
3268
  samples: { conflicts: "Conflicts, never guessed", unmatchedVariants: "Variants without a match (SKU)", noPrice: "Without a price in this level" },
2571
3269
  blocked: {
2572
3270
  currency_mismatch: "The price level is in another currency than priceCurrency: nothing was planned.",
@@ -2576,11 +3274,11 @@ const en = {
2576
3274
  tasks: {
2577
3275
  title: "Queue",
2578
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.",
2579
- 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" },
2580
3279
  filters: { attention: "Need attention", open: "Open", done: "Done", all: "All" },
2581
3280
  search: "Order number",
2582
- empty: "Nothing here.",
2583
- 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: "" },
2584
3282
  kinds: { "order.create": "Create ZK", "order.cancel": "Cancel ZK", "order.fulfill": "Issue WZ", "order.document": "Issue sales document" },
2585
3283
  documentKinds: { fs: "Issue FS", pa: "Issue PA" },
2586
3284
  statuses: {
@@ -2603,17 +3301,20 @@ const en = {
2603
3301
  documents: {
2604
3302
  title: "Documents",
2605
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",
2606
3306
  filters: { all: "All", ZK: "ZK", WZ: "WZ", FS: "FS", PA: "PA" },
2607
- empty: "No documents yet.",
2608
- columns: { number: "Number", order: "Order in the store", issued: "Issued", source: "Source", status: "Status", ksef: "KSeF number" },
2609
- 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" },
2610
3310
  statuses: { open: "Open", canceled: "Canceled", completed: "Completed" },
2611
3311
  ksefWaiting: "waiting for KSeF"
2612
3312
  },
2613
3313
  stock: {
2614
3314
  title: "Stock",
2615
3315
  subtitle: "Subiekt to Medusa, by EAN first, then SKU against the product symbol.",
2616
- never: "No stock sync yet.",
3316
+ points: { direction: "Subiekt to Medusa", match: "EAN first, then SKU" },
3317
+ never: "No stock sync yet",
2617
3318
  dryRun: "Dry run",
2618
3319
  counters: {
2619
3320
  subiektProducts: "Products in Subiekt",
@@ -2634,9 +3335,10 @@ const en = {
2634
3335
  },
2635
3336
  runs: {
2636
3337
  title: "History",
2637
- empty: "No runs yet.",
3338
+ empty: "No runs yet",
3339
+ points: { newest: "Newest first", jobs: "Background jobs and clicks" },
2638
3340
  columns: { kind: "Job", trigger: "Trigger", status: "Result", message: "Summary", started: "Started", duration: "Time" },
2639
- 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" },
2640
3342
  triggers: { schedule: "Schedule", manual: "Manual", webhook: "Webhook", event: "Event", auto: "Automatic" },
2641
3343
  statuses: { success: "OK", partial: "Partial", error: "Error", skipped: "Skipped" },
2642
3344
  summary: {
@@ -2648,15 +3350,27 @@ const en = {
2648
3350
  eventsNone: "Nothing new.",
2649
3351
  health: "Bridge and Subiekt answer.",
2650
3352
  productsPlan: "Plan: {{prices}} price change(s), {{creates}} new product(s). No writer armed.",
2651
- 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)."
2652
3356
  }
2653
3357
  },
2654
3358
  widget: {
2655
3359
  title: "Subiekt nexo",
2656
3360
  demo: "Demo",
2657
3361
  more: "Panel",
2658
- none: "This order has not been sent to Subiekt.",
2659
- 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
+ },
2660
3374
  send: "Send to Subiekt now",
2661
3375
  sent: "Queued. The ZK appears here in a few seconds.",
2662
3376
  ksef: "KSeF {{number}}",
@@ -2665,7 +3379,29 @@ const en = {
2665
3379
  issuePa: "Issue receipt (PA)",
2666
3380
  issued: "Queued. The document appears here in a few seconds.",
2667
3381
  autoOff: "Automatic sales documents are off: arm the writer on the Subiekt page.",
2668
- 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
+ }
2669
3405
  },
2670
3406
  toast: {
2671
3407
  started: "Started. Results appear here in a moment.",
@@ -2676,18 +3412,6 @@ const en = {
2676
3412
  released: "Released. The next run tries it again.",
2677
3413
  error: "Something went wrong: {{error}}"
2678
3414
  },
2679
- references: {
2680
- title: "Running in stores built by Koda Plus",
2681
- subtitle: "Live stores implemented by Koda Plus that run on this integration every day.",
2682
- open: "Open the store",
2683
- badgeOne: "Running in 1 store",
2684
- badgeMany: "Running in {{count}} stores",
2685
- badgeSoonOne: "Coming to 1 store",
2686
- badgeSoonMany: "Coming to {{count}} stores",
2687
- soon: "Soon",
2688
- soonMore: "+{{count}} soon",
2689
- review: "Read the review"
2690
- },
2691
3415
  community: communityEn,
2692
3416
  guide: {
2693
3417
  intro: {
@@ -2950,10 +3674,18 @@ const pl$1 = {
2950
3674
  title: "Subiekt nexo",
2951
3675
  by: "by Koda Plus",
2952
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
+ },
2953
3685
  view: { panel: "Panel", guide: "Przewodnik wdrożenia" },
2954
3686
  settings: {
2955
3687
  title: "Ustawienia",
2956
- 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",
2957
3689
  tab: {
2958
3690
  connection: "Połączenie",
2959
3691
  bridge: "Most",
@@ -2972,6 +3704,7 @@ const pl$1 = {
2972
3704
  },
2973
3705
  actions: {
2974
3706
  moreActions: "Więcej akcji",
3707
+ refresh: "Odśwież",
2975
3708
  check: "Sprawdź połączenie",
2976
3709
  checking: "Sprawdzam",
2977
3710
  stock: "Synchronizuj stany",
@@ -3003,7 +3736,9 @@ const pl$1 = {
3003
3736
  attention: "Wymagają uwagi",
3004
3737
  zk: "Dokumenty ZK",
3005
3738
  wz: "Dokumenty WZ",
3006
- sales: "FS i PA"
3739
+ sales: "FS i PA",
3740
+ hintAttention: "Wyślij ponownie niżej",
3741
+ hintWaiting: "Wysyłka po płatności"
3007
3742
  },
3008
3743
  store: {
3009
3744
  openOrder: "Otwórz zamówienie",
@@ -3031,11 +3766,12 @@ const pl$1 = {
3031
3766
  never: "nigdy",
3032
3767
  none: "brak",
3033
3768
  eventsReadAt: "Dokumenty pobrane",
3034
- 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ę" }
3035
3770
  },
3036
3771
  bridge: {
3037
3772
  title: "Most",
3038
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" },
3039
3775
  versions: "Wersje",
3040
3776
  versionsValue: "most {{bridge}}, kontrakt {{contract}}, wtyczka {{plugin}}",
3041
3777
  sdk: "nexo SDK i baza",
@@ -3114,6 +3850,7 @@ const pl$1 = {
3114
3850
  writers: {
3115
3851
  title: "Przełączniki zapisu",
3116
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" },
3117
3854
  demoNote: "Demo: włączone zapisy tylko symulują. W tym sklepie nic się nie zmienia.",
3118
3855
  names: {
3119
3856
  prices: "Ceny z Subiekta",
@@ -3160,6 +3897,7 @@ const pl$1 = {
3160
3897
  products: {
3161
3898
  title: "Produkty z Subiekta",
3162
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" },
3163
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.",
3164
3902
  matchedKey: "Dopasowane po {{by}}: {{code}}",
3165
3903
  settings: "Ceny z {{level}} ({{type}}) do: {{target}}, w walucie {{currency}}.",
@@ -3195,10 +3933,11 @@ const pl$1 = {
3195
3933
  columns: { product: "Towar w Subiekcie", change: "Zmiana", store: "Produkt w sklepie", matched: "Dopasowanie", status: "Status", details: "Szczegóły" },
3196
3934
  matchedBy: { ean: "EAN", sku: "SKU" },
3197
3935
  newProduct: "nowy, {{price}}",
3198
- empty: "Nic w tym planie.",
3936
+ empty: "Nic w tym planie",
3199
3937
  search: "Symbol, SKU albo EAN",
3200
3938
  quarantine: "W kwarantannie po kolejnych błędach",
3201
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ę" },
3202
3941
  samples: { conflicts: "Konflikty, nigdy nie zgadujemy", unmatchedVariants: "Warianty bez dopasowania (SKU)", noPrice: "Bez ceny w tym poziomie" },
3203
3942
  blocked: {
3204
3943
  currency_mismatch: "Poziom cen jest w innej walucie niż priceCurrency: nic nie zaplanowano.",
@@ -3208,11 +3947,11 @@ const pl$1 = {
3208
3947
  tasks: {
3209
3948
  title: "Kolejka",
3210
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.",
3211
- 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" },
3212
3952
  filters: { attention: "Wymagają uwagi", open: "Otwarte", done: "Zakończone", all: "Wszystkie" },
3213
3953
  search: "Numer zamówienia",
3214
- empty: "Nic tu nie ma.",
3215
- 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: "" },
3216
3955
  kinds: { "order.create": "Utwórz ZK", "order.cancel": "Anuluj ZK", "order.fulfill": "Wystaw WZ", "order.document": "Wystaw dokument sprzedaży" },
3217
3956
  documentKinds: { fs: "Wystaw FS", pa: "Wystaw PA" },
3218
3957
  statuses: {
@@ -3235,17 +3974,20 @@ const pl$1 = {
3235
3974
  documents: {
3236
3975
  title: "Dokumenty",
3237
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",
3238
3979
  filters: { all: "Wszystkie", ZK: "ZK", WZ: "WZ", FS: "FS", PA: "PA" },
3239
- empty: "Jeszcze nie ma dokumentów.",
3240
- columns: { number: "Numer", order: "Zamówienie w sklepie", issued: "Wystawiono", source: "Źródło", status: "Status", ksef: "Numer KSeF" },
3241
- 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" },
3242
3983
  statuses: { open: "Otwarty", canceled: "Anulowany", completed: "Zrealizowany" },
3243
3984
  ksefWaiting: "czeka na KSeF"
3244
3985
  },
3245
3986
  stock: {
3246
3987
  title: "Stany",
3247
3988
  subtitle: "Z Subiekta do Medusy, najpierw po EAN, potem po SKU porównanym z symbolem towaru.",
3248
- 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",
3249
3991
  dryRun: "Próba na sucho",
3250
3992
  counters: {
3251
3993
  subiektProducts: "Towary w Subiekcie",
@@ -3266,9 +4008,10 @@ const pl$1 = {
3266
4008
  },
3267
4009
  runs: {
3268
4010
  title: "Historia",
3269
- 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" },
3270
4013
  columns: { kind: "Zadanie", trigger: "Wyzwalacz", status: "Wynik", message: "Podsumowanie", started: "Start", duration: "Czas" },
3271
- 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" },
3272
4015
  triggers: { schedule: "Harmonogram", manual: "Ręcznie", webhook: "Webhook", event: "Zdarzenie", auto: "Automatycznie" },
3273
4016
  statuses: { success: "OK", partial: "Częściowo", error: "Błąd", skipped: "Pominięto" },
3274
4017
  summary: {
@@ -3280,15 +4023,27 @@ const pl$1 = {
3280
4023
  eventsNone: "Nic nowego.",
3281
4024
  health: "Most i Subiekt odpowiadają.",
3282
4025
  productsPlan: "Plan: zmiany cen {{prices}}, nowe produkty {{creates}}. Żaden zapis nie jest włączony.",
3283
- 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}}."
3284
4029
  }
3285
4030
  },
3286
4031
  widget: {
3287
4032
  title: "Subiekt nexo",
3288
4033
  demo: "Demo",
3289
4034
  more: "Panel",
3290
- none: "To zamówienie nie zostało wysłane do Subiekta.",
3291
- 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
+ },
3292
4047
  send: "Wyślij do Subiekta teraz",
3293
4048
  sent: "W kolejce. ZK pojawi się tu za kilka sekund.",
3294
4049
  ksef: "KSeF {{number}}",
@@ -3297,7 +4052,29 @@ const pl$1 = {
3297
4052
  issuePa: "Wystaw paragon (PA)",
3298
4053
  issued: "W kolejce. Dokument pojawi się tu za kilka sekund.",
3299
4054
  autoOff: "Automatyczne dokumenty sprzedaży są wyłączone: włącz zapis na stronie Subiekta.",
3300
- 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
+ }
3301
4078
  },
3302
4079
  toast: {
3303
4080
  started: "Uruchomione. Wynik pojawi się tu za chwilę.",
@@ -3308,18 +4085,6 @@ const pl$1 = {
3308
4085
  released: "Zwolnione. Następny przebieg spróbuje ponownie.",
3309
4086
  error: "Coś poszło nie tak: {{error}}"
3310
4087
  },
3311
- references: {
3312
- title: "Działa w sklepach wdrożonych przez Koda Plus",
3313
- subtitle: "Prawdziwe sklepy z wdrożeniem Koda Plus, które pracują na tej integracji na co dzień.",
3314
- open: "Otwórz sklep",
3315
- badgeOne: "Działa w 1 sklepie",
3316
- badgeMany: "Działa w {{count}} sklepach",
3317
- badgeSoonOne: "Wkrótce w 1 sklepie",
3318
- badgeSoonMany: "Wkrótce w {{count}} sklepach",
3319
- soon: "Wkrótce",
3320
- soonMore: "+{{count}} wkrótce",
3321
- review: "Zobacz opinię"
3322
- },
3323
4088
  community: communityPl,
3324
4089
  guide: {
3325
4090
  intro: {