mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-26 21:19:43 -08:00
add more views
This commit is contained in:
parent
56f02b3362
commit
1057616fb9
|
@ -8,8 +8,8 @@
|
|||
@opened="showDocumentHelp = true"
|
||||
>
|
||||
<div class="data-display" v-if="node" >
|
||||
<NodeSettings @valueChanged="valueChanged" />
|
||||
<RunData />
|
||||
<NodeSettings ref="settings" @valueChanged="valueChanged" />
|
||||
<RunData @openSettings="openSettings" />
|
||||
|
||||
</div>
|
||||
</el-dialog>
|
||||
|
@ -68,6 +68,12 @@ export default mixins(externalHooks, nodeHelpers, workflowHelpers).extend({
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
openSettings() {
|
||||
const settings = this.$refs.settings as Vue | null;
|
||||
if (settings) {
|
||||
settings.$emit('openSettings');
|
||||
}
|
||||
},
|
||||
valueChanged (parameterData: IUpdateInformation) {
|
||||
this.$emit('valueChanged', parameterData);
|
||||
},
|
||||
|
|
|
@ -519,6 +519,9 @@ export default mixins(
|
|||
},
|
||||
mounted () {
|
||||
this.setNodeValues();
|
||||
this.$on('openSettings', () => {
|
||||
this.openPanel = 'settings';
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<div :class="['run-data-view', $style.container]" v-loading="workflowRunning">
|
||||
<div :class="['run-data-view', $style.container]">
|
||||
<BinaryDataDisplay :windowVisible="binaryDataDisplayVisible" :displayData="binaryDataDisplayData" @close="closeBinaryDataDisplay"/>
|
||||
|
||||
<div :class="$style.header">
|
||||
|
@ -16,11 +16,8 @@
|
|||
<font-awesome-icon icon="info-circle" :class="$style.infoIcon" />
|
||||
</n8n-tooltip>
|
||||
</div>
|
||||
<div class="title-text">
|
||||
<!-- <n8n-text :bold="true" v-if="dataCount < maxDisplayItems">
|
||||
{{ $locale.baseText('runData.items') }}: {{ dataCount }}
|
||||
</n8n-text>
|
||||
<div v-else class="title-text">
|
||||
<div>
|
||||
<!-- <div v-else class="title-text">
|
||||
<n8n-text :bold="true">{{ $locale.baseText('runData.items') }}:</n8n-text>
|
||||
<span class="opts">
|
||||
<n8n-select size="mini" v-model="maxDisplayItems" @click.stop>
|
||||
|
@ -33,30 +30,31 @@
|
|||
<!-- <n8n-text :bold="true" v-if="maxOutputIndex > 0">
|
||||
| {{ $locale.baseText('runData.output') }}:
|
||||
</n8n-text> -->
|
||||
<span class="opts" v-if="maxOutputIndex > 0" >
|
||||
<!-- <span class="opts" v-if="maxOutputIndex > 0" >
|
||||
<n8n-select size="mini" v-model="outputIndex" @click.stop>
|
||||
<n8n-option v-for="option in (maxOutputIndex + 1)" :label="getOutputName(option-1)" :value="option -1" :key="option">
|
||||
</n8n-option>
|
||||
</n8n-select>
|
||||
</span>
|
||||
</span> -->
|
||||
|
||||
<n8n-text :bold="true" v-if="maxRunIndex > 0">
|
||||
<!-- <n8n-text :bold="true" v-if="maxRunIndex > 0">
|
||||
| {{ $locale.baseText('runData.dataOfExecution') }}:
|
||||
</n8n-text>
|
||||
</n8n-text> -->
|
||||
<span class="opts">
|
||||
<n8n-select v-if="maxRunIndex > 0" size="mini" v-model="runIndex" @click.stop>
|
||||
<n8n-option v-for="option in (maxRunIndex + 1)" :label="option + '/' + (maxRunIndex+1)" :value="option-1" :key="option">
|
||||
</n8n-option>
|
||||
</n8n-select>
|
||||
</span>
|
||||
|
||||
</div>
|
||||
|
||||
<div v-if="hasNodeRun && !hasRunError" class="title-data-display-selector" @click.stop>
|
||||
<n8n-radio-buttons
|
||||
v-model="displayMode"
|
||||
:options="buttons"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div v-if="hasNodeRun && !hasRunError && displayMode === 'json' && state.path !== deselectedPlaceholder" class="select-button">
|
||||
<el-dropdown trigger="click" @command="handleCopyClick">
|
||||
<span class="el-dropdown-link">
|
||||
|
@ -76,53 +74,60 @@
|
|||
</el-dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<div class="data-display-content">
|
||||
<span v-if="node && workflowRunData !== null && workflowRunData.hasOwnProperty(node.name)">
|
||||
<div v-if="workflowRunData[node.name][runIndex].error" class="error-display">
|
||||
|
||||
<div v-if="!hasNodeRun" :class="$style.center">
|
||||
<div v-if="workflowRunning">
|
||||
<div :class="$style.spinner"><n8n-spinner /></div>
|
||||
<n8n-text>{{ $locale.baseText('node.output.executing') }}</n8n-text>
|
||||
</div>
|
||||
<n8n-text v-else>{{ $locale.baseText('node.output.runNodeHint') }}</n8n-text>
|
||||
</div>
|
||||
|
||||
<div v-else-if="hasNodeRun && hasRunError">
|
||||
<NodeErrorView :error="workflowRunData[node.name][runIndex].error" />
|
||||
</div>
|
||||
<span v-else>
|
||||
<div v-if="showData === false" class="too-much-data">
|
||||
<h3>
|
||||
{{ $locale.baseText('runData.nodeReturnedALargeAmountOfData') }}
|
||||
</h3>
|
||||
|
||||
<div class="text">
|
||||
<span v-html="$locale.baseText(
|
||||
'runData.theNodeContains',
|
||||
{
|
||||
interpolate: {
|
||||
numberOfKb: parseInt(dataSize/1024).toLocaleString()
|
||||
}
|
||||
}
|
||||
)"></span>
|
||||
<div v-else-if="hasNodeRun && jsonData && jsonData.length === 0" :class="$style.center">
|
||||
<n8n-text :bold="true">{{ $locale.baseText('node.output.noOutputData.title') }}</n8n-text>
|
||||
<n8n-text>
|
||||
{{ $locale.baseText('node.output.noOutputData.message') }}
|
||||
<a @click="openSettings">{{ $locale.baseText('node.output.noOutputData.message.settings') }}</a>
|
||||
{{ $locale.baseText('node.output.noOutputData.message.settingsOption') }}
|
||||
</n8n-text>
|
||||
</div>
|
||||
|
||||
<div v-else-if="hasNodeRun && !showData" :class="$style.center">
|
||||
<n8n-text :bold="true">{{ $locale.baseText('node.output.tooMuchData.title') }}</n8n-text>
|
||||
<n8n-text align="center" tag="div"><span v-html="$locale.baseText('node.output.tooMuchData.message', { interpolate: {size: dataSizeInMB }})"></span></n8n-text>
|
||||
|
||||
<n8n-button
|
||||
icon="eye"
|
||||
:label="$locale.baseText('runData.displayDataAnyway')"
|
||||
@click="displayMode = 'table';showData = true;"
|
||||
type="outline"
|
||||
:label="$locale.baseText('node.output.tooMuchData.showDataAnyway')"
|
||||
@click="showData = true"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="['json', 'table'].includes(displayMode)">
|
||||
<div v-if="jsonData.length === 0" class="no-data">
|
||||
{{ $locale.baseText('runData.noTextDataFound') }}
|
||||
|
||||
<div v-else-if="hasNodeRun && displayMode === 'table' && tableData && tableData.columns && tableData.columns.length === 0" :class="$style.center">
|
||||
<n8n-text align="center" tag="div">{{ $locale.baseText('runData.entriesExistButThey') }}</n8n-text>
|
||||
</div>
|
||||
<div v-else-if="displayMode === 'table'">
|
||||
<div v-if="tableData !== null && tableData.columns.length === 0" class="no-data">
|
||||
{{ $locale.baseText('runData.entriesExistButThey') }}
|
||||
</div>
|
||||
<table v-else-if="tableData !== null">
|
||||
|
||||
<div v-else-if="hasNodeRun && displayMode === 'table' && tableData" :class="$style.dataDisplay">
|
||||
<n8n-text tag="div">
|
||||
{{ dataCount }} {{ $locale.baseText(dataCount === 1 ? 'node.output.item' : 'node.output.items') }}
|
||||
</n8n-text>
|
||||
|
||||
<table :class="$style.table">
|
||||
<tr>
|
||||
<th v-for="column in tableData.columns" :key="column">{{column}}</th>
|
||||
<th v-for="column in (tableData.columns || [])" :key="column">{{column}}</th>
|
||||
</tr>
|
||||
<tr v-for="(row, index1) in tableData.data" :key="index1">
|
||||
<td v-for="(data, index2) in row" :key="index2">{{ [null, undefined].includes(data) ? ' ' : data }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div v-else-if="hasNodeRun && displayMode === 'json'" :class="$style.dataDisplay">
|
||||
<vue-json-pretty
|
||||
v-else-if="displayMode === 'json'"
|
||||
:data="jsonData"
|
||||
:deep="10"
|
||||
v-model="state.path"
|
||||
|
@ -136,12 +141,12 @@
|
|||
class="json-data"
|
||||
/>
|
||||
</div>
|
||||
<div v-else-if="displayMode === 'binary'">
|
||||
<div v-if="binaryData.length === 0" class="no-data">
|
||||
{{ $locale.baseText('runData.noBinaryDataFound') }}
|
||||
|
||||
<div v-else-if="displayMode === 'binary' && binaryData.length === 0">
|
||||
<n8n-text align="center" tag="div">{{ $locale.baseText('runData.noBinaryDataFound') }}</n8n-text>
|
||||
</div>
|
||||
|
||||
<div v-else>
|
||||
<div v-else-if="displayMode === 'binary'">
|
||||
<div v-for="(binaryDataEntry, index) in binaryData" :key="index">
|
||||
<div class="binary-data-row-index">
|
||||
<div class="binary-data-cell-index">
|
||||
|
@ -175,24 +180,13 @@
|
|||
<div class="binary-data-show-data-button-wrapper">
|
||||
<n8n-button size="small" :label="$locale.baseText('runData.showBinaryData')" class="binary-data-show-data-button" @click="displayBinaryData(index, key)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
</span>
|
||||
<div v-else class="message">
|
||||
<div>
|
||||
<n8n-text :bold="true">{{ $locale.baseText('runData.noData') }}</n8n-text ><br />
|
||||
<br />
|
||||
{{ $locale.baseText('runData.dataReturnedByThisNodeWillDisplayHere') }}<br />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
@ -364,6 +358,9 @@ export default mixins(
|
|||
|
||||
return inputData.length;
|
||||
},
|
||||
dataSizeInMB(): string {
|
||||
return (this.dataSize / 1024 / 1000).toLocaleString();
|
||||
},
|
||||
maxOutputIndex (): number {
|
||||
if (this.node === null) {
|
||||
return 0;
|
||||
|
@ -437,6 +434,9 @@ export default mixins(
|
|||
},
|
||||
},
|
||||
methods: {
|
||||
openSettings() {
|
||||
this.$emit('openSettings');
|
||||
},
|
||||
init() {
|
||||
// Reset the selected output index every time another node gets selected
|
||||
this.outputIndex = 0;
|
||||
|
@ -659,6 +659,31 @@ export default mixins(
|
|||
color: var(--color-foreground-dark);
|
||||
}
|
||||
|
||||
.center {
|
||||
display: flex;
|
||||
height: 80%;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
> * {
|
||||
max-width: 316px;
|
||||
margin-bottom: var(--spacing-2xs);
|
||||
}
|
||||
}
|
||||
|
||||
.spinner {
|
||||
* {
|
||||
color: var(--color-primary);
|
||||
min-height: 40px;
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
|
||||
.title {
|
||||
text-transform: uppercase;
|
||||
color: var(--color-text-light);
|
||||
|
@ -683,26 +708,48 @@ export default mixins(
|
|||
flex-grow: 1;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.run-data-view {
|
||||
|
||||
.data-display-content {
|
||||
.dataDisplay {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
top: 50px;
|
||||
left: 0;
|
||||
top: 60px;
|
||||
left: 16px;
|
||||
right: 0;
|
||||
overflow-y: auto;
|
||||
line-height: 1.5;
|
||||
word-break: normal;
|
||||
font-size: var(--font-size-s);
|
||||
|
||||
.binary-data-row {
|
||||
> * {
|
||||
margin-bottom: var(--spacing-s);
|
||||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
width: calc(100% - 1px);
|
||||
border: var(--border-base);
|
||||
font-size: var(--font-size-2xs);
|
||||
|
||||
th {
|
||||
padding: var(--spacing-2xs);
|
||||
background-color: var(--color-background-base);
|
||||
border: var(--border-base);
|
||||
}
|
||||
|
||||
td {
|
||||
padding: var(--spacing-2xs);
|
||||
border: var(--border-base);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
<style lang="scss">
|
||||
|
||||
.binary-data-row {
|
||||
display: inline-flex;
|
||||
padding: 0.5em 1em;
|
||||
font-size: var(--font-size-2xs);
|
||||
|
||||
.binary-data-cell {
|
||||
display: inline-block;
|
||||
|
@ -742,11 +789,12 @@ export default mixins(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.binary-data-row-index {
|
||||
.binary-data-row-index {
|
||||
display: block;
|
||||
padding: 1em 1em 0.25em 1em;
|
||||
font-size: var(--font-size-2xs);
|
||||
|
||||
.binary-data-cell-index {
|
||||
display: inline-block;
|
||||
|
@ -760,97 +808,6 @@ export default mixins(
|
|||
font-weight: 600;
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.json-data {
|
||||
line-height: 1.5;
|
||||
|
||||
&.vjs-tree {
|
||||
color: $--custom-input-font;
|
||||
}
|
||||
}
|
||||
|
||||
.error-display,
|
||||
.json-data,
|
||||
.message,
|
||||
.no-data {
|
||||
margin: 1em;
|
||||
}
|
||||
|
||||
.too-much-data {
|
||||
margin: 1em;
|
||||
text-align: center;
|
||||
|
||||
.text {
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
border-collapse: collapse;
|
||||
text-align: left;
|
||||
width: calc(100% - 1px);
|
||||
border-left: 25px solid #00000000;
|
||||
border-right: 25px solid #00000000;
|
||||
|
||||
th {
|
||||
background-color: $--custom-table-background-main;
|
||||
color: #fff;
|
||||
padding: 12px;
|
||||
}
|
||||
td {
|
||||
padding: 12px;
|
||||
}
|
||||
tr:nth-child(even) {
|
||||
background: #fff;;
|
||||
}
|
||||
tr:nth-child(odd) {
|
||||
background: $--custom-table-background-stripe-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// .header {
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
// height: 40px;
|
||||
|
||||
// .select-button {
|
||||
// height: 30px;
|
||||
// top: 50px;
|
||||
// right: 30px;
|
||||
// position: absolute;
|
||||
// text-align: right;
|
||||
// width: 200px;
|
||||
// z-index: 10;
|
||||
// }
|
||||
|
||||
// .title-text {
|
||||
// display: inline-flex;
|
||||
// align-items: center;
|
||||
|
||||
// > * {
|
||||
// margin-right: 2px;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .title-data-display-selector {
|
||||
// position: absolute;
|
||||
// left: calc(50% - 105px);
|
||||
// width: 210px;
|
||||
// display: inline-block;
|
||||
// text-align: center;
|
||||
|
||||
// .entry.active {
|
||||
// font-weight: bold;
|
||||
// }
|
||||
// }
|
||||
|
||||
// .opts {
|
||||
// width: 80px;
|
||||
// z-index: 1;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -748,7 +748,7 @@
|
|||
"ms": "ms",
|
||||
"noBinaryDataFound": "No binary data found",
|
||||
"noData": "No data",
|
||||
"noTextDataFound": "No text data found",
|
||||
"": "No text data found",
|
||||
"nodeReturnedALargeAmountOfData": "Node returned a large amount of data",
|
||||
"output": "Output",
|
||||
"showBinaryData": "Show Binary Data",
|
||||
|
@ -1147,6 +1147,17 @@
|
|||
"node.execute.hint": "Executes this {nodeName} node after executing any previous nodes that have not yet returned data",
|
||||
"node.execute.executeNode": "Execute node",
|
||||
"node.execute.executing": "Executing",
|
||||
"node.output.runNodeHint": "Execute this node to output data",
|
||||
"node.output.executing": "Executing node...",
|
||||
"node.output.noOutputData.title": "No output data returned",
|
||||
"node.output.noOutputData.message": "n8n stops executing the workflow when a node has no output data. You can change this default behaviour via",
|
||||
"node.output.noOutputData.message.settings": "Settings",
|
||||
"node.output.noOutputData.message.settingsOption": "> “Always Output Data”.",
|
||||
"node.output.tooMuchData.title": "Output data is huge!",
|
||||
"node.output.tooMuchData.message": "The node contains {size} MB of data. Displaying it may cause problems. <br /> If you do decide to display it, avoid the JSON view.",
|
||||
"node.output.tooMuchData.showDataAnyway": "Show data anyway",
|
||||
"node.output.items": "items",
|
||||
"node.output.item": "items",
|
||||
"openWorkflow.workflowImportError": "Could not import workflow",
|
||||
"openWorkflow.workflowNotFoundError": "Could not find workflow",
|
||||
"settings": "Settings",
|
||||
|
|
Loading…
Reference in a new issue