@gorgo/medusa-integration 0.1.3 → 0.1.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 +218 -39
- package/.medusa/server/src/admin/index.mjs +219 -40
- package/.medusa/server/src/lib/__tests__/catalog-fallback.unit.spec.js +10 -5
- package/.medusa/server/src/lib/__tests__/catalog.unit.spec.js +64 -1
- package/.medusa/server/src/lib/catalog.generated.js +37 -21
- package/.medusa/server/src/lib/catalog.js +46 -2
- package/.medusa/server/src/lib/markdown/__tests__/inline.unit.spec.d.ts +1 -0
- package/.medusa/server/src/lib/markdown/__tests__/inline.unit.spec.js +90 -0
- package/.medusa/server/src/lib/markdown/__tests__/no-raw-html.unit.spec.d.ts +1 -0
- package/.medusa/server/src/lib/markdown/__tests__/no-raw-html.unit.spec.js +20 -0
- package/.medusa/server/src/lib/markdown/__tests__/parse.unit.spec.d.ts +1 -0
- package/.medusa/server/src/lib/markdown/__tests__/parse.unit.spec.js +91 -0
- package/.medusa/server/src/lib/markdown/href.d.ts +9 -0
- package/.medusa/server/src/lib/markdown/href.js +20 -0
- package/.medusa/server/src/lib/markdown/inline.d.ts +2 -0
- package/.medusa/server/src/lib/markdown/inline.js +51 -0
- package/.medusa/server/src/lib/markdown/parse.d.ts +12 -0
- package/.medusa/server/src/lib/markdown/parse.js +97 -0
- package/.medusa/server/src/lib/markdown/types.d.ts +39 -0
- package/.medusa/server/src/lib/markdown/types.js +3 -0
- package/.medusa/server/src/modules/integration/descriptor/__tests__/build-zod.unit.spec.js +30 -1
- package/.medusa/server/src/modules/integration/descriptor/__tests__/define.unit.spec.js +34 -1
- package/.medusa/server/src/modules/integration/descriptor/build-zod.js +11 -3
- package/.medusa/server/src/modules/integration/descriptor/define.js +13 -1
- package/.medusa/server/src/modules/integration/descriptor/option.d.ts +2 -2
- package/.medusa/server/src/types/http/integration/admin/entities.d.ts +11 -3
- package/.medusa/server/src/types/integration/common.d.ts +1 -1
- package/README.md +5 -5
- package/package.json +3 -2
|
@@ -1957,15 +1957,25 @@ function renderControl(field, f, secretConfigured, t) {
|
|
|
1957
1957
|
switch (field.control) {
|
|
1958
1958
|
case "switch":
|
|
1959
1959
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Switch, { checked: !!f.value, onCheckedChange: f.onChange, disabled });
|
|
1960
|
-
case "select":
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1960
|
+
case "select": {
|
|
1961
|
+
const declared = field.options ?? [];
|
|
1962
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1963
|
+
ui.Select,
|
|
1964
|
+
{
|
|
1965
|
+
value: f.value == null ? "" : String(f.value),
|
|
1966
|
+
onValueChange: (next) => f.onChange(declared.find((o) => String(o) === next) ?? next),
|
|
1967
|
+
disabled,
|
|
1968
|
+
children: [
|
|
1969
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Trigger, { children: /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Value, { placeholder }) }),
|
|
1970
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Select.Content, { children: declared.map((o) => {
|
|
1971
|
+
var _a;
|
|
1972
|
+
const labelKey = (_a = field.optionLabels) == null ? void 0 : _a[String(o)];
|
|
1973
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Select.Item, { value: String(o), children: labelKey ? t(labelKey) : String(o) }, String(o));
|
|
1974
|
+
}) })
|
|
1975
|
+
]
|
|
1976
|
+
}
|
|
1977
|
+
);
|
|
1978
|
+
}
|
|
1969
1979
|
case "number":
|
|
1970
1980
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1971
1981
|
ui.Input,
|
|
@@ -2300,38 +2310,205 @@ const IntegrationBreadcrumb = ({ params }) => {
|
|
|
2300
2310
|
const handle$1 = {
|
|
2301
2311
|
breadcrumb: ({ params }) => /* @__PURE__ */ jsxRuntime.jsx(IntegrationBreadcrumb, { params })
|
|
2302
2312
|
};
|
|
2313
|
+
function isSafeHref(raw) {
|
|
2314
|
+
try {
|
|
2315
|
+
return new URL(raw).protocol === "https:";
|
|
2316
|
+
} catch {
|
|
2317
|
+
return false;
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
const INLINE_RE = /`([^`\n]+)`|\[([^\]\n]*)\]\(([^)\s]+)\)|\*\*([^*\n]+)\*\*|\*([^*\n]+)\*|_([^_\n]+)_/;
|
|
2321
|
+
const MAX_DEPTH = 3;
|
|
2322
|
+
function parseInline(src, depth = 0) {
|
|
2323
|
+
if (!src) return [];
|
|
2324
|
+
if (depth >= MAX_DEPTH) return [{ type: "text", value: src }];
|
|
2325
|
+
const out = [];
|
|
2326
|
+
const re = new RegExp(INLINE_RE, "g");
|
|
2327
|
+
let last = 0;
|
|
2328
|
+
let m;
|
|
2329
|
+
while ((m = re.exec(src)) !== null) {
|
|
2330
|
+
const [full, code, linkText, linkHref, strong, star, underscore] = m;
|
|
2331
|
+
if (m.index > last) out.push({ type: "text", value: src.slice(last, m.index) });
|
|
2332
|
+
last = m.index + full.length;
|
|
2333
|
+
if (code !== void 0) {
|
|
2334
|
+
out.push({ type: "code", value: code });
|
|
2335
|
+
} else if (linkHref !== void 0) {
|
|
2336
|
+
const isImage = m.index > 0 && src[m.index - 1] === "!";
|
|
2337
|
+
if (!isImage && isSafeHref(linkHref)) {
|
|
2338
|
+
out.push({ type: "link", href: linkHref, children: parseInline(linkText, depth + 1) });
|
|
2339
|
+
} else {
|
|
2340
|
+
out.push({ type: "text", value: full });
|
|
2341
|
+
}
|
|
2342
|
+
} else if (strong !== void 0) {
|
|
2343
|
+
out.push({ type: "strong", children: parseInline(strong, depth + 1) });
|
|
2344
|
+
} else {
|
|
2345
|
+
out.push({ type: "em", children: parseInline(star ?? underscore, depth + 1) });
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
if (last < src.length) out.push({ type: "text", value: src.slice(last) });
|
|
2349
|
+
return out;
|
|
2350
|
+
}
|
|
2351
|
+
const MD_MAX_CHARS = 8e3;
|
|
2352
|
+
const MD_MAX_BLOCKS = 200;
|
|
2353
|
+
const FENCE_RE = /^```(.*)$/;
|
|
2354
|
+
const HEADING_RE = /^(#{1,3})\s+(.*)$/;
|
|
2355
|
+
const HR_RE = /^-{3,}\s*$/;
|
|
2356
|
+
const UL_RE = /^[-*]\s+(.*)$/;
|
|
2357
|
+
const OL_RE = /^\d+\.\s+(.*)$/;
|
|
2358
|
+
function fenceLabel(info) {
|
|
2359
|
+
const first = info.trim().split(/\s+/)[0] ?? "";
|
|
2360
|
+
return first.replace(/[^a-zA-Z0-9._/-]/g, "").slice(0, 40) || null;
|
|
2361
|
+
}
|
|
2362
|
+
function parseMarkdown(src) {
|
|
2363
|
+
if (typeof src !== "string" || !src) return [];
|
|
2364
|
+
if (src.length > MD_MAX_CHARS) return [{ type: "truncated" }];
|
|
2365
|
+
const lines = src.replace(/\r\n?/g, "\n").split("\n");
|
|
2366
|
+
const blocks = [];
|
|
2367
|
+
let para = [];
|
|
2368
|
+
const flushPara = () => {
|
|
2369
|
+
if (!para.length) return;
|
|
2370
|
+
blocks.push({ type: "paragraph", children: parseInline(para.join(" ")) });
|
|
2371
|
+
para = [];
|
|
2372
|
+
};
|
|
2373
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2374
|
+
const line = lines[i];
|
|
2375
|
+
const fence = FENCE_RE.exec(line);
|
|
2376
|
+
if (fence) {
|
|
2377
|
+
flushPara();
|
|
2378
|
+
const body = [];
|
|
2379
|
+
i++;
|
|
2380
|
+
while (i < lines.length && !FENCE_RE.test(lines[i])) body.push(lines[i++]);
|
|
2381
|
+
blocks.push({ type: "codeBlock", label: fenceLabel(fence[1]), value: body.join("\n") });
|
|
2382
|
+
continue;
|
|
2383
|
+
}
|
|
2384
|
+
if (!line.trim()) {
|
|
2385
|
+
flushPara();
|
|
2386
|
+
continue;
|
|
2387
|
+
}
|
|
2388
|
+
if (HR_RE.test(line)) {
|
|
2389
|
+
flushPara();
|
|
2390
|
+
blocks.push({ type: "hr" });
|
|
2391
|
+
continue;
|
|
2392
|
+
}
|
|
2393
|
+
const heading = HEADING_RE.exec(line);
|
|
2394
|
+
if (heading) {
|
|
2395
|
+
flushPara();
|
|
2396
|
+
blocks.push({
|
|
2397
|
+
type: "heading",
|
|
2398
|
+
level: heading[1].length + 1,
|
|
2399
|
+
children: parseInline(heading[2])
|
|
2400
|
+
});
|
|
2401
|
+
continue;
|
|
2402
|
+
}
|
|
2403
|
+
const ul = UL_RE.exec(line);
|
|
2404
|
+
const ol = ul ? null : OL_RE.exec(line);
|
|
2405
|
+
if (ul || ol) {
|
|
2406
|
+
flushPara();
|
|
2407
|
+
const ordered = !!ol;
|
|
2408
|
+
const itemRe = ordered ? OL_RE : UL_RE;
|
|
2409
|
+
const items = [];
|
|
2410
|
+
while (i < lines.length) {
|
|
2411
|
+
const item = itemRe.exec(lines[i]);
|
|
2412
|
+
if (!item) break;
|
|
2413
|
+
items.push(parseInline(item[1]));
|
|
2414
|
+
i++;
|
|
2415
|
+
}
|
|
2416
|
+
i--;
|
|
2417
|
+
blocks.push({ type: "list", ordered, items });
|
|
2418
|
+
continue;
|
|
2419
|
+
}
|
|
2420
|
+
para.push(line);
|
|
2421
|
+
}
|
|
2422
|
+
flushPara();
|
|
2423
|
+
const weight = blocks.reduce((n, b) => n + (b.type === "list" ? b.items.length : 1), 0);
|
|
2424
|
+
return weight > MD_MAX_BLOCKS ? [{ type: "truncated" }] : blocks;
|
|
2425
|
+
}
|
|
2426
|
+
const Inline = ({ nodes }) => /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: nodes.map((node, i) => {
|
|
2427
|
+
switch (node.type) {
|
|
2428
|
+
case "text":
|
|
2429
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { children: node.value }, i);
|
|
2430
|
+
case "code":
|
|
2431
|
+
return /* @__PURE__ */ jsxRuntime.jsx("code", { className: "txt-compact-small bg-ui-bg-component rounded px-1 py-0.5", children: node.value }, i);
|
|
2432
|
+
case "strong":
|
|
2433
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "txt-compact-small-plus", children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: node.children }) }, i);
|
|
2434
|
+
case "em":
|
|
2435
|
+
return /* @__PURE__ */ jsxRuntime.jsx("em", { children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: node.children }) }, i);
|
|
2436
|
+
case "link":
|
|
2437
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2438
|
+
"a",
|
|
2439
|
+
{
|
|
2440
|
+
href: node.href,
|
|
2441
|
+
target: "_blank",
|
|
2442
|
+
rel: "noopener noreferrer",
|
|
2443
|
+
className: "text-ui-fg-interactive hover:underline",
|
|
2444
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: node.children })
|
|
2445
|
+
},
|
|
2446
|
+
i
|
|
2447
|
+
);
|
|
2448
|
+
}
|
|
2449
|
+
}) });
|
|
2450
|
+
const Block = ({ block, truncatedLabel }) => {
|
|
2451
|
+
switch (block.type) {
|
|
2452
|
+
case "heading":
|
|
2453
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Heading, { level: block.level === 2 ? "h2" : "h3", children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: block.children }) });
|
|
2454
|
+
case "paragraph":
|
|
2455
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: block.children }) });
|
|
2456
|
+
case "list": {
|
|
2457
|
+
const List = block.ordered ? "ol" : "ul";
|
|
2458
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2459
|
+
List,
|
|
2460
|
+
{
|
|
2461
|
+
className: `text-ui-fg-subtle txt-small flex flex-col gap-y-1 pl-5 ${block.ordered ? "list-decimal" : "list-disc"}`,
|
|
2462
|
+
children: block.items.map((item, i) => /* @__PURE__ */ jsxRuntime.jsx("li", { children: /* @__PURE__ */ jsxRuntime.jsx(Inline, { nodes: item }) }, i))
|
|
2463
|
+
}
|
|
2464
|
+
);
|
|
2465
|
+
}
|
|
2466
|
+
case "codeBlock":
|
|
2467
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 pb-1 pt-2", children: [
|
|
2468
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
|
|
2469
|
+
block.label ? /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: block.label }) : /* @__PURE__ */ jsxRuntime.jsx("span", {}),
|
|
2470
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: block.value })
|
|
2471
|
+
] }),
|
|
2472
|
+
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre pb-2", children: block.value })
|
|
2473
|
+
] });
|
|
2474
|
+
case "hr":
|
|
2475
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-ui-border-base border-t" });
|
|
2476
|
+
case "truncated":
|
|
2477
|
+
return /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-muted", children: truncatedLabel });
|
|
2478
|
+
}
|
|
2479
|
+
};
|
|
2480
|
+
const Markdown = ({
|
|
2481
|
+
source,
|
|
2482
|
+
truncatedLabel
|
|
2483
|
+
}) => {
|
|
2484
|
+
const blocks = React.useMemo(() => parseMarkdown(source), [source]);
|
|
2485
|
+
if (!blocks.length) return null;
|
|
2486
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-y-4", children: blocks.map((block, i) => /* @__PURE__ */ jsxRuntime.jsx(Block, { block, truncatedLabel }, i)) });
|
|
2487
|
+
};
|
|
2303
2488
|
const PUBLISH_URL = "https://docs.gorgojs.com/medusa-modules/integration";
|
|
2304
2489
|
const API_URL = "https://gorgojs.com";
|
|
2305
|
-
const
|
|
2306
|
-
|
|
2490
|
+
const iconSrc = (icon) => icon.startsWith("data:") ? icon : API_URL + icon;
|
|
2491
|
+
const InstallModal = ({
|
|
2492
|
+
item,
|
|
2493
|
+
onOpenChange
|
|
2494
|
+
}) => {
|
|
2495
|
+
var _a, _b, _c;
|
|
2496
|
+
const { t, i18n } = reactI18next.useTranslation();
|
|
2497
|
+
const lang = i18n.language.split("-")[0] === "ru" ? "ru" : "en";
|
|
2498
|
+
const source = ((_a = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _a[lang]) || ((_b = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _b.en) || ((_c = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _c.ru) || "";
|
|
2307
2499
|
return /* @__PURE__ */ jsxRuntime.jsx(ui.Drawer, { open: !!item, onOpenChange, children: /* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Content, { children: [
|
|
2308
2500
|
/* @__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:
|
|
2501
|
+
item && /* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: iconSrc(item.icon), alt: item.label, size: "small" }),
|
|
2310
2502
|
/* @__PURE__ */ jsxRuntime.jsx("span", { children: item == null ? void 0 : item.label })
|
|
2311
2503
|
] }) }) }),
|
|
2312
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children:
|
|
2313
|
-
|
|
2314
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2315
|
-
|
|
2316
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: `yarn add @gorgo/medusa-integration ${item.npm}@beta` })
|
|
2317
|
-
] }),
|
|
2318
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-between gap-x-2 rounded-md px-3 py-2", children: [
|
|
2319
|
-
/* @__PURE__ */ jsxRuntime.jsx("code", { className: "txt-compact-small text-ui-fg-subtle", children: `npm install @gorgo/medusa-integration ${item.npm}@beta` }),
|
|
2320
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: `npm install @gorgo/medusa-integration ${item.npm}@beta` })
|
|
2321
|
-
] }),
|
|
2322
|
-
item.configSnippet && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 py-2", children: [
|
|
2323
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
|
|
2324
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: "medusa-config.ts" }),
|
|
2325
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.Copy, { content: item.configSnippet })
|
|
2326
|
-
] }),
|
|
2327
|
-
/* @__PURE__ */ jsxRuntime.jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre", children: item.configSnippet })
|
|
2328
|
-
] }),
|
|
2329
|
-
/* @__PURE__ */ jsxRuntime.jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
|
|
2504
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children: source.trim() ? /* @__PURE__ */ jsxRuntime.jsx(Markdown, { source, truncatedLabel: t("integration.browse.install_truncated") }) : /* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.install_empty") }) }),
|
|
2505
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.Drawer.Footer, { children: [
|
|
2506
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }),
|
|
2507
|
+
(item == null ? void 0 : item.docsUrl) && /* @__PURE__ */ jsxRuntime.jsx(ui.Button, { size: "small", variant: "primary", asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noopener noreferrer", children: [
|
|
2330
2508
|
t("integration.browse.install_docs"),
|
|
2331
|
-
|
|
2332
|
-
] })
|
|
2333
|
-
] })
|
|
2334
|
-
/* @__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") }) }) })
|
|
2509
|
+
/* @__PURE__ */ jsxRuntime.jsx(icons.ArrowUpRightOnBox, {})
|
|
2510
|
+
] }) })
|
|
2511
|
+
] })
|
|
2335
2512
|
] }) });
|
|
2336
2513
|
};
|
|
2337
2514
|
const BrowsePage = () => {
|
|
@@ -2380,7 +2557,7 @@ const BrowsePage = () => {
|
|
|
2380
2557
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-1 flex-col gap-y-3 p-4", children: [
|
|
2381
2558
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
|
|
2382
2559
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-x-3", children: [
|
|
2383
|
-
/* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src:
|
|
2560
|
+
/* @__PURE__ */ jsxRuntime.jsx(IntegrationIcon, { src: iconSrc(item.icon), alt: item.label }),
|
|
2384
2561
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
|
|
2385
2562
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "small", weight: "plus", leading: "compact", children: item.label }),
|
|
2386
2563
|
/* @__PURE__ */ jsxRuntime.jsx(ui.Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.browse.by", { author: item.authorLocalized }) })
|
|
@@ -2446,8 +2623,9 @@ const integration$1 = {
|
|
|
2446
2623
|
notInstalled: "Not installed",
|
|
2447
2624
|
add: "Add",
|
|
2448
2625
|
settings: "Settings",
|
|
2449
|
-
|
|
2450
|
-
|
|
2626
|
+
install_docs: "Read docs",
|
|
2627
|
+
install_empty: "Setup instructions for this integration aren't available yet.",
|
|
2628
|
+
install_truncated: "These instructions are too long to show here — open the documentation."
|
|
2451
2629
|
},
|
|
2452
2630
|
columns: {
|
|
2453
2631
|
integration: "Integration",
|
|
@@ -2549,8 +2727,9 @@ const integration = {
|
|
|
2549
2727
|
notInstalled: "Не установлено",
|
|
2550
2728
|
add: "Добавить",
|
|
2551
2729
|
settings: "Настройки",
|
|
2552
|
-
|
|
2553
|
-
|
|
2730
|
+
install_docs: "Читать документацию",
|
|
2731
|
+
install_empty: "Инструкция по настройке для этой интеграции пока недоступна.",
|
|
2732
|
+
install_truncated: "Инструкция слишком длинная для показа здесь — откройте документацию."
|
|
2554
2733
|
},
|
|
2555
2734
|
columns: {
|
|
2556
2735
|
integration: "Интеграция",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { defineRouteConfig } from "@medusajs/admin-sdk";
|
|
3
|
-
import { PuzzleSolid, CogSixTooth, Trash, Spinner, EllipsisHorizontal, PencilSquare, Plus } from "@medusajs/icons";
|
|
3
|
+
import { PuzzleSolid, CogSixTooth, Trash, Spinner, EllipsisHorizontal, PencilSquare, Plus, ArrowUpRightOnBox } from "@medusajs/icons";
|
|
4
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
5
|
import { useQueryClient, useQuery, keepPreviousData, useMutation } from "@tanstack/react-query";
|
|
6
6
|
import React, { useState, useMemo } from "react";
|
|
@@ -1953,15 +1953,25 @@ function renderControl(field, f, secretConfigured, t) {
|
|
|
1953
1953
|
switch (field.control) {
|
|
1954
1954
|
case "switch":
|
|
1955
1955
|
return /* @__PURE__ */ jsx(Switch, { checked: !!f.value, onCheckedChange: f.onChange, disabled });
|
|
1956
|
-
case "select":
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1956
|
+
case "select": {
|
|
1957
|
+
const declared = field.options ?? [];
|
|
1958
|
+
return /* @__PURE__ */ jsxs(
|
|
1959
|
+
Select,
|
|
1960
|
+
{
|
|
1961
|
+
value: f.value == null ? "" : String(f.value),
|
|
1962
|
+
onValueChange: (next) => f.onChange(declared.find((o) => String(o) === next) ?? next),
|
|
1963
|
+
disabled,
|
|
1964
|
+
children: [
|
|
1965
|
+
/* @__PURE__ */ jsx(Select.Trigger, { children: /* @__PURE__ */ jsx(Select.Value, { placeholder }) }),
|
|
1966
|
+
/* @__PURE__ */ jsx(Select.Content, { children: declared.map((o) => {
|
|
1967
|
+
var _a;
|
|
1968
|
+
const labelKey = (_a = field.optionLabels) == null ? void 0 : _a[String(o)];
|
|
1969
|
+
return /* @__PURE__ */ jsx(Select.Item, { value: String(o), children: labelKey ? t(labelKey) : String(o) }, String(o));
|
|
1970
|
+
}) })
|
|
1971
|
+
]
|
|
1972
|
+
}
|
|
1973
|
+
);
|
|
1974
|
+
}
|
|
1965
1975
|
case "number":
|
|
1966
1976
|
return /* @__PURE__ */ jsx(
|
|
1967
1977
|
Input,
|
|
@@ -2296,38 +2306,205 @@ const IntegrationBreadcrumb = ({ params }) => {
|
|
|
2296
2306
|
const handle$1 = {
|
|
2297
2307
|
breadcrumb: ({ params }) => /* @__PURE__ */ jsx(IntegrationBreadcrumb, { params })
|
|
2298
2308
|
};
|
|
2309
|
+
function isSafeHref(raw) {
|
|
2310
|
+
try {
|
|
2311
|
+
return new URL(raw).protocol === "https:";
|
|
2312
|
+
} catch {
|
|
2313
|
+
return false;
|
|
2314
|
+
}
|
|
2315
|
+
}
|
|
2316
|
+
const INLINE_RE = /`([^`\n]+)`|\[([^\]\n]*)\]\(([^)\s]+)\)|\*\*([^*\n]+)\*\*|\*([^*\n]+)\*|_([^_\n]+)_/;
|
|
2317
|
+
const MAX_DEPTH = 3;
|
|
2318
|
+
function parseInline(src, depth = 0) {
|
|
2319
|
+
if (!src) return [];
|
|
2320
|
+
if (depth >= MAX_DEPTH) return [{ type: "text", value: src }];
|
|
2321
|
+
const out = [];
|
|
2322
|
+
const re = new RegExp(INLINE_RE, "g");
|
|
2323
|
+
let last = 0;
|
|
2324
|
+
let m;
|
|
2325
|
+
while ((m = re.exec(src)) !== null) {
|
|
2326
|
+
const [full, code, linkText, linkHref, strong, star, underscore] = m;
|
|
2327
|
+
if (m.index > last) out.push({ type: "text", value: src.slice(last, m.index) });
|
|
2328
|
+
last = m.index + full.length;
|
|
2329
|
+
if (code !== void 0) {
|
|
2330
|
+
out.push({ type: "code", value: code });
|
|
2331
|
+
} else if (linkHref !== void 0) {
|
|
2332
|
+
const isImage = m.index > 0 && src[m.index - 1] === "!";
|
|
2333
|
+
if (!isImage && isSafeHref(linkHref)) {
|
|
2334
|
+
out.push({ type: "link", href: linkHref, children: parseInline(linkText, depth + 1) });
|
|
2335
|
+
} else {
|
|
2336
|
+
out.push({ type: "text", value: full });
|
|
2337
|
+
}
|
|
2338
|
+
} else if (strong !== void 0) {
|
|
2339
|
+
out.push({ type: "strong", children: parseInline(strong, depth + 1) });
|
|
2340
|
+
} else {
|
|
2341
|
+
out.push({ type: "em", children: parseInline(star ?? underscore, depth + 1) });
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
if (last < src.length) out.push({ type: "text", value: src.slice(last) });
|
|
2345
|
+
return out;
|
|
2346
|
+
}
|
|
2347
|
+
const MD_MAX_CHARS = 8e3;
|
|
2348
|
+
const MD_MAX_BLOCKS = 200;
|
|
2349
|
+
const FENCE_RE = /^```(.*)$/;
|
|
2350
|
+
const HEADING_RE = /^(#{1,3})\s+(.*)$/;
|
|
2351
|
+
const HR_RE = /^-{3,}\s*$/;
|
|
2352
|
+
const UL_RE = /^[-*]\s+(.*)$/;
|
|
2353
|
+
const OL_RE = /^\d+\.\s+(.*)$/;
|
|
2354
|
+
function fenceLabel(info) {
|
|
2355
|
+
const first = info.trim().split(/\s+/)[0] ?? "";
|
|
2356
|
+
return first.replace(/[^a-zA-Z0-9._/-]/g, "").slice(0, 40) || null;
|
|
2357
|
+
}
|
|
2358
|
+
function parseMarkdown(src) {
|
|
2359
|
+
if (typeof src !== "string" || !src) return [];
|
|
2360
|
+
if (src.length > MD_MAX_CHARS) return [{ type: "truncated" }];
|
|
2361
|
+
const lines = src.replace(/\r\n?/g, "\n").split("\n");
|
|
2362
|
+
const blocks = [];
|
|
2363
|
+
let para = [];
|
|
2364
|
+
const flushPara = () => {
|
|
2365
|
+
if (!para.length) return;
|
|
2366
|
+
blocks.push({ type: "paragraph", children: parseInline(para.join(" ")) });
|
|
2367
|
+
para = [];
|
|
2368
|
+
};
|
|
2369
|
+
for (let i = 0; i < lines.length; i++) {
|
|
2370
|
+
const line = lines[i];
|
|
2371
|
+
const fence = FENCE_RE.exec(line);
|
|
2372
|
+
if (fence) {
|
|
2373
|
+
flushPara();
|
|
2374
|
+
const body = [];
|
|
2375
|
+
i++;
|
|
2376
|
+
while (i < lines.length && !FENCE_RE.test(lines[i])) body.push(lines[i++]);
|
|
2377
|
+
blocks.push({ type: "codeBlock", label: fenceLabel(fence[1]), value: body.join("\n") });
|
|
2378
|
+
continue;
|
|
2379
|
+
}
|
|
2380
|
+
if (!line.trim()) {
|
|
2381
|
+
flushPara();
|
|
2382
|
+
continue;
|
|
2383
|
+
}
|
|
2384
|
+
if (HR_RE.test(line)) {
|
|
2385
|
+
flushPara();
|
|
2386
|
+
blocks.push({ type: "hr" });
|
|
2387
|
+
continue;
|
|
2388
|
+
}
|
|
2389
|
+
const heading = HEADING_RE.exec(line);
|
|
2390
|
+
if (heading) {
|
|
2391
|
+
flushPara();
|
|
2392
|
+
blocks.push({
|
|
2393
|
+
type: "heading",
|
|
2394
|
+
level: heading[1].length + 1,
|
|
2395
|
+
children: parseInline(heading[2])
|
|
2396
|
+
});
|
|
2397
|
+
continue;
|
|
2398
|
+
}
|
|
2399
|
+
const ul = UL_RE.exec(line);
|
|
2400
|
+
const ol = ul ? null : OL_RE.exec(line);
|
|
2401
|
+
if (ul || ol) {
|
|
2402
|
+
flushPara();
|
|
2403
|
+
const ordered = !!ol;
|
|
2404
|
+
const itemRe = ordered ? OL_RE : UL_RE;
|
|
2405
|
+
const items = [];
|
|
2406
|
+
while (i < lines.length) {
|
|
2407
|
+
const item = itemRe.exec(lines[i]);
|
|
2408
|
+
if (!item) break;
|
|
2409
|
+
items.push(parseInline(item[1]));
|
|
2410
|
+
i++;
|
|
2411
|
+
}
|
|
2412
|
+
i--;
|
|
2413
|
+
blocks.push({ type: "list", ordered, items });
|
|
2414
|
+
continue;
|
|
2415
|
+
}
|
|
2416
|
+
para.push(line);
|
|
2417
|
+
}
|
|
2418
|
+
flushPara();
|
|
2419
|
+
const weight = blocks.reduce((n, b) => n + (b.type === "list" ? b.items.length : 1), 0);
|
|
2420
|
+
return weight > MD_MAX_BLOCKS ? [{ type: "truncated" }] : blocks;
|
|
2421
|
+
}
|
|
2422
|
+
const Inline = ({ nodes }) => /* @__PURE__ */ jsx(Fragment, { children: nodes.map((node, i) => {
|
|
2423
|
+
switch (node.type) {
|
|
2424
|
+
case "text":
|
|
2425
|
+
return /* @__PURE__ */ jsx("span", { children: node.value }, i);
|
|
2426
|
+
case "code":
|
|
2427
|
+
return /* @__PURE__ */ jsx("code", { className: "txt-compact-small bg-ui-bg-component rounded px-1 py-0.5", children: node.value }, i);
|
|
2428
|
+
case "strong":
|
|
2429
|
+
return /* @__PURE__ */ jsx("span", { className: "txt-compact-small-plus", children: /* @__PURE__ */ jsx(Inline, { nodes: node.children }) }, i);
|
|
2430
|
+
case "em":
|
|
2431
|
+
return /* @__PURE__ */ jsx("em", { children: /* @__PURE__ */ jsx(Inline, { nodes: node.children }) }, i);
|
|
2432
|
+
case "link":
|
|
2433
|
+
return /* @__PURE__ */ jsx(
|
|
2434
|
+
"a",
|
|
2435
|
+
{
|
|
2436
|
+
href: node.href,
|
|
2437
|
+
target: "_blank",
|
|
2438
|
+
rel: "noopener noreferrer",
|
|
2439
|
+
className: "text-ui-fg-interactive hover:underline",
|
|
2440
|
+
children: /* @__PURE__ */ jsx(Inline, { nodes: node.children })
|
|
2441
|
+
},
|
|
2442
|
+
i
|
|
2443
|
+
);
|
|
2444
|
+
}
|
|
2445
|
+
}) });
|
|
2446
|
+
const Block = ({ block, truncatedLabel }) => {
|
|
2447
|
+
switch (block.type) {
|
|
2448
|
+
case "heading":
|
|
2449
|
+
return /* @__PURE__ */ jsx(Heading, { level: block.level === 2 ? "h2" : "h3", children: /* @__PURE__ */ jsx(Inline, { nodes: block.children }) });
|
|
2450
|
+
case "paragraph":
|
|
2451
|
+
return /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: /* @__PURE__ */ jsx(Inline, { nodes: block.children }) });
|
|
2452
|
+
case "list": {
|
|
2453
|
+
const List = block.ordered ? "ol" : "ul";
|
|
2454
|
+
return /* @__PURE__ */ jsx(
|
|
2455
|
+
List,
|
|
2456
|
+
{
|
|
2457
|
+
className: `text-ui-fg-subtle txt-small flex flex-col gap-y-1 pl-5 ${block.ordered ? "list-decimal" : "list-disc"}`,
|
|
2458
|
+
children: block.items.map((item, i) => /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsx(Inline, { nodes: item }) }, i))
|
|
2459
|
+
}
|
|
2460
|
+
);
|
|
2461
|
+
}
|
|
2462
|
+
case "codeBlock":
|
|
2463
|
+
return /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 pb-1 pt-2", children: [
|
|
2464
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
|
|
2465
|
+
block.label ? /* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: block.label }) : /* @__PURE__ */ jsx("span", {}),
|
|
2466
|
+
/* @__PURE__ */ jsx(Copy, { content: block.value })
|
|
2467
|
+
] }),
|
|
2468
|
+
/* @__PURE__ */ jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre pb-2", children: block.value })
|
|
2469
|
+
] });
|
|
2470
|
+
case "hr":
|
|
2471
|
+
return /* @__PURE__ */ jsx("div", { className: "border-ui-border-base border-t" });
|
|
2472
|
+
case "truncated":
|
|
2473
|
+
return /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-muted", children: truncatedLabel });
|
|
2474
|
+
}
|
|
2475
|
+
};
|
|
2476
|
+
const Markdown = ({
|
|
2477
|
+
source,
|
|
2478
|
+
truncatedLabel
|
|
2479
|
+
}) => {
|
|
2480
|
+
const blocks = useMemo(() => parseMarkdown(source), [source]);
|
|
2481
|
+
if (!blocks.length) return null;
|
|
2482
|
+
return /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-y-4", children: blocks.map((block, i) => /* @__PURE__ */ jsx(Block, { block, truncatedLabel }, i)) });
|
|
2483
|
+
};
|
|
2299
2484
|
const PUBLISH_URL = "https://docs.gorgojs.com/medusa-modules/integration";
|
|
2300
2485
|
const API_URL = "https://gorgojs.com";
|
|
2301
|
-
const
|
|
2302
|
-
|
|
2486
|
+
const iconSrc = (icon) => icon.startsWith("data:") ? icon : API_URL + icon;
|
|
2487
|
+
const InstallModal = ({
|
|
2488
|
+
item,
|
|
2489
|
+
onOpenChange
|
|
2490
|
+
}) => {
|
|
2491
|
+
var _a, _b, _c;
|
|
2492
|
+
const { t, i18n } = useTranslation();
|
|
2493
|
+
const lang = i18n.language.split("-")[0] === "ru" ? "ru" : "en";
|
|
2494
|
+
const source = ((_a = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _a[lang]) || ((_b = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _b.en) || ((_c = item == null ? void 0 : item.docsSnippet) == null ? void 0 : _c.ru) || "";
|
|
2303
2495
|
return /* @__PURE__ */ jsx(Drawer, { open: !!item, onOpenChange, children: /* @__PURE__ */ jsxs(Drawer.Content, { children: [
|
|
2304
2496
|
/* @__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:
|
|
2497
|
+
item && /* @__PURE__ */ jsx(IntegrationIcon, { src: iconSrc(item.icon), alt: item.label, size: "small" }),
|
|
2306
2498
|
/* @__PURE__ */ jsx("span", { children: item == null ? void 0 : item.label })
|
|
2307
2499
|
] }) }) }),
|
|
2308
|
-
/* @__PURE__ */ jsx(Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children:
|
|
2309
|
-
|
|
2310
|
-
/* @__PURE__ */
|
|
2311
|
-
|
|
2312
|
-
/* @__PURE__ */ jsx(Copy, { content: `yarn add @gorgo/medusa-integration ${item.npm}@beta` })
|
|
2313
|
-
] }),
|
|
2314
|
-
/* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex items-center justify-between gap-x-2 rounded-md px-3 py-2", children: [
|
|
2315
|
-
/* @__PURE__ */ jsx("code", { className: "txt-compact-small text-ui-fg-subtle", children: `npm install @gorgo/medusa-integration ${item.npm}@beta` }),
|
|
2316
|
-
/* @__PURE__ */ jsx(Copy, { content: `npm install @gorgo/medusa-integration ${item.npm}@beta` })
|
|
2317
|
-
] }),
|
|
2318
|
-
item.configSnippet && /* @__PURE__ */ jsxs("div", { className: "bg-ui-bg-subtle flex flex-col gap-y-2 rounded-md px-3 py-2", children: [
|
|
2319
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-x-2", children: [
|
|
2320
|
-
/* @__PURE__ */ jsx(Text, { size: "xsmall", weight: "plus", className: "text-ui-fg-subtle", children: "medusa-config.ts" }),
|
|
2321
|
-
/* @__PURE__ */ jsx(Copy, { content: item.configSnippet })
|
|
2322
|
-
] }),
|
|
2323
|
-
/* @__PURE__ */ jsx("pre", { className: "txt-compact-small text-ui-fg-subtle overflow-x-auto whitespace-pre", children: item.configSnippet })
|
|
2324
|
-
] }),
|
|
2325
|
-
/* @__PURE__ */ jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noreferrer", className: "text-ui-fg-base txt-small", children: [
|
|
2500
|
+
/* @__PURE__ */ jsx(Drawer.Body, { className: "flex flex-1 flex-col gap-y-4 overflow-auto", children: source.trim() ? /* @__PURE__ */ jsx(Markdown, { source, truncatedLabel: t("integration.browse.install_truncated") }) : /* @__PURE__ */ jsx(Text, { size: "small", className: "text-ui-fg-subtle", children: t("integration.browse.install_empty") }) }),
|
|
2501
|
+
/* @__PURE__ */ jsxs(Drawer.Footer, { children: [
|
|
2502
|
+
/* @__PURE__ */ jsx(Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }),
|
|
2503
|
+
(item == null ? void 0 : item.docsUrl) && /* @__PURE__ */ jsx(Button, { size: "small", variant: "primary", asChild: true, children: /* @__PURE__ */ jsxs("a", { href: item.docsUrl, target: "_blank", rel: "noopener noreferrer", children: [
|
|
2326
2504
|
t("integration.browse.install_docs"),
|
|
2327
|
-
|
|
2328
|
-
] })
|
|
2329
|
-
] })
|
|
2330
|
-
/* @__PURE__ */ jsx(Drawer.Footer, { children: /* @__PURE__ */ jsx(Drawer.Close, { asChild: true, children: /* @__PURE__ */ jsx(Button, { size: "small", variant: "secondary", children: t("integration.actions.cancel") }) }) })
|
|
2505
|
+
/* @__PURE__ */ jsx(ArrowUpRightOnBox, {})
|
|
2506
|
+
] }) })
|
|
2507
|
+
] })
|
|
2331
2508
|
] }) });
|
|
2332
2509
|
};
|
|
2333
2510
|
const BrowsePage = () => {
|
|
@@ -2376,7 +2553,7 @@ const BrowsePage = () => {
|
|
|
2376
2553
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-1 flex-col gap-y-3 p-4", children: [
|
|
2377
2554
|
/* @__PURE__ */ jsxs("div", { className: "flex items-start justify-between gap-x-2", children: [
|
|
2378
2555
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-x-3", children: [
|
|
2379
|
-
/* @__PURE__ */ jsx(IntegrationIcon, { src:
|
|
2556
|
+
/* @__PURE__ */ jsx(IntegrationIcon, { src: iconSrc(item.icon), alt: item.label }),
|
|
2380
2557
|
/* @__PURE__ */ jsxs("div", { className: "flex flex-col", children: [
|
|
2381
2558
|
/* @__PURE__ */ jsx(Text, { size: "small", weight: "plus", leading: "compact", children: item.label }),
|
|
2382
2559
|
/* @__PURE__ */ jsx(Text, { size: "xsmall", leading: "compact", className: "text-ui-fg-subtle", children: t("integration.browse.by", { author: item.authorLocalized }) })
|
|
@@ -2442,8 +2619,9 @@ const integration$1 = {
|
|
|
2442
2619
|
notInstalled: "Not installed",
|
|
2443
2620
|
add: "Add",
|
|
2444
2621
|
settings: "Settings",
|
|
2445
|
-
|
|
2446
|
-
|
|
2622
|
+
install_docs: "Read docs",
|
|
2623
|
+
install_empty: "Setup instructions for this integration aren't available yet.",
|
|
2624
|
+
install_truncated: "These instructions are too long to show here — open the documentation."
|
|
2447
2625
|
},
|
|
2448
2626
|
columns: {
|
|
2449
2627
|
integration: "Integration",
|
|
@@ -2545,8 +2723,9 @@ const integration = {
|
|
|
2545
2723
|
notInstalled: "Не установлено",
|
|
2546
2724
|
add: "Добавить",
|
|
2547
2725
|
settings: "Настройки",
|
|
2548
|
-
|
|
2549
|
-
|
|
2726
|
+
install_docs: "Читать документацию",
|
|
2727
|
+
install_empty: "Инструкция по настройке для этой интеграции пока недоступна.",
|
|
2728
|
+
install_truncated: "Инструкция слишком длинная для показа здесь — откройте документацию."
|
|
2550
2729
|
},
|
|
2551
2730
|
columns: {
|
|
2552
2731
|
integration: "Интеграция",
|