@revenexx/studio-integrations 2.9.0 → 2.10.0
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/CHANGELOG.md +6 -0
- package/dist/module.json +2 -2
- package/dist/runtime/components/Integrations/NodePalette.vue +3 -7
- package/dist/runtime/components/Integrations/WorkflowNodeView.vue +8 -0
- package/dist/runtime/data/integrationTemplates.js +3 -4
- package/dist/runtime/utils/apiError.js +7 -4
- package/dist/runtime/utils/packageLabel.d.ts +17 -0
- package/dist/runtime/utils/packageLabel.js +6 -0
- package/package.json +3 -3
- package/dist/runtime/components/Integrations/NodeLogo.d.vue.ts +0 -21
- package/dist/runtime/components/Integrations/NodeLogo.vue +0 -10
- package/dist/runtime/components/Integrations/NodeLogo.vue.d.ts +0 -21
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# @revenexx/studio-integrations
|
|
2
2
|
|
|
3
|
+
## 2.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 0a303a8: A node card names the package its node comes from, on the line under the name and in front of the version: `ERPNext · v1.0.0`, `Core · v1.0.0`. Until now only the vendor's logo in the corner said so, which tells nobody who does not know the logo, and core nodes carry none. A node its author has renamed shows the package here too. A package version that declares no label is named after its package name, the same way the template gallery names it. The card does not grow (PO-823).
|
|
8
|
+
|
|
3
9
|
## 2.9.0
|
|
4
10
|
|
|
5
11
|
### Minor Changes
|
package/dist/module.json
CHANGED
|
@@ -7,6 +7,7 @@ import { INTEGRATION_NODE_CATALOG, isOffered, NODE_CATEGORIES, TRIGGER_TEMPLATES
|
|
|
7
7
|
import { resolveLocalized, studioLocale } from "../../utils/localize";
|
|
8
8
|
import { orderFolderLeaves, orderFolders } from "../../utils/paletteOrder";
|
|
9
9
|
import { declaredFolderIcon } from "../../utils/folderMark";
|
|
10
|
+
import { packageLabel, packageTail } from "../../utils/packageLabel";
|
|
10
11
|
import { nodeIcon } from "../../data/nodeIcons";
|
|
11
12
|
const { load: loadNodes } = useIntegrationsNodes();
|
|
12
13
|
onMounted(() => {
|
|
@@ -54,11 +55,6 @@ const VERB_PREFIX = /^(create|get|list|update|delete|search|send|sync|upsert|can
|
|
|
54
55
|
function titleize(kebab) {
|
|
55
56
|
return kebab.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" ");
|
|
56
57
|
}
|
|
57
|
-
function packageAppLabel(pkg) {
|
|
58
|
-
if (pkg.label) return pkg.label;
|
|
59
|
-
const tail = pkg.name.split("/").pop() ?? pkg.name;
|
|
60
|
-
return titleize(tail.replace(/^integrations-nodes-/, ""));
|
|
61
|
-
}
|
|
62
58
|
function isAppPackage(pkg) {
|
|
63
59
|
if (!pkg) return false;
|
|
64
60
|
const tail = pkg.name.split("/").pop() ?? pkg.name;
|
|
@@ -74,9 +70,9 @@ function groupPath(m) {
|
|
|
74
70
|
return [coreFolder(m).label, ...path.slice(1)];
|
|
75
71
|
}
|
|
76
72
|
if (isAppPackage(m.__package)) {
|
|
77
|
-
const app =
|
|
73
|
+
const app = packageLabel(m.__package);
|
|
78
74
|
const local = m.slug.split(":").pop() ?? m.slug;
|
|
79
|
-
const pkgKey = (m.__package.name
|
|
75
|
+
const pkgKey = packageTail(m.__package.name);
|
|
80
76
|
const rest = local.startsWith(`${pkgKey}-`) ? local.slice(pkgKey.length + 1) : local;
|
|
81
77
|
const verb = VERB_PREFIX.exec(rest);
|
|
82
78
|
return verb ? [app, titleize(verb[2])] : [app];
|
|
@@ -13,6 +13,7 @@ import { resolveLocalized } from "../../utils/localize";
|
|
|
13
13
|
import { SIDE_POSITION, distributedStyle, spacedByLabel } from "./canvasSides";
|
|
14
14
|
import { fieldDisplayLabel, nodeDisplayLabel } from "../../utils/validationFindings";
|
|
15
15
|
import { nodeDisplayName } from "../../utils/nodeDisplayName";
|
|
16
|
+
import { packageLabel } from "../../utils/packageLabel";
|
|
16
17
|
const props = defineProps({
|
|
17
18
|
id: { type: String, required: true },
|
|
18
19
|
data: { type: Object, required: true },
|
|
@@ -24,6 +25,7 @@ const t = useIntegrationsT();
|
|
|
24
25
|
const manifest = computed(() => findManifest(props.data.nodeSlug, props.data.nodeVersion));
|
|
25
26
|
const category = computed(() => NODE_CATEGORIES.find((c) => c.key === manifest.value?.category));
|
|
26
27
|
const title = computed(() => nodeDisplayName(props.data));
|
|
28
|
+
const fromPackage = computed(() => manifest.value?.__package ? packageLabel(manifest.value.__package) : null);
|
|
27
29
|
const invalidFields = computed(() => props.data.__invalidFields ?? []);
|
|
28
30
|
const invalidLabel = computed(() => t("integration.canvas.node.badge.invalidConfig", invalidFields.value.length, {
|
|
29
31
|
fields: invalidFields.value.map((key) => fieldDisplayLabel(props.data, key)).join(", ")
|
|
@@ -573,6 +575,12 @@ function remove() {
|
|
|
573
575
|
inspector. Left-aligned and on the second line, clear of the
|
|
574
576
|
top-right edit affordance (PO-192). -->
|
|
575
577
|
<div v-if="data.nodeVersion" class="mt-0.5 flex items-center gap-1.5 text-sm text-muted-foreground">
|
|
578
|
+
<span
|
|
579
|
+
v-if="fromPackage"
|
|
580
|
+
:title="fromPackage"
|
|
581
|
+
class="min-w-0 truncate text-[10px] font-medium leading-none text-muted-foreground/70"
|
|
582
|
+
>{{ fromPackage }}</span>
|
|
583
|
+
<span v-if="fromPackage" aria-hidden="true" class="text-[10px] leading-none text-muted-foreground/40">·</span>
|
|
576
584
|
<span
|
|
577
585
|
class="shrink-0 text-[10px] font-medium leading-none tabular-nums text-muted-foreground/55"
|
|
578
586
|
:title="t('integration.canvas.node.meta.versionTitle', { version: data.nodeVersion })"
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useIntegrationsT } from "../composables/useIntegrationsT.js";
|
|
2
|
+
import { packageLabel, packageTail } from "../utils/packageLabel.js";
|
|
2
3
|
export const TEMPLATE_CATEGORIES = [
|
|
3
4
|
// Uniform muted pill — the label carries the meaning, no rainbow needed.
|
|
4
5
|
{ key: "commerce", label: "Commerce", color: "bg-slate-100 text-slate-700" },
|
|
@@ -23,8 +24,6 @@ export function templateCategoryLabel(key) {
|
|
|
23
24
|
}
|
|
24
25
|
export function templatePackageLabel(tpl) {
|
|
25
26
|
const pkg = tpl.package;
|
|
26
|
-
if (!pkg) return null;
|
|
27
|
-
|
|
28
|
-
if (tail === "core") return null;
|
|
29
|
-
return pkg.label ?? tail.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" ");
|
|
27
|
+
if (!pkg || packageTail(pkg.name) === "core") return null;
|
|
28
|
+
return packageLabel(pkg);
|
|
30
29
|
}
|
|
@@ -23,11 +23,14 @@ export function apiRefusal(err, drawn) {
|
|
|
23
23
|
if (!(err instanceof IntegrationsApiError) || err.status !== 422) return refusal;
|
|
24
24
|
const errors = err.body?.errors;
|
|
25
25
|
if (!errors || typeof errors !== "object") return refusal;
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const entries = Object.entries(errors).filter(([key]) => key !== "blob" && !key.startsWith("blob.")).map(([key, val]) => ({
|
|
27
|
+
key,
|
|
28
|
+
messages: (Array.isArray(val) ? val : [val]).filter((message) => message !== void 0 && message !== null).map(String)
|
|
29
|
+
}));
|
|
30
|
+
for (const { key, messages } of entries) {
|
|
30
31
|
if (!messages.length) continue;
|
|
32
|
+
const isContainerOnly = !drawn.includes(key);
|
|
33
|
+
if (isContainerOnly && entries.some((other) => other.key.startsWith(`${key}.`) && other.messages.length)) continue;
|
|
31
34
|
if (drawn.includes(key)) refusal.atFields[key] = messages[0];
|
|
32
35
|
else refusal.unshown.push(...messages.map((message) => ({ key, message })));
|
|
33
36
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a node package is called where a person reads it: the label the package
|
|
3
|
+
* declares, or — for a version published before packages carried one — its npm
|
|
4
|
+
* name without scope and `integrations-nodes-` prefix, title-cased.
|
|
5
|
+
*
|
|
6
|
+
* One function because three surfaces name packages: the palette's folder for
|
|
7
|
+
* an app package, the template gallery's badge for the integration a template
|
|
8
|
+
* ships with, and the canvas card's line for the package a node comes from. They
|
|
9
|
+
* must not disagree on what a package is called. An empty label counts as none,
|
|
10
|
+
* as it always has in the palette.
|
|
11
|
+
*/
|
|
12
|
+
export declare function packageLabel(pkg: {
|
|
13
|
+
name: string;
|
|
14
|
+
label?: string | null;
|
|
15
|
+
}): string;
|
|
16
|
+
/** The npm name without scope and `integrations-nodes-` prefix: `erpnext`, `core`. */
|
|
17
|
+
export declare function packageTail(name: string): string;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export function packageLabel(pkg) {
|
|
2
|
+
return pkg.label || packageTail(pkg.name).split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join(" ");
|
|
3
|
+
}
|
|
4
|
+
export function packageTail(name) {
|
|
5
|
+
return (name.split("/").pop() ?? name).replace(/^integrations-nodes-/, "");
|
|
6
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@revenexx/studio-integrations",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.10.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Integration Studio (core: workflows, node editor, runs, schedules, credentials, secrets, audit) as a standalone, publishable Nuxt module.",
|
|
6
6
|
"repository": {
|
|
@@ -56,8 +56,8 @@
|
|
|
56
56
|
"@changesets/cli": "^3.0.3",
|
|
57
57
|
"@nuxt/eslint-config": "^1.17.0",
|
|
58
58
|
"@nuxt/kit": "^4.0.0",
|
|
59
|
-
"@nuxt/module-builder": "^1.0.
|
|
60
|
-
"@nuxt/schema": "^4.
|
|
59
|
+
"@nuxt/module-builder": "^1.0.3",
|
|
60
|
+
"@nuxt/schema": "^4.5.2",
|
|
61
61
|
"@playwright/test": "^1.57.0",
|
|
62
62
|
"@revenexx/talkback-js": "^0.3.0",
|
|
63
63
|
"eslint": "^10.11.0",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated Use `NodeMark` directly. This is a thin back-compat shim kept so
|
|
3
|
-
* that hosts still referencing the auto-registered `<IntegrationsNodeLogo>`
|
|
4
|
-
* (e.g. integrations/studio-ui `local-nodes.vue`) keep resolving the component
|
|
5
|
-
* after PO-194 renamed NodeLogo → NodeMark. Auto-registered components are
|
|
6
|
-
* public API surface for the hosts, so a silent delete breaks them at a
|
|
7
|
-
* different repo's build, invisible to this repo's CI.
|
|
8
|
-
*
|
|
9
|
-
* The old NodeLogo rendered "logo OR glyph, logo preferred" — exactly
|
|
10
|
-
* `NodeMark`'s `logo-only` behaviour (logo when present, glyph fallback). Drop
|
|
11
|
-
* this shim one release after the hosts have migrated to `NodeMark`.
|
|
12
|
-
*/
|
|
13
|
-
import type { NodeManifest } from '../../types/integrations.js';
|
|
14
|
-
type __VLS_Props = {
|
|
15
|
-
manifest: NodeManifest | null;
|
|
16
|
-
size?: number;
|
|
17
|
-
};
|
|
18
|
-
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
19
|
-
size: number;
|
|
20
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
-
export default _default;
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @deprecated Use `NodeMark` directly. This is a thin back-compat shim kept so
|
|
3
|
-
* that hosts still referencing the auto-registered `<IntegrationsNodeLogo>`
|
|
4
|
-
* (e.g. integrations/studio-ui `local-nodes.vue`) keep resolving the component
|
|
5
|
-
* after PO-194 renamed NodeLogo → NodeMark. Auto-registered components are
|
|
6
|
-
* public API surface for the hosts, so a silent delete breaks them at a
|
|
7
|
-
* different repo's build, invisible to this repo's CI.
|
|
8
|
-
*
|
|
9
|
-
* The old NodeLogo rendered "logo OR glyph, logo preferred" — exactly
|
|
10
|
-
* `NodeMark`'s `logo-only` behaviour (logo when present, glyph fallback). Drop
|
|
11
|
-
* this shim one release after the hosts have migrated to `NodeMark`.
|
|
12
|
-
*/
|
|
13
|
-
import type { NodeManifest } from '../../types/integrations.js';
|
|
14
|
-
type __VLS_Props = {
|
|
15
|
-
manifest: NodeManifest | null;
|
|
16
|
-
size?: number;
|
|
17
|
-
};
|
|
18
|
-
declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {
|
|
19
|
-
size: number;
|
|
20
|
-
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
-
export default _default;
|