@gorgo/medusa-integration 0.0.3 → 0.0.5
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/.medusa/server/src/admin/index.js +546 -119
- package/.medusa/server/src/admin/index.mjs +549 -122
- package/.medusa/server/src/api/admin/integrations/[provider_id]/route.js +7 -2
- package/.medusa/server/src/api/admin/integrations/__tests__/helpers.unit.spec.d.ts +1 -0
- package/.medusa/server/src/api/admin/integrations/__tests__/helpers.unit.spec.js +30 -0
- package/.medusa/server/src/api/admin/integrations/_helpers.d.ts +3 -3
- package/.medusa/server/src/api/admin/integrations/_helpers.js +8 -8
- package/.medusa/server/src/api/admin/integrations/catalog/route.d.ts +3 -0
- package/.medusa/server/src/api/admin/integrations/catalog/route.js +10 -0
- package/.medusa/server/src/api/admin/integrations/middlewares.js +16 -1
- package/.medusa/server/src/api/admin/integrations/route.js +17 -3
- package/.medusa/server/src/api/admin/integrations/validators.d.ts +7 -0
- package/.medusa/server/src/api/admin/integrations/validators.js +8 -2
- package/.medusa/server/src/index.d.ts +1 -1
- package/.medusa/server/src/jobs/__tests__/test-integration-connections.unit.spec.d.ts +1 -0
- package/.medusa/server/src/jobs/__tests__/test-integration-connections.unit.spec.js +27 -0
- package/.medusa/server/src/jobs/test-integration-connections.d.ts +7 -0
- package/.medusa/server/src/jobs/test-integration-connections.js +21 -8
- package/.medusa/server/src/lib/__tests__/catalog-fallback.unit.spec.d.ts +1 -0
- package/.medusa/server/src/lib/__tests__/catalog-fallback.unit.spec.js +37 -0
- package/.medusa/server/src/lib/__tests__/catalog.unit.spec.d.ts +1 -0
- package/.medusa/server/src/lib/__tests__/catalog.unit.spec.js +71 -0
- package/.medusa/server/src/lib/catalog.d.ts +9 -0
- package/.medusa/server/src/lib/catalog.generated.d.ts +2 -0
- package/.medusa/server/src/lib/catalog.generated.js +88 -0
- package/.medusa/server/src/lib/catalog.js +55 -0
- package/.medusa/server/src/modules/integration/descriptor/__tests__/build-zod.unit.spec.js +43 -1
- package/.medusa/server/src/modules/integration/descriptor/__tests__/define.unit.spec.js +3 -3
- package/.medusa/server/src/modules/integration/descriptor/__tests__/introspect.unit.spec.js +3 -3
- package/.medusa/server/src/modules/integration/descriptor/__tests__/section-write.unit.spec.d.ts +1 -0
- package/.medusa/server/src/modules/integration/descriptor/__tests__/section-write.unit.spec.js +64 -0
- package/.medusa/server/src/modules/integration/descriptor/__tests__/validate.unit.spec.js +28 -2
- package/.medusa/server/src/modules/integration/descriptor/build-zod.js +7 -1
- package/.medusa/server/src/modules/integration/descriptor/define.d.ts +5 -5
- package/.medusa/server/src/modules/integration/descriptor/define.js +1 -1
- package/.medusa/server/src/modules/integration/descriptor/introspect.js +2 -2
- package/.medusa/server/src/modules/integration/descriptor/meta.d.ts +1 -1
- package/.medusa/server/src/modules/integration/descriptor/section-write.d.ts +10 -0
- package/.medusa/server/src/modules/integration/descriptor/section-write.js +24 -0
- package/.medusa/server/src/modules/integration/loaders/__tests__/package-meta.unit.spec.d.ts +1 -0
- package/.medusa/server/src/modules/integration/loaders/__tests__/package-meta.unit.spec.js +63 -0
- package/.medusa/server/src/modules/integration/loaders/load-providers.js +10 -38
- package/.medusa/server/src/modules/integration/loaders/package-meta.d.ts +22 -0
- package/.medusa/server/src/modules/integration/loaders/package-meta.js +45 -0
- package/.medusa/server/src/modules/integration/loaders/resolve-package-meta.d.ts +8 -0
- package/.medusa/server/src/modules/integration/loaders/resolve-package-meta.js +59 -0
- package/.medusa/server/src/modules/integration/migrations/Migration20260720130920.d.ts +5 -0
- package/.medusa/server/src/modules/integration/migrations/Migration20260720130920.js +18 -0
- package/.medusa/server/src/modules/integration/migrations/Migration20260724101525.d.ts +5 -0
- package/.medusa/server/src/modules/integration/migrations/Migration20260724101525.js +16 -0
- package/.medusa/server/src/modules/integration/models/integration.d.ts +9 -5
- package/.medusa/server/src/modules/integration/models/integration.js +3 -3
- package/.medusa/server/src/modules/integration/services/__tests__/integration-module.unit.spec.d.ts +1 -0
- package/.medusa/server/src/modules/integration/services/__tests__/integration-module.unit.spec.js +344 -0
- package/.medusa/server/src/modules/integration/services/__tests__/integration-provider.unit.spec.js +2 -2
- package/.medusa/server/src/modules/integration/services/integration-module.d.ts +48 -11
- package/.medusa/server/src/modules/integration/services/integration-module.js +56 -6
- package/.medusa/server/src/modules/integration/types/index.d.ts +11 -0
- package/.medusa/server/src/modules/integration/types/index.js +4 -2
- package/.medusa/server/src/modules/integration/utils/integration.d.ts +11 -7
- package/.medusa/server/src/modules/integration/utils/integration.js +12 -8
- package/.medusa/server/src/subscribers/__tests__/invalidate-options-cache.unit.spec.d.ts +1 -0
- package/.medusa/server/src/subscribers/__tests__/invalidate-options-cache.unit.spec.js +53 -0
- package/.medusa/server/src/types/http/integration/admin/entities.d.ts +39 -4
- package/.medusa/server/src/types/http/integration/admin/responses.d.ts +17 -2
- package/.medusa/server/src/types/integration/common.d.ts +3 -3
- package/.medusa/server/src/workflows/integration/steps/apply-integration-section.d.ts +1 -1
- package/.medusa/server/src/workflows/integration/steps/apply-integration-section.js +13 -20
- package/.medusa/server/src/workflows/integration/steps/set-integration-enabled.d.ts +1 -1
- package/.medusa/server/src/workflows/integration/steps/upsert-integration-record.d.ts +2 -2
- package/.medusa/server/src/workflows/integration/workflows/set-integration-enabled.d.ts +1 -1
- package/.medusa/server/src/workflows/integration/workflows/upsert-integration.js +2 -2
- package/README.md +41 -2
- package/README.ru.md +85 -0
- package/package.json +7 -3
|
@@ -4,14 +4,14 @@ const adminSdk = require("@medusajs/admin-sdk");
|
|
|
4
4
|
const icons = require("@medusajs/icons");
|
|
5
5
|
const ui = require("@medusajs/ui");
|
|
6
6
|
const reactQuery = require("@tanstack/react-query");
|
|
7
|
+
const React = require("react");
|
|
7
8
|
const reactI18next = require("react-i18next");
|
|
8
9
|
const reactRouterDom = require("react-router-dom");
|
|
9
10
|
const Medusa = require("@medusajs/js-sdk");
|
|
10
|
-
const React = require("react");
|
|
11
11
|
const components = require("@medusajs/dashboard/components");
|
|
12
12
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
13
|
-
const Medusa__default = /* @__PURE__ */ _interopDefault(Medusa);
|
|
14
13
|
const React__default = /* @__PURE__ */ _interopDefault(React);
|
|
14
|
+
const Medusa__default = /* @__PURE__ */ _interopDefault(Medusa);
|
|
15
15
|
const sdk = new Medusa__default.default({
|
|
16
16
|
baseUrl: "/",
|
|
17
17
|
debug: false,
|
|
@@ -22,9 +22,23 @@ const sdk = new Medusa__default.default({
|
|
|
22
22
|
const IntegrationIcon = ({
|
|
23
23
|
src,
|
|
24
24
|
alt,
|
|
25
|
-
size = "base"
|
|
25
|
+
size = "base",
|
|
26
|
+
framed = true
|
|
26
27
|
}) => {
|
|
27
|
-
const dim = size === "small" ? "h-6 w-6" : "h-
|
|
28
|
+
const dim = size === "small" ? "h-6 w-6" : "h-10 w-10";
|
|
29
|
+
const [errored, setErrored] = React.useState(false);
|
|
30
|
+
const showImage = !!src && !errored;
|
|
31
|
+
if (showImage && !framed) {
|
|
32
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
33
|
+
"img",
|
|
34
|
+
{
|
|
35
|
+
src,
|
|
36
|
+
alt,
|
|
37
|
+
className: ui.clx("shrink-0 object-contain", dim),
|
|
38
|
+
onError: () => setErrored(true)
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
28
42
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
29
43
|
"div",
|
|
30
44
|
{
|
|
@@ -32,50 +46,237 @@ const IntegrationIcon = ({
|
|
|
32
46
|
"bg-ui-bg-component shadow-borders-base flex shrink-0 items-center justify-center overflow-hidden rounded-md",
|
|
33
47
|
dim
|
|
34
48
|
),
|
|
35
|
-
children:
|
|
49
|
+
children: showImage ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
50
|
+
"img",
|
|
51
|
+
{
|
|
52
|
+
src,
|
|
53
|
+
alt,
|
|
54
|
+
className: "h-full w-full object-cover",
|
|
55
|
+
onError: () => setErrored(true)
|
|
56
|
+
}
|
|
57
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(icons.PuzzleSolid, { className: "text-ui-fg-subtle" })
|
|
36
58
|
}
|
|
37
59
|
);
|
|
38
60
|
};
|
|
61
|
+
const PAGE_SIZE = 20;
|
|
62
|
+
const DOCS_URL = "https://docs.gorgojs.com/ru/medusa-plugins/integration-module";
|
|
63
|
+
const IntegrationCell = ({ item }) => {
|
|
64
|
+
const { t } = reactI18next.useTranslation();
|
|
65
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
66
|
+
/* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: item.icon, alt: t(item.display_name), size: "base" }),
|
|
67
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
68
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
69
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", weight: "plus", children: t(item.display_name) }),
|
|
70
|
+
item.provider_id && /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: item.provider_id })
|
|
71
|
+
] }),
|
|
72
|
+
item.version && /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: [
|
|
73
|
+
t("integration.meta.version", { version: item.version }),
|
|
74
|
+
item.author && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
75
|
+
" • ",
|
|
76
|
+
t("integration.meta.authorPrefix"),
|
|
77
|
+
" ",
|
|
78
|
+
item.author_url ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
79
|
+
"a",
|
|
80
|
+
{
|
|
81
|
+
href: item.author_url,
|
|
82
|
+
target: "_blank",
|
|
83
|
+
rel: "noreferrer",
|
|
84
|
+
className: "text-ui-fg-interactive",
|
|
85
|
+
onClick: (e) => e.stopPropagation(),
|
|
86
|
+
children: item.author
|
|
87
|
+
}
|
|
88
|
+
) : item.author
|
|
89
|
+
] })
|
|
90
|
+
] })
|
|
91
|
+
] })
|
|
92
|
+
] });
|
|
93
|
+
};
|
|
94
|
+
const StatusCell = ({ item }) => {
|
|
95
|
+
const { t } = reactI18next.useTranslation();
|
|
96
|
+
const lifecycle = !item.is_configured ? { color: "grey", label: t("integration.status.notConfigured") } : !item.is_complete ? { color: "orange", label: t("integration.status.incomplete") } : item.is_enabled ? { color: "green", label: t("integration.status.enabled") } : { color: "grey", label: t("integration.status.disabled") };
|
|
97
|
+
const connection = item.has_test_connection ? item.last_test_status === "passed" ? { color: "green", label: t("integration.status.connected") } : item.last_test_status === "failed" ? { color: "red", label: t("integration.status.connectionFailed") } : null : null;
|
|
98
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-1", children: [
|
|
99
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: lifecycle.color, children: lifecycle.label }),
|
|
100
|
+
connection && /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: connection.color, children: connection.label })
|
|
101
|
+
] });
|
|
102
|
+
};
|
|
103
|
+
const columnHelper = ui.createDataTableColumnHelper();
|
|
39
104
|
const IntegrationsPage = () => {
|
|
40
105
|
const { t } = reactI18next.useTranslation();
|
|
106
|
+
const navigate = reactRouterDom.useNavigate();
|
|
107
|
+
const qc = reactQuery.useQueryClient();
|
|
108
|
+
const prompt = ui.usePrompt();
|
|
109
|
+
const [activeTab, setActiveTab] = React.useState("all");
|
|
110
|
+
const [search, setSearch] = React.useState("");
|
|
111
|
+
const [pagination, setPagination] = React.useState({ pageIndex: 0, pageSize: PAGE_SIZE });
|
|
112
|
+
const category = activeTab === "all" ? void 0 : activeTab;
|
|
113
|
+
const queryParams = {
|
|
114
|
+
q: search || void 0,
|
|
115
|
+
category,
|
|
116
|
+
limit: pagination.pageSize,
|
|
117
|
+
offset: pagination.pageIndex * pagination.pageSize
|
|
118
|
+
};
|
|
41
119
|
const { data, isLoading } = reactQuery.useQuery({
|
|
42
|
-
queryKey: ["integration-overview"],
|
|
43
|
-
queryFn: () => sdk.client.fetch("/admin/integrations")
|
|
120
|
+
queryKey: ["integration-overview", queryParams],
|
|
121
|
+
queryFn: () => sdk.client.fetch("/admin/integrations", { query: queryParams }),
|
|
122
|
+
placeholderData: reactQuery.keepPreviousData
|
|
44
123
|
});
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
124
|
+
const integrations = (data == null ? void 0 : data.integrations) ?? [];
|
|
125
|
+
const count = (data == null ? void 0 : data.count) ?? 0;
|
|
126
|
+
const categories = (data == null ? void 0 : data.categories) ?? [];
|
|
127
|
+
const invalidate = () => qc.invalidateQueries({ queryKey: ["integration-overview"] });
|
|
128
|
+
const toggleEnabled = reactQuery.useMutation({
|
|
129
|
+
mutationFn: ({ providerId, next }) => sdk.client.fetch(`/admin/integrations/${providerId}/enable`, {
|
|
130
|
+
method: "POST",
|
|
131
|
+
body: { is_enabled: next }
|
|
132
|
+
}),
|
|
133
|
+
onSuccess: (_d, { next }) => {
|
|
134
|
+
ui.toast.success(next ? t("integration.toast.enabled") : t("integration.toast.disabled"));
|
|
135
|
+
invalidate();
|
|
136
|
+
},
|
|
137
|
+
onError: (e) => ui.toast.error((e == null ? void 0 : e.message) ?? t("integration.toast.updateFailed"))
|
|
138
|
+
});
|
|
139
|
+
const test = reactQuery.useMutation({
|
|
140
|
+
mutationFn: (providerId) => sdk.client.fetch(
|
|
141
|
+
`/admin/integrations/${providerId}/test-connection`,
|
|
142
|
+
{ method: "POST" }
|
|
143
|
+
),
|
|
144
|
+
onSuccess: (r) => {
|
|
145
|
+
r.status === "passed" ? ui.toast.success(t("integration.toast.connectionOk")) : ui.toast.warning(r.message ?? r.status);
|
|
146
|
+
invalidate();
|
|
147
|
+
},
|
|
148
|
+
onError: (e) => ui.toast.error((e == null ? void 0 : e.message) ?? t("integration.toast.testFailed"))
|
|
149
|
+
});
|
|
150
|
+
const remove = reactQuery.useMutation({
|
|
151
|
+
mutationFn: (providerId) => sdk.client.fetch(`/admin/integrations/${providerId}`, { method: "DELETE" }),
|
|
152
|
+
onSuccess: () => {
|
|
153
|
+
ui.toast.success(t("integration.toast.deleted"));
|
|
154
|
+
invalidate();
|
|
155
|
+
},
|
|
156
|
+
onError: (e) => ui.toast.error((e == null ? void 0 : e.message) ?? t("integration.toast.deleteFailed"))
|
|
157
|
+
});
|
|
158
|
+
const onDelete = async (item) => {
|
|
159
|
+
const confirmed = await prompt({
|
|
160
|
+
title: t("integration.delete.title"),
|
|
161
|
+
description: t("integration.delete.description", { name: t(item.display_name) }),
|
|
162
|
+
confirmText: t("integration.actions.delete"),
|
|
163
|
+
cancelText: t("integration.actions.cancel")
|
|
164
|
+
});
|
|
165
|
+
if (confirmed) remove.mutate(item.provider_id);
|
|
166
|
+
};
|
|
167
|
+
const buildActions = (item) => {
|
|
168
|
+
const groups = [];
|
|
169
|
+
const primary = [];
|
|
170
|
+
if (item.is_configured) {
|
|
171
|
+
primary.push({
|
|
172
|
+
label: item.is_enabled ? t("integration.actions.disable") : t("integration.actions.enable"),
|
|
173
|
+
onClick: () => toggleEnabled.mutate({ providerId: item.provider_id, next: !item.is_enabled })
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
if (item.is_configured && item.has_test_connection && item.is_complete) {
|
|
177
|
+
primary.push({
|
|
178
|
+
label: t("integration.actions.test"),
|
|
179
|
+
onClick: () => test.mutate(item.provider_id)
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (primary.length) groups.push(primary);
|
|
183
|
+
if (item.is_configured) {
|
|
184
|
+
groups.push([
|
|
185
|
+
{
|
|
186
|
+
label: t("integration.actions.delete"),
|
|
187
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(icons.Trash, {}),
|
|
188
|
+
onClick: () => onDelete(item)
|
|
189
|
+
}
|
|
190
|
+
]);
|
|
191
|
+
}
|
|
192
|
+
return groups.length > 0 ? groups : null;
|
|
193
|
+
};
|
|
194
|
+
const columns = React.useMemo(
|
|
195
|
+
() => [
|
|
196
|
+
columnHelper.display({
|
|
197
|
+
id: "integration",
|
|
198
|
+
header: t("integration.columns.integration"),
|
|
199
|
+
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx(IntegrationCell, { item: row.original })
|
|
200
|
+
}),
|
|
201
|
+
columnHelper.display({
|
|
202
|
+
id: "description",
|
|
203
|
+
header: t("integration.columns.description"),
|
|
204
|
+
cell: ({ row }) => row.original.description ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle line-clamp-2", children: t(row.original.description) }) : null
|
|
205
|
+
}),
|
|
206
|
+
columnHelper.display({
|
|
207
|
+
id: "category",
|
|
208
|
+
header: t("integration.columns.category"),
|
|
209
|
+
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: t(`integration.categories.${row.original.category}`) })
|
|
210
|
+
}),
|
|
211
|
+
columnHelper.display({
|
|
212
|
+
id: "status",
|
|
213
|
+
header: t("integration.columns.status"),
|
|
214
|
+
cell: ({ row }) => /* @__PURE__ */ jsxRuntime.jsx(StatusCell, { item: row.original })
|
|
215
|
+
}),
|
|
216
|
+
columnHelper.action({
|
|
217
|
+
actions: (ctx) => buildActions(ctx.row.original)
|
|
218
|
+
})
|
|
219
|
+
],
|
|
220
|
+
// Safe to memo on [t] only: react-query keeps each mutation's `mutate` ref stable across
|
|
221
|
+
// renders (options updated internally), so the closed-over buildActions/mutations stay current.
|
|
222
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
223
|
+
[t]
|
|
224
|
+
);
|
|
225
|
+
const table = ui.useDataTable({
|
|
226
|
+
data: integrations,
|
|
227
|
+
columns,
|
|
228
|
+
rowCount: count,
|
|
229
|
+
isLoading,
|
|
230
|
+
getRowId: (row) => row.provider_id,
|
|
231
|
+
onRowClick: (_e, row) => {
|
|
232
|
+
const item = row.original;
|
|
233
|
+
navigate(`/settings/integrations/${item.provider_id}`);
|
|
234
|
+
},
|
|
235
|
+
search: { state: search, onSearchChange: setSearch },
|
|
236
|
+
pagination: { state: pagination, onPaginationChange: setPagination }
|
|
237
|
+
});
|
|
238
|
+
const isFiltered = activeTab !== "all" || search.trim().length > 0;
|
|
51
239
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
|
|
52
|
-
/* @__PURE__ */ jsxRuntime.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
240
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between px-6 py-4", children: [
|
|
241
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
242
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("integration.list.title") }),
|
|
243
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.subtitle") })
|
|
244
|
+
] }),
|
|
245
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "primary", onClick: () => navigate("/settings/integrations/browse"), children: t("integration.list.browseIntegrations") })
|
|
246
|
+
] }),
|
|
247
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DataTable, { instance: table, className: "[&_td]:py-3", children: [
|
|
248
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Toolbar, { children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center justify-between gap-3", children: [
|
|
249
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
250
|
+
ui.Tabs,
|
|
59
251
|
{
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
252
|
+
value: activeTab,
|
|
253
|
+
onValueChange: (v) => {
|
|
254
|
+
setActiveTab(v);
|
|
255
|
+
setPagination((p) => ({ ...p, pageIndex: 0 }));
|
|
256
|
+
},
|
|
257
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.List, { children: [
|
|
258
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Tabs.Trigger, { value: "all", children: t("integration.list.tabs.all") }),
|
|
259
|
+
categories.map((c) => /* @__PURE__ */ jsxRuntime.jsx(ui.Tabs.Trigger, { value: c, children: t(`integration.categories.${c}`) }, c))
|
|
260
|
+
] })
|
|
261
|
+
}
|
|
262
|
+
),
|
|
263
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Search, { placeholder: t("integration.list.searchPlaceholder") })
|
|
264
|
+
] }) }),
|
|
265
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
266
|
+
ui.DataTable.Table,
|
|
267
|
+
{
|
|
268
|
+
emptyState: {
|
|
269
|
+
empty: { heading: isFiltered ? t("integration.list.emptyFiltered") : t("integration.list.empty") },
|
|
270
|
+
filtered: { heading: t("integration.list.emptyFiltered") }
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
),
|
|
274
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DataTable.Pagination, {})
|
|
275
|
+
] }),
|
|
276
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center px-6 py-4", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: DOCS_URL, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
|
|
277
|
+
t("integration.list.learnMore"),
|
|
278
|
+
" →"
|
|
279
|
+
] }) })
|
|
79
280
|
] });
|
|
80
281
|
};
|
|
81
282
|
const config = adminSdk.defineRouteConfig({
|
|
@@ -87,7 +288,7 @@ const IntegrationsBreadcrumb = () => {
|
|
|
87
288
|
const { t } = reactI18next.useTranslation();
|
|
88
289
|
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: t("integration.list.title") });
|
|
89
290
|
};
|
|
90
|
-
const handle$
|
|
291
|
+
const handle$2 = {
|
|
91
292
|
breadcrumb: () => /* @__PURE__ */ jsxRuntime.jsx(IntegrationsBreadcrumb, {})
|
|
92
293
|
};
|
|
93
294
|
const Dash = () => /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: "-" });
|
|
@@ -1683,7 +1884,7 @@ function useForm(props = {}) {
|
|
|
1683
1884
|
_formControl.current.formState = getProxyFormState(formState, control);
|
|
1684
1885
|
return _formControl.current;
|
|
1685
1886
|
}
|
|
1686
|
-
const jsonToText = (v) => v
|
|
1887
|
+
const jsonToText = (v) => v == null || v === "" ? "" : JSON.stringify(v, null, 2);
|
|
1687
1888
|
const JsonField = ({ field, f }) => {
|
|
1688
1889
|
const { t } = reactI18next.useTranslation();
|
|
1689
1890
|
const [raw, setRaw] = React.useState(() => jsonToText(f.value));
|
|
@@ -1703,7 +1904,7 @@ const JsonField = ({ field, f }) => {
|
|
|
1703
1904
|
setRaw(text);
|
|
1704
1905
|
if (text.trim() === "") {
|
|
1705
1906
|
setError(null);
|
|
1706
|
-
f.onChange(
|
|
1907
|
+
f.onChange(null);
|
|
1707
1908
|
return;
|
|
1708
1909
|
}
|
|
1709
1910
|
try {
|
|
@@ -1773,7 +1974,18 @@ function renderControl(field, f, secretConfigured, t) {
|
|
|
1773
1974
|
placeholder,
|
|
1774
1975
|
value: f.value ?? "",
|
|
1775
1976
|
disabled,
|
|
1776
|
-
onChange: (e) => f.onChange(e.target.value === "" ?
|
|
1977
|
+
onChange: (e) => f.onChange(e.target.value === "" ? null : e.target.valueAsNumber)
|
|
1978
|
+
}
|
|
1979
|
+
);
|
|
1980
|
+
case "url":
|
|
1981
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1982
|
+
ui.Input,
|
|
1983
|
+
{
|
|
1984
|
+
type: "url",
|
|
1985
|
+
placeholder,
|
|
1986
|
+
value: f.value ?? "",
|
|
1987
|
+
disabled,
|
|
1988
|
+
onChange: f.onChange
|
|
1777
1989
|
}
|
|
1778
1990
|
);
|
|
1779
1991
|
case "secret":
|
|
@@ -1784,7 +1996,8 @@ function renderControl(field, f, secretConfigured, t) {
|
|
|
1784
1996
|
placeholder: secretConfigured ? t("integration.form.keepSecret") : placeholder ?? "",
|
|
1785
1997
|
value: f.value ?? "",
|
|
1786
1998
|
disabled,
|
|
1787
|
-
onChange: f.onChange
|
|
1999
|
+
onChange: f.onChange,
|
|
2000
|
+
className: !f.value ? "[&~div]:hidden" : void 0
|
|
1788
2001
|
}
|
|
1789
2002
|
);
|
|
1790
2003
|
case "json":
|
|
@@ -1822,10 +2035,11 @@ const EditSectionDrawer = ({
|
|
|
1822
2035
|
providerId,
|
|
1823
2036
|
section,
|
|
1824
2037
|
values,
|
|
1825
|
-
|
|
2038
|
+
configuredSecrets = []
|
|
1826
2039
|
}) => {
|
|
1827
2040
|
const { t } = reactI18next.useTranslation();
|
|
1828
2041
|
const qc = reactQuery.useQueryClient();
|
|
2042
|
+
const configured = new Set(configuredSecrets);
|
|
1829
2043
|
const [defaults] = React.useState(() => sectionDefaults(section, values));
|
|
1830
2044
|
const form = useForm({ values: defaults });
|
|
1831
2045
|
const current = form.watch();
|
|
@@ -1852,7 +2066,7 @@ const EditSectionDrawer = ({
|
|
|
1852
2066
|
{
|
|
1853
2067
|
field: f,
|
|
1854
2068
|
control: form.control,
|
|
1855
|
-
secretConfigured:
|
|
2069
|
+
secretConfigured: configured.has(f.name)
|
|
1856
2070
|
},
|
|
1857
2071
|
f.name
|
|
1858
2072
|
)) }),
|
|
@@ -1870,7 +2084,6 @@ const EditSectionDrawer = ({
|
|
|
1870
2084
|
] })
|
|
1871
2085
|
] }) });
|
|
1872
2086
|
};
|
|
1873
|
-
const testColor = (s) => s === "passed" ? "green" : s === "failed" ? "red" : "grey";
|
|
1874
2087
|
const Row = ({ label, children }) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "text-ui-fg-subtle grid grid-cols-2 px-6 py-4", children: [
|
|
1875
2088
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: label }),
|
|
1876
2089
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-x-2", children })
|
|
@@ -1942,10 +2155,16 @@ const EditPage = () => {
|
|
|
1942
2155
|
if (!descriptor) {
|
|
1943
2156
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "p-6", children: [
|
|
1944
2157
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.unknown", { id: provider_id }) }),
|
|
1945
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: "/settings/integrations", className: "text-ui-fg-
|
|
2158
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactRouterDom.Link, { to: "/settings/integrations", className: "text-ui-fg-base", children: t("integration.back") })
|
|
1946
2159
|
] });
|
|
1947
2160
|
}
|
|
2161
|
+
const version = (data == null ? void 0 : data.version) ?? null;
|
|
2162
|
+
const author = (data == null ? void 0 : data.author) ?? null;
|
|
2163
|
+
const authorUrl = (data == null ? void 0 : data.author_url) ?? null;
|
|
2164
|
+
const lifecycle = !isConfigured ? { color: "grey", label: t("integration.status.notConfigured") } : !isComplete ? { color: "orange", label: t("integration.status.incomplete") } : record.is_enabled ? { color: "green", label: t("integration.status.enabled") } : { color: "grey", label: t("integration.status.disabled") };
|
|
2165
|
+
const connection = descriptor.hasTestConnection ? (record == null ? void 0 : record.last_test_status) === "passed" ? { color: "green", label: t("integration.status.connected") } : (record == null ? void 0 : record.last_test_status) === "failed" ? { color: "red", label: t("integration.status.connectionFailed") } : null : null;
|
|
1948
2166
|
const editing = descriptor.sections.find((s) => s.id === editingSection) ?? null;
|
|
2167
|
+
const configuredSecrets = new Set((record == null ? void 0 : record.configured_secrets) ?? []);
|
|
1949
2168
|
const sectionData = {
|
|
1950
2169
|
providerId: provider_id,
|
|
1951
2170
|
identifier: descriptor.identifier,
|
|
@@ -1970,7 +2189,7 @@ const EditPage = () => {
|
|
|
1970
2189
|
{
|
|
1971
2190
|
field: f,
|
|
1972
2191
|
value: (_a = record == null ? void 0 : record.values) == null ? void 0 : _a[f.name],
|
|
1973
|
-
secretConfigured:
|
|
2192
|
+
secretConfigured: configuredSecrets.has(f.name)
|
|
1974
2193
|
}
|
|
1975
2194
|
) }, f.name);
|
|
1976
2195
|
})
|
|
@@ -1979,40 +2198,62 @@ const EditPage = () => {
|
|
|
1979
2198
|
const sideSections = descriptor.sections.filter((s) => s.column === "side");
|
|
1980
2199
|
const main = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1981
2200
|
/* @__PURE__ */ jsxRuntime.jsx(components.LayoutComposer.Entry, { id: "main", children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
|
|
1982
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex
|
|
1983
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center
|
|
1984
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1985
|
-
|
|
1986
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex
|
|
1987
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2201
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
|
|
2202
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
2203
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
|
|
2204
|
+
/* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: descriptor.icon, alt: t(descriptor.displayName) }),
|
|
2205
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-1", children: [
|
|
2206
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
|
|
2207
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { children: t(descriptor.displayName) }),
|
|
2208
|
+
provider_id && /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: provider_id })
|
|
2209
|
+
] }),
|
|
2210
|
+
version && /* @__PURE__ */ jsxRuntime.jsxs(ui.Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: [
|
|
2211
|
+
t("integration.meta.version", { version }),
|
|
2212
|
+
author && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2213
|
+
" • ",
|
|
2214
|
+
t("integration.meta.authorPrefix"),
|
|
2215
|
+
" ",
|
|
2216
|
+
authorUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2217
|
+
"a",
|
|
2218
|
+
{
|
|
2219
|
+
href: authorUrl,
|
|
2220
|
+
target: "_blank",
|
|
2221
|
+
rel: "noreferrer",
|
|
2222
|
+
className: "text-ui-fg-interactive",
|
|
2223
|
+
children: author
|
|
2224
|
+
}
|
|
2225
|
+
) : author
|
|
2226
|
+
] })
|
|
2227
|
+
] })
|
|
2228
|
+
] })
|
|
2229
|
+
] }),
|
|
2230
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
|
|
2231
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: lifecycle.color, children: lifecycle.label }),
|
|
2232
|
+
connection && /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: connection.color, children: connection.label }),
|
|
2233
|
+
isConfigured && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
2234
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.IconButton, { size: "small", variant: "transparent", children: /* @__PURE__ */ jsxRuntime.jsx(icons.EllipsisHorizontal, {}) }) }),
|
|
2235
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Content, { children: [
|
|
2236
|
+
descriptor.hasTestConnection && record.is_enabled && isComplete && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Item, { disabled: test.isPending, onClick: () => test.mutate(), children: t("integration.actions.test") }),
|
|
2237
|
+
isConfigured && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2238
|
+
ui.DropdownMenu.Item,
|
|
2239
|
+
{
|
|
2240
|
+
disabled: toggleEnabled.isPending,
|
|
2241
|
+
onClick: () => toggleEnabled.mutate(!record.is_enabled),
|
|
2242
|
+
children: record.is_enabled ? t("integration.actions.disable") : t("integration.actions.enable")
|
|
2243
|
+
}
|
|
2244
|
+
),
|
|
2245
|
+
isConfigured && /* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenu.Separator, {}),
|
|
2246
|
+
isConfigured && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu.Item, { className: "gap-x-2", onClick: onDelete, children: [
|
|
2247
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.Trash, { className: "text-ui-fg-subtle" }),
|
|
2248
|
+
t("integration.actions.delete")
|
|
2249
|
+
] })
|
|
2250
|
+
] })
|
|
2009
2251
|
] })
|
|
2010
2252
|
] })
|
|
2011
|
-
] })
|
|
2253
|
+
] }),
|
|
2254
|
+
descriptor.description && /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t(descriptor.description) })
|
|
2012
2255
|
] }),
|
|
2013
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: t("integration.labels.
|
|
2014
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: t("integration.labels.module"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: t(`integration.modules.${descriptor.module}`) }) }),
|
|
2015
|
-
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: t("integration.labels.lastTest"), children: (record == null ? void 0 : record.last_test_status) ? /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: testColor(record.last_test_status), children: t(`integration.testStatus.${record.last_test_status}`) }) }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.labels.neverTested") }) })
|
|
2256
|
+
/* @__PURE__ */ jsxRuntime.jsx(Row, { label: t("integration.labels.category"), children: /* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: t(`integration.categories.${descriptor.category}`) }) })
|
|
2016
2257
|
] }) }),
|
|
2017
2258
|
mainSections.map(renderSection),
|
|
2018
2259
|
editing && /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2023,7 +2264,7 @@ const EditPage = () => {
|
|
|
2023
2264
|
providerId: provider_id,
|
|
2024
2265
|
section: editing,
|
|
2025
2266
|
values: (record == null ? void 0 : record.values) ?? {},
|
|
2026
|
-
|
|
2267
|
+
configuredSecrets: (record == null ? void 0 : record.configured_secrets) ?? []
|
|
2027
2268
|
},
|
|
2028
2269
|
editing.id
|
|
2029
2270
|
)
|
|
@@ -2049,50 +2290,199 @@ const IntegrationBreadcrumb = ({ params }) => {
|
|
|
2049
2290
|
enabled: !!providerId
|
|
2050
2291
|
});
|
|
2051
2292
|
const descriptor = data == null ? void 0 : data.descriptor;
|
|
2052
|
-
if (!descriptor) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
2293
|
+
if (!descriptor) return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
2053
2294
|
const name = t(descriptor.displayName);
|
|
2054
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
2295
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2296
|
+
name + " ",
|
|
2297
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Badge, { size: "2xsmall", color: "grey", children: providerId })
|
|
2298
|
+
] });
|
|
2055
2299
|
};
|
|
2056
|
-
const handle = {
|
|
2300
|
+
const handle$1 = {
|
|
2057
2301
|
breadcrumb: ({ params }) => /* @__PURE__ */ jsxRuntime.jsx(IntegrationBreadcrumb, { params })
|
|
2058
2302
|
};
|
|
2303
|
+
const PUBLISH_URL = "https://docs.gorgojs.com/integrations";
|
|
2304
|
+
const API_URL = "https://gorgojs.com";
|
|
2305
|
+
const InstallModal = ({ item, onOpenChange }) => {
|
|
2306
|
+
const { t } = reactI18next.useTranslation();
|
|
2307
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: !!item, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
|
|
2308
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Title, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-2", children: [
|
|
2309
|
+
item && /* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: API_URL + item.icon, alt: item.label, size: "small" }),
|
|
2310
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: item == null ? void 0 : item.label })
|
|
2311
|
+
] }) }) }),
|
|
2312
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children: item && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2313
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.install_addToConfig") }),
|
|
2314
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-between gap-x-2 rounded-md px-3 py-2", children: [
|
|
2315
|
+
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "txt-compact-small text-ui-fg-subtle", children: `npm i ${item.npm}` }),
|
|
2316
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: `npm i ${item.npm}` })
|
|
2317
|
+
] }),
|
|
2318
|
+
item.configSnippet && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 py-2", children: [
|
|
2319
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
|
|
2320
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: "medusa-config.ts" }),
|
|
2321
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: item.configSnippet })
|
|
2322
|
+
] }),
|
|
2323
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre", children: item.configSnippet })
|
|
2324
|
+
] }),
|
|
2325
|
+
/* @__PURE__ */ jsxRuntime.jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
|
|
2326
|
+
t("integration.browse.install_docs"),
|
|
2327
|
+
" →"
|
|
2328
|
+
] })
|
|
2329
|
+
] }) }),
|
|
2330
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Footer, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }) })
|
|
2331
|
+
] }) });
|
|
2332
|
+
};
|
|
2333
|
+
const BrowsePage = () => {
|
|
2334
|
+
const { t } = reactI18next.useTranslation();
|
|
2335
|
+
const navigate = reactRouterDom.useNavigate();
|
|
2336
|
+
const [activeTab, setActiveTab] = React.useState("all");
|
|
2337
|
+
const [search, setSearch] = React.useState("");
|
|
2338
|
+
const [installItem, setInstallItem] = React.useState(null);
|
|
2339
|
+
const { data, isLoading } = reactQuery.useQuery({
|
|
2340
|
+
queryKey: ["integration-catalog"],
|
|
2341
|
+
queryFn: () => sdk.client.fetch("/admin/integrations/catalog")
|
|
2342
|
+
});
|
|
2343
|
+
const items = (data == null ? void 0 : data.integrations) ?? [];
|
|
2344
|
+
const categories = React.useMemo(() => [...new Set(items.map((i) => i.category))], [items]);
|
|
2345
|
+
const q = search.trim().toLowerCase();
|
|
2346
|
+
const filtered = items.filter((i) => {
|
|
2347
|
+
if (activeTab !== "all" && i.category !== activeTab) return false;
|
|
2348
|
+
if (q && ![i.label, i.shortDescription, i.npm].some((s) => s.toLowerCase().includes(q))) return false;
|
|
2349
|
+
return true;
|
|
2350
|
+
});
|
|
2351
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-y-3", children: [
|
|
2352
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Container, { className: "divide-y p-0", children: [
|
|
2353
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between px-6 py-4", children: [
|
|
2354
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
2355
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: "h2", children: t("integration.browse.title") }),
|
|
2356
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.subtitle") })
|
|
2357
|
+
] }),
|
|
2358
|
+
false
|
|
2359
|
+
] }),
|
|
2360
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-3 px-6 py-4", children: [
|
|
2361
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Tabs, { value: activeTab, onValueChange: setActiveTab, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Tabs.List, { children: [
|
|
2362
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Tabs.Trigger, { value: "all", children: t("integration.list.tabs.all") }),
|
|
2363
|
+
categories.map((c) => /* @__PURE__ */ jsxRuntime.jsx(ui.Tabs.Trigger, { value: c, children: t(`integration.categories.${c}`) }, c))
|
|
2364
|
+
] }) }),
|
|
2365
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-64", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2366
|
+
ui.Input,
|
|
2367
|
+
{
|
|
2368
|
+
placeholder: t("integration.browse.searchPlaceholder"),
|
|
2369
|
+
value: search,
|
|
2370
|
+
onChange: (e) => setSearch(e.target.value)
|
|
2371
|
+
}
|
|
2372
|
+
) })
|
|
2373
|
+
] })
|
|
2374
|
+
] }),
|
|
2375
|
+
isLoading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(icons.Spinner, { className: "text-ui-fg-subtle animate-spin" }) }) : filtered.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.emptyFiltered") }) }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4", children: filtered.map((item) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "shadow-borders-base bg-ui-bg-base flex flex-col rounded-lg", children: [
|
|
2376
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-y-3 p-4", children: [
|
|
2377
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
|
|
2378
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
|
|
2379
|
+
/* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: API_URL + item.icon, alt: item.label }),
|
|
2380
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
2381
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.label }),
|
|
2382
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.browse.by", { author: item.authorLocalized }) })
|
|
2383
|
+
] })
|
|
2384
|
+
] }),
|
|
2385
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.StatusBadge, { color: item.installed ? "green" : "grey", children: item.installed ? t("integration.browse.installed") : t("integration.browse.notInstalled") })
|
|
2386
|
+
] }),
|
|
2387
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle line-clamp-2", children: item.shortDescription })
|
|
2388
|
+
] }),
|
|
2389
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between border-t px-4 py-3", children: [
|
|
2390
|
+
item.installed && item.provider_id ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2391
|
+
ui.Button,
|
|
2392
|
+
{
|
|
2393
|
+
size: "small",
|
|
2394
|
+
variant: "primary",
|
|
2395
|
+
onClick: () => navigate(`/settings/integrations/${item.provider_id}`),
|
|
2396
|
+
children: t("integration.browse.settings")
|
|
2397
|
+
}
|
|
2398
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(ui.Button, { size: "small", variant: "secondary", onClick: () => setInstallItem(item), children: [
|
|
2399
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.Plus, {}),
|
|
2400
|
+
t("integration.browse.add")
|
|
2401
|
+
] }),
|
|
2402
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t(`integration.categories.${item.category}`) })
|
|
2403
|
+
] })
|
|
2404
|
+
] }, item.integrationId)) }),
|
|
2405
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Container, { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: PUBLISH_URL, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
|
|
2406
|
+
t("integration.browse.learnMore"),
|
|
2407
|
+
" →"
|
|
2408
|
+
] }) }),
|
|
2409
|
+
/* @__PURE__ */ jsxRuntime.jsx(InstallModal, { item: installItem, onOpenChange: (open) => !open && setInstallItem(null) })
|
|
2410
|
+
] });
|
|
2411
|
+
};
|
|
2412
|
+
const BrowseBreadcrumb = () => {
|
|
2413
|
+
const { t } = reactI18next.useTranslation();
|
|
2414
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: t("integration.browse.title") });
|
|
2415
|
+
};
|
|
2416
|
+
const handle = {
|
|
2417
|
+
breadcrumb: () => /* @__PURE__ */ jsxRuntime.jsx(BrowseBreadcrumb, {})
|
|
2418
|
+
};
|
|
2059
2419
|
const integration$1 = {
|
|
2060
2420
|
list: {
|
|
2061
2421
|
title: "Integrations",
|
|
2422
|
+
subtitle: "Manage integrations settings",
|
|
2423
|
+
browseIntegrations: "Browse Integrations",
|
|
2424
|
+
learnMore: "Learn how to build integrations",
|
|
2425
|
+
searchPlaceholder: "Search integrations",
|
|
2062
2426
|
empty: "No integrations registered. Declare providers under the integration plugin's options.providers in medusa-config.",
|
|
2427
|
+
emptyFiltered: "No integrations match your filters.",
|
|
2063
2428
|
tested: "tested",
|
|
2064
|
-
testFailed: "test failed"
|
|
2429
|
+
testFailed: "test failed",
|
|
2430
|
+
tabs: {
|
|
2431
|
+
all: "All"
|
|
2432
|
+
}
|
|
2433
|
+
},
|
|
2434
|
+
browse: {
|
|
2435
|
+
title: "Browse",
|
|
2436
|
+
subtitle: "Find available integrations",
|
|
2437
|
+
publish: "Add Integration",
|
|
2438
|
+
learnMore: "Learn how to build and publish your own integration",
|
|
2439
|
+
searchPlaceholder: "Search integrations",
|
|
2440
|
+
by: "by {{author}}",
|
|
2441
|
+
installed: "Installed",
|
|
2442
|
+
notInstalled: "Not installed",
|
|
2443
|
+
add: "Add",
|
|
2444
|
+
settings: "Settings",
|
|
2445
|
+
install_addToConfig: "Add this to your medusa-config.ts and restart the server.",
|
|
2446
|
+
install_docs: "Documentation"
|
|
2447
|
+
},
|
|
2448
|
+
columns: {
|
|
2449
|
+
integration: "Integration",
|
|
2450
|
+
description: "Description",
|
|
2451
|
+
category: "Category",
|
|
2452
|
+
status: "Status"
|
|
2065
2453
|
},
|
|
2066
2454
|
status: {
|
|
2067
2455
|
notConfigured: "Not configured",
|
|
2068
2456
|
incomplete: "Incomplete",
|
|
2069
2457
|
enabled: "Enabled",
|
|
2070
2458
|
disabled: "Disabled",
|
|
2071
|
-
configured: "Configured"
|
|
2459
|
+
configured: "Configured",
|
|
2460
|
+
connected: "Connected",
|
|
2461
|
+
connectionFailed: "Connection failed"
|
|
2462
|
+
},
|
|
2463
|
+
meta: {
|
|
2464
|
+
version: "v{{version}}",
|
|
2465
|
+
authorPrefix: "by"
|
|
2072
2466
|
},
|
|
2073
2467
|
labels: {
|
|
2074
|
-
|
|
2075
|
-
module: "Module",
|
|
2076
|
-
lastTest: "Last test",
|
|
2077
|
-
neverTested: "Never tested"
|
|
2468
|
+
category: "Category"
|
|
2078
2469
|
},
|
|
2079
|
-
|
|
2470
|
+
categories: {
|
|
2080
2471
|
payment: "Payment",
|
|
2472
|
+
notification: "Notification",
|
|
2081
2473
|
fulfillment: "Fulfillment",
|
|
2082
|
-
|
|
2083
|
-
|
|
2474
|
+
search: "Search",
|
|
2475
|
+
content: "Content",
|
|
2476
|
+
analytics: "Analytics",
|
|
2477
|
+
authentication: "Authentication",
|
|
2084
2478
|
erp: "ERP",
|
|
2479
|
+
crm: "CRM",
|
|
2085
2480
|
pim: "PIM",
|
|
2086
|
-
|
|
2481
|
+
marketplace: "Marketplace",
|
|
2087
2482
|
feed: "Feed",
|
|
2088
|
-
|
|
2483
|
+
file_providers: "File providers",
|
|
2089
2484
|
other: "Other"
|
|
2090
2485
|
},
|
|
2091
|
-
testStatus: {
|
|
2092
|
-
passed: "Passed",
|
|
2093
|
-
failed: "Failed",
|
|
2094
|
-
skipped: "Skipped"
|
|
2095
|
-
},
|
|
2096
2486
|
actions: {
|
|
2097
2487
|
test: "Test connection",
|
|
2098
2488
|
enable: "Enable",
|
|
@@ -2109,7 +2499,7 @@ const integration$1 = {
|
|
|
2109
2499
|
form: {
|
|
2110
2500
|
required: "{{field}} is required",
|
|
2111
2501
|
invalidJson: "Invalid JSON",
|
|
2112
|
-
keepSecret: "••••••
|
|
2502
|
+
keepSecret: "•••••• – leave blank to keep",
|
|
2113
2503
|
items: "{{count}} items"
|
|
2114
2504
|
},
|
|
2115
2505
|
toast: {
|
|
@@ -2132,40 +2522,70 @@ const en = {
|
|
|
2132
2522
|
const integration = {
|
|
2133
2523
|
list: {
|
|
2134
2524
|
title: "Интеграции",
|
|
2525
|
+
subtitle: "Управление настройками интеграций",
|
|
2526
|
+
browseIntegrations: "Найти интеграции",
|
|
2527
|
+
learnMore: "Как создавать интеграции",
|
|
2528
|
+
searchPlaceholder: "Поиск интеграций",
|
|
2135
2529
|
empty: "Нет зарегистрированных интеграций. Объявите провайдеров в options.providers плагина интеграций в medusa-config.",
|
|
2530
|
+
emptyFiltered: "Нет интеграций по заданным фильтрам",
|
|
2136
2531
|
tested: "проверено",
|
|
2137
|
-
testFailed: "ошибка проверки"
|
|
2532
|
+
testFailed: "ошибка проверки",
|
|
2533
|
+
tabs: {
|
|
2534
|
+
all: "Все"
|
|
2535
|
+
}
|
|
2536
|
+
},
|
|
2537
|
+
browse: {
|
|
2538
|
+
title: "Каталог",
|
|
2539
|
+
subtitle: "Поиск доступных интеграций",
|
|
2540
|
+
publish: "Добавить интеграцию",
|
|
2541
|
+
learnMore: "Как создать и опубликовать свою интеграцию",
|
|
2542
|
+
searchPlaceholder: "Поиск интеграций",
|
|
2543
|
+
by: "от {{author}}",
|
|
2544
|
+
installed: "Установлено",
|
|
2545
|
+
notInstalled: "Не установлено",
|
|
2546
|
+
add: "Добавить",
|
|
2547
|
+
settings: "Настройки",
|
|
2548
|
+
install_addToConfig: "Добавьте это в medusa-config.ts и перезапустите сервер.",
|
|
2549
|
+
install_docs: "Документация"
|
|
2550
|
+
},
|
|
2551
|
+
columns: {
|
|
2552
|
+
integration: "Интеграция",
|
|
2553
|
+
description: "Описание",
|
|
2554
|
+
category: "Категория",
|
|
2555
|
+
status: "Статус"
|
|
2138
2556
|
},
|
|
2139
2557
|
status: {
|
|
2140
2558
|
notConfigured: "Не настроено",
|
|
2141
2559
|
incomplete: "Не завершено",
|
|
2142
2560
|
enabled: "Включено",
|
|
2143
2561
|
disabled: "Выключено",
|
|
2144
|
-
configured: "Настроено"
|
|
2562
|
+
configured: "Настроено",
|
|
2563
|
+
connected: "Подключено",
|
|
2564
|
+
connectionFailed: "Ошибка подключения"
|
|
2565
|
+
},
|
|
2566
|
+
meta: {
|
|
2567
|
+
version: "v{{version}}",
|
|
2568
|
+
authorPrefix: "от"
|
|
2145
2569
|
},
|
|
2146
2570
|
labels: {
|
|
2147
|
-
|
|
2148
|
-
module: "Модуль",
|
|
2149
|
-
lastTest: "Последняя проверка",
|
|
2150
|
-
neverTested: "Не проверялось"
|
|
2571
|
+
category: "Категория"
|
|
2151
2572
|
},
|
|
2152
|
-
|
|
2573
|
+
categories: {
|
|
2153
2574
|
payment: "Платежи",
|
|
2575
|
+
notification: "Уведомления",
|
|
2154
2576
|
fulfillment: "Доставка",
|
|
2155
|
-
|
|
2156
|
-
|
|
2577
|
+
search: "Поиск",
|
|
2578
|
+
content: "Контент",
|
|
2579
|
+
analytics: "Аналитика",
|
|
2580
|
+
authentication: "Аутентификация",
|
|
2157
2581
|
erp: "ERP",
|
|
2582
|
+
crm: "CRM",
|
|
2158
2583
|
pim: "PIM",
|
|
2159
|
-
|
|
2584
|
+
marketplace: "Маркетплейс",
|
|
2160
2585
|
feed: "Фиды",
|
|
2161
|
-
|
|
2586
|
+
file_providers: "Файловые провайдеры",
|
|
2162
2587
|
other: "Прочее"
|
|
2163
2588
|
},
|
|
2164
|
-
testStatus: {
|
|
2165
|
-
passed: "Пройдено",
|
|
2166
|
-
failed: "Ошибка",
|
|
2167
|
-
skipped: "Пропущено"
|
|
2168
|
-
},
|
|
2169
2589
|
actions: {
|
|
2170
2590
|
test: "Проверить соединение",
|
|
2171
2591
|
enable: "Включить",
|
|
@@ -2182,7 +2602,7 @@ const integration = {
|
|
|
2182
2602
|
form: {
|
|
2183
2603
|
required: "Поле «{{field}}» обязательно",
|
|
2184
2604
|
invalidJson: "Некорректный JSON",
|
|
2185
|
-
keepSecret: "••••••
|
|
2605
|
+
keepSecret: "•••••• – оставьте пустым, чтобы не менять",
|
|
2186
2606
|
items: "{{count}} шт."
|
|
2187
2607
|
},
|
|
2188
2608
|
toast: {
|
|
@@ -2212,11 +2632,16 @@ const routeModule = {
|
|
|
2212
2632
|
{
|
|
2213
2633
|
Component: IntegrationsPage,
|
|
2214
2634
|
path: "/settings/integrations",
|
|
2215
|
-
handle: handle$
|
|
2635
|
+
handle: { label: config.label, translationNs: config.translationNs, ...handle$2 }
|
|
2216
2636
|
},
|
|
2217
2637
|
{
|
|
2218
2638
|
Component: EditPage,
|
|
2219
2639
|
path: "/settings/integrations/:provider_id",
|
|
2640
|
+
handle: handle$1
|
|
2641
|
+
},
|
|
2642
|
+
{
|
|
2643
|
+
Component: BrowsePage,
|
|
2644
|
+
path: "/settings/integrations/browse",
|
|
2220
2645
|
handle
|
|
2221
2646
|
}
|
|
2222
2647
|
]
|
|
@@ -2238,6 +2663,7 @@ const displayModule = {
|
|
|
2238
2663
|
displays: {}
|
|
2239
2664
|
};
|
|
2240
2665
|
const i18nModule = { resources: i18nTranslations0 };
|
|
2666
|
+
const cellRendererModule = {};
|
|
2241
2667
|
const layoutModule = { layouts: [] };
|
|
2242
2668
|
const plugin = {
|
|
2243
2669
|
widgetModule,
|
|
@@ -2246,6 +2672,7 @@ const plugin = {
|
|
|
2246
2672
|
formModule,
|
|
2247
2673
|
displayModule,
|
|
2248
2674
|
i18nModule,
|
|
2675
|
+
cellRendererModule,
|
|
2249
2676
|
layoutModule
|
|
2250
2677
|
};
|
|
2251
2678
|
module.exports = plugin;
|