@flowselections/floriday-authenticatie-module 1.0.79 → 1.0.83

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 (26) hide show
  1. package/dist-lib/components/floriday/FlorydayApiLogPage.d.ts.map +1 -1
  2. package/dist-lib/components/floriday/FlorydayApiLogPage.js +29 -3
  3. package/dist-lib/components/floriday/FlorydayWebhooksCard.d.ts.map +1 -1
  4. package/dist-lib/components/floriday/FlorydayWebhooksCard.js +20 -2
  5. package/dist-lib/components/floriday/TokenHealthCard.d.ts.map +1 -1
  6. package/dist-lib/components/floriday/TokenHealthCard.js +1 -1
  7. package/dist-lib/integrations/supabase/types.d.ts +495 -2
  8. package/dist-lib/integrations/supabase/types.d.ts.map +1 -1
  9. package/dist-lib/integrations/supabase/types.js +1 -0
  10. package/dist-lib/lib/floriday-sync.functions.d.ts +24 -192
  11. package/dist-lib/lib/floriday-sync.functions.d.ts.map +1 -1
  12. package/dist-lib/lib/floriday-webhooks.functions.d.ts +37 -0
  13. package/dist-lib/lib/floriday-webhooks.functions.d.ts.map +1 -1
  14. package/dist-lib/lib/floriday-webhooks.functions.js +95 -2
  15. package/dist-lib/lib/floriday.functions.d.ts +14 -1
  16. package/dist-lib/lib/floriday.functions.d.ts.map +1 -1
  17. package/dist-lib/lib/floriday.functions.js +56 -28
  18. package/dist-lib/lib/gateway/customer-stickers.d.ts +12 -8
  19. package/dist-lib/lib/gateway/customer-stickers.d.ts.map +1 -1
  20. package/dist-lib/lib/gateway/customer-stickers.js +190 -37
  21. package/dist-lib/lib/gateway/webhook.d.ts +17 -2
  22. package/dist-lib/lib/gateway/webhook.d.ts.map +1 -1
  23. package/dist-lib/lib/gateway/webhook.js +81 -6
  24. package/dist-lib/lib/module-version.d.ts +1 -1
  25. package/dist-lib/lib/module-version.js +1 -1
  26. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"FlorydayApiLogPage.d.ts","sourceRoot":"","sources":["../../../src/components/floriday/FlorydayApiLogPage.tsx"],"names":[],"mappings":"AAgEA,wBAAgB,kBAAkB,gCAuZjC"}
1
+ {"version":3,"file":"FlorydayApiLogPage.d.ts","sourceRoot":"","sources":["../../../src/components/floriday/FlorydayApiLogPage.tsx"],"names":[],"mappings":"AA0FA,wBAAgB,kBAAkB,gCAyZjC"}
@@ -32,6 +32,32 @@ function describeKind(row) {
32
32
  }
33
33
  }
34
34
  const POLL_KINDS = new Set(["poll-check", "poll-empty", "poll-changed"]);
35
+ /** Nederlandse naam voor de kolom Soort. */
36
+ const SOORT_NL = {
37
+ "sales-order": "Verkooporder",
38
+ "fulfillment-order": "Levering",
39
+ "delivery-order": "Leveropdracht",
40
+ "trade-item": "Artikel",
41
+ "supply-line": "Aanbod",
42
+ "base-supply": "Weekaanbod",
43
+ "clock-supply": "Klokaanbod",
44
+ customer: "Klant",
45
+ warehouse: "Magazijn",
46
+ "delivery-location": "Afleverlocatie",
47
+ connection: "Connectie",
48
+ "price-group": "Prijsgroep",
49
+ "catalog-price": "Catalogusprijs",
50
+ trip: "Rit",
51
+ packing: "Verpakking",
52
+ "logistic-label": "Verzendlabel",
53
+ "auction-letter": "Veilingbrief",
54
+ "customer-sticker": "Sticker",
55
+ };
56
+ function soortLabel(type, templateLabel) {
57
+ if (type && SOORT_NL[type])
58
+ return SOORT_NL[type];
59
+ return templateLabel ?? type ?? "—";
60
+ }
35
61
  export function FlorydayApiLogPage() {
36
62
  const [direction, setDirection] = useState("all");
37
63
  const [onlyFailed, setOnlyFailed] = useState(false);
@@ -122,7 +148,7 @@ export function FlorydayApiLogPage() {
122
148
  }, children: "Alleen wijzigingen" }), _jsx("input", { className: "h-9 min-w-[16rem] flex-1 rounded-md border border-input bg-background px-3 text-sm", placeholder: "Zoek op Floriday-referentie, ons kenmerk of pad", value: search, onChange: (e) => {
123
149
  setSearch(e.target.value);
124
150
  setPage(0);
125
- } }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => logQuery.refetch(), children: "Vernieuwen" })] }), _jsx("div", { className: "overflow-x-auto", children: _jsxs("table", { className: "w-full text-sm", children: [_jsx("thead", { className: "text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "py-2 pr-3", children: "Tijd" }), _jsx("th", { className: "py-2 pr-3", children: "Richting" }), _jsx("th", { className: "py-2 pr-3", children: "Aard" }), _jsx("th", { className: "py-2 pr-3", children: "Soort" }), _jsx("th", { className: "py-2 pr-3", children: "Actie" }), _jsx("th", { className: "py-2 pr-3", children: "Status" }), _jsx("th", { className: "py-2 pr-3", children: "Floriday-referentie" }), _jsx("th", { className: "py-2 pr-3", children: "Ons item" })] }) }), _jsxs("tbody", { children: [rows.map((row) => {
151
+ } }), _jsx(Button, { size: "sm", variant: "outline", onClick: () => logQuery.refetch(), children: "Vernieuwen" })] }), _jsx("div", { className: "w-full", children: _jsxs("table", { className: "w-full table-fixed text-sm [&_td]:break-words [&_td]:[overflow-wrap:anywhere]", children: [_jsxs("colgroup", { children: [_jsx("col", { className: "w-[9%]" }), _jsx("col", { className: "w-[9%]" }), _jsx("col", { className: "w-[13%]" }), _jsx("col", { className: "w-[10%]" }), _jsx("col", { className: "w-[25%]" }), _jsx("col", { className: "w-[10%]" }), _jsx("col", { className: "w-[14%]" }), _jsx("col", { className: "w-[10%]" })] }), _jsx("thead", { className: "text-left text-muted-foreground", children: _jsxs("tr", { children: [_jsx("th", { className: "py-2 pr-3", children: "Tijd" }), _jsx("th", { className: "py-2 pr-3", children: "Richting" }), _jsx("th", { className: "py-2 pr-3", children: "Aard" }), _jsx("th", { className: "py-2 pr-3", children: "Soort" }), _jsx("th", { className: "py-2 pr-3", children: "Actie" }), _jsx("th", { className: "py-2 pr-3", children: "Status" }), _jsx("th", { className: "py-2 pr-3", children: "Floriday-referentie" }), _jsx("th", { className: "py-2 pr-3", children: "Ons item" })] }) }), _jsxs("tbody", { children: [rows.map((row) => {
126
152
  const tpl = row.resource_type ? templateByType.get(row.resource_type) : undefined;
127
153
  // Een ophaalronde zonder herkenbaar item blijft een "routineronde";
128
154
  // zodra we er één order/artikel uit konden halen tonen we die gewoon.
@@ -137,10 +163,10 @@ export function FlorydayApiLogPage() {
137
163
  const floridayHref = !isPoll && tpl?.floriday_url_template && row.floriday_id
138
164
  ? fillTemplate(tpl.floriday_url_template, row)
139
165
  : null;
140
- return (_jsxs("tr", { className: "border-t border-border align-top", children: [_jsx("td", { className: "py-2 pr-3 whitespace-nowrap", children: new Date(row.created_at).toLocaleString("nl-NL") }), _jsx("td", { className: "py-2 pr-3", children: _jsx(Badge, { variant: row.direction === "outbound" ? "default" : "secondary", children: row.direction === "outbound" ? "Versturen" : "Ophalen" }) }), _jsxs("td", { className: "py-2 pr-3", children: [_jsx("div", { children: kind.label }), kind.hint ? (_jsx("div", { className: "text-xs text-muted-foreground", children: kind.hint })) : null] }), _jsx("td", { className: "py-2 pr-3", children: tpl?.label ?? row.resource_type ?? "—" }), _jsxs("td", { className: "py-2 pr-3", children: [_jsx("div", { children: row.action ?? `${row.method} ${row.path}` }), row.cursor_from != null ? (_jsxs("div", { className: "text-xs text-muted-foreground", children: ["vanaf volgnummer ", row.cursor_from] })) : null, row.error ? _jsx(FullErrorMessage, { error: row.error, response: row.response, createdAt: row.created_at }) : null] }), _jsx("td", { className: "py-2 pr-3", children: _jsxs(Badge, { variant: row.ok ? "secondary" : "destructive", children: [row.ok ? "Gelukt" : "Mislukt", " ", row.http_status || ""] }) }), _jsx("td", { className: "py-2 pr-3", children: isPoll ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "Geen los item (routineronde)" })) : floridayShown ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-mono text-xs", title: row.floriday_id ?? undefined, children: floridayShown }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
166
+ return (_jsxs("tr", { className: "border-t border-border align-top", children: [_jsx("td", { className: "py-2 pr-3", children: new Date(row.created_at).toLocaleString("nl-NL") }), _jsx("td", { className: "py-2 pr-3", children: _jsx(Badge, { variant: row.direction === "outbound" ? "default" : "secondary", children: row.direction === "outbound" ? "Versturen" : "Ophalen" }) }), _jsxs("td", { className: "py-2 pr-3", children: [_jsx("div", { children: kind.label }), kind.hint ? (_jsx("div", { className: "text-xs text-muted-foreground", children: kind.hint })) : null] }), _jsx("td", { className: "py-2 pr-3", children: soortLabel(row.resource_type, tpl?.label) }), _jsxs("td", { className: "py-2 pr-3", children: [_jsx("div", { children: row.action ?? `${row.method} ${row.path}` }), row.cursor_from != null ? (_jsxs("div", { className: "text-xs text-muted-foreground", children: ["vanaf volgnummer ", row.cursor_from] })) : null, row.error ? _jsx(FullErrorMessage, { error: row.error, response: row.response, createdAt: row.created_at }) : null] }), _jsx("td", { className: "py-2 pr-3", children: _jsxs(Badge, { variant: row.ok ? "secondary" : "destructive", children: [row.ok ? "Gelukt" : "Mislukt", " ", row.http_status || ""] }) }), _jsx("td", { className: "py-2 pr-3", children: isPoll ? null : floridayShown ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-mono text-xs", title: row.floriday_id ?? undefined, children: floridayShown }), _jsx(Button, { size: "sm", variant: "ghost", onClick: () => {
141
167
  navigator.clipboard?.writeText(floridayShown);
142
168
  toast.success("Referentie gekopieerd");
143
- }, children: "Kopieer" }), floridayHref ? (_jsx("a", { className: "text-xs underline", href: floridayHref, target: "_blank", rel: "noreferrer", children: "Floriday" })) : null] })) : ("—") }), _jsx("td", { className: "py-2 pr-3", children: isPoll ? ("—") : localHref ? (_jsx("a", { href: localHref, className: "text-xs underline", title: localShown ?? undefined, children: localShown ?? "Openen" })) : localShown ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("span", { className: "font-mono text-xs", title: row.local_id ?? undefined, children: localShown }), !tpl?.local_url_template ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "(geen adres ingesteld)" })) : null] })) : tpl?.local_url_template ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "Nog niet in onze cache" })) : (_jsx("span", { className: "text-xs text-muted-foreground", children: "Geen adres ingesteld" })) })] }, row.id));
169
+ }, children: "Kopieer" }), floridayHref ? (_jsx("a", { className: "text-xs underline", href: floridayHref, target: "_blank", rel: "noreferrer", children: "Floriday" })) : null] })) : ("—") }), _jsx("td", { className: "py-2 pr-3", children: isPoll ? ("—") : localHref ? (_jsx("a", { href: localHref, className: "text-xs underline", title: localShown ?? undefined, children: localShown ?? "Openen" })) : localShown ? (_jsx("div", { className: "flex items-center gap-2", children: _jsx("span", { className: "font-mono text-xs", title: row.local_id ?? undefined, children: localShown }) })) : tpl?.local_url_template ? (_jsx("span", { className: "text-xs text-muted-foreground", children: "Nog niet in onze cache" })) : (_jsx("span", { className: "text-xs text-muted-foreground", title: "Geen pagina in deze module voor dit type", children: "\u2014" })) })] }, row.id));
144
170
  }), rows.length === 0 ? (_jsx("tr", { children: _jsx("td", { colSpan: 8, className: "py-6 text-center text-muted-foreground", children: logQuery.isLoading ? "Bezig met laden…" : "Nog geen berichten gevonden." }) })) : null] })] }) }), _jsxs("div", { className: "flex items-center justify-between text-sm text-muted-foreground", children: [_jsxs("span", { children: [total, " berichten \u2014 pagina ", page + 1] }), _jsxs("div", { className: "flex gap-2", children: [_jsx(Button, { size: "sm", variant: "outline", disabled: page === 0, onClick: () => setPage((p) => Math.max(0, p - 1)), children: "Vorige" }), _jsx(Button, { size: "sm", variant: "outline", disabled: (page + 1) * PAGE_SIZE >= total, onClick: () => setPage((p) => p + 1), children: "Volgende" })] })] })] }), _jsxs(Card, { className: "p-4 space-y-3", children: [_jsxs("div", { children: [_jsx("h2", { className: "text-lg font-semibold", children: "Doorklik-adressen" }), _jsxs("p", { className: "text-sm text-muted-foreground", children: ["Stel per soort in waar een regel naartoe moet linken. Gebruik", " ", _jsx("code", { children: "{id}" }), " voor ons kenmerk en ", _jsx("code", { children: "{floridayId}" }), " voor de Floriday-referentie. Bijvoorbeeld", " ", _jsxs("code", { children: ["/floriday-verkoop/verkooporders/", "{id}"] }), "."] })] }), _jsx("div", { className: "space-y-2", children: templates.map((t) => (_jsx(TemplateRow, { template: t, onSave: (local, floriday) => saveTemplateMutation.mutate({
145
171
  resourceType: t.resource_type,
146
172
  label: t.label,
@@ -1 +1 @@
1
- {"version":3,"file":"FlorydayWebhooksCard.d.ts","sourceRoot":"","sources":["../../../src/components/floriday/FlorydayWebhooksCard.tsx"],"names":[],"mappings":"AAsBA,wBAAgB,oBAAoB,gCAyFnC"}
1
+ {"version":3,"file":"FlorydayWebhooksCard.d.ts","sourceRoot":"","sources":["../../../src/components/floriday/FlorydayWebhooksCard.tsx"],"names":[],"mappings":"AAwBA,wBAAgB,oBAAoB,gCA+InC"}
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
3
3
  import { useServerFn } from "@tanstack/react-start";
4
4
  import { useState } from "react";
5
- import { getFloridayWebhookStatus, subscribeFloridayWebhook, unsubscribeFloridayWebhook, } from "../../lib/floriday-webhooks.functions.js";
5
+ import { getFloridayWebhookStatus, listStaleWebhookCallbacks, unsubscribeStaleWebhookCallback, subscribeFloridayWebhook, unsubscribeFloridayWebhook, } from "../../lib/floriday-webhooks.functions.js";
6
6
  function badge(s, isActiveConn) {
7
7
  if (!isActiveConn)
8
8
  return { text: "Geen actieve koppeling", cls: "bg-muted text-muted-foreground" };
@@ -23,6 +23,18 @@ export function FlorydayWebhooksCard() {
23
23
  const subscribe = useServerFn(subscribeFloridayWebhook);
24
24
  const unsubscribe = useServerFn(unsubscribeFloridayWebhook);
25
25
  const [message, setMessage] = useState(null);
26
+ const listStale = useServerFn(listStaleWebhookCallbacks);
27
+ const unsubStale = useServerFn(unsubscribeStaleWebhookCallback);
28
+ const staleQ = useQuery({ queryKey: ["floriday-webhooks-stale"], queryFn: () => listStale(), retry: false });
29
+ const staleMut = useMutation({
30
+ mutationFn: (key) => unsubStale({ data: { key } }),
31
+ onSuccess: (r) => {
32
+ setMessage(r?.results
33
+ ? `Afmelden: ${r.results.map((x) => `${x.environment === "live" ? "productie" : "test"} ${x.status}`).join(", ")}`
34
+ : r?.error ?? "Mislukt");
35
+ qc.invalidateQueries({ queryKey: ["floriday-webhooks-stale"] });
36
+ },
37
+ });
26
38
  const q = useQuery({ queryKey: ["floriday-webhooks"], queryFn: () => getStatus(), refetchInterval: 30000 });
27
39
  const done = (r) => {
28
40
  setMessage(r?.ok ? "Gelukt." : r?.error ?? "Mislukt");
@@ -31,6 +43,7 @@ export function FlorydayWebhooksCard() {
31
43
  const sub = useMutation({ mutationFn: (environment) => subscribe({ data: { environment } }), onSuccess: done });
32
44
  const unsub = useMutation({ mutationFn: (environment) => unsubscribe({ data: { environment } }), onSuccess: done });
33
45
  const subs = (q.data?.subscriptions ?? []);
46
+ const reasons = q.data?.rejectedByReason ?? {};
34
47
  const counts = q.data?.last24h ?? {};
35
48
  const activeEnvs = (q.data?.activeEnvironments ?? []);
36
49
  const envs = ["staging", "live"];
@@ -43,5 +56,10 @@ export function FlorydayWebhooksCard() {
43
56
  catch {
44
57
  return "—";
45
58
  } })()] })), s?.status === "error" && (_jsxs("div", { className: "text-destructive text-xs mt-1 space-y-0.5", children: [_jsx("div", { children: s.last_error }), s.next_attempt_at && _jsxs("div", { children: ["Volgende automatische poging: ", fmt(s.next_attempt_at)] }), s.last_error_kind === "scope" && (_jsx("div", { children: "Dit staat op de lijst met vragen voor de beheerder van Central Auth." }))] }))] }), _jsxs("div", { className: "flex gap-2 shrink-0", children: [_jsx("button", { className: "rounded-md border px-3 py-1 text-xs hover:bg-accent disabled:opacity-50", disabled: sub.isPending, onClick: () => sub.mutate(env), children: s ? "Opnieuw aanmelden" : "Aanmelden" }), s && (_jsx("button", { className: "rounded-md border px-3 py-1 text-xs hover:bg-accent disabled:opacity-50", disabled: unsub.isPending, onClick: () => unsub.mutate(env), children: "Afmelden" }))] })] }, env));
46
- }) }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Laatste 24 uur: ", counts.processed ?? 0, " verwerkt \u00B7 ", counts.duplicate ?? 0, " dubbel \u00B7", " ", counts.ignored ?? 0, " genegeerd \u00B7 ", (counts.failed ?? 0) + (counts.failed_retry ?? 0), " mislukt \u00B7", " ", counts.rejected ?? 0, " geweigerd"] }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Laatste automatische controle: ", fmt(q.data?.lastEnsureAt)] }), message && _jsx("p", { className: "text-xs", children: message })] }));
59
+ }) }), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Laatste 24 uur: ", counts.processed ?? 0, " verwerkt \u00B7 ", counts.duplicate ?? 0, " dubbel \u00B7", " ", counts.ignored ?? 0, " genegeerd \u00B7 ", (counts.failed ?? 0) + (counts.failed_retry ?? 0), " mislukt \u00B7", " ", counts.rejected ?? 0, " geweigerd"] }), Object.keys(reasons).length > 0 && (_jsx("ul", { className: "text-xs text-muted-foreground space-y-0.5", children: Object.entries(reasons).map(([r, n]) => (_jsxs("li", { children: [String(n), " geweigerd: ", r, r === "Onbekend callback-token" ? " (waarschijnlijk een oude aanmelding bij Floriday)" : ""] }, r))) })), Array.isArray(staleQ.data) && staleQ.data.length > 0 && (_jsxs("div", { className: "space-y-2", children: [_jsx("h3", { className: "text-sm font-medium", children: "Oude aanmeldingen" }), _jsx("ul", { className: "space-y-2", children: staleQ.data.map((s) => (_jsxs("li", { className: "flex items-start justify-between gap-4 text-xs", children: [_jsxs("div", { children: [_jsx("div", { className: "font-mono break-all", children: s.callbackUrlMasked }), _jsxs("div", { className: "text-muted-foreground", children: [s.count, " meldingen sinds ", fmt(s.firstAt), " \u00B7 laatste ", fmt(s.lastAt), s.unsubscribe
60
+ ? ` · afgemeld ${fmt(s.unsubscribe.at)} (${(s.unsubscribe.results ?? []).map((x) => x.status).join(", ")})`
61
+ : ""] })] }), _jsx("button", { className: "shrink-0 rounded-md border px-3 py-1 hover:bg-accent disabled:opacity-50", disabled: staleMut.isPending, onClick: () => {
62
+ if (window.confirm(`Oude aanmelding afmelden bij Floriday?\n${s.callbackUrlMasked}`))
63
+ staleMut.mutate(s.key);
64
+ }, children: "Oude aanmelding afmelden" })] }, s.key))) })] })), _jsxs("p", { className: "text-xs text-muted-foreground", children: ["Laatste automatische controle: ", fmt(q.data?.lastEnsureAt)] }), message && _jsx("p", { className: "text-xs", children: message })] }));
47
65
  }
@@ -1 +1 @@
1
- {"version":3,"file":"TokenHealthCard.d.ts","sourceRoot":"","sources":["../../../src/components/floriday/TokenHealthCard.tsx"],"names":[],"mappings":"AA2DA,wBAAgB,eAAe,gCAqL9B"}
1
+ {"version":3,"file":"TokenHealthCard.d.ts","sourceRoot":"","sources":["../../../src/components/floriday/TokenHealthCard.tsx"],"names":[],"mappings":"AA2DA,wBAAgB,eAAe,gCAoL9B"}
@@ -87,7 +87,7 @@ export function TokenHealthCard() {
87
87
  const jobs = (cronStatus.data?.jobs ?? []);
88
88
  const tokenJob = jobs.find((j) => j.jobname === "refresh-floriday-tokens-hourly");
89
89
  const cronUrlMismatch = Boolean(expectedBase && tokenJob?.url && !tokenJob.url.startsWith(expectedBase));
90
- return (_jsxs("div", { className: "rounded-lg border p-4 space-y-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold", children: "Token gezondheid" }), _jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "De achtergrond-cron vernieuwt tokens elke 15 minuten. Bij elke API-aanroep wordt bovendien automatisch geretried met een vers token bij een 401." })] }), lastOk && (_jsxs("span", { className: "text-xs text-muted-foreground shrink-0", children: ["Laatste succesvolle refresh:", " ", new Date(lastOk.attempted_at).toLocaleString("nl-NL")] }))] }), conns.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen actieve koppelingen." })) : (_jsx("ul", { className: "space-y-2", children: conns.map((c) => {
90
+ return (_jsxs("div", { className: "rounded-lg border p-4 space-y-4", children: [_jsxs("div", { className: "flex items-start justify-between gap-4", children: [_jsxs("div", { children: [_jsx("h2", { className: "font-semibold", children: "Token gezondheid" }), _jsx("p", { className: "text-xs text-muted-foreground mt-1", children: "De koppeling wordt elke 15 minuten automatisch vernieuwd." })] }), lastOk && (_jsxs("span", { className: "text-xs text-muted-foreground shrink-0", children: ["Laatste succesvolle refresh:", " ", new Date(lastOk.attempted_at).toLocaleString("nl-NL")] }))] }), conns.length === 0 ? (_jsx("p", { className: "text-sm text-muted-foreground", children: "Geen actieve koppelingen." })) : (_jsx("ul", { className: "space-y-2", children: conns.map((c) => {
91
91
  const st = statusFromLog(recent.filter((r) => r.connection_id === c.id));
92
92
  return (_jsxs("li", { className: "flex items-center justify-between gap-3 text-sm", children: [_jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [_jsx("span", { className: `inline-block h-2.5 w-2.5 rounded-full shrink-0 ${st.color}` }), _jsx("span", { className: "font-medium capitalize", children: c.environment }), _jsx("span", { className: st.bad ? "text-red-600" : "text-muted-foreground", title: st.error ?? undefined, children: st.label })] }), _jsx("button", { type: "button", onClick: () => refresh.mutate(c.environment), disabled: busyEnv === c.environment, className: "rounded-md border px-2.5 py-1 text-xs hover:bg-muted disabled:opacity-50 shrink-0", children: busyEnv === c.environment ? "Vernieuwen…" : "Nu vernieuwen" })] }, c.id));
93
93
  }) })), _jsxs("div", { className: "border-t pt-3 space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between gap-3", children: [_jsx("h3", { className: "text-sm font-medium", children: "Geplande cron-taken" }), _jsx("button", { type: "button", onClick: () => reinstallMutation.mutate(), disabled: reinstallMutation.isPending, className: "rounded-md border px-2.5 py-1 text-xs hover:bg-muted disabled:opacity-50", children: reinstallMutation.isPending ? "Installeren…" : "Cron opnieuw installeren" })] }), cronStatus.isLoading ? (_jsx("p", { className: "text-xs text-muted-foreground", children: "Status laden\u2026" })) : jobs.length === 0 ? (_jsx("p", { className: "text-xs text-amber-600", children: "Geen Floriday-cron jobs gevonden. Klik \"Cron opnieuw installeren\" om ze in te plannen." })) : (_jsx("ul", { className: "space-y-1 text-xs", children: jobs.map((j) => {