mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
feat(editor): Add "Rendered" display mode to the logs view (#14994)
This commit is contained in:
@@ -95,6 +95,7 @@ import ViewSubExecution from './ViewSubExecution.vue';
|
||||
import RunDataItemCount from '@/components/RunDataItemCount.vue';
|
||||
import RunDataDisplayModeSelect from '@/components/RunDataDisplayModeSelect.vue';
|
||||
import RunDataPaginationBar from '@/components/RunDataPaginationBar.vue';
|
||||
import { parseAiContent } from '@/utils/aiUtils';
|
||||
|
||||
const LazyRunDataTable = defineAsyncComponent(
|
||||
async () => await import('@/components/RunDataTable.vue'),
|
||||
@@ -109,6 +110,9 @@ const LazyRunDataSchema = defineAsyncComponent(
|
||||
const LazyRunDataHtml = defineAsyncComponent(
|
||||
async () => await import('@/components/RunDataHtml.vue'),
|
||||
);
|
||||
const LazyRunDataAi = defineAsyncComponent(
|
||||
async () => await import('@/components/RunDataParsedAiContent.vue'),
|
||||
);
|
||||
const LazyRunDataSearch = defineAsyncComponent(
|
||||
async () => await import('@/components/RunDataSearch.vue'),
|
||||
);
|
||||
@@ -125,6 +129,7 @@ type Props = {
|
||||
executingMessage: string;
|
||||
pushRef?: string;
|
||||
paneType: NodePanelType;
|
||||
displayMode: IRunDataDisplayMode;
|
||||
noDataInBranchMessage: string;
|
||||
node?: INodeUi | null;
|
||||
nodes?: IConnectedNode[];
|
||||
@@ -145,6 +150,7 @@ type Props = {
|
||||
compact?: boolean;
|
||||
tableHeaderBgColor?: 'base' | 'light';
|
||||
disableHoverHighlight?: boolean;
|
||||
disableAiContent?: boolean;
|
||||
};
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -166,6 +172,7 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
compact: false,
|
||||
tableHeaderBgColor: 'base',
|
||||
workflowExecution: undefined,
|
||||
disableAiContent: false,
|
||||
});
|
||||
|
||||
defineSlots<{
|
||||
@@ -198,6 +205,7 @@ const emit = defineEmits<{
|
||||
avgRowHeight: number;
|
||||
},
|
||||
];
|
||||
displayModeChange: [IRunDataDisplayMode];
|
||||
}>();
|
||||
|
||||
const connectionType = ref<NodeConnectionType>(NodeConnectionTypes.Main);
|
||||
@@ -236,17 +244,12 @@ const node = toRef(props, 'node');
|
||||
|
||||
const pinnedData = usePinnedData(node, {
|
||||
runIndex: props.runIndex,
|
||||
displayMode:
|
||||
props.paneType === 'input' ? ndvStore.inputPanelDisplayMode : ndvStore.outputPanelDisplayMode,
|
||||
displayMode: props.displayMode,
|
||||
});
|
||||
const { isSubNodeType } = useNodeType({
|
||||
node,
|
||||
});
|
||||
|
||||
const displayMode = computed(() =>
|
||||
props.paneType === 'input' ? ndvStore.inputPanelDisplayMode : ndvStore.outputPanelDisplayMode,
|
||||
);
|
||||
|
||||
const isReadOnlyRoute = computed(() => route.meta.readOnlyCanvas === true);
|
||||
const isWaitNodeWaiting = computed(() => {
|
||||
return (
|
||||
@@ -263,7 +266,7 @@ const nodeType = computed(() => {
|
||||
return nodeTypesStore.getNodeType(node.value.type, node.value.typeVersion);
|
||||
});
|
||||
|
||||
const isSchemaView = computed(() => displayMode.value === 'schema');
|
||||
const isSchemaView = computed(() => props.displayMode === 'schema');
|
||||
const isSearchInSchemaView = computed(() => isSchemaView.value && !!search.value);
|
||||
const hasMultipleInputNodes = computed(() => props.paneType === 'input' && props.nodes.length > 0);
|
||||
const displaysMultipleNodes = computed(() => isSchemaView.value && hasMultipleInputNodes.value);
|
||||
@@ -617,6 +620,14 @@ const itemsCountProps = computed<InstanceType<typeof RunDataItemCount>['$props']
|
||||
subExecutionsCount: activeTaskMetadata.value?.subExecutionsCount,
|
||||
}));
|
||||
|
||||
const parsedAiContent = computed(() =>
|
||||
props.disableAiContent ? [] : parseAiContent(rawInputData.value, connectionType.value),
|
||||
);
|
||||
|
||||
const hasParsedAiContent = computed(() =>
|
||||
parsedAiContent.value.some((prr) => prr.parsedContent?.parsed),
|
||||
);
|
||||
|
||||
function setInputBranchIndex(value: number) {
|
||||
if (props.paneType === 'input') {
|
||||
outputIndex.value = value;
|
||||
@@ -659,9 +670,9 @@ watch(jsonData, (data: IDataObject[], prevData: IDataObject[]) => {
|
||||
});
|
||||
|
||||
watch(binaryData, (newData, prevData) => {
|
||||
if (newData.length && !prevData.length && displayMode.value !== 'binary') {
|
||||
if (newData.length && !prevData.length && props.displayMode !== 'binary') {
|
||||
switchToBinary();
|
||||
} else if (!newData.length && displayMode.value === 'binary') {
|
||||
} else if (!newData.length && props.displayMode === 'binary') {
|
||||
onDisplayModeChange('table');
|
||||
}
|
||||
});
|
||||
@@ -677,6 +688,17 @@ watch(search, (newSearch) => {
|
||||
emit('search', newSearch);
|
||||
});
|
||||
|
||||
// Switch to AI display mode if it's most suitable
|
||||
watch(
|
||||
hasParsedAiContent,
|
||||
(hasAiContent) => {
|
||||
if (hasAiContent && props.displayMode !== 'ai') {
|
||||
emit('displayModeChange', 'ai');
|
||||
}
|
||||
},
|
||||
{ immediate: true },
|
||||
);
|
||||
|
||||
onMounted(() => {
|
||||
init();
|
||||
|
||||
@@ -869,7 +891,7 @@ function enterEditMode({ origin }: EnterEditModeArgs) {
|
||||
push_ref: props.pushRef,
|
||||
run_index: props.runIndex,
|
||||
is_output_present: hasNodeRun.value || pinnedData.hasData.value,
|
||||
view: !hasNodeRun.value && !pinnedData.hasData.value ? 'undefined' : displayMode.value,
|
||||
view: !hasNodeRun.value && !pinnedData.hasData.value ? 'undefined' : props.displayMode,
|
||||
is_data_pinned: pinnedData.hasData.value,
|
||||
});
|
||||
}
|
||||
@@ -912,7 +934,7 @@ function onExitEditMode({ type }: { type: 'save' | 'cancel' }) {
|
||||
node_type: activeNode.value?.type,
|
||||
push_ref: props.pushRef,
|
||||
run_index: props.runIndex,
|
||||
view: displayMode.value,
|
||||
view: props.displayMode,
|
||||
type,
|
||||
});
|
||||
}
|
||||
@@ -927,7 +949,7 @@ async function onTogglePinData({ source }: { source: PinDataSource | UnpinDataSo
|
||||
node_type: activeNode.value?.type,
|
||||
push_ref: props.pushRef,
|
||||
run_index: props.runIndex,
|
||||
view: !hasNodeRun.value && !pinnedData.hasData.value ? 'none' : displayMode.value,
|
||||
view: !hasNodeRun.value && !pinnedData.hasData.value ? 'none' : props.displayMode,
|
||||
};
|
||||
|
||||
void externalHooks.run('runData.onTogglePinData', telemetryPayload);
|
||||
@@ -1046,8 +1068,8 @@ function onPageSizeChange(newPageSize: number) {
|
||||
}
|
||||
|
||||
function onDisplayModeChange(newDisplayMode: IRunDataDisplayMode) {
|
||||
const previous = displayMode.value;
|
||||
ndvStore.setPanelDisplayMode({ pane: props.paneType, mode: newDisplayMode });
|
||||
const previous = props.displayMode;
|
||||
emit('displayModeChange', newDisplayMode);
|
||||
|
||||
if (!userEnabledShowData.value) updateShowData();
|
||||
|
||||
@@ -1193,15 +1215,9 @@ function init() {
|
||||
}
|
||||
connectionType.value = outputTypes.length === 0 ? NodeConnectionTypes.Main : outputTypes[0];
|
||||
if (binaryData.value.length > 0) {
|
||||
ndvStore.setPanelDisplayMode({
|
||||
pane: props.paneType,
|
||||
mode: 'binary',
|
||||
});
|
||||
} else if (displayMode.value === 'binary') {
|
||||
ndvStore.setPanelDisplayMode({
|
||||
pane: props.paneType,
|
||||
mode: 'schema',
|
||||
});
|
||||
emit('displayModeChange', 'binary');
|
||||
} else if (props.displayMode === 'binary') {
|
||||
emit('displayModeChange', 'schema');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1317,10 +1333,7 @@ function setDisplayMode() {
|
||||
activeNode.value.parameters.operation === 'generateHtmlTemplate';
|
||||
|
||||
if (shouldDisplayHtml) {
|
||||
ndvStore.setPanelDisplayMode({
|
||||
pane: 'output',
|
||||
mode: 'html',
|
||||
});
|
||||
emit('displayModeChange', 'html');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1426,6 +1439,7 @@ defineExpose({ enterEditMode });
|
||||
activeNode?.type === HTML_NODE_TYPE &&
|
||||
activeNode.parameters.operation === 'generateHtmlTemplate'
|
||||
"
|
||||
:has-renderable-data="hasParsedAiContent"
|
||||
@change="onDisplayModeChange"
|
||||
/>
|
||||
|
||||
@@ -1625,7 +1639,12 @@ defineExpose({ enterEditMode });
|
||||
"
|
||||
:class="$style.stretchVertically"
|
||||
>
|
||||
<NodeErrorView :error="subworkflowExecutionError" :class="$style.errorDisplay" />
|
||||
<NodeErrorView
|
||||
:compact="compact"
|
||||
:error="subworkflowExecutionError"
|
||||
:class="$style.errorDisplay"
|
||||
show-details
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-else-if="isWaitNodeWaiting" :class="$style.center">
|
||||
@@ -1687,7 +1706,7 @@ defineExpose({ enterEditMode });
|
||||
v-if="workflowRunErrorAsNodeError"
|
||||
:error="workflowRunErrorAsNodeError"
|
||||
:class="$style.inlineError"
|
||||
compact
|
||||
:compact="compact"
|
||||
/>
|
||||
<slot name="content"></slot>
|
||||
</div>
|
||||
@@ -1695,6 +1714,8 @@ defineExpose({ enterEditMode });
|
||||
v-else-if="workflowRunErrorAsNodeError"
|
||||
:error="workflowRunErrorAsNodeError"
|
||||
:class="$style.dataDisplay"
|
||||
:compact="compact"
|
||||
show-details
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1835,6 +1856,10 @@ defineExpose({ enterEditMode });
|
||||
<LazyRunDataHtml :input-html="inputHtml" />
|
||||
</Suspense>
|
||||
|
||||
<Suspense v-else-if="hasNodeRun && displayMode === 'ai'">
|
||||
<LazyRunDataAi render-type="rendered" :compact="compact" :content="parsedAiContent" />
|
||||
</Suspense>
|
||||
|
||||
<Suspense v-else-if="(hasNodeRun || hasPreviewSchema) && isSchemaView">
|
||||
<LazyRunDataSchema
|
||||
:nodes="nodes"
|
||||
|
||||
Reference in New Issue
Block a user