mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 10:02:05 +00:00
feat(editor): Log details panel (#14409)
Co-authored-by: कारतोफ्फेलस्क्रिप्ट™ <aditya@netroy.in>
This commit is contained in:
@@ -78,7 +78,6 @@ import {
|
||||
N8nInfoTip,
|
||||
N8nLink,
|
||||
N8nOption,
|
||||
N8nRadioButtons,
|
||||
N8nSelect,
|
||||
N8nSpinner,
|
||||
N8nTabs,
|
||||
@@ -92,6 +91,8 @@ import { useSchemaPreviewStore } from '@/stores/schemaPreview.store';
|
||||
import { asyncComputed } from '@vueuse/core';
|
||||
import { usePostHog } from '@/stores/posthog.store';
|
||||
import ViewSubExecution from './ViewSubExecution.vue';
|
||||
import RunDataItemCount from '@/components/RunDataItemCount.vue';
|
||||
import RunDataDisplayModeSelect from '@/components/RunDataDisplayModeSelect.vue';
|
||||
|
||||
const LazyRunDataTable = defineAsyncComponent(
|
||||
async () => await import('@/components/RunDataTable.vue'),
|
||||
@@ -119,7 +120,7 @@ type Props = {
|
||||
runIndex: number;
|
||||
tooMuchDataTitle: string;
|
||||
executingMessage: string;
|
||||
pushRef: string;
|
||||
pushRef?: string;
|
||||
paneType: NodePanelType;
|
||||
noDataInBranchMessage: string;
|
||||
node?: INodeUi | null;
|
||||
@@ -135,6 +136,11 @@ type Props = {
|
||||
isPaneActive?: boolean;
|
||||
hidePagination?: boolean;
|
||||
calloutMessage?: string;
|
||||
disableRunIndexSelection?: boolean;
|
||||
disableEdit?: boolean;
|
||||
disablePin?: boolean;
|
||||
compact?: boolean;
|
||||
tableHeaderBgColor?: 'base' | 'light';
|
||||
};
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@@ -149,7 +155,26 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
isExecuting: false,
|
||||
hidePagination: false,
|
||||
calloutMessage: undefined,
|
||||
disableRunIndexSelection: false,
|
||||
disableEdit: false,
|
||||
disablePin: false,
|
||||
compact: false,
|
||||
tableHeaderBgColor: 'base',
|
||||
});
|
||||
|
||||
defineSlots<{
|
||||
content: {};
|
||||
'callout-message': {};
|
||||
header: {};
|
||||
'input-select': {};
|
||||
'before-data': {};
|
||||
'run-info': {};
|
||||
'node-waiting': {};
|
||||
'node-not-run': {};
|
||||
'no-output-data': {};
|
||||
'recovered-artificial-output-data': {};
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
search: [search: string];
|
||||
runChange: [runIndex: number];
|
||||
@@ -249,27 +274,6 @@ const canPinData = computed(
|
||||
pinnedData.isValidNodeType.value &&
|
||||
!(binaryData.value && binaryData.value.length > 0),
|
||||
);
|
||||
const displayModes = computed(() => {
|
||||
const defaults: Array<{ label: string; value: IRunDataDisplayMode }> = [
|
||||
{ label: i18n.baseText('runData.schema'), value: 'schema' },
|
||||
{ label: i18n.baseText('runData.table'), value: 'table' },
|
||||
{ label: i18n.baseText('runData.json'), value: 'json' },
|
||||
];
|
||||
|
||||
if (binaryData.value.length) {
|
||||
defaults.push({ label: i18n.baseText('runData.binary'), value: 'binary' });
|
||||
}
|
||||
|
||||
if (
|
||||
isPaneTypeOutput.value &&
|
||||
activeNode.value?.type === HTML_NODE_TYPE &&
|
||||
activeNode.value.parameters.operation === 'generateHtmlTemplate'
|
||||
) {
|
||||
defaults.unshift({ label: 'HTML', value: 'html' });
|
||||
}
|
||||
|
||||
return defaults;
|
||||
});
|
||||
|
||||
const hasNodeRun = computed(() =>
|
||||
Boolean(
|
||||
@@ -512,6 +516,9 @@ const parentNodePinnedData = computed(() => {
|
||||
});
|
||||
|
||||
const showPinButton = computed(() => {
|
||||
if (props.disablePin) {
|
||||
return false;
|
||||
}
|
||||
if (!rawInputData.value.length && !pinnedData.hasData.value) {
|
||||
return false;
|
||||
}
|
||||
@@ -593,6 +600,14 @@ const hasPreviewSchema = asyncComputed(async () => {
|
||||
return false;
|
||||
}, false);
|
||||
|
||||
const itemsCountProps = computed<InstanceType<typeof RunDataItemCount>['$props']>(() => ({
|
||||
search: search.value,
|
||||
dataCount: dataCount.value,
|
||||
unfilteredDataCount: unfilteredDataCount.value,
|
||||
subExecutionsCount: activeTaskMetadata.value?.subExecutionsCount,
|
||||
muted: props.compact || (props.paneType === 'input' && maxRunIndex.value === 0),
|
||||
}));
|
||||
|
||||
watch(node, (newNode, prevNode) => {
|
||||
if (newNode?.id === prevNode?.id) return;
|
||||
init();
|
||||
@@ -1303,7 +1318,10 @@ defineExpose({ enterEditMode });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div :class="['run-data', $style.container]" @mouseover="activatePane">
|
||||
<div
|
||||
:class="['run-data', $style.container, props.compact ? $style.compact : '']"
|
||||
@mouseover="activatePane"
|
||||
>
|
||||
<N8nCallout
|
||||
v-if="
|
||||
!isPaneTypeInput &&
|
||||
@@ -1371,19 +1389,27 @@ defineExpose({ enterEditMode });
|
||||
/>
|
||||
</Suspense>
|
||||
|
||||
<N8nRadioButtons
|
||||
<RunDataDisplayModeSelect
|
||||
v-show="
|
||||
hasPreviewSchema ||
|
||||
(hasNodeRun && (inputData.length || binaryData.length || search) && !editMode.enabled)
|
||||
"
|
||||
:model-value="displayMode"
|
||||
:options="displayModes"
|
||||
data-test-id="ndv-run-data-display-mode"
|
||||
@update:model-value="onDisplayModeChange"
|
||||
:class="$style.displayModeSelect"
|
||||
:compact="props.compact"
|
||||
:value="displayMode"
|
||||
:has-binary-data="binaryData.length > 0"
|
||||
:pane-type="paneType"
|
||||
:node-generates-html="
|
||||
activeNode?.type === HTML_NODE_TYPE &&
|
||||
activeNode.parameters.operation === 'generateHtmlTemplate'
|
||||
"
|
||||
@change="onDisplayModeChange"
|
||||
/>
|
||||
|
||||
<RunDataItemCount v-if="props.compact" v-bind="itemsCountProps" />
|
||||
|
||||
<N8nIconButton
|
||||
v-if="canPinData && !isReadOnlyRoute && !readOnlyEnv"
|
||||
v-if="!props.disableEdit && canPinData && !isReadOnlyRoute && !readOnlyEnv"
|
||||
v-show="!editMode.enabled"
|
||||
:title="i18n.baseText('runData.editOutput')"
|
||||
:circle="false"
|
||||
@@ -1407,7 +1433,7 @@ defineExpose({ enterEditMode });
|
||||
@toggle-pin-data="onTogglePinData({ source: 'pin-icon-click' })"
|
||||
/>
|
||||
|
||||
<div v-show="editMode.enabled" :class="$style.editModeActions">
|
||||
<div v-if="!props.disableEdit" v-show="editMode.enabled" :class="$style.editModeActions">
|
||||
<N8nButton
|
||||
type="tertiary"
|
||||
:label="i18n.baseText('runData.editor.cancel')"
|
||||
@@ -1428,7 +1454,7 @@ defineExpose({ enterEditMode });
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="maxRunIndex > 0 && !displaysMultipleNodes"
|
||||
v-if="maxRunIndex > 0 && !displaysMultipleNodes && !props.disableRunIndexSelection"
|
||||
v-show="!editMode.enabled"
|
||||
:class="$style.runSelector"
|
||||
>
|
||||
@@ -1479,9 +1505,11 @@ defineExpose({ enterEditMode });
|
||||
|
||||
<slot v-if="!displaysMultipleNodes" name="before-data" />
|
||||
|
||||
<div v-if="props.calloutMessage" :class="$style.hintCallout">
|
||||
<div v-if="props.calloutMessage || $slots['callout-message']" :class="$style.hintCallout">
|
||||
<N8nCallout theme="info" data-test-id="run-data-callout">
|
||||
<N8nText v-n8n-html="props.calloutMessage" size="small"></N8nText>
|
||||
<slot name="callout-message">
|
||||
<N8nText v-n8n-html="props.calloutMessage" size="small"></N8nText>
|
||||
</slot>
|
||||
</N8nCallout>
|
||||
</div>
|
||||
|
||||
@@ -1518,6 +1546,7 @@ defineExpose({ enterEditMode });
|
||||
|
||||
<div
|
||||
v-else-if="
|
||||
!props.compact &&
|
||||
hasNodeRun &&
|
||||
!isSearchInSchemaView &&
|
||||
((dataCount > 0 && maxRunIndex === 0) || search) &&
|
||||
@@ -1525,37 +1554,12 @@ defineExpose({ enterEditMode });
|
||||
!displaysMultipleNodes
|
||||
"
|
||||
v-show="!editMode.enabled"
|
||||
:class="[$style.itemsCount, { [$style.muted]: paneType === 'input' && maxRunIndex === 0 }]"
|
||||
:class="$style.itemsCount"
|
||||
data-test-id="ndv-items-count"
|
||||
>
|
||||
<slot v-if="inputSelectLocation === 'items'" name="input-select"></slot>
|
||||
|
||||
<N8nText v-if="search" :class="$style.itemsText">
|
||||
{{
|
||||
i18n.baseText('ndv.search.items', {
|
||||
adjustToNumber: unfilteredDataCount,
|
||||
interpolate: { matched: dataCount, count: unfilteredDataCount },
|
||||
})
|
||||
}}
|
||||
</N8nText>
|
||||
<N8nText v-else :class="$style.itemsText">
|
||||
<span>
|
||||
{{
|
||||
i18n.baseText('ndv.output.items', {
|
||||
adjustToNumber: dataCount,
|
||||
interpolate: { count: dataCount },
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
<span v-if="activeTaskMetadata?.subExecutionsCount">
|
||||
{{
|
||||
i18n.baseText('ndv.output.andSubExecutions', {
|
||||
adjustToNumber: activeTaskMetadata.subExecutionsCount,
|
||||
interpolate: { count: activeTaskMetadata.subExecutionsCount },
|
||||
})
|
||||
}}
|
||||
</span>
|
||||
</N8nText>
|
||||
<RunDataItemCount v-bind="itemsCountProps" />
|
||||
<ViewSubExecution
|
||||
v-if="activeTaskMetadata && !(paneType === 'input' && hasInputOverwrite)"
|
||||
:task-metadata="activeTaskMetadata"
|
||||
@@ -1771,6 +1775,7 @@ defineExpose({ enterEditMode });
|
||||
:total-runs="maxRunIndex"
|
||||
:has-default-hover-state="paneType === 'input' && !search"
|
||||
:search="search"
|
||||
:header-bg-color="tableHeaderBgColor"
|
||||
@mounted="emit('tableMounted', $event)"
|
||||
@active-row-changed="onItemHover"
|
||||
@display-mode-change="onDisplayModeChange"
|
||||
@@ -1947,6 +1952,8 @@ defineExpose({ enterEditMode });
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
@import '@/styles/variables';
|
||||
|
||||
.infoIcon {
|
||||
color: var(--color-foreground-dark);
|
||||
}
|
||||
@@ -1970,7 +1977,6 @@ defineExpose({ enterEditMode });
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--color-run-data-background);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@@ -1994,6 +2000,11 @@ defineExpose({ enterEditMode });
|
||||
min-height: calc(30px + var(--spacing-s));
|
||||
scrollbar-width: thin;
|
||||
|
||||
.compact & {
|
||||
margin-bottom: var(--spacing-4xs);
|
||||
padding: var(--spacing-4xs) var(--spacing-s) 0 var(--spacing-s);
|
||||
}
|
||||
|
||||
> *:first-child {
|
||||
flex-grow: 1;
|
||||
}
|
||||
@@ -2055,18 +2066,6 @@ defineExpose({ enterEditMode });
|
||||
padding-right: var(--spacing-s);
|
||||
padding-bottom: var(--spacing-s);
|
||||
flex-flow: wrap;
|
||||
|
||||
.itemsText {
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
&.muted .itemsText {
|
||||
color: var(--color-text-light);
|
||||
font-size: var(--font-size-2xs);
|
||||
}
|
||||
}
|
||||
|
||||
.inputSelect {
|
||||
@@ -2183,6 +2182,7 @@ defineExpose({ enterEditMode });
|
||||
.displayModes {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
flex-grow: 1;
|
||||
gap: var(--spacing-2xs);
|
||||
}
|
||||
@@ -2260,6 +2260,20 @@ defineExpose({ enterEditMode });
|
||||
.schema {
|
||||
padding: 0 var(--spacing-s);
|
||||
}
|
||||
|
||||
.search,
|
||||
.displayModeSelect {
|
||||
.compact & {
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
transition: opacity 0.3s $ease-out-expo;
|
||||
}
|
||||
|
||||
.compact:hover & {
|
||||
opacity: 1;
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
Reference in New Issue
Block a user