@open-mercato/tillio 0.7.1-develop.7176.1.d229567a50
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.
- package/.turbo/turbo-build.log +2 -0
- package/build.mjs +7 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +7 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-001-pull-readiness.spec.js +17 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-001-pull-readiness.spec.js.map +7 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-002-pull-blocked.spec.js +27 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-002-pull-blocked.spec.js.map +7 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-003-operators.spec.js +47 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-003-operators.spec.js.map +7 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-004-pull-widget.spec.js +11 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-004-pull-widget.spec.js.map +7 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-005-operators-widget.spec.js +13 -0
- package/dist/modules/tillio/__integration__/TC-PHONE-005-operators-widget.spec.js.map +7 -0
- package/dist/modules/tillio/acl.js +9 -0
- package/dist/modules/tillio/acl.js.map +7 -0
- package/dist/modules/tillio/api/operators/[id]/route.js +78 -0
- package/dist/modules/tillio/api/operators/[id]/route.js.map +7 -0
- package/dist/modules/tillio/api/operators/route.js +171 -0
- package/dist/modules/tillio/api/operators/route.js.map +7 -0
- package/dist/modules/tillio/api/pull/route.js +180 -0
- package/dist/modules/tillio/api/pull/route.js.map +7 -0
- package/dist/modules/tillio/cli.js +108 -0
- package/dist/modules/tillio/cli.js.map +7 -0
- package/dist/modules/tillio/di.js +16 -0
- package/dist/modules/tillio/di.js.map +7 -0
- package/dist/modules/tillio/index.js +12 -0
- package/dist/modules/tillio/index.js.map +7 -0
- package/dist/modules/tillio/integration.js +62 -0
- package/dist/modules/tillio/integration.js.map +7 -0
- package/dist/modules/tillio/lib/adapter.js +107 -0
- package/dist/modules/tillio/lib/adapter.js.map +7 -0
- package/dist/modules/tillio/lib/client.js +249 -0
- package/dist/modules/tillio/lib/client.js.map +7 -0
- package/dist/modules/tillio/lib/environment.js +34 -0
- package/dist/modules/tillio/lib/environment.js.map +7 -0
- package/dist/modules/tillio/lib/error-codes.js +59 -0
- package/dist/modules/tillio/lib/error-codes.js.map +7 -0
- package/dist/modules/tillio/lib/errors.js +12 -0
- package/dist/modules/tillio/lib/errors.js.map +7 -0
- package/dist/modules/tillio/lib/health.js +41 -0
- package/dist/modules/tillio/lib/health.js.map +7 -0
- package/dist/modules/tillio/lib/locking.js +18 -0
- package/dist/modules/tillio/lib/locking.js.map +7 -0
- package/dist/modules/tillio/lib/normalizer.js +134 -0
- package/dist/modules/tillio/lib/normalizer.js.map +7 -0
- package/dist/modules/tillio/lib/operators-store.js +62 -0
- package/dist/modules/tillio/lib/operators-store.js.map +7 -0
- package/dist/modules/tillio/lib/operators.js +168 -0
- package/dist/modules/tillio/lib/operators.js.map +7 -0
- package/dist/modules/tillio/lib/preset.js +122 -0
- package/dist/modules/tillio/lib/preset.js.map +7 -0
- package/dist/modules/tillio/lib/pull-job.js +265 -0
- package/dist/modules/tillio/lib/pull-job.js.map +7 -0
- package/dist/modules/tillio/lib/pull-readiness.js +36 -0
- package/dist/modules/tillio/lib/pull-readiness.js.map +7 -0
- package/dist/modules/tillio/lib/queue.js +22 -0
- package/dist/modules/tillio/lib/queue.js.map +7 -0
- package/dist/modules/tillio/lib/tz.js +85 -0
- package/dist/modules/tillio/lib/tz.js.map +7 -0
- package/dist/modules/tillio/lib/url-guard.js +24 -0
- package/dist/modules/tillio/lib/url-guard.js.map +7 -0
- package/dist/modules/tillio/setup.js +45 -0
- package/dist/modules/tillio/setup.js.map +7 -0
- package/dist/modules/tillio/widgets/injection/operators-config/widget.client.js +208 -0
- package/dist/modules/tillio/widgets/injection/operators-config/widget.client.js.map +7 -0
- package/dist/modules/tillio/widgets/injection/operators-config/widget.js +17 -0
- package/dist/modules/tillio/widgets/injection/operators-config/widget.js.map +7 -0
- package/dist/modules/tillio/widgets/injection/pull-calls/widget.client.js +148 -0
- package/dist/modules/tillio/widgets/injection/pull-calls/widget.client.js.map +7 -0
- package/dist/modules/tillio/widgets/injection/pull-calls/widget.js +17 -0
- package/dist/modules/tillio/widgets/injection/pull-calls/widget.js.map +7 -0
- package/dist/modules/tillio/widgets/injection-table.js +21 -0
- package/dist/modules/tillio/widgets/injection-table.js.map +7 -0
- package/dist/modules/tillio/workers/tillio-pull.js +17 -0
- package/dist/modules/tillio/workers/tillio-pull.js.map +7 -0
- package/jest.config.cjs +35 -0
- package/package.json +92 -0
- package/src/index.ts +1 -0
- package/src/modules/tillio/__integration__/TC-PHONE-001-pull-readiness.spec.ts +38 -0
- package/src/modules/tillio/__integration__/TC-PHONE-002-pull-blocked.spec.ts +44 -0
- package/src/modules/tillio/__integration__/TC-PHONE-003-operators.spec.ts +76 -0
- package/src/modules/tillio/__integration__/TC-PHONE-004-pull-widget.spec.ts +22 -0
- package/src/modules/tillio/__integration__/TC-PHONE-005-operators-widget.spec.ts +27 -0
- package/src/modules/tillio/__tests__/adapter-fetch-calls.test.ts +148 -0
- package/src/modules/tillio/__tests__/client.test.ts +203 -0
- package/src/modules/tillio/__tests__/health.test.ts +122 -0
- package/src/modules/tillio/__tests__/normalizer.test.ts +143 -0
- package/src/modules/tillio/__tests__/operators-routes.test.ts +100 -0
- package/src/modules/tillio/__tests__/operators-store.test.ts +104 -0
- package/src/modules/tillio/__tests__/operators.test.ts +250 -0
- package/src/modules/tillio/__tests__/preset.test.ts +337 -0
- package/src/modules/tillio/__tests__/pull-body.test.ts +43 -0
- package/src/modules/tillio/__tests__/pull-job.test.ts +250 -0
- package/src/modules/tillio/__tests__/pull-readiness.test.ts +143 -0
- package/src/modules/tillio/__tests__/pull-route.test.ts +148 -0
- package/src/modules/tillio/__tests__/tz.test.ts +53 -0
- package/src/modules/tillio/__tests__/url-guard.test.ts +46 -0
- package/src/modules/tillio/acl.ts +5 -0
- package/src/modules/tillio/api/operators/[id]/route.ts +90 -0
- package/src/modules/tillio/api/operators/route.ts +191 -0
- package/src/modules/tillio/api/pull/route.ts +213 -0
- package/src/modules/tillio/cli.ts +125 -0
- package/src/modules/tillio/di.ts +16 -0
- package/src/modules/tillio/i18n/de.json +73 -0
- package/src/modules/tillio/i18n/en.json +73 -0
- package/src/modules/tillio/i18n/es.json +73 -0
- package/src/modules/tillio/i18n/ko.json +73 -0
- package/src/modules/tillio/i18n/pl.json +73 -0
- package/src/modules/tillio/index.ts +8 -0
- package/src/modules/tillio/integration.ts +58 -0
- package/src/modules/tillio/lib/adapter.ts +135 -0
- package/src/modules/tillio/lib/client.ts +329 -0
- package/src/modules/tillio/lib/environment.ts +53 -0
- package/src/modules/tillio/lib/error-codes.ts +67 -0
- package/src/modules/tillio/lib/errors.ts +11 -0
- package/src/modules/tillio/lib/health.ts +57 -0
- package/src/modules/tillio/lib/locking.ts +30 -0
- package/src/modules/tillio/lib/normalizer.ts +184 -0
- package/src/modules/tillio/lib/operators-store.ts +77 -0
- package/src/modules/tillio/lib/operators.ts +269 -0
- package/src/modules/tillio/lib/preset.ts +226 -0
- package/src/modules/tillio/lib/pull-job.ts +390 -0
- package/src/modules/tillio/lib/pull-readiness.ts +77 -0
- package/src/modules/tillio/lib/queue.ts +33 -0
- package/src/modules/tillio/lib/tz.ts +121 -0
- package/src/modules/tillio/lib/url-guard.ts +34 -0
- package/src/modules/tillio/setup.ts +49 -0
- package/src/modules/tillio/widgets/injection/operators-config/widget.client.tsx +304 -0
- package/src/modules/tillio/widgets/injection/operators-config/widget.ts +16 -0
- package/src/modules/tillio/widgets/injection/pull-calls/widget.client.tsx +214 -0
- package/src/modules/tillio/widgets/injection/pull-calls/widget.ts +16 -0
- package/src/modules/tillio/widgets/injection-table.ts +19 -0
- package/src/modules/tillio/workers/tillio-pull.ts +18 -0
- package/tsconfig.json +9 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
5
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
6
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
7
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
8
|
+
import { useConfirmDialog } from "@open-mercato/ui/backend/confirm-dialog";
|
|
9
|
+
import { tillioErrorCopy } from "../../../lib/error-codes.js";
|
|
10
|
+
import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives/alert";
|
|
11
|
+
import { StatusBadge } from "@open-mercato/ui/primitives/status-badge";
|
|
12
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
13
|
+
import { FormField } from "@open-mercato/ui/primitives/form-field";
|
|
14
|
+
import { Input } from "@open-mercato/ui/primitives/input";
|
|
15
|
+
import { Label } from "@open-mercato/ui/primitives/label";
|
|
16
|
+
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
17
|
+
function OperatorsConfigWidget(_props) {
|
|
18
|
+
const t = useT();
|
|
19
|
+
const attachErrorText = React.useCallback((code) => {
|
|
20
|
+
const copy = tillioErrorCopy(code, "attach_failed");
|
|
21
|
+
return t(copy.key, copy.fallback);
|
|
22
|
+
}, [t]);
|
|
23
|
+
const detachErrorText = React.useCallback((code) => {
|
|
24
|
+
const copy = tillioErrorCopy(code, "detach_failed");
|
|
25
|
+
return t(copy.key, copy.fallback);
|
|
26
|
+
}, [t]);
|
|
27
|
+
const [state, setState] = React.useState(null);
|
|
28
|
+
const [loading, setLoading] = React.useState(true);
|
|
29
|
+
const [keyInput, setKeyInput] = React.useState("");
|
|
30
|
+
const [pending, setPending] = React.useState(false);
|
|
31
|
+
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
32
|
+
contextId: "tillio-operators",
|
|
33
|
+
blockedMessage: t("tillio.operators.blocked", "Operator change blocked by validation.")
|
|
34
|
+
});
|
|
35
|
+
const mutationContext = React.useMemo(
|
|
36
|
+
() => ({ providerKey: "tillio", retryLastMutation }),
|
|
37
|
+
[retryLastMutation]
|
|
38
|
+
);
|
|
39
|
+
const { confirm, ConfirmDialogElement } = useConfirmDialog();
|
|
40
|
+
const load = React.useCallback(async () => {
|
|
41
|
+
setLoading(true);
|
|
42
|
+
try {
|
|
43
|
+
const response = await apiCall("/api/tillio/operators");
|
|
44
|
+
if (response.ok && response.result) {
|
|
45
|
+
setState(response.result);
|
|
46
|
+
} else {
|
|
47
|
+
setState(null);
|
|
48
|
+
flash(t("tillio.operators.loadFailed", "Failed to load Tillio operators."), "error");
|
|
49
|
+
}
|
|
50
|
+
} finally {
|
|
51
|
+
setLoading(false);
|
|
52
|
+
}
|
|
53
|
+
}, [t]);
|
|
54
|
+
React.useEffect(() => {
|
|
55
|
+
void load();
|
|
56
|
+
}, [load]);
|
|
57
|
+
const attach = React.useCallback(async () => {
|
|
58
|
+
if (pending) return;
|
|
59
|
+
const key = keyInput.trim();
|
|
60
|
+
if (!key) {
|
|
61
|
+
flash(t("tillio.operators.keyRequired", "Enter the Ringostat key first."), "error");
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
setPending(true);
|
|
65
|
+
try {
|
|
66
|
+
const response = await runMutation({
|
|
67
|
+
context: mutationContext,
|
|
68
|
+
mutationPayload: { providerKey: "tillio", plugin: "Ringostat" },
|
|
69
|
+
operation: () => apiCall("/api/tillio/operators", {
|
|
70
|
+
method: "POST",
|
|
71
|
+
headers: { "content-type": "application/json" },
|
|
72
|
+
body: JSON.stringify({ plugin: "Ringostat", config: { key } })
|
|
73
|
+
})
|
|
74
|
+
});
|
|
75
|
+
const body = response.result;
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
flash(attachErrorText(body?.code), "error");
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
flash(t("tillio.operators.attached", "Operator attached."), "success");
|
|
81
|
+
setKeyInput("");
|
|
82
|
+
await load();
|
|
83
|
+
} finally {
|
|
84
|
+
setPending(false);
|
|
85
|
+
}
|
|
86
|
+
}, [attachErrorText, keyInput, load, mutationContext, pending, runMutation, t]);
|
|
87
|
+
const sendDetach = React.useCallback(async (operatorId, force) => {
|
|
88
|
+
const query = force ? "?force=true" : "";
|
|
89
|
+
return runMutation({
|
|
90
|
+
context: mutationContext,
|
|
91
|
+
mutationPayload: { providerKey: "tillio", force },
|
|
92
|
+
operation: () => apiCall(`/api/tillio/operators/${encodeURIComponent(operatorId)}${query}`, { method: "DELETE" })
|
|
93
|
+
});
|
|
94
|
+
}, [mutationContext, runMutation]);
|
|
95
|
+
const detach = React.useCallback(async (operatorId) => {
|
|
96
|
+
const confirmed = await confirm({
|
|
97
|
+
title: t("tillio.operators.detachConfirmTitle", "Detach this operator?"),
|
|
98
|
+
text: t("tillio.operators.detachConfirmText", "The operator will be removed and its Tillio token revoked. You can attach it again afterwards."),
|
|
99
|
+
confirmText: t("tillio.operators.detachConfirmAction", "Detach"),
|
|
100
|
+
cancelText: t("tillio.operators.cancel", "Cancel"),
|
|
101
|
+
variant: "destructive"
|
|
102
|
+
});
|
|
103
|
+
if (!confirmed) return;
|
|
104
|
+
setPending(true);
|
|
105
|
+
try {
|
|
106
|
+
const response = await sendDetach(operatorId, false);
|
|
107
|
+
const body = response.result;
|
|
108
|
+
if (response.ok) {
|
|
109
|
+
flash(t("tillio.operators.detached", "Operator detached."), "success");
|
|
110
|
+
await load();
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (!body?.canForce) {
|
|
114
|
+
flash(detachErrorText(body?.code), "error");
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const forceConfirmed = await confirm({
|
|
118
|
+
title: t("tillio.operators.forceDetachTitle", "Detach without revoking?"),
|
|
119
|
+
text: t("tillio.operators.forceDetachText", "The Tillio token could not be revoked, so it stays active until you remove it in Tillio. Remove the operator here anyway?"),
|
|
120
|
+
confirmText: t("tillio.operators.forceDetachAction", "Detach anyway"),
|
|
121
|
+
cancelText: t("tillio.operators.cancel", "Cancel"),
|
|
122
|
+
variant: "destructive"
|
|
123
|
+
});
|
|
124
|
+
if (!forceConfirmed) return;
|
|
125
|
+
const forced = await sendDetach(operatorId, true);
|
|
126
|
+
if (!forced.ok) {
|
|
127
|
+
flash(t("tillio.operators.detachFailed", "Could not detach the operator."), "error");
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
flash(t("tillio.operators.detachedNotRevoked", "Operator removed. Revoke its token in Tillio manually."), "success");
|
|
131
|
+
await load();
|
|
132
|
+
} finally {
|
|
133
|
+
setPending(false);
|
|
134
|
+
}
|
|
135
|
+
}, [confirm, detachErrorText, load, sendDetach, t]);
|
|
136
|
+
const copyTenantDomain = React.useCallback(async (tenantDomain) => {
|
|
137
|
+
try {
|
|
138
|
+
await navigator.clipboard.writeText(tenantDomain);
|
|
139
|
+
flash(t("tillio.operators.copied", "Webhook domain copied."), "success");
|
|
140
|
+
} catch {
|
|
141
|
+
flash(t("tillio.operators.copyFailed", "Could not copy to clipboard."), "error");
|
|
142
|
+
}
|
|
143
|
+
}, [t]);
|
|
144
|
+
if (loading) {
|
|
145
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-6 text-sm text-muted-foreground", children: [
|
|
146
|
+
/* @__PURE__ */ jsx(Spinner, {}),
|
|
147
|
+
t("tillio.operators.loading", "Loading operators...")
|
|
148
|
+
] });
|
|
149
|
+
}
|
|
150
|
+
if (!state) {
|
|
151
|
+
return /* @__PURE__ */ jsxs(Alert, { status: "error", children: [
|
|
152
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: t("tillio.operators.loadFailed", "Failed to load Tillio operators.") }),
|
|
153
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void load(), children: t("tillio.operators.retry", "Retry") }) })
|
|
154
|
+
] });
|
|
155
|
+
}
|
|
156
|
+
const operator = state.operators[0] ?? null;
|
|
157
|
+
return /* @__PURE__ */ jsxs("div", { className: "grid gap-4", children: [
|
|
158
|
+
ConfirmDialogElement,
|
|
159
|
+
!state.environmentReady ? /* @__PURE__ */ jsxs(Alert, { status: "warning", children: [
|
|
160
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: state.environmentBlocker === "integration_disabled" ? t("tillio.operators.integrationDisabledTitle", "Integration disabled") : t("tillio.operators.envNotReadyTitle", "Environment not ready") }),
|
|
161
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: state.environmentBlocker === "integration_disabled" ? t("tillio.errors.integrationDisabled", "The Tillio integration is disabled. Enable it first.") : t("tillio.operators.envNotReadyText", "Save the Tillio API URL and key in the Credentials tab, then run the health Check before attaching an operator.") })
|
|
162
|
+
] }) : null,
|
|
163
|
+
operator && operator.stale ? /* @__PURE__ */ jsxs(Alert, { status: "warning", children: [
|
|
164
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: t("tillio.operators.driftTitle", "Environment changed") }),
|
|
165
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: t("tillio.operators.driftText", "The environment changed after this operator was attached, so its token may be invalid. Detach and attach it again.") })
|
|
166
|
+
] }) : null,
|
|
167
|
+
operator ? /* @__PURE__ */ jsxs("div", { className: "grid gap-3 rounded-md border border-border p-4", children: [
|
|
168
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
|
|
169
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
170
|
+
/* @__PURE__ */ jsx("span", { className: "font-medium", children: operator.plugin }),
|
|
171
|
+
operator.stale ? /* @__PURE__ */ jsx(StatusBadge, { variant: "warning", dot: true, children: t("tillio.operators.stale", "Stale") }) : /* @__PURE__ */ jsx(StatusBadge, { variant: "success", dot: true, children: t("tillio.operators.active", "Active") })
|
|
172
|
+
] }),
|
|
173
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void detach(operator.id), disabled: pending, children: t("tillio.operators.detach", "Detach") })
|
|
174
|
+
] }),
|
|
175
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-1.5", children: [
|
|
176
|
+
/* @__PURE__ */ jsx(Label, { asChild: true, children: /* @__PURE__ */ jsx("span", { children: t("tillio.operators.webhookDomain", "Webhook domain (X-Tenant-Domain)") }) }),
|
|
177
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
|
|
178
|
+
/* @__PURE__ */ jsx("code", { className: "min-w-0 flex-1 truncate rounded-md bg-muted px-2 py-1 text-sm", children: operator.tenantDomain }),
|
|
179
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void copyTenantDomain(operator.tenantDomain), children: t("tillio.operators.copy", "Copy") })
|
|
180
|
+
] }),
|
|
181
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t("tillio.operators.webhookHint", "Register this URL in your operator panel so Tillio forwards its webhooks here.") })
|
|
182
|
+
] })
|
|
183
|
+
] }) : state.environmentReady ? /* @__PURE__ */ jsxs("div", { className: "grid gap-3 rounded-md border border-border p-4", children: [
|
|
184
|
+
/* @__PURE__ */ jsx(
|
|
185
|
+
FormField,
|
|
186
|
+
{
|
|
187
|
+
label: t("tillio.operators.ringostatKey", "Ringostat key"),
|
|
188
|
+
description: t("tillio.operators.ringostatKeyHint", "One operator at a time. Detach the current one before attaching another."),
|
|
189
|
+
children: /* @__PURE__ */ jsx(
|
|
190
|
+
Input,
|
|
191
|
+
{
|
|
192
|
+
type: "password",
|
|
193
|
+
autoComplete: "off",
|
|
194
|
+
value: keyInput,
|
|
195
|
+
onChange: (event) => setKeyInput(event.target.value),
|
|
196
|
+
placeholder: t("tillio.operators.ringostatKeyPlaceholder", "Paste the Ringostat integration key")
|
|
197
|
+
}
|
|
198
|
+
)
|
|
199
|
+
}
|
|
200
|
+
),
|
|
201
|
+
/* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Button, { type: "button", onClick: () => void attach(), disabled: pending, children: pending ? t("tillio.operators.attaching", "Attaching...") : t("tillio.operators.attach", "Attach operator") }) })
|
|
202
|
+
] }) : null
|
|
203
|
+
] });
|
|
204
|
+
}
|
|
205
|
+
export {
|
|
206
|
+
OperatorsConfigWidget as default
|
|
207
|
+
};
|
|
208
|
+
//# sourceMappingURL=widget.client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/tillio/widgets/injection/operators-config/widget.client.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { useConfirmDialog } from '@open-mercato/ui/backend/confirm-dialog'\nimport { tillioErrorCopy } from '../../../lib/error-codes'\nimport type { EnvironmentBlocker } from '../../../lib/pull-readiness'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { StatusBadge } from '@open-mercato/ui/primitives/status-badge'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport { FormField } from '@open-mercato/ui/primitives/form-field'\nimport { Input } from '@open-mercato/ui/primitives/input'\nimport { Label } from '@open-mercato/ui/primitives/label'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\n\ntype OperatorSummary = {\n id: string\n plugin: string\n tenantDomain: string\n stale: boolean\n}\n\ntype OperatorsResponse = {\n ok: boolean\n environmentReady: boolean\n environmentBlocker: EnvironmentBlocker | null\n tenantSystemId: string | null\n supportedPlugins: string[]\n operators: OperatorSummary[]\n defaultOperatorId: string | null\n envDrift: boolean\n}\n\ntype AttachResult = {\n ok: boolean\n code?: string\n section?: 'environment' | 'operator'\n operator?: { id: string; plugin: string; tenantDomain: string }\n}\n\ntype DetachResult = {\n ok: boolean\n code?: string\n section?: 'environment' | 'operator'\n detached?: boolean\n revoked?: boolean\n /** Set when the record survived because the token could not be revoked. */\n canForce?: boolean\n}\n\nexport default function OperatorsConfigWidget(\n _props: InjectionWidgetComponentProps<Record<string, unknown>, Record<string, unknown>>,\n) {\n const t = useT()\n const attachErrorText = React.useCallback((code: string | undefined) => {\n const copy = tillioErrorCopy(code, 'attach_failed')\n return t(copy.key, copy.fallback)\n }, [t])\n const detachErrorText = React.useCallback((code: string | undefined) => {\n const copy = tillioErrorCopy(code, 'detach_failed')\n return t(copy.key, copy.fallback)\n }, [t])\n const [state, setState] = React.useState<OperatorsResponse | null>(null)\n const [loading, setLoading] = React.useState(true)\n const [keyInput, setKeyInput] = React.useState('')\n const [pending, setPending] = React.useState(false)\n const { runMutation, retryLastMutation } = useGuardedMutation({\n contextId: 'tillio-operators',\n blockedMessage: t('tillio.operators.blocked', 'Operator change blocked by validation.'),\n })\n const mutationContext = React.useMemo(\n () => ({ providerKey: 'tillio', retryLastMutation }),\n [retryLastMutation],\n )\n const { confirm, ConfirmDialogElement } = useConfirmDialog()\n\n const load = React.useCallback(async () => {\n setLoading(true)\n try {\n const response = await apiCall<OperatorsResponse>('/api/tillio/operators')\n if (response.ok && response.result) {\n setState(response.result)\n } else {\n setState(null)\n flash(t('tillio.operators.loadFailed', 'Failed to load Tillio operators.'), 'error')\n }\n } finally {\n setLoading(false)\n }\n }, [t])\n\n React.useEffect(() => {\n void load()\n }, [load])\n\n const attach = React.useCallback(async () => {\n if (pending) return\n const key = keyInput.trim()\n if (!key) {\n flash(t('tillio.operators.keyRequired', 'Enter the Ringostat key first.'), 'error')\n return\n }\n setPending(true)\n try {\n const response = await runMutation({\n context: mutationContext,\n mutationPayload: { providerKey: 'tillio', plugin: 'Ringostat' },\n operation: () =>\n apiCall<AttachResult>('/api/tillio/operators', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ plugin: 'Ringostat', config: { key } }),\n }),\n })\n const body = response.result as AttachResult | undefined\n if (!response.ok) {\n flash(attachErrorText(body?.code), 'error')\n return\n }\n flash(t('tillio.operators.attached', 'Operator attached.'), 'success')\n setKeyInput('')\n await load()\n } finally {\n setPending(false)\n }\n }, [attachErrorText, keyInput, load, mutationContext, pending, runMutation, t])\n\n const sendDetach = React.useCallback(async (operatorId: string, force: boolean) => {\n const query = force ? '?force=true' : ''\n return runMutation({\n context: mutationContext,\n mutationPayload: { providerKey: 'tillio', force },\n operation: () =>\n apiCall<DetachResult>(`/api/tillio/operators/${encodeURIComponent(operatorId)}${query}`, { method: 'DELETE' }),\n })\n }, [mutationContext, runMutation])\n\n const detach = React.useCallback(async (operatorId: string) => {\n const confirmed = await confirm({\n title: t('tillio.operators.detachConfirmTitle', 'Detach this operator?'),\n text: t('tillio.operators.detachConfirmText', 'The operator will be removed and its Tillio token revoked. You can attach it again afterwards.'),\n confirmText: t('tillio.operators.detachConfirmAction', 'Detach'),\n cancelText: t('tillio.operators.cancel', 'Cancel'),\n variant: 'destructive',\n })\n if (!confirmed) return\n setPending(true)\n try {\n const response = await sendDetach(operatorId, false)\n const body = response.result as DetachResult | undefined\n if (response.ok) {\n flash(t('tillio.operators.detached', 'Operator detached.'), 'success')\n await load()\n return\n }\n\n // The token is still live on Tillio's side, so the record stayed. Removing it anyway\n // is a separate, explicit decision \u2014 it leaves that token behind with no handle to it.\n if (!body?.canForce) {\n flash(detachErrorText(body?.code), 'error')\n return\n }\n const forceConfirmed = await confirm({\n title: t('tillio.operators.forceDetachTitle', 'Detach without revoking?'),\n text: t('tillio.operators.forceDetachText', 'The Tillio token could not be revoked, so it stays active until you remove it in Tillio. Remove the operator here anyway?'),\n confirmText: t('tillio.operators.forceDetachAction', 'Detach anyway'),\n cancelText: t('tillio.operators.cancel', 'Cancel'),\n variant: 'destructive',\n })\n if (!forceConfirmed) return\n\n const forced = await sendDetach(operatorId, true)\n if (!forced.ok) {\n flash(t('tillio.operators.detachFailed', 'Could not detach the operator.'), 'error')\n return\n }\n flash(t('tillio.operators.detachedNotRevoked', 'Operator removed. Revoke its token in Tillio manually.'), 'success')\n await load()\n } finally {\n setPending(false)\n }\n }, [confirm, detachErrorText, load, sendDetach, t])\n\n const copyTenantDomain = React.useCallback(async (tenantDomain: string) => {\n try {\n await navigator.clipboard.writeText(tenantDomain)\n flash(t('tillio.operators.copied', 'Webhook domain copied.'), 'success')\n } catch {\n flash(t('tillio.operators.copyFailed', 'Could not copy to clipboard.'), 'error')\n }\n }, [t])\n\n if (loading) {\n return (\n <div className=\"flex items-center gap-2 py-6 text-sm text-muted-foreground\">\n <Spinner />\n {t('tillio.operators.loading', 'Loading operators...')}\n </div>\n )\n }\n\n if (!state) {\n return (\n <Alert status=\"error\">\n <AlertTitle>{t('tillio.operators.loadFailed', 'Failed to load Tillio operators.')}</AlertTitle>\n <AlertDescription>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void load()}>\n {t('tillio.operators.retry', 'Retry')}\n </Button>\n </AlertDescription>\n </Alert>\n )\n }\n\n const operator = state.operators[0] ?? null\n\n return (\n <div className=\"grid gap-4\">\n {ConfirmDialogElement}\n\n {!state.environmentReady ? (\n <Alert status=\"warning\">\n <AlertTitle>\n {state.environmentBlocker === 'integration_disabled'\n ? t('tillio.operators.integrationDisabledTitle', 'Integration disabled')\n : t('tillio.operators.envNotReadyTitle', 'Environment not ready')}\n </AlertTitle>\n <AlertDescription>\n {state.environmentBlocker === 'integration_disabled'\n ? t('tillio.errors.integrationDisabled', 'The Tillio integration is disabled. Enable it first.')\n : t('tillio.operators.envNotReadyText', 'Save the Tillio API URL and key in the Credentials tab, then run the health Check before attaching an operator.')}\n </AlertDescription>\n </Alert>\n ) : null}\n\n {operator && operator.stale ? (\n <Alert status=\"warning\">\n <AlertTitle>{t('tillio.operators.driftTitle', 'Environment changed')}</AlertTitle>\n <AlertDescription>\n {t('tillio.operators.driftText', 'The environment changed after this operator was attached, so its token may be invalid. Detach and attach it again.')}\n </AlertDescription>\n </Alert>\n ) : null}\n\n {operator ? (\n <div className=\"grid gap-3 rounded-md border border-border p-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"flex items-center gap-2\">\n <span className=\"font-medium\">{operator.plugin}</span>\n {operator.stale ? (\n <StatusBadge variant=\"warning\" dot>{t('tillio.operators.stale', 'Stale')}</StatusBadge>\n ) : (\n <StatusBadge variant=\"success\" dot>{t('tillio.operators.active', 'Active')}</StatusBadge>\n )}\n </div>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void detach(operator.id)} disabled={pending}>\n {t('tillio.operators.detach', 'Detach')}\n </Button>\n </div>\n <div className=\"grid gap-1.5\">\n <Label asChild>\n <span>{t('tillio.operators.webhookDomain', 'Webhook domain (X-Tenant-Domain)')}</span>\n </Label>\n <div className=\"flex items-center gap-2\">\n <code className=\"min-w-0 flex-1 truncate rounded-md bg-muted px-2 py-1 text-sm\">{operator.tenantDomain}</code>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void copyTenantDomain(operator.tenantDomain)}>\n {t('tillio.operators.copy', 'Copy')}\n </Button>\n </div>\n <span className=\"text-xs text-muted-foreground\">\n {t('tillio.operators.webhookHint', 'Register this URL in your operator panel so Tillio forwards its webhooks here.')}\n </span>\n </div>\n </div>\n ) : state.environmentReady ? (\n <div className=\"grid gap-3 rounded-md border border-border p-4\">\n <FormField\n label={t('tillio.operators.ringostatKey', 'Ringostat key')}\n description={t('tillio.operators.ringostatKeyHint', 'One operator at a time. Detach the current one before attaching another.')}\n >\n <Input\n type=\"password\"\n autoComplete=\"off\"\n value={keyInput}\n onChange={(event) => setKeyInput(event.target.value)}\n placeholder={t('tillio.operators.ringostatKeyPlaceholder', 'Paste the Ringostat integration key')}\n />\n </FormField>\n <div>\n <Button type=\"button\" onClick={() => void attach()} disabled={pending}>\n {pending\n ? t('tillio.operators.attaching', 'Attaching...')\n : t('tillio.operators.attach', 'Attach operator')}\n </Button>\n </div>\n </div>\n ) : null}\n </div>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import OperatorsConfigWidget from "./widget.client.js";
|
|
2
|
+
const widget = {
|
|
3
|
+
metadata: {
|
|
4
|
+
id: "tillio.injection.operators",
|
|
5
|
+
title: "Operator configuration",
|
|
6
|
+
description: "Attach one Tillio operator (Ringostat) on top of the configured environment.",
|
|
7
|
+
features: ["tillio.manage", "integrations.manage"],
|
|
8
|
+
priority: 100,
|
|
9
|
+
enabled: true
|
|
10
|
+
},
|
|
11
|
+
Widget: OperatorsConfigWidget
|
|
12
|
+
};
|
|
13
|
+
var widget_default = widget;
|
|
14
|
+
export {
|
|
15
|
+
widget_default as default
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=widget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/tillio/widgets/injection/operators-config/widget.ts"],
|
|
4
|
+
"sourcesContent": ["import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'\nimport OperatorsConfigWidget from './widget.client'\n\nconst widget: InjectionWidgetModule<Record<string, unknown>, Record<string, unknown>> = {\n metadata: {\n id: 'tillio.injection.operators',\n title: 'Operator configuration',\n description: 'Attach one Tillio operator (Ringostat) on top of the configured environment.',\n features: ['tillio.manage', 'integrations.manage'],\n priority: 100,\n enabled: true,\n },\n Widget: OperatorsConfigWidget,\n}\n\nexport default widget\n"],
|
|
5
|
+
"mappings": "AACA,OAAO,2BAA2B;AAElC,MAAM,SAAkF;AAAA,EACtF,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU,CAAC,iBAAiB,qBAAqB;AAAA,IACjD,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AACV;AAEA,IAAO,iBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { useT } from "@open-mercato/shared/lib/i18n/context";
|
|
5
|
+
import { flash } from "@open-mercato/ui/backend/FlashMessages";
|
|
6
|
+
import { useGuardedMutation } from "@open-mercato/ui/backend/injection/useGuardedMutation";
|
|
7
|
+
import { apiCall } from "@open-mercato/ui/backend/utils/apiCall";
|
|
8
|
+
import { Alert, AlertDescription, AlertTitle } from "@open-mercato/ui/primitives/alert";
|
|
9
|
+
import { Button } from "@open-mercato/ui/primitives/button";
|
|
10
|
+
import {
|
|
11
|
+
Dialog,
|
|
12
|
+
DialogContent,
|
|
13
|
+
DialogDescription,
|
|
14
|
+
DialogFooter,
|
|
15
|
+
DialogHeader,
|
|
16
|
+
DialogTitle
|
|
17
|
+
} from "@open-mercato/ui/primitives/dialog";
|
|
18
|
+
import { DateRangePicker } from "@open-mercato/ui/primitives/date-range-picker";
|
|
19
|
+
import { Spinner } from "@open-mercato/ui/primitives/spinner";
|
|
20
|
+
import { PULL_BLOCKER_COPY, tillioErrorCopy } from "../../../lib/error-codes.js";
|
|
21
|
+
const DEFAULT_RANGE_DAYS = 7;
|
|
22
|
+
function toDayString(date) {
|
|
23
|
+
const pad = (value) => String(value).padStart(2, "0");
|
|
24
|
+
return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
|
|
25
|
+
}
|
|
26
|
+
function defaultRange() {
|
|
27
|
+
const end = /* @__PURE__ */ new Date();
|
|
28
|
+
const start = new Date(end);
|
|
29
|
+
start.setDate(start.getDate() - (DEFAULT_RANGE_DAYS - 1));
|
|
30
|
+
return { start, end };
|
|
31
|
+
}
|
|
32
|
+
function PullCallsWidget(_props) {
|
|
33
|
+
const t = useT();
|
|
34
|
+
const [open, setOpen] = React.useState(false);
|
|
35
|
+
const [range, setRange] = React.useState(defaultRange);
|
|
36
|
+
const [pending, setPending] = React.useState(false);
|
|
37
|
+
const [readiness, setReadiness] = React.useState(null);
|
|
38
|
+
const [checking, setChecking] = React.useState(false);
|
|
39
|
+
const { runMutation, retryLastMutation } = useGuardedMutation({
|
|
40
|
+
contextId: "tillio-pull-calls",
|
|
41
|
+
blockedMessage: t("tillio.pull.blocked", "Pull blocked by validation.")
|
|
42
|
+
});
|
|
43
|
+
const mutationContext = React.useMemo(
|
|
44
|
+
() => ({ providerKey: "tillio", retryLastMutation }),
|
|
45
|
+
[retryLastMutation]
|
|
46
|
+
);
|
|
47
|
+
const openDialog = React.useCallback(async () => {
|
|
48
|
+
setOpen(true);
|
|
49
|
+
setChecking(true);
|
|
50
|
+
try {
|
|
51
|
+
const response = await apiCall("/api/tillio/pull");
|
|
52
|
+
setReadiness(response.ok ? response.result ?? null : null);
|
|
53
|
+
} catch {
|
|
54
|
+
setReadiness(null);
|
|
55
|
+
} finally {
|
|
56
|
+
setChecking(false);
|
|
57
|
+
}
|
|
58
|
+
}, []);
|
|
59
|
+
const blockerMessage = React.useCallback(
|
|
60
|
+
(blocker2) => {
|
|
61
|
+
const copy = PULL_BLOCKER_COPY[blocker2];
|
|
62
|
+
return copy ? t(copy.key, copy.fallback) : t("tillio.pull.blocked", "Pull blocked by validation.");
|
|
63
|
+
},
|
|
64
|
+
[t]
|
|
65
|
+
);
|
|
66
|
+
const pull = React.useCallback(async () => {
|
|
67
|
+
if (pending) return;
|
|
68
|
+
if (!range?.start || !range.end) {
|
|
69
|
+
flash(t("tillio.pull.rangeRequired", "Pick a date range first."), "error");
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const from = toDayString(range.start);
|
|
73
|
+
const to = toDayString(range.end);
|
|
74
|
+
setPending(true);
|
|
75
|
+
try {
|
|
76
|
+
const response = await runMutation({
|
|
77
|
+
context: mutationContext,
|
|
78
|
+
mutationPayload: { providerKey: "tillio", from, to },
|
|
79
|
+
operation: () => apiCall("/api/tillio/pull", {
|
|
80
|
+
method: "POST",
|
|
81
|
+
headers: { "content-type": "application/json" },
|
|
82
|
+
body: JSON.stringify({ from, to })
|
|
83
|
+
})
|
|
84
|
+
});
|
|
85
|
+
const body = response.result;
|
|
86
|
+
if (!response.ok) {
|
|
87
|
+
const copy = tillioErrorCopy(body?.code, "pull_failed");
|
|
88
|
+
flash(t(copy.key, copy.fallback), "error");
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
flash(t("tillio.pull.queued", "Pulling calls from Tillio. Track it in the progress bar."), "success");
|
|
92
|
+
setOpen(false);
|
|
93
|
+
} finally {
|
|
94
|
+
setPending(false);
|
|
95
|
+
}
|
|
96
|
+
}, [mutationContext, pending, range, runMutation, t]);
|
|
97
|
+
const handleKeyDown = React.useCallback(
|
|
98
|
+
(event) => {
|
|
99
|
+
if ((event.metaKey || event.ctrlKey) && event.key === "Enter") {
|
|
100
|
+
event.preventDefault();
|
|
101
|
+
void pull();
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
[pull]
|
|
105
|
+
);
|
|
106
|
+
const blocker = readiness?.blocker ?? null;
|
|
107
|
+
const blocked = checking || !readiness || Boolean(blocker);
|
|
108
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
109
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => void openDialog(), children: t("tillio.pull.action", "Pull calls") }),
|
|
110
|
+
/* @__PURE__ */ jsx(Dialog, { open, onOpenChange: (next) => {
|
|
111
|
+
if (!pending) setOpen(next);
|
|
112
|
+
}, children: /* @__PURE__ */ jsxs(DialogContent, { onKeyDown: handleKeyDown, children: [
|
|
113
|
+
/* @__PURE__ */ jsxs(DialogHeader, { children: [
|
|
114
|
+
/* @__PURE__ */ jsx(DialogTitle, { children: t("tillio.pull.title", "Pull calls from Tillio") }),
|
|
115
|
+
/* @__PURE__ */ jsx(DialogDescription, { children: t("tillio.pull.description", "Calls in the selected range are ingested from the attached operator. Pulling the same range again updates existing calls instead of duplicating them.") })
|
|
116
|
+
] }),
|
|
117
|
+
checking ? /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 py-6 text-sm text-muted-foreground", children: [
|
|
118
|
+
/* @__PURE__ */ jsx(Spinner, {}),
|
|
119
|
+
t("tillio.pull.checking", "Checking the Tillio connection...")
|
|
120
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
121
|
+
!readiness ? /* @__PURE__ */ jsxs(Alert, { status: "error", children: [
|
|
122
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: t("tillio.pull.checkFailed", "Could not check the Tillio connection.") }),
|
|
123
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: /* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", size: "sm", onClick: () => void openDialog(), children: t("tillio.pull.retry", "Retry") }) })
|
|
124
|
+
] }) : null,
|
|
125
|
+
blocker ? /* @__PURE__ */ jsxs(Alert, { status: "warning", children: [
|
|
126
|
+
/* @__PURE__ */ jsx(AlertTitle, { children: t("tillio.pull.notReadyTitle", "Tillio is not ready") }),
|
|
127
|
+
/* @__PURE__ */ jsx(AlertDescription, { children: blockerMessage(blocker) })
|
|
128
|
+
] }) : null,
|
|
129
|
+
/* @__PURE__ */ jsxs("div", { className: "grid gap-2 py-2", children: [
|
|
130
|
+
/* @__PURE__ */ jsx(DateRangePicker, { value: range, onChange: setRange, disabled: pending || blocked }),
|
|
131
|
+
readiness?.timeZone ? /* @__PURE__ */ jsx("span", { className: "text-xs text-muted-foreground", children: t(
|
|
132
|
+
"tillio.pull.timezoneHint",
|
|
133
|
+
"Days are interpreted in the {{timeZone}} timezone that Tillio uses.",
|
|
134
|
+
{ timeZone: readiness.timeZone }
|
|
135
|
+
) }) : null
|
|
136
|
+
] })
|
|
137
|
+
] }),
|
|
138
|
+
/* @__PURE__ */ jsxs(DialogFooter, { children: [
|
|
139
|
+
/* @__PURE__ */ jsx(Button, { type: "button", variant: "outline", onClick: () => setOpen(false), disabled: pending, children: t("tillio.pull.cancel", "Cancel") }),
|
|
140
|
+
/* @__PURE__ */ jsx(Button, { type: "button", onClick: () => void pull(), disabled: pending || blocked, children: pending ? t("tillio.pull.pulling", "Pulling...") : t("tillio.pull.confirm", "Pull calls") })
|
|
141
|
+
] })
|
|
142
|
+
] }) })
|
|
143
|
+
] });
|
|
144
|
+
}
|
|
145
|
+
export {
|
|
146
|
+
PullCallsWidget as default
|
|
147
|
+
};
|
|
148
|
+
//# sourceMappingURL=widget.client.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/tillio/widgets/injection/pull-calls/widget.client.tsx"],
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport type { InjectionWidgetComponentProps } from '@open-mercato/shared/modules/widgets/injection'\nimport { useT } from '@open-mercato/shared/lib/i18n/context'\nimport { flash } from '@open-mercato/ui/backend/FlashMessages'\nimport { useGuardedMutation } from '@open-mercato/ui/backend/injection/useGuardedMutation'\nimport { apiCall } from '@open-mercato/ui/backend/utils/apiCall'\nimport { Alert, AlertDescription, AlertTitle } from '@open-mercato/ui/primitives/alert'\nimport { Button } from '@open-mercato/ui/primitives/button'\nimport {\n Dialog,\n DialogContent,\n DialogDescription,\n DialogFooter,\n DialogHeader,\n DialogTitle,\n} from '@open-mercato/ui/primitives/dialog'\nimport { DateRangePicker } from '@open-mercato/ui/primitives/date-range-picker'\nimport { Spinner } from '@open-mercato/ui/primitives/spinner'\nimport type { DateRange } from '@open-mercato/ui/backend/date-range/dateRanges'\nimport { PULL_BLOCKER_COPY, tillioErrorCopy } from '../../../lib/error-codes'\nimport type { PullBlocker } from '../../../lib/pull-readiness'\n\nconst DEFAULT_RANGE_DAYS = 7\n\ntype PullReadiness = {\n ok: boolean\n environmentReady: boolean\n operatorAttached: boolean\n envDrift: boolean\n blocker: PullBlocker | null\n timeZone: string | null\n}\n\ntype PullResult = {\n ok: boolean\n code?: string\n progressJobId?: string\n}\n\nfunction toDayString(date: Date): string {\n const pad = (value: number): string => String(value).padStart(2, '0')\n return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`\n}\n\nfunction defaultRange(): DateRange {\n const end = new Date()\n const start = new Date(end)\n start.setDate(start.getDate() - (DEFAULT_RANGE_DAYS - 1))\n return { start, end }\n}\n\nexport default function PullCallsWidget(\n _props: InjectionWidgetComponentProps<Record<string, unknown>, Record<string, unknown>>,\n) {\n const t = useT()\n const [open, setOpen] = React.useState(false)\n const [range, setRange] = React.useState<DateRange | null>(defaultRange)\n const [pending, setPending] = React.useState(false)\n const [readiness, setReadiness] = React.useState<PullReadiness | null>(null)\n const [checking, setChecking] = React.useState(false)\n const { runMutation, retryLastMutation } = useGuardedMutation({\n contextId: 'tillio-pull-calls',\n blockedMessage: t('tillio.pull.blocked', 'Pull blocked by validation.'),\n })\n const mutationContext = React.useMemo(\n () => ({ providerKey: 'tillio', retryLastMutation }),\n [retryLastMutation],\n )\n\n // Readiness is checked when the dialog opens rather than on mount, so the\n // calls list does not pay for a request every visitor never needs.\n const openDialog = React.useCallback(async () => {\n setOpen(true)\n setChecking(true)\n try {\n const response = await apiCall<PullReadiness>('/api/tillio/pull')\n setReadiness(response.ok ? (response.result ?? null) : null)\n } catch {\n // A null readiness already renders the \"could not check\" notice, so the failure is\n // handled here rather than escaping the void call as an unhandled rejection.\n setReadiness(null)\n } finally {\n setChecking(false)\n }\n }, [])\n\n const blockerMessage = React.useCallback(\n (blocker: PullBlocker): string => {\n // The lookup can still miss at runtime when this bundle is older than the server it talks to.\n const copy = PULL_BLOCKER_COPY[blocker]\n return copy ? t(copy.key, copy.fallback) : t('tillio.pull.blocked', 'Pull blocked by validation.')\n },\n [t],\n )\n\n const pull = React.useCallback(async () => {\n if (pending) return\n if (!range?.start || !range.end) {\n flash(t('tillio.pull.rangeRequired', 'Pick a date range first.'), 'error')\n return\n }\n const from = toDayString(range.start)\n const to = toDayString(range.end)\n\n setPending(true)\n try {\n const response = await runMutation({\n context: mutationContext,\n mutationPayload: { providerKey: 'tillio', from, to },\n operation: () =>\n apiCall<PullResult>('/api/tillio/pull', {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify({ from, to }),\n }),\n })\n const body = response.result as PullResult | undefined\n if (!response.ok) {\n const copy = tillioErrorCopy(body?.code, 'pull_failed')\n flash(t(copy.key, copy.fallback), 'error')\n return\n }\n // The sweep runs in a worker, so the dialog only confirms the handover; the top bar owns\n // the rest and the list picks the calls up on its next load.\n flash(t('tillio.pull.queued', 'Pulling calls from Tillio. Track it in the progress bar.'), 'success')\n setOpen(false)\n } finally {\n setPending(false)\n }\n }, [mutationContext, pending, range, runMutation, t])\n\n const handleKeyDown = React.useCallback(\n (event: React.KeyboardEvent<HTMLDivElement>) => {\n if ((event.metaKey || event.ctrlKey) && event.key === 'Enter') {\n event.preventDefault()\n void pull()\n }\n },\n [pull],\n )\n\n const blocker = readiness?.blocker ?? null\n const blocked = checking || !readiness || Boolean(blocker)\n\n return (\n <>\n <Button type=\"button\" variant=\"outline\" onClick={() => void openDialog()}>\n {t('tillio.pull.action', 'Pull calls')}\n </Button>\n\n <Dialog open={open} onOpenChange={(next) => { if (!pending) setOpen(next) }}>\n <DialogContent onKeyDown={handleKeyDown}>\n <DialogHeader>\n <DialogTitle>{t('tillio.pull.title', 'Pull calls from Tillio')}</DialogTitle>\n <DialogDescription>\n {t('tillio.pull.description', 'Calls in the selected range are ingested from the attached operator. Pulling the same range again updates existing calls instead of duplicating them.')}\n </DialogDescription>\n </DialogHeader>\n\n {checking ? (\n <div className=\"flex items-center gap-2 py-6 text-sm text-muted-foreground\">\n <Spinner />\n {t('tillio.pull.checking', 'Checking the Tillio connection...')}\n </div>\n ) : (\n <>\n {!readiness ? (\n <Alert status=\"error\">\n <AlertTitle>{t('tillio.pull.checkFailed', 'Could not check the Tillio connection.')}</AlertTitle>\n <AlertDescription>\n <Button type=\"button\" variant=\"outline\" size=\"sm\" onClick={() => void openDialog()}>\n {t('tillio.pull.retry', 'Retry')}\n </Button>\n </AlertDescription>\n </Alert>\n ) : null}\n\n {blocker ? (\n <Alert status=\"warning\">\n <AlertTitle>{t('tillio.pull.notReadyTitle', 'Tillio is not ready')}</AlertTitle>\n <AlertDescription>{blockerMessage(blocker)}</AlertDescription>\n </Alert>\n ) : null}\n\n <div className=\"grid gap-2 py-2\">\n <DateRangePicker value={range} onChange={setRange} disabled={pending || blocked} />\n {readiness?.timeZone ? (\n <span className=\"text-xs text-muted-foreground\">\n {t(\n 'tillio.pull.timezoneHint',\n 'Days are interpreted in the {{timeZone}} timezone that Tillio uses.',\n { timeZone: readiness.timeZone },\n )}\n </span>\n ) : null}\n </div>\n </>\n )}\n\n <DialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setOpen(false)} disabled={pending}>\n {t('tillio.pull.cancel', 'Cancel')}\n </Button>\n <Button type=\"button\" onClick={() => void pull()} disabled={pending || blocked}>\n {pending ? t('tillio.pull.pulling', 'Pulling...') : t('tillio.pull.confirm', 'Pull calls')}\n </Button>\n </DialogFooter>\n </DialogContent>\n </Dialog>\n </>\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["blocker"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import PullCallsWidget from "./widget.client.js";
|
|
2
|
+
const widget = {
|
|
3
|
+
metadata: {
|
|
4
|
+
id: "tillio.injection.pull-calls",
|
|
5
|
+
title: "Pull calls from Tillio",
|
|
6
|
+
description: "Manually ingest phone calls from the attached Tillio operator for a chosen date range.",
|
|
7
|
+
features: ["phone_calls.manage", "integrations.manage"],
|
|
8
|
+
priority: 20,
|
|
9
|
+
enabled: true
|
|
10
|
+
},
|
|
11
|
+
Widget: PullCallsWidget
|
|
12
|
+
};
|
|
13
|
+
var widget_default = widget;
|
|
14
|
+
export {
|
|
15
|
+
widget_default as default
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=widget.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../../../src/modules/tillio/widgets/injection/pull-calls/widget.ts"],
|
|
4
|
+
"sourcesContent": ["import type { InjectionWidgetModule } from '@open-mercato/shared/modules/widgets/injection'\nimport PullCallsWidget from './widget.client'\n\nconst widget: InjectionWidgetModule<Record<string, unknown>, Record<string, unknown>> = {\n metadata: {\n id: 'tillio.injection.pull-calls',\n title: 'Pull calls from Tillio',\n description: 'Manually ingest phone calls from the attached Tillio operator for a chosen date range.',\n features: ['phone_calls.manage', 'integrations.manage'],\n priority: 20,\n enabled: true,\n },\n Widget: PullCallsWidget,\n}\n\nexport default widget\n"],
|
|
5
|
+
"mappings": "AACA,OAAO,qBAAqB;AAE5B,MAAM,SAAkF;AAAA,EACtF,UAAU;AAAA,IACR,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,aAAa;AAAA,IACb,UAAU,CAAC,sBAAsB,qBAAqB;AAAA,IACtD,UAAU;AAAA,IACV,SAAS;AAAA,EACX;AAAA,EACA,QAAQ;AACV;AAEA,IAAO,iBAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { tillioDetailWidgetSpotId } from "../integration.js";
|
|
2
|
+
const injectionTable = {
|
|
3
|
+
[tillioDetailWidgetSpotId]: [
|
|
4
|
+
{
|
|
5
|
+
widgetId: "tillio.injection.operators",
|
|
6
|
+
kind: "tab",
|
|
7
|
+
groupLabel: "tillio.operators.tab",
|
|
8
|
+
priority: 100
|
|
9
|
+
}
|
|
10
|
+
],
|
|
11
|
+
"data-table:phone_calls.calls:toolbar": {
|
|
12
|
+
widgetId: "tillio.injection.pull-calls",
|
|
13
|
+
priority: 20
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var injection_table_default = injectionTable;
|
|
17
|
+
export {
|
|
18
|
+
injection_table_default as default,
|
|
19
|
+
injectionTable
|
|
20
|
+
};
|
|
21
|
+
//# sourceMappingURL=injection-table.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/tillio/widgets/injection-table.ts"],
|
|
4
|
+
"sourcesContent": ["import type { ModuleInjectionTable } from '@open-mercato/shared/modules/widgets/injection'\nimport { tillioDetailWidgetSpotId } from '../integration'\n\nexport const injectionTable: ModuleInjectionTable = {\n [tillioDetailWidgetSpotId]: [\n {\n widgetId: 'tillio.injection.operators',\n kind: 'tab',\n groupLabel: 'tillio.operators.tab',\n priority: 100,\n },\n ],\n 'data-table:phone_calls.calls:toolbar': {\n widgetId: 'tillio.injection.pull-calls',\n priority: 20,\n },\n}\n\nexport default injectionTable\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,gCAAgC;AAElC,MAAM,iBAAuC;AAAA,EAClD,CAAC,wBAAwB,GAAG;AAAA,IAC1B;AAAA,MACE,UAAU;AAAA,MACV,MAAM;AAAA,MACN,YAAY;AAAA,MACZ,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EACA,wCAAwC;AAAA,IACtC,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;AAEA,IAAO,0BAAQ;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { createRequestContainer } from "@open-mercato/shared/lib/di/container";
|
|
2
|
+
import { runTillioPullJob } from "../lib/pull-job.js";
|
|
3
|
+
import { resolveTillioQueueConcurrency, TILLIO_PULL_QUEUE } from "../lib/queue.js";
|
|
4
|
+
const metadata = {
|
|
5
|
+
queue: TILLIO_PULL_QUEUE,
|
|
6
|
+
id: "tillio:pull-calls",
|
|
7
|
+
concurrency: resolveTillioQueueConcurrency()
|
|
8
|
+
};
|
|
9
|
+
async function handle(job, _ctx) {
|
|
10
|
+
const container = await createRequestContainer();
|
|
11
|
+
await runTillioPullJob({ container, payload: job.payload });
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
handle as default,
|
|
15
|
+
metadata
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=tillio-pull.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../../src/modules/tillio/workers/tillio-pull.ts"],
|
|
4
|
+
"sourcesContent": ["import type { JobContext, QueuedJob, WorkerMeta } from '@open-mercato/queue'\nimport { createRequestContainer } from '@open-mercato/shared/lib/di/container'\nimport { runTillioPullJob, type TillioPullJobPayload } from '../lib/pull-job'\nimport { resolveTillioQueueConcurrency, TILLIO_PULL_QUEUE } from '../lib/queue'\n\nexport const metadata: WorkerMeta = {\n queue: TILLIO_PULL_QUEUE,\n id: 'tillio:pull-calls',\n concurrency: resolveTillioQueueConcurrency(),\n}\n\nexport default async function handle(\n job: QueuedJob<TillioPullJobPayload>,\n _ctx: JobContext,\n): Promise<void> {\n const container = await createRequestContainer()\n await runTillioPullJob({ container, payload: job.payload })\n}\n"],
|
|
5
|
+
"mappings": "AACA,SAAS,8BAA8B;AACvC,SAAS,wBAAmD;AAC5D,SAAS,+BAA+B,yBAAyB;AAE1D,MAAM,WAAuB;AAAA,EAClC,OAAO;AAAA,EACP,IAAI;AAAA,EACJ,aAAa,8BAA8B;AAC7C;AAEA,eAAO,OACL,KACA,MACe;AACf,QAAM,YAAY,MAAM,uBAAuB;AAC/C,QAAM,iBAAiB,EAAE,WAAW,SAAS,IAAI,QAAQ,CAAC;AAC5D;",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
package/jest.config.cjs
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** @type {import('jest').Config} */
|
|
2
|
+
const base = require('../../jest.config.base.cjs')
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
...base,
|
|
6
|
+
testEnvironment: 'node',
|
|
7
|
+
watchman: false,
|
|
8
|
+
rootDir: '.',
|
|
9
|
+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json'],
|
|
10
|
+
moduleNameMapper: {
|
|
11
|
+
'^#generated/(.*)$': '<rootDir>/../core/generated/$1',
|
|
12
|
+
'^@open-mercato/tillio/(.*)$': '<rootDir>/src/$1',
|
|
13
|
+
'^@open-mercato/core/(.*)$': '<rootDir>/../core/src/$1',
|
|
14
|
+
'^@open-mercato/shared/(.*)$': '<rootDir>/../shared/src/$1',
|
|
15
|
+
'^@open-mercato/queue/(.*)$': '<rootDir>/../queue/src/$1',
|
|
16
|
+
'^@open-mercato/ui/(.*)$': '<rootDir>/../ui/src/$1',
|
|
17
|
+
},
|
|
18
|
+
transform: {
|
|
19
|
+
'^.+\\.(t|j)sx?$': [
|
|
20
|
+
'<rootDir>/../../scripts/jest-mikroorm-transformer.cjs',
|
|
21
|
+
{
|
|
22
|
+
tsconfig: {
|
|
23
|
+
jsx: 'react-jsx',
|
|
24
|
+
rootDir: '.',
|
|
25
|
+
ignoreDeprecations: '6.0',
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
},
|
|
30
|
+
transformIgnorePatterns: [
|
|
31
|
+
'node_modules/(?!(@mikro-orm|kysely)/)',
|
|
32
|
+
],
|
|
33
|
+
testMatch: ['<rootDir>/src/**/__tests__/**/*.test.(ts|tsx)'],
|
|
34
|
+
passWithNoTests: true,
|
|
35
|
+
}
|