@gorgo/medusa-integration 0.0.4 → 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.
Files changed (42) hide show
  1. package/.medusa/server/src/admin/index.js +519 -106
  2. package/.medusa/server/src/admin/index.mjs +522 -109
  3. package/.medusa/server/src/api/admin/integrations/[provider_id]/route.js +7 -2
  4. package/.medusa/server/src/api/admin/integrations/catalog/route.d.ts +3 -0
  5. package/.medusa/server/src/api/admin/integrations/catalog/route.js +10 -0
  6. package/.medusa/server/src/api/admin/integrations/middlewares.js +16 -1
  7. package/.medusa/server/src/api/admin/integrations/route.js +17 -3
  8. package/.medusa/server/src/api/admin/integrations/validators.d.ts +7 -0
  9. package/.medusa/server/src/api/admin/integrations/validators.js +8 -2
  10. package/.medusa/server/src/jobs/test-integration-connections.js +3 -3
  11. package/.medusa/server/src/lib/__tests__/catalog-fallback.unit.spec.d.ts +1 -0
  12. package/.medusa/server/src/lib/__tests__/catalog-fallback.unit.spec.js +37 -0
  13. package/.medusa/server/src/lib/__tests__/catalog.unit.spec.d.ts +1 -0
  14. package/.medusa/server/src/lib/__tests__/catalog.unit.spec.js +71 -0
  15. package/.medusa/server/src/lib/catalog.d.ts +9 -0
  16. package/.medusa/server/src/lib/catalog.generated.d.ts +2 -0
  17. package/.medusa/server/src/lib/catalog.generated.js +88 -0
  18. package/.medusa/server/src/lib/catalog.js +55 -0
  19. package/.medusa/server/src/modules/integration/loaders/__tests__/package-meta.unit.spec.d.ts +1 -0
  20. package/.medusa/server/src/modules/integration/loaders/__tests__/package-meta.unit.spec.js +63 -0
  21. package/.medusa/server/src/modules/integration/loaders/load-providers.js +9 -37
  22. package/.medusa/server/src/modules/integration/loaders/package-meta.d.ts +22 -0
  23. package/.medusa/server/src/modules/integration/loaders/package-meta.js +45 -0
  24. package/.medusa/server/src/modules/integration/loaders/resolve-package-meta.d.ts +8 -0
  25. package/.medusa/server/src/modules/integration/loaders/resolve-package-meta.js +59 -0
  26. package/.medusa/server/src/modules/integration/migrations/Migration20260724101525.d.ts +5 -0
  27. package/.medusa/server/src/modules/integration/migrations/Migration20260724101525.js +16 -0
  28. package/.medusa/server/src/modules/integration/models/integration.d.ts +8 -4
  29. package/.medusa/server/src/modules/integration/services/__tests__/integration-module.unit.spec.js +107 -3
  30. package/.medusa/server/src/modules/integration/services/integration-module.d.ts +46 -9
  31. package/.medusa/server/src/modules/integration/services/integration-module.js +54 -4
  32. package/.medusa/server/src/modules/integration/types/index.d.ts +11 -0
  33. package/.medusa/server/src/modules/integration/types/index.js +4 -2
  34. package/.medusa/server/src/modules/integration/utils/integration.d.ts +8 -4
  35. package/.medusa/server/src/modules/integration/utils/integration.js +9 -5
  36. package/.medusa/server/src/types/http/integration/admin/entities.d.ts +34 -0
  37. package/.medusa/server/src/types/http/integration/admin/responses.d.ts +17 -2
  38. package/.medusa/server/src/workflows/integration/steps/set-integration-enabled.d.ts +1 -1
  39. package/.medusa/server/src/workflows/integration/workflows/set-integration-enabled.d.ts +1 -1
  40. package/README.md +5 -5
  41. package/README.ru.md +5 -5
  42. package/package.json +7 -3
@@ -1,12 +1,12 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
2
  import { defineRouteConfig } from "@medusajs/admin-sdk";
3
- import { PuzzleSolid, CogSixTooth, Spinner, EllipsisHorizontal, Trash, PencilSquare } from "@medusajs/icons";
4
- import { clx, Container, Heading, Text, Badge, StatusBadge, Label, Input, Select, Switch, Textarea, toast, Drawer, Button, usePrompt, DropdownMenu, IconButton } from "@medusajs/ui";
5
- import { useQuery, useQueryClient, useMutation } from "@tanstack/react-query";
3
+ import { PuzzleSolid, CogSixTooth, Trash, Spinner, EllipsisHorizontal, PencilSquare, Plus } from "@medusajs/icons";
4
+ import { clx, createDataTableColumnHelper, usePrompt, toast, Text, Badge, useDataTable, Container, Heading, Button, DataTable, Tabs, StatusBadge, Label, Input, Select, Switch, Textarea, Drawer, DropdownMenu, IconButton, Copy } from "@medusajs/ui";
5
+ import { useQueryClient, useQuery, keepPreviousData, useMutation } from "@tanstack/react-query";
6
+ import React, { useState, useMemo } from "react";
6
7
  import { useTranslation } from "react-i18next";
7
- import { Link, useParams, useNavigate } from "react-router-dom";
8
+ import { useNavigate, useParams, Link } from "react-router-dom";
8
9
  import Medusa from "@medusajs/js-sdk";
9
- import React, { useState } from "react";
10
10
  import { LayoutComposer } from "@medusajs/dashboard/components";
11
11
  const sdk = new Medusa({
12
12
  baseUrl: "/",
@@ -18,9 +18,23 @@ const sdk = new Medusa({
18
18
  const IntegrationIcon = ({
19
19
  src,
20
20
  alt,
21
- size = "base"
21
+ size = "base",
22
+ framed = true
22
23
  }) => {
23
24
  const dim = size === "small" ? "h-6 w-6" : "h-10 w-10";
25
+ const [errored, setErrored] = useState(false);
26
+ const showImage = !!src && !errored;
27
+ if (showImage && !framed) {
28
+ return /* @__PURE__ */ jsx(
29
+ "img",
30
+ {
31
+ src,
32
+ alt,
33
+ className: clx("shrink-0 object-contain", dim),
34
+ onError: () => setErrored(true)
35
+ }
36
+ );
37
+ }
24
38
  return /* @__PURE__ */ jsx(
25
39
  "div",
26
40
  {
@@ -28,50 +42,237 @@ const IntegrationIcon = ({
28
42
  "bg-ui-bg-component shadow-borders-base flex shrink-0 items-center justify-center overflow-hidden rounded-md",
29
43
  dim
30
44
  ),
31
- children: src ? /* @__PURE__ */ jsx("img", { src, alt, className: "h-full w-full object-cover" }) : /* @__PURE__ */ jsx(PuzzleSolid, { className: "text-ui-fg-subtle" })
45
+ children: showImage ? /* @__PURE__ */ jsx(
46
+ "img",
47
+ {
48
+ src,
49
+ alt,
50
+ className: "h-full w-full object-cover",
51
+ onError: () => setErrored(true)
52
+ }
53
+ ) : /* @__PURE__ */ jsx(PuzzleSolid, { className: "text-ui-fg-subtle" })
32
54
  }
33
55
  );
34
56
  };
57
+ const PAGE_SIZE = 20;
58
+ const DOCS_URL = "https://docs.gorgojs.com/ru/medusa-plugins/integration-module";
59
+ const IntegrationCell = ({ item }) => {
60
+ const { t } = useTranslation();
61
+ return /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
62
+ /* @__PURE__ */ jsx(IntegrationIcon, { src: item.icon, alt: t(item.display_name), size: "base" }),
63
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
64
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
65
+ /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", weight: "plus", children: t(item.display_name) }),
66
+ item.provider_id && /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: item.provider_id })
67
+ ] }),
68
+ item.version && /* @__PURE__ */ jsxs(Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: [
69
+ t("integration.meta.version", { version: item.version }),
70
+ item.author && /* @__PURE__ */ jsxs(Fragment, { children: [
71
+ " • ",
72
+ t("integration.meta.authorPrefix"),
73
+ " ",
74
+ item.author_url ? /* @__PURE__ */ jsx(
75
+ "a",
76
+ {
77
+ href: item.author_url,
78
+ target: "_blank",
79
+ rel: "noreferrer",
80
+ className: "text-ui-fg-interactive",
81
+ onClick: (e) => e.stopPropagation(),
82
+ children: item.author
83
+ }
84
+ ) : item.author
85
+ ] })
86
+ ] })
87
+ ] })
88
+ ] });
89
+ };
90
+ const StatusCell = ({ item }) => {
91
+ const { t } = useTranslation();
92
+ 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") };
93
+ 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;
94
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-start gap-1", children: [
95
+ /* @__PURE__ */ jsx(StatusBadge, { color: lifecycle.color, children: lifecycle.label }),
96
+ connection && /* @__PURE__ */ jsx(StatusBadge, { color: connection.color, children: connection.label })
97
+ ] });
98
+ };
99
+ const columnHelper = createDataTableColumnHelper();
35
100
  const IntegrationsPage = () => {
36
101
  const { t } = useTranslation();
102
+ const navigate = useNavigate();
103
+ const qc = useQueryClient();
104
+ const prompt = usePrompt();
105
+ const [activeTab, setActiveTab] = useState("all");
106
+ const [search, setSearch] = useState("");
107
+ const [pagination, setPagination] = useState({ pageIndex: 0, pageSize: PAGE_SIZE });
108
+ const category = activeTab === "all" ? void 0 : activeTab;
109
+ const queryParams = {
110
+ q: search || void 0,
111
+ category,
112
+ limit: pagination.pageSize,
113
+ offset: pagination.pageIndex * pagination.pageSize
114
+ };
37
115
  const { data, isLoading } = useQuery({
38
- queryKey: ["integration-overview"],
39
- queryFn: () => sdk.client.fetch("/admin/integrations")
116
+ queryKey: ["integration-overview", queryParams],
117
+ queryFn: () => sdk.client.fetch("/admin/integrations", { query: queryParams }),
118
+ placeholderData: keepPreviousData
40
119
  });
41
- const items = (data == null ? void 0 : data.integrations) ?? [];
42
- const byCategory = items.reduce((acc, i) => {
43
- var _a;
44
- (acc[_a = i.category] ?? (acc[_a] = [])).push(i);
45
- return acc;
46
- }, {});
120
+ const integrations = (data == null ? void 0 : data.integrations) ?? [];
121
+ const count = (data == null ? void 0 : data.count) ?? 0;
122
+ const categories = (data == null ? void 0 : data.categories) ?? [];
123
+ const invalidate = () => qc.invalidateQueries({ queryKey: ["integration-overview"] });
124
+ const toggleEnabled = useMutation({
125
+ mutationFn: ({ providerId, next }) => sdk.client.fetch(`/admin/integrations/${providerId}/enable`, {
126
+ method: "POST",
127
+ body: { is_enabled: next }
128
+ }),
129
+ onSuccess: (_d, { next }) => {
130
+ toast.success(next ? t("integration.toast.enabled") : t("integration.toast.disabled"));
131
+ invalidate();
132
+ },
133
+ onError: (e) => toast.error((e == null ? void 0 : e.message) ?? t("integration.toast.updateFailed"))
134
+ });
135
+ const test = useMutation({
136
+ mutationFn: (providerId) => sdk.client.fetch(
137
+ `/admin/integrations/${providerId}/test-connection`,
138
+ { method: "POST" }
139
+ ),
140
+ onSuccess: (r) => {
141
+ r.status === "passed" ? toast.success(t("integration.toast.connectionOk")) : toast.warning(r.message ?? r.status);
142
+ invalidate();
143
+ },
144
+ onError: (e) => toast.error((e == null ? void 0 : e.message) ?? t("integration.toast.testFailed"))
145
+ });
146
+ const remove = useMutation({
147
+ mutationFn: (providerId) => sdk.client.fetch(`/admin/integrations/${providerId}`, { method: "DELETE" }),
148
+ onSuccess: () => {
149
+ toast.success(t("integration.toast.deleted"));
150
+ invalidate();
151
+ },
152
+ onError: (e) => toast.error((e == null ? void 0 : e.message) ?? t("integration.toast.deleteFailed"))
153
+ });
154
+ const onDelete = async (item) => {
155
+ const confirmed = await prompt({
156
+ title: t("integration.delete.title"),
157
+ description: t("integration.delete.description", { name: t(item.display_name) }),
158
+ confirmText: t("integration.actions.delete"),
159
+ cancelText: t("integration.actions.cancel")
160
+ });
161
+ if (confirmed) remove.mutate(item.provider_id);
162
+ };
163
+ const buildActions = (item) => {
164
+ const groups = [];
165
+ const primary = [];
166
+ if (item.is_configured) {
167
+ primary.push({
168
+ label: item.is_enabled ? t("integration.actions.disable") : t("integration.actions.enable"),
169
+ onClick: () => toggleEnabled.mutate({ providerId: item.provider_id, next: !item.is_enabled })
170
+ });
171
+ }
172
+ if (item.is_configured && item.has_test_connection && item.is_complete) {
173
+ primary.push({
174
+ label: t("integration.actions.test"),
175
+ onClick: () => test.mutate(item.provider_id)
176
+ });
177
+ }
178
+ if (primary.length) groups.push(primary);
179
+ if (item.is_configured) {
180
+ groups.push([
181
+ {
182
+ label: t("integration.actions.delete"),
183
+ icon: /* @__PURE__ */ jsx(Trash, {}),
184
+ onClick: () => onDelete(item)
185
+ }
186
+ ]);
187
+ }
188
+ return groups.length > 0 ? groups : null;
189
+ };
190
+ const columns = useMemo(
191
+ () => [
192
+ columnHelper.display({
193
+ id: "integration",
194
+ header: t("integration.columns.integration"),
195
+ cell: ({ row }) => /* @__PURE__ */ jsx(IntegrationCell, { item: row.original })
196
+ }),
197
+ columnHelper.display({
198
+ id: "description",
199
+ header: t("integration.columns.description"),
200
+ cell: ({ row }) => row.original.description ? /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle line-clamp-2", children: t(row.original.description) }) : null
201
+ }),
202
+ columnHelper.display({
203
+ id: "category",
204
+ header: t("integration.columns.category"),
205
+ cell: ({ row }) => /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: t(`integration.categories.${row.original.category}`) })
206
+ }),
207
+ columnHelper.display({
208
+ id: "status",
209
+ header: t("integration.columns.status"),
210
+ cell: ({ row }) => /* @__PURE__ */ jsx(StatusCell, { item: row.original })
211
+ }),
212
+ columnHelper.action({
213
+ actions: (ctx) => buildActions(ctx.row.original)
214
+ })
215
+ ],
216
+ // Safe to memo on [t] only: react-query keeps each mutation's `mutate` ref stable across
217
+ // renders (options updated internally), so the closed-over buildActions/mutations stay current.
218
+ // eslint-disable-next-line react-hooks/exhaustive-deps
219
+ [t]
220
+ );
221
+ const table = useDataTable({
222
+ data: integrations,
223
+ columns,
224
+ rowCount: count,
225
+ isLoading,
226
+ getRowId: (row) => row.provider_id,
227
+ onRowClick: (_e, row) => {
228
+ const item = row.original;
229
+ navigate(`/settings/integrations/${item.provider_id}`);
230
+ },
231
+ search: { state: search, onSearchChange: setSearch },
232
+ pagination: { state: pagination, onPaginationChange: setPagination }
233
+ });
234
+ const isFiltered = activeTab !== "all" || search.trim().length > 0;
47
235
  return /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
48
- /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Heading, { level: "h2", children: t("integration.list.title") }) }),
49
- isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center px-6 py-8", children: /* @__PURE__ */ jsx(Spinner, { className: "text-ui-fg-subtle animate-spin" }) }) : items.length === 0 ? /* @__PURE__ */ jsx("div", { className: "px-6 py-4", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.empty") }) }) : Object.entries(byCategory).map(([category, group]) => /* @__PURE__ */ jsxs("div", { className: "px-6 py-4", children: [
50
- /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", children: t(`integration.categories.${category}`) }),
51
- /* @__PURE__ */ jsx("div", { className: "mt-2 flex flex-col gap-2", children: group.map((i) => {
52
- const configured = i.is_configured && i.is_enabled;
53
- return /* @__PURE__ */ jsxs(
54
- Link,
236
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between px-6 py-4", children: [
237
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
238
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: t("integration.list.title") }),
239
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.subtitle") })
240
+ ] }),
241
+ /* @__PURE__ */ jsx(Button, { size: "small", variant: "primary", onClick: () => navigate("/settings/integrations/browse"), children: t("integration.list.browseIntegrations") })
242
+ ] }),
243
+ /* @__PURE__ */ jsxs(DataTable, { instance: table, className: "[&_td]:py-3", children: [
244
+ /* @__PURE__ */ jsx(DataTable.Toolbar, { children: /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-3", children: [
245
+ /* @__PURE__ */ jsx(
246
+ Tabs,
55
247
  {
56
- to: `/settings/integrations/${i.provider_id}`,
57
- className: "flex items-center justify-between rounded-md border px-3 py-2 hover:bg-ui-bg-base-hover",
58
- children: [
59
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
60
- /* @__PURE__ */ jsx(IntegrationIcon, { src: i.icon, alt: t(i.display_name), size: "small" }),
61
- /* @__PURE__ */ jsx(Text, { size: "small", children: t(i.display_name) }),
62
- i.instance_id && /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: i.instance_id })
63
- ] }),
64
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2", children: [
65
- i.last_test_status === "passed" && /* @__PURE__ */ jsx(Badge, { color: "green", size: "2xsmall", children: t("integration.list.tested") }),
66
- i.last_test_status === "failed" && /* @__PURE__ */ jsx(Badge, { color: "red", size: "2xsmall", children: t("integration.list.testFailed") }),
67
- i.is_configured && !i.is_complete ? /* @__PURE__ */ jsx(StatusBadge, { color: "orange", children: t("integration.status.incomplete") }) : /* @__PURE__ */ jsx(StatusBadge, { color: configured ? "green" : "grey", children: !i.is_configured ? t("integration.status.notConfigured") : i.is_enabled ? t("integration.status.enabled") : t("integration.status.disabled") })
68
- ] })
69
- ]
70
- },
71
- i.provider_id
72
- );
73
- }) })
74
- ] }, category))
248
+ value: activeTab,
249
+ onValueChange: (v) => {
250
+ setActiveTab(v);
251
+ setPagination((p) => ({ ...p, pageIndex: 0 }));
252
+ },
253
+ children: /* @__PURE__ */ jsxs(Tabs.List, { children: [
254
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "all", children: t("integration.list.tabs.all") }),
255
+ categories.map((c) => /* @__PURE__ */ jsx(Tabs.Trigger, { value: c, children: t(`integration.categories.${c}`) }, c))
256
+ ] })
257
+ }
258
+ ),
259
+ /* @__PURE__ */ jsx(DataTable.Search, { placeholder: t("integration.list.searchPlaceholder") })
260
+ ] }) }),
261
+ /* @__PURE__ */ jsx(
262
+ DataTable.Table,
263
+ {
264
+ emptyState: {
265
+ empty: { heading: isFiltered ? t("integration.list.emptyFiltered") : t("integration.list.empty") },
266
+ filtered: { heading: t("integration.list.emptyFiltered") }
267
+ }
268
+ }
269
+ ),
270
+ /* @__PURE__ */ jsx(DataTable.Pagination, {})
271
+ ] }),
272
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center px-6 py-4", children: /* @__PURE__ */ jsxs("a", { href: DOCS_URL, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
273
+ t("integration.list.learnMore"),
274
+ " →"
275
+ ] }) })
75
276
  ] });
76
277
  };
77
278
  const config = defineRouteConfig({
@@ -83,7 +284,7 @@ const IntegrationsBreadcrumb = () => {
83
284
  const { t } = useTranslation();
84
285
  return /* @__PURE__ */ jsx(Fragment, { children: t("integration.list.title") });
85
286
  };
86
- const handle$1 = {
287
+ const handle$2 = {
87
288
  breadcrumb: () => /* @__PURE__ */ jsx(IntegrationsBreadcrumb, {})
88
289
  };
89
290
  const Dash = () => /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: "-" });
@@ -1879,7 +2080,6 @@ const EditSectionDrawer = ({
1879
2080
  ] })
1880
2081
  ] }) });
1881
2082
  };
1882
- const testColor = (s) => s === "passed" ? "green" : s === "failed" ? "red" : "grey";
1883
2083
  const Row = ({ label, children }) => /* @__PURE__ */ jsxs("div", { className: "text-ui-fg-subtle grid grid-cols-2 px-6 py-4", children: [
1884
2084
  /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: label }),
1885
2085
  /* @__PURE__ */ jsx("div", { className: "flex items-center gap-x-2", children })
@@ -1951,9 +2151,14 @@ const EditPage = () => {
1951
2151
  if (!descriptor) {
1952
2152
  return /* @__PURE__ */ jsxs(Container, { className: "p-6", children: [
1953
2153
  /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.unknown", { id: provider_id }) }),
1954
- /* @__PURE__ */ jsx(Link, { to: "/settings/integrations", className: "text-ui-fg-interactive", children: t("integration.back") })
2154
+ /* @__PURE__ */ jsx(Link, { to: "/settings/integrations", className: "text-ui-fg-base", children: t("integration.back") })
1955
2155
  ] });
1956
2156
  }
2157
+ const version = (data == null ? void 0 : data.version) ?? null;
2158
+ const author = (data == null ? void 0 : data.author) ?? null;
2159
+ const authorUrl = (data == null ? void 0 : data.author_url) ?? null;
2160
+ 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") };
2161
+ 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;
1957
2162
  const editing = descriptor.sections.find((s) => s.id === editingSection) ?? null;
1958
2163
  const configuredSecrets = new Set((record == null ? void 0 : record.configured_secrets) ?? []);
1959
2164
  const sectionData = {
@@ -1989,40 +2194,62 @@ const EditPage = () => {
1989
2194
  const sideSections = descriptor.sections.filter((s) => s.column === "side");
1990
2195
  const main = /* @__PURE__ */ jsxs(Fragment, { children: [
1991
2196
  /* @__PURE__ */ jsx(LayoutComposer.Entry, { id: "main", children: /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
1992
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-6 py-4", children: [
1993
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
1994
- /* @__PURE__ */ jsx(IntegrationIcon, { src: descriptor.icon, alt: t(descriptor.displayName) }),
1995
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
1996
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
1997
- /* @__PURE__ */ jsx(Heading, { children: t(descriptor.displayName) }),
1998
- descriptor.instanceId && /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: descriptor.instanceId })
1999
- ] }),
2000
- descriptor.description && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t(descriptor.description) })
2001
- ] })
2002
- ] }),
2003
- isConfigured && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2004
- /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { size: "small", variant: "transparent", children: /* @__PURE__ */ jsx(EllipsisHorizontal, {}) }) }),
2005
- /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
2006
- descriptor.hasTestConnection && record.is_enabled && isComplete && /* @__PURE__ */ jsx(DropdownMenu.Item, { disabled: test.isPending, onClick: () => test.mutate(), children: t("integration.actions.test") }),
2007
- isConfigured && /* @__PURE__ */ jsx(
2008
- DropdownMenu.Item,
2009
- {
2010
- disabled: toggleEnabled.isPending,
2011
- onClick: () => toggleEnabled.mutate(!record.is_enabled),
2012
- children: record.is_enabled ? t("integration.actions.disable") : t("integration.actions.enable")
2013
- }
2014
- ),
2015
- isConfigured && /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
2016
- isConfigured && /* @__PURE__ */ jsxs(DropdownMenu.Item, { className: "gap-x-2", onClick: onDelete, children: [
2017
- /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
2018
- t("integration.actions.delete")
2197
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-3 px-6 py-4", children: [
2198
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
2199
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
2200
+ /* @__PURE__ */ jsx(IntegrationIcon, { src: descriptor.icon, alt: t(descriptor.displayName) }),
2201
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-1", children: [
2202
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
2203
+ /* @__PURE__ */ jsx(Heading, { children: t(descriptor.displayName) }),
2204
+ provider_id && /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: provider_id })
2205
+ ] }),
2206
+ version && /* @__PURE__ */ jsxs(Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: [
2207
+ t("integration.meta.version", { version }),
2208
+ author && /* @__PURE__ */ jsxs(Fragment, { children: [
2209
+ " • ",
2210
+ t("integration.meta.authorPrefix"),
2211
+ " ",
2212
+ authorUrl ? /* @__PURE__ */ jsx(
2213
+ "a",
2214
+ {
2215
+ href: authorUrl,
2216
+ target: "_blank",
2217
+ rel: "noreferrer",
2218
+ className: "text-ui-fg-interactive",
2219
+ children: author
2220
+ }
2221
+ ) : author
2222
+ ] })
2223
+ ] })
2224
+ ] })
2225
+ ] }),
2226
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
2227
+ /* @__PURE__ */ jsx(StatusBadge, { color: lifecycle.color, children: lifecycle.label }),
2228
+ connection && /* @__PURE__ */ jsx(StatusBadge, { color: connection.color, children: connection.label }),
2229
+ isConfigured && /* @__PURE__ */ jsxs(DropdownMenu, { children: [
2230
+ /* @__PURE__ */ jsx(DropdownMenu.Trigger, { asChild: true, children: /* @__PURE__ */ jsx(IconButton, { size: "small", variant: "transparent", children: /* @__PURE__ */ jsx(EllipsisHorizontal, {}) }) }),
2231
+ /* @__PURE__ */ jsxs(DropdownMenu.Content, { children: [
2232
+ descriptor.hasTestConnection && record.is_enabled && isComplete && /* @__PURE__ */ jsx(DropdownMenu.Item, { disabled: test.isPending, onClick: () => test.mutate(), children: t("integration.actions.test") }),
2233
+ isConfigured && /* @__PURE__ */ jsx(
2234
+ DropdownMenu.Item,
2235
+ {
2236
+ disabled: toggleEnabled.isPending,
2237
+ onClick: () => toggleEnabled.mutate(!record.is_enabled),
2238
+ children: record.is_enabled ? t("integration.actions.disable") : t("integration.actions.enable")
2239
+ }
2240
+ ),
2241
+ isConfigured && /* @__PURE__ */ jsx(DropdownMenu.Separator, {}),
2242
+ isConfigured && /* @__PURE__ */ jsxs(DropdownMenu.Item, { className: "gap-x-2", onClick: onDelete, children: [
2243
+ /* @__PURE__ */ jsx(Trash, { className: "text-ui-fg-subtle" }),
2244
+ t("integration.actions.delete")
2245
+ ] })
2246
+ ] })
2019
2247
  ] })
2020
2248
  ] })
2021
- ] })
2249
+ ] }),
2250
+ descriptor.description && /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t(descriptor.description) })
2022
2251
  ] }),
2023
- /* @__PURE__ */ jsx(Row, { label: t("integration.labels.status"), children: !isConfigured ? /* @__PURE__ */ jsx(StatusBadge, { color: "grey", children: t("integration.status.notConfigured") }) : !isComplete ? /* @__PURE__ */ jsx(StatusBadge, { color: "orange", children: t("integration.status.incomplete") }) : /* @__PURE__ */ jsx(StatusBadge, { color: record.is_enabled ? "green" : "grey", children: record.is_enabled ? t("integration.status.enabled") : t("integration.status.disabled") }) }),
2024
- /* @__PURE__ */ jsx(Row, { label: t("integration.labels.category"), children: /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: t(`integration.categories.${descriptor.category}`) }) }),
2025
- /* @__PURE__ */ jsx(Row, { label: t("integration.labels.lastTest"), children: (record == null ? void 0 : record.last_test_status) ? /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(StatusBadge, { color: testColor(record.last_test_status), children: t(`integration.testStatus.${record.last_test_status}`) }) }) : /* @__PURE__ */ jsx(Text, { size: "small", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.labels.neverTested") }) })
2252
+ /* @__PURE__ */ jsx(Row, { label: t("integration.labels.category"), children: /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: t(`integration.categories.${descriptor.category}`) }) })
2026
2253
  ] }) }),
2027
2254
  mainSections.map(renderSection),
2028
2255
  editing && /* @__PURE__ */ jsx(
@@ -2059,50 +2286,199 @@ const IntegrationBreadcrumb = ({ params }) => {
2059
2286
  enabled: !!providerId
2060
2287
  });
2061
2288
  const descriptor = data == null ? void 0 : data.descriptor;
2062
- if (!descriptor) return /* @__PURE__ */ jsx(Fragment, { children: providerId });
2289
+ if (!descriptor) return /* @__PURE__ */ jsx(Fragment, {});
2063
2290
  const name = t(descriptor.displayName);
2064
- return /* @__PURE__ */ jsx(Fragment, { children: descriptor.instanceId ? `${name} · ${descriptor.instanceId}` : name });
2291
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
2292
+ name + " ",
2293
+ /* @__PURE__ */ jsx(Badge, { size: "2xsmall", color: "grey", children: providerId })
2294
+ ] });
2065
2295
  };
2066
- const handle = {
2296
+ const handle$1 = {
2067
2297
  breadcrumb: ({ params }) => /* @__PURE__ */ jsx(IntegrationBreadcrumb, { params })
2068
2298
  };
2299
+ const PUBLISH_URL = "https://docs.gorgojs.com/integrations";
2300
+ const API_URL = "https://gorgojs.com";
2301
+ const InstallModal = ({ item, onOpenChange }) => {
2302
+ const { t } = useTranslation();
2303
+ return /* @__PURE__ */ jsx(Drawer, { open: !!item, onOpenChange, children: /* @__PURE__ */ jsxs(Drawer.Content, { children: [
2304
+ /* @__PURE__ */ jsx(Drawer.Header, { children: /* @__PURE__ */ jsx(Drawer.Title, { asChild: true, children: /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-2", children: [
2305
+ item && /* @__PURE__ */ jsx(IntegrationIcon, { src: API_URL + item.icon, alt: item.label, size: "small" }),
2306
+ /* @__PURE__ */ jsx("span", { children: item == null ? void 0 : item.label })
2307
+ ] }) }) }),
2308
+ /* @__PURE__ */ jsx(Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children: item && /* @__PURE__ */ jsxs(Fragment, { children: [
2309
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.install_addToConfig") }),
2310
+ /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-between gap-x-2 rounded-md px-3 py-2", children: [
2311
+ /* @__PURE__ */ jsx("code", { className: "txt-compact-small text-ui-fg-subtle", children: `npm i ${item.npm}` }),
2312
+ /* @__PURE__ */ jsx(Copy, { content: `npm i ${item.npm}` })
2313
+ ] }),
2314
+ item.configSnippet && /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 py-2", children: [
2315
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
2316
+ /* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: "medusa-config.ts" }),
2317
+ /* @__PURE__ */ jsx(Copy, { content: item.configSnippet })
2318
+ ] }),
2319
+ /* @__PURE__ */ jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre", children: item.configSnippet })
2320
+ ] }),
2321
+ /* @__PURE__ */ jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
2322
+ t("integration.browse.install_docs"),
2323
+ " →"
2324
+ ] })
2325
+ ] }) }),
2326
+ /* @__PURE__ */ jsx(Drawer.Footer, { children: /* @__PURE__ */ jsx(Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }) })
2327
+ ] }) });
2328
+ };
2329
+ const BrowsePage = () => {
2330
+ const { t } = useTranslation();
2331
+ const navigate = useNavigate();
2332
+ const [activeTab, setActiveTab] = useState("all");
2333
+ const [search, setSearch] = useState("");
2334
+ const [installItem, setInstallItem] = useState(null);
2335
+ const { data, isLoading } = useQuery({
2336
+ queryKey: ["integration-catalog"],
2337
+ queryFn: () => sdk.client.fetch("/admin/integrations/catalog")
2338
+ });
2339
+ const items = (data == null ? void 0 : data.integrations) ?? [];
2340
+ const categories = useMemo(() => [...new Set(items.map((i) => i.category))], [items]);
2341
+ const q = search.trim().toLowerCase();
2342
+ const filtered = items.filter((i) => {
2343
+ if (activeTab !== "all" && i.category !== activeTab) return false;
2344
+ if (q && ![i.label, i.shortDescription, i.npm].some((s) => s.toLowerCase().includes(q))) return false;
2345
+ return true;
2346
+ });
2347
+ return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-y-3", children: [
2348
+ /* @__PURE__ */ jsxs(Container, { className: "divide-y p-0", children: [
2349
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between px-6 py-4", children: [
2350
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-1", children: [
2351
+ /* @__PURE__ */ jsx(Heading, { level: "h2", children: t("integration.browse.title") }),
2352
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.subtitle") })
2353
+ ] }),
2354
+ false
2355
+ ] }),
2356
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3 px-6 py-4", children: [
2357
+ /* @__PURE__ */ jsx(Tabs, { value: activeTab, onValueChange: setActiveTab, children: /* @__PURE__ */ jsxs(Tabs.List, { children: [
2358
+ /* @__PURE__ */ jsx(Tabs.Trigger, { value: "all", children: t("integration.list.tabs.all") }),
2359
+ categories.map((c) => /* @__PURE__ */ jsx(Tabs.Trigger, { value: c, children: t(`integration.categories.${c}`) }, c))
2360
+ ] }) }),
2361
+ /* @__PURE__ */ jsx("div", { className: "w-64", children: /* @__PURE__ */ jsx(
2362
+ Input,
2363
+ {
2364
+ placeholder: t("integration.browse.searchPlaceholder"),
2365
+ value: search,
2366
+ onChange: (e) => setSearch(e.target.value)
2367
+ }
2368
+ ) })
2369
+ ] })
2370
+ ] }),
2371
+ isLoading ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx(Spinner, { className: "text-ui-fg-subtle animate-spin" }) }) : filtered.length === 0 ? /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center py-8", children: /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.list.emptyFiltered") }) }) : /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 md:grid-cols-2 xl:grid-cols-4", children: filtered.map((item) => /* @__PURE__ */ jsxs("div", { className: "shadow-borders-base bg-ui-bg-base flex flex-col rounded-lg", children: [
2372
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-y-3 p-4", children: [
2373
+ /* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
2374
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
2375
+ /* @__PURE__ */ jsx(IntegrationIcon, { src: API_URL + item.icon, alt: item.label }),
2376
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
2377
+ /* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.label }),
2378
+ /* @__PURE__ */ jsx(Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.browse.by", { author: item.authorLocalized }) })
2379
+ ] })
2380
+ ] }),
2381
+ /* @__PURE__ */ jsx(StatusBadge, { color: item.installed ? "green" : "grey", children: item.installed ? t("integration.browse.installed") : t("integration.browse.notInstalled") })
2382
+ ] }),
2383
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle line-clamp-2", children: item.shortDescription })
2384
+ ] }),
2385
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between border-t px-4 py-3", children: [
2386
+ item.installed && item.provider_id ? /* @__PURE__ */ jsx(
2387
+ Button,
2388
+ {
2389
+ size: "small",
2390
+ variant: "primary",
2391
+ onClick: () => navigate(`/settings/integrations/${item.provider_id}`),
2392
+ children: t("integration.browse.settings")
2393
+ }
2394
+ ) : /* @__PURE__ */ jsxs(Button, { size: "small", variant: "secondary", onClick: () => setInstallItem(item), children: [
2395
+ /* @__PURE__ */ jsx(Plus, {}),
2396
+ t("integration.browse.add")
2397
+ ] }),
2398
+ /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t(`integration.categories.${item.category}`) })
2399
+ ] })
2400
+ ] }, item.integrationId)) }),
2401
+ /* @__PURE__ */ jsx(Container, { className: "flex items-center justify-center p-4", children: /* @__PURE__ */ jsxs("a", { href: PUBLISH_URL, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
2402
+ t("integration.browse.learnMore"),
2403
+ " →"
2404
+ ] }) }),
2405
+ /* @__PURE__ */ jsx(InstallModal, { item: installItem, onOpenChange: (open) => !open && setInstallItem(null) })
2406
+ ] });
2407
+ };
2408
+ const BrowseBreadcrumb = () => {
2409
+ const { t } = useTranslation();
2410
+ return /* @__PURE__ */ jsx(Fragment, { children: t("integration.browse.title") });
2411
+ };
2412
+ const handle = {
2413
+ breadcrumb: () => /* @__PURE__ */ jsx(BrowseBreadcrumb, {})
2414
+ };
2069
2415
  const integration$1 = {
2070
2416
  list: {
2071
2417
  title: "Integrations",
2418
+ subtitle: "Manage integrations settings",
2419
+ browseIntegrations: "Browse Integrations",
2420
+ learnMore: "Learn how to build integrations",
2421
+ searchPlaceholder: "Search integrations",
2072
2422
  empty: "No integrations registered. Declare providers under the integration plugin's options.providers in medusa-config.",
2423
+ emptyFiltered: "No integrations match your filters.",
2073
2424
  tested: "tested",
2074
- testFailed: "test failed"
2425
+ testFailed: "test failed",
2426
+ tabs: {
2427
+ all: "All"
2428
+ }
2429
+ },
2430
+ browse: {
2431
+ title: "Browse",
2432
+ subtitle: "Find available integrations",
2433
+ publish: "Add Integration",
2434
+ learnMore: "Learn how to build and publish your own integration",
2435
+ searchPlaceholder: "Search integrations",
2436
+ by: "by {{author}}",
2437
+ installed: "Installed",
2438
+ notInstalled: "Not installed",
2439
+ add: "Add",
2440
+ settings: "Settings",
2441
+ install_addToConfig: "Add this to your medusa-config.ts and restart the server.",
2442
+ install_docs: "Documentation"
2443
+ },
2444
+ columns: {
2445
+ integration: "Integration",
2446
+ description: "Description",
2447
+ category: "Category",
2448
+ status: "Status"
2075
2449
  },
2076
2450
  status: {
2077
2451
  notConfigured: "Not configured",
2078
2452
  incomplete: "Incomplete",
2079
2453
  enabled: "Enabled",
2080
2454
  disabled: "Disabled",
2081
- configured: "Configured"
2455
+ configured: "Configured",
2456
+ connected: "Connected",
2457
+ connectionFailed: "Connection failed"
2458
+ },
2459
+ meta: {
2460
+ version: "v{{version}}",
2461
+ authorPrefix: "by"
2082
2462
  },
2083
2463
  labels: {
2084
- status: "Status",
2085
- category: "Category",
2086
- lastTest: "Last test",
2087
- neverTested: "Never tested"
2464
+ category: "Category"
2088
2465
  },
2089
2466
  categories: {
2090
2467
  payment: "Payment",
2468
+ notification: "Notification",
2091
2469
  fulfillment: "Fulfillment",
2092
- marketplace: "Marketplace",
2093
- crm: "CRM",
2470
+ search: "Search",
2471
+ content: "Content",
2472
+ analytics: "Analytics",
2473
+ authentication: "Authentication",
2094
2474
  erp: "ERP",
2475
+ crm: "CRM",
2095
2476
  pim: "PIM",
2096
- notification: "Notification",
2477
+ marketplace: "Marketplace",
2097
2478
  feed: "Feed",
2098
- tax: "Tax",
2479
+ file_providers: "File providers",
2099
2480
  other: "Other"
2100
2481
  },
2101
- testStatus: {
2102
- passed: "Passed",
2103
- failed: "Failed",
2104
- skipped: "Skipped"
2105
- },
2106
2482
  actions: {
2107
2483
  test: "Test connection",
2108
2484
  enable: "Enable",
@@ -2142,40 +2518,70 @@ const en = {
2142
2518
  const integration = {
2143
2519
  list: {
2144
2520
  title: "Интеграции",
2521
+ subtitle: "Управление настройками интеграций",
2522
+ browseIntegrations: "Найти интеграции",
2523
+ learnMore: "Как создавать интеграции",
2524
+ searchPlaceholder: "Поиск интеграций",
2145
2525
  empty: "Нет зарегистрированных интеграций. Объявите провайдеров в options.providers плагина интеграций в medusa-config.",
2526
+ emptyFiltered: "Нет интеграций по заданным фильтрам",
2146
2527
  tested: "проверено",
2147
- testFailed: "ошибка проверки"
2528
+ testFailed: "ошибка проверки",
2529
+ tabs: {
2530
+ all: "Все"
2531
+ }
2532
+ },
2533
+ browse: {
2534
+ title: "Каталог",
2535
+ subtitle: "Поиск доступных интеграций",
2536
+ publish: "Добавить интеграцию",
2537
+ learnMore: "Как создать и опубликовать свою интеграцию",
2538
+ searchPlaceholder: "Поиск интеграций",
2539
+ by: "от {{author}}",
2540
+ installed: "Установлено",
2541
+ notInstalled: "Не установлено",
2542
+ add: "Добавить",
2543
+ settings: "Настройки",
2544
+ install_addToConfig: "Добавьте это в medusa-config.ts и перезапустите сервер.",
2545
+ install_docs: "Документация"
2546
+ },
2547
+ columns: {
2548
+ integration: "Интеграция",
2549
+ description: "Описание",
2550
+ category: "Категория",
2551
+ status: "Статус"
2148
2552
  },
2149
2553
  status: {
2150
2554
  notConfigured: "Не настроено",
2151
2555
  incomplete: "Не завершено",
2152
2556
  enabled: "Включено",
2153
2557
  disabled: "Выключено",
2154
- configured: "Настроено"
2558
+ configured: "Настроено",
2559
+ connected: "Подключено",
2560
+ connectionFailed: "Ошибка подключения"
2561
+ },
2562
+ meta: {
2563
+ version: "v{{version}}",
2564
+ authorPrefix: "от"
2155
2565
  },
2156
2566
  labels: {
2157
- status: "Статус",
2158
- category: "Категория",
2159
- lastTest: "Последняя проверка",
2160
- neverTested: "Не проверялось"
2567
+ category: "Категория"
2161
2568
  },
2162
2569
  categories: {
2163
2570
  payment: "Платежи",
2571
+ notification: "Уведомления",
2164
2572
  fulfillment: "Доставка",
2165
- marketplace: "Маркетплейс",
2166
- crm: "CRM",
2573
+ search: "Поиск",
2574
+ content: "Контент",
2575
+ analytics: "Аналитика",
2576
+ authentication: "Аутентификация",
2167
2577
  erp: "ERP",
2578
+ crm: "CRM",
2168
2579
  pim: "PIM",
2169
- notification: "Уведомления",
2580
+ marketplace: "Маркетплейс",
2170
2581
  feed: "Фиды",
2171
- tax: "Налоги",
2582
+ file_providers: "Файловые провайдеры",
2172
2583
  other: "Прочее"
2173
2584
  },
2174
- testStatus: {
2175
- passed: "Пройдено",
2176
- failed: "Ошибка",
2177
- skipped: "Пропущено"
2178
- },
2179
2585
  actions: {
2180
2586
  test: "Проверить соединение",
2181
2587
  enable: "Включить",
@@ -2222,11 +2628,16 @@ const routeModule = {
2222
2628
  {
2223
2629
  Component: IntegrationsPage,
2224
2630
  path: "/settings/integrations",
2225
- handle: handle$1
2631
+ handle: { label: config.label, translationNs: config.translationNs, ...handle$2 }
2226
2632
  },
2227
2633
  {
2228
2634
  Component: EditPage,
2229
2635
  path: "/settings/integrations/:provider_id",
2636
+ handle: handle$1
2637
+ },
2638
+ {
2639
+ Component: BrowsePage,
2640
+ path: "/settings/integrations/browse",
2230
2641
  handle
2231
2642
  }
2232
2643
  ]
@@ -2248,6 +2659,7 @@ const displayModule = {
2248
2659
  displays: {}
2249
2660
  };
2250
2661
  const i18nModule = { resources: i18nTranslations0 };
2662
+ const cellRendererModule = {};
2251
2663
  const layoutModule = { layouts: [] };
2252
2664
  const plugin = {
2253
2665
  widgetModule,
@@ -2256,6 +2668,7 @@ const plugin = {
2256
2668
  formModule,
2257
2669
  displayModule,
2258
2670
  i18nModule,
2671
+ cellRendererModule,
2259
2672
  layoutModule
2260
2673
  };
2261
2674
  export {