From 8790a0df3de2bc6a1909358017abf6734823faad Mon Sep 17 00:00:00 2001 From: Elias Meire Date: Wed, 5 Mar 2025 10:29:13 +0100 Subject: [PATCH] feat(editor): Schema preview UI updates (#13578) --- .../src/components/VirtualSchema.vue | 13 +- .../src/components/VirtualSchemaHeader.vue | 22 +- .../src/components/VirtualSchemaItem.vue | 27 ++- .../__snapshots__/VirtualSchema.test.ts.snap | 220 +++++++----------- .../src/composables/useDataSchema.ts | 23 +- packages/frontend/editor-ui/src/constants.ts | 1 + .../src/plugins/i18n/locales/en.json | 5 +- 7 files changed, 148 insertions(+), 163 deletions(-) diff --git a/packages/frontend/editor-ui/src/components/VirtualSchema.vue b/packages/frontend/editor-ui/src/components/VirtualSchema.vue index 87e259aeb5..ea6641f8f1 100644 --- a/packages/frontend/editor-ui/src/components/VirtualSchema.vue +++ b/packages/frontend/editor-ui/src/components/VirtualSchema.vue @@ -314,7 +314,7 @@ const onDragEnd = (el: HTMLElement) => { @click="toggleNodeAndScrollTop(item.id)" /> { @click="toggleLeaf(item.id)" > + + + + @@ -347,4 +351,11 @@ const onDragEnd = (el: HTMLElement) => { text-align: center; padding: var(--spacing-s) var(--spacing-s) var(--spacing-xl) var(--spacing-s); } + +.icon { + display: inline-flex; + margin-left: var(--spacing-xl); + color: var(--color-text-light); + margin-bottom: var(--spacing-s); +} diff --git a/packages/frontend/editor-ui/src/components/VirtualSchemaHeader.vue b/packages/frontend/editor-ui/src/components/VirtualSchemaHeader.vue index 65daae051d..497e040dc7 100644 --- a/packages/frontend/editor-ui/src/components/VirtualSchemaHeader.vue +++ b/packages/frontend/editor-ui/src/components/VirtualSchemaHeader.vue @@ -4,8 +4,7 @@ import NodeIcon from '@/components/NodeIcon.vue'; import { type INodeTypeDescription } from 'n8n-workflow'; import { useI18n } from '@/composables/useI18n'; import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'; -import { DATA_EDITING_DOCS_URL } from '@/constants'; -import { N8nNotice } from '@n8n/design-system'; +import { SCHEMA_PREVIEW_DOCS_URL } from '@/constants'; const props = defineProps<{ title: string; @@ -42,24 +41,28 @@ const emit = defineEmits<{ {{ info }} -
+
{{ i18n.baseText('ndv.output.items', { interpolate: { count: itemCount } }) }}
+
+ {{ i18n.baseText('dataMapping.schemaView.previewNode') }} +
- - + @@ -117,7 +120,7 @@ const emit = defineEmits<{ color: var(--color-primary); } -.item-count { +.extra-info { font-size: var(--font-size-2xs); color: var(--color-text-light); margin-left: auto; @@ -126,6 +129,9 @@ const emit = defineEmits<{ .notice { margin-left: var(--spacing-2xl); margin-top: var(--spacing-2xs); - margin-bottom: 0; + padding-bottom: var(--spacing-2xs); + color: var(--color-text-base); + font-size: var(--font-size-2xs); + line-height: var(--font-line-height-loose); } diff --git a/packages/frontend/editor-ui/src/components/VirtualSchemaItem.vue b/packages/frontend/editor-ui/src/components/VirtualSchemaItem.vue index e8c7df6792..0b9ee3242a 100644 --- a/packages/frontend/editor-ui/src/components/VirtualSchemaItem.vue +++ b/packages/frontend/editor-ui/src/components/VirtualSchemaItem.vue @@ -43,7 +43,10 @@ const emit = defineEmits<{ :data-node-type="nodeType" data-target="mappable" class="pill" - :class="{ 'pill--highlight': highlight, 'pill--preview': preview }" + :class="{ + 'pill--highlight': highlight, + 'pill--preview': preview, + }" data-test-id="run-data-schema-node-name" > @@ -77,6 +80,7 @@ const emit = defineEmits<{ justify-content: center; cursor: pointer; font-size: var(--font-size-s); + color: var(--color-text-light); } .pill { @@ -98,16 +102,31 @@ const emit = defineEmits<{ } &.pill--preview { - border-style: dashed; - border-width: 1.5px; + /* Cannot use CSS variable inside data URL, so instead switching based on data-theme and media query */ + --schema-preview-dashed-border: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' viewBox='0 0 400 400' fill='none' rx='4' ry='4' stroke='%230000002A' stroke-width='2' stroke-dasharray='4%2c 4' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e"); + --schema-preview-dashed-border-dark: url("data:image/svg+xml,%3csvg width='100%25' height='100%25' xmlns='http://www.w3.org/2000/svg'%3e%3crect width='100%25' height='100%25' viewBox='0 0 400 400' fill='none' rx='4' ry='4' stroke='%23FFFFFF2A' stroke-width='2' stroke-dasharray='4%2c 4' stroke-dashoffset='0' stroke-linecap='square'/%3e%3c/svg%3e"); + color: var(--color-text-light); + background-color: var(--color-run-data-background); + border: none; + max-width: calc(100% - var(--spacing-l)); + background-image: var(--schema-preview-dashed-border); .title { color: var(--color-text-light); - border-left: 1.5px dashed var(--color-foreground-light); } } } +@media (prefers-color-scheme: dark) { + body:not([data-theme]) .pill--preview { + background-image: var(--schema-preview-dashed-border-dark); + } +} + +[data-theme='dark'] .pill--preview { + background-image: var(--schema-preview-dashed-border-dark); +} + .draggable .pill.pill--highlight { color: var(--color-primary); border-color: var(--color-primary-tint-1); diff --git a/packages/frontend/editor-ui/src/components/__snapshots__/VirtualSchema.test.ts.snap b/packages/frontend/editor-ui/src/components/__snapshots__/VirtualSchema.test.ts.snap index 9d526dc740..8f72865bea 100644 --- a/packages/frontend/editor-ui/src/components/__snapshots__/VirtualSchema.test.ts.snap +++ b/packages/frontend/editor-ui/src/components/__snapshots__/VirtualSchema.test.ts.snap @@ -110,7 +110,12 @@ exports[`VirtualSchema.vue > renders preview schema when enabled and available 1 swapopacity="false" symbol="false" /> - +
+ Preview +
renders preview schema when enabled and available 1 theme="warning" > - - This is a preview of the schema, execute the node to see the exact schema and data. + Usually outputs the following fields. Execute the node to see the actual ones. @@ -133,7 +137,7 @@ exports[`VirtualSchema.vue > renders preview schema when enabled and available 1 class="primary" > @@ -146,7 +150,6 @@ exports[`VirtualSchema.vue > renders preview schema when enabled and available 1 -
@@ -328,70 +331,38 @@ exports[`VirtualSchema.vue > renders preview schema when enabled and available 1 -
-
- -
-
- - - - - - ... - - - -
- - - -
+ + + + + + + @@ -464,7 +435,12 @@ exports[`VirtualSchema.vue > renders preview schema when enabled and available 1 - +
+ Preview +
renders preview schema when enabled and available 1 theme="warning" > - - This is a preview of the schema, execute the node to see the exact schema and data. + Usually outputs the following fields. Execute the node to see the actual ones. @@ -487,7 +462,7 @@ exports[`VirtualSchema.vue > renders preview schema when enabled and available 1 class="primary" > @@ -500,7 +475,6 @@ exports[`VirtualSchema.vue > renders preview schema when enabled and available 1 -
@@ -682,70 +656,38 @@ exports[`VirtualSchema.vue > renders preview schema when enabled and available 1 -
-
- -
-
- - - - - - ... - - - -
- - - -
+ + + + + + + @@ -821,7 +763,7 @@ exports[`VirtualSchema.vue > renders previous nodes schema for AI tools 1`] = `
@@ -893,7 +835,7 @@ exports[`VirtualSchema.vue > renders schema for correct output branch 1`] = `
@@ -1447,7 +1389,7 @@ exports[`VirtualSchema.vue > renders schema with spaces and dots 1`] = ` symbol="false" />
diff --git a/packages/frontend/editor-ui/src/composables/useDataSchema.ts b/packages/frontend/editor-ui/src/composables/useDataSchema.ts index ee4b617cfb..20ab524fb0 100644 --- a/packages/frontend/editor-ui/src/composables/useDataSchema.ts +++ b/packages/frontend/editor-ui/src/composables/useDataSchema.ts @@ -261,7 +261,14 @@ export type RenderHeader = { preview?: boolean; }; -type Renders = RenderHeader | RenderItem; +export type RenderIcon = { + id: string; + type: 'icon'; + icon: string; + tooltip: string; +}; + +type Renders = RenderHeader | RenderItem | RenderIcon; const icons = { object: 'cube', @@ -285,13 +292,11 @@ const emptyItem = (): RenderItem => ({ type: 'item', }); -const dummyItem = (): RenderItem => ({ - id: `dummy-${window.crypto.randomUUID()}`, - icon: '', - level: 1, - title: '...', - type: 'item', - preview: true, +const moreFieldsItem = (): RenderIcon => ({ + id: `moreFields-${window.crypto.randomUUID()}`, + type: 'icon', + icon: 'ellipsis-h', + tooltip: useI18n().baseText('dataMapping.schemaView.previewExtraFields'), }); const isDataEmpty = (schema: Schema) => { @@ -445,7 +450,7 @@ export const useFlattenSchema = () => { acc.push(...flattenSchema(item)); if (item.preview) { - acc.push(dummyItem()); + acc.push(moreFieldsItem()); } return acc; diff --git a/packages/frontend/editor-ui/src/constants.ts b/packages/frontend/editor-ui/src/constants.ts index aefb6d574d..37fad8ca31 100644 --- a/packages/frontend/editor-ui/src/constants.ts +++ b/packages/frontend/editor-ui/src/constants.ts @@ -92,6 +92,7 @@ export const BUILTIN_NODES_DOCS_URL = `https://${DOCS_DOMAIN}/integrations/built export const BUILTIN_CREDENTIALS_DOCS_URL = `https://${DOCS_DOMAIN}/integrations/builtin/credentials/`; export const DATA_PINNING_DOCS_URL = `https://${DOCS_DOMAIN}/data/data-pinning/`; export const DATA_EDITING_DOCS_URL = `https://${DOCS_DOMAIN}/data/data-editing/`; +export const SCHEMA_PREVIEW_DOCS_URL = `https://${DOCS_DOMAIN}/data/schema-preview/`; export const MFA_DOCS_URL = `https://${DOCS_DOMAIN}/user-management/two-factor-auth/`; export const NPM_COMMUNITY_NODE_SEARCH_API_URL = 'https://api.npms.io/v2/'; export const NPM_PACKAGE_DOCS_BASE_URL = 'https://www.npmjs.com/package/'; diff --git a/packages/frontend/editor-ui/src/plugins/i18n/locales/en.json b/packages/frontend/editor-ui/src/plugins/i18n/locales/en.json index 0bce1a0310..579033ebe2 100644 --- a/packages/frontend/editor-ui/src/plugins/i18n/locales/en.json +++ b/packages/frontend/editor-ui/src/plugins/i18n/locales/en.json @@ -661,8 +661,9 @@ "dataMapping.schemaView.emptyData": "No fields - item(s) exist, but they're empty", "dataMapping.schemaView.disabled": "This node is disabled and will just pass data through", "dataMapping.schemaView.noMatches": "No results for '{search}'", - "dataMapping.schemaView.preview": "This is a preview of the schema, execute the node to see the exact schema and data. {link}", - "dataMapping.schemaView.previewNode": "(schema preview)", + "dataMapping.schemaView.preview": "Usually outputs the following fields. Execute the node to see the actual ones. {link}", + "dataMapping.schemaView.previewExtraFields": "There may be more fields. Execute the node to be sure.", + "dataMapping.schemaView.previewNode": "Preview", "displayWithChange.cancelEdit": "Cancel Edit", "displayWithChange.clickToChange": "Click to Change", "displayWithChange.setValue": "Set Value",