mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
feat(editor): Schema view (#4615)
* feat(editor): Generate custom schema from data (#4562) * feat(core): adding a type package to n8n * feat(editor): adding custom schema generator * fix: add new types package to lock file * fix: remove n8n_io/types package * fix: adding path to generated schema * fix: handling nested lists in schema generation * fix: add date support to schema generation * fix: define dates in ISO format * fix: using test instead of it in repeated tests * fix(editor): JSON schema treat nested lists as object to allow mapping each level * fix(editor): rename JSON schema type * fix(editor): make JSON schema path required * fix(editor): using JSON schema bracket notation for object props to handle exceptional keys * fix(editor): reorder JSON schema generator function args * feat(editor): Add date recognizer util function (#4620) * ✨ Implemented date recogniser fuction * ✅ Added unit tests for date recogniser * ✔️ Fixing linting errors * 👌 Updating test cases * feat(editor): Implement JSON Schema view UI functionalities (#4601) * feat(core): adding a type package to n8n * feat(editor): adding custom schema generator * fix: add new types package to lock file * fix: remove n8n_io/types package * fix: adding path to generated schema * fix: handling nested lists in schema generation * fix: add date support to schema generation * fix: define dates in ISO format * fix: using test instead of it in repeated tests * fix(editor): JSON schema treat nested lists as object to allow mapping each level * fix(editor): rename JSON schema type * fix(editor): make JSON schema path required * fix(editor): using JSON schema bracket notation for object props to handle exceptional keys * fix(editor): reorder JSON schema generator function args * fix(editor): WIP json schema view * fix(editor): formatting fix * fix(editor): WIP json schema viewer * fix(editor): fix schema generator and add deep merge * fix(editor): WIP update json schema view components * fix(editor): extend valid date checking * fix(editor): WIP improving JSON schema view * chore(editor): code formatting * feat(editor): WIP Json schema view mapping + animations * feat(editor): WIP update mergeDeep * feat(editor): adding first item of json data to the end once more to get sample data from the first item * feat(editor): adding first item of json data to the end once more to get sample data from the first item * fix(editor): improving draggable design * fix(editor): move util functions to their correct place after merge conflict * fix(editor): move some type guards * fix(editor): move some type guards * fix(editor): change import path in unit test * fix(editor): import missing interface * fix(editor): remove unused functions and parts from json schema generation * feat(editor): Add telemetry calls to JSON schema mapping (#4695) * feat(editor): WIP JSON schema telemetry call * feat(editor): make telemetry usable outside of Vue component context * chore(editor): remove unused variable * Merge branch 'feature/json-schema-view' of github.com:n8n-io/n8n into n8n-5410-add-telemetry-calls # Conflicts: # packages/editor-ui/src/components/RunDataJsonSchema.vue * fix(editor): VUE typing for telemetry * fix(editor): enable PostHog feature flag * fix(editor): Schema design review (#4740) * refactor(editor): rename JsonSchema to Schema * fix(editor): schema component name * fix(editor): schema pill style * fix(editor): schema type date as string * fix(editor): schema styles (support long text + firefox) * fix(editor): schema truncate text if it's too long * fix(editor): schema types * fix(editor): droppable styles * fix(editor): schema component props * fix(editor): fix draggable pill styles * fix(editor): schema view styles * fix(editor): schema mapping tooltip * fix(editor): schema mapping styles * fix(editor): mapping styles * fix(editor): empty schema case * fix(editor): delay mapping tooltip * test(editor): add schema view snapshot test * fix(editor): schema empty string * fix(editor): schema string without space * fix(editor): update schema test snapshot * fix(editor): applying review comments * fix(editor): make n8nExternalHooks optional * fix(editor): remove TODO comment Co-authored-by: Milorad FIlipović <milorad@n8n.io>
This commit is contained in:
267
packages/editor-ui/src/components/RunDataSchemaItem.vue
Normal file
267
packages/editor-ui/src/components/RunDataSchemaItem.vue
Normal file
@@ -0,0 +1,267 @@
|
||||
<script lang="ts" setup>
|
||||
import { computed } from 'vue';
|
||||
import { INodeUi, Schema } from "@/Interface";
|
||||
import { checkExhaustive, shorten } from "@/utils";
|
||||
|
||||
type Props = {
|
||||
schema: Schema
|
||||
level: number
|
||||
parent: Schema | null
|
||||
subKey: string
|
||||
mappingEnabled: boolean
|
||||
draggingPath: string
|
||||
distanceFromActive: number
|
||||
node: INodeUi | null
|
||||
}
|
||||
|
||||
const props = defineProps<Props>();
|
||||
|
||||
const isSchemaValueArray = computed(() => Array.isArray(props.schema.value));
|
||||
const isSchemaParentTypeArray = computed(() => props.parent?.type === 'array');
|
||||
const isFlat = computed(() => props.level === 0 && Array.isArray(props.schema.value) && props.schema.value.every(v => !Array.isArray(v.value)));
|
||||
const key = computed((): string | undefined => isSchemaParentTypeArray.value ? `[${props.schema.key}]` : props.schema.key);
|
||||
const schemaName = computed(() => isSchemaParentTypeArray.value ? `${props.schema.type}[${props.schema.key}]` : props.schema.key);
|
||||
const text = computed(() => Array.isArray(props.schema.value) ? '' : shorten(props.schema.value, 600, 0));
|
||||
|
||||
const getJsonParameterPath = (path: string): string => `{{ ${props.distanceFromActive === 1 ? '$json' : `$node["${ props.node!.name }"].json`}${path} }}`;
|
||||
const transitionDelay = (i:number) => `${i * 0.033}s`;
|
||||
|
||||
const getIconBySchemaType = (type: Schema['type']): string => {
|
||||
switch (type) {
|
||||
case 'object':
|
||||
return 'cube';
|
||||
case 'array':
|
||||
return 'list';
|
||||
case 'string':
|
||||
case 'null':
|
||||
return 'font';
|
||||
case 'number':
|
||||
return 'hashtag';
|
||||
case 'boolean':
|
||||
return 'check-square';
|
||||
case 'function':
|
||||
return 'code';
|
||||
case 'bigint':
|
||||
return 'calculator';
|
||||
case 'symbol':
|
||||
return 'sun';
|
||||
case 'undefined':
|
||||
return 'ban';
|
||||
}
|
||||
|
||||
checkExhaustive(type);
|
||||
};
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="$style.item">
|
||||
<div
|
||||
v-if="level > 0 || level === 0 && !isSchemaValueArray"
|
||||
:title="schema.type"
|
||||
:class="{
|
||||
[$style.pill]: true,
|
||||
[$style.mappable]: mappingEnabled,
|
||||
[$style.dragged]: draggingPath === schema.path,
|
||||
}"
|
||||
>
|
||||
<span
|
||||
:class="$style.label"
|
||||
:data-value="getJsonParameterPath(schema.path)"
|
||||
:data-name="schemaName"
|
||||
:data-path="schema.path"
|
||||
:data-depth="level"
|
||||
data-target="mappable"
|
||||
>
|
||||
<font-awesome-icon :icon="getIconBySchemaType(schema.type)" size="sm"/>
|
||||
<span v-if="isSchemaParentTypeArray">{{ parent.key }}</span>
|
||||
<span v-if="key" :class="{[$style.arrayIndex]: isSchemaParentTypeArray}">{{ key }}</span>
|
||||
</span>
|
||||
</div>
|
||||
<span v-if="text" :class="$style.text">{{ text }}</span>
|
||||
<input :id="subKey" type="checkbox" checked />
|
||||
<label v-if="level > 0 && isSchemaValueArray" :class="$style.toggle" :for="subKey">
|
||||
<font-awesome-icon icon="angle-up" />
|
||||
</label>
|
||||
<div v-if="isSchemaValueArray" :class="{[$style.sub]: true, [$style.flat]: isFlat}">
|
||||
<run-data-schema-item v-for="(s, i) in schema.value"
|
||||
:key="`${s.type}-${level}-${i}`"
|
||||
:schema="s"
|
||||
:level="level + 1"
|
||||
:parent="schema"
|
||||
:subKey="`${s.type}-${level}-${i}`"
|
||||
:mappingEnabled="mappingEnabled"
|
||||
:draggingPath="draggingPath"
|
||||
:distanceFromActive="distanceFromActive"
|
||||
:node="node"
|
||||
:style="{transitionDelay: transitionDelay(i)}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
@import '@/styles/css-animation-helpers.scss';
|
||||
|
||||
.item {
|
||||
display: block;
|
||||
position: relative;
|
||||
transition: all 0.3s $ease-out-expo;
|
||||
|
||||
.item {
|
||||
padding-top: var(--spacing-2xs);
|
||||
padding-left: var(--spacing-l);
|
||||
}
|
||||
|
||||
input {
|
||||
position: absolute;
|
||||
left: -100%;
|
||||
|
||||
~ .sub {
|
||||
height: 0;
|
||||
|
||||
> .item {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
}
|
||||
|
||||
&:checked {
|
||||
~ .toggle svg {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
~ .sub {
|
||||
height: auto;
|
||||
|
||||
> .item {
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&::after {
|
||||
content: '';
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
}
|
||||
|
||||
.sub {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
transition: all 0.2s $ease-out-expo;
|
||||
clear: both;
|
||||
|
||||
&.flat {
|
||||
> .item {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
&:nth-of-type(1) {
|
||||
> .item:nth-of-type(1) {
|
||||
padding-top: 0;
|
||||
|
||||
.toggle {
|
||||
top: -2px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pill {
|
||||
float: left;
|
||||
display: inline-flex;
|
||||
height: 24px;
|
||||
padding: 0 var(--spacing-3xs);
|
||||
border: 1px solid var(--color-foreground-light);
|
||||
border-radius: 4px;
|
||||
background: var(--color-background-xlight);
|
||||
font-size: var(--font-size-2xs);
|
||||
color: var(--color-text-dark);
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: var(--color-text-light);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.mappable {
|
||||
cursor: grab;
|
||||
|
||||
&:hover {
|
||||
&,
|
||||
span span {
|
||||
background-color: var(--color-background-light);
|
||||
border-color: var(--color-foreground-base);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.dragged {
|
||||
&,
|
||||
&:hover,
|
||||
span {
|
||||
color: var(--color-primary);
|
||||
border-color: var(--color-primary-tint-1);
|
||||
background: var(--color-primary-tint-3);
|
||||
|
||||
svg {
|
||||
path {
|
||||
fill: var(--color-primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
> span {
|
||||
margin-left: var(--spacing-3xs);
|
||||
padding-left: var(--spacing-3xs);
|
||||
border-left: 1px solid var(--color-foreground-light);
|
||||
|
||||
&.arrayIndex {
|
||||
border: 0;
|
||||
padding-left: 0;
|
||||
margin-left: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.text {
|
||||
display: block;
|
||||
padding-top: var(--spacing-4xs);
|
||||
padding-left: var(--spacing-2xs);
|
||||
font-weight: var(--font-weight-normal);
|
||||
font-size: var(--font-size-2xs);
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
padding: var(--spacing-2xs);
|
||||
left: 0;
|
||||
top: 5px;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
font-weight: normal;
|
||||
font-size: var(--font-size-s);
|
||||
overflow: hidden;
|
||||
|
||||
svg {
|
||||
transition: all 0.3s $ease-out-expo;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user