add more views

This commit is contained in:
Mutasem 2022-03-28 22:26:37 +02:00
parent 56f02b3362
commit 1057616fb9
4 changed files with 247 additions and 270 deletions

View file

@ -8,8 +8,8 @@
@opened="showDocumentHelp = true" @opened="showDocumentHelp = true"
> >
<div class="data-display" v-if="node" > <div class="data-display" v-if="node" >
<NodeSettings @valueChanged="valueChanged" /> <NodeSettings ref="settings" @valueChanged="valueChanged" />
<RunData /> <RunData @openSettings="openSettings" />
</div> </div>
</el-dialog> </el-dialog>
@ -68,6 +68,12 @@ export default mixins(externalHooks, nodeHelpers, workflowHelpers).extend({
}, },
}, },
methods: { methods: {
openSettings() {
const settings = this.$refs.settings as Vue | null;
if (settings) {
settings.$emit('openSettings');
}
},
valueChanged (parameterData: IUpdateInformation) { valueChanged (parameterData: IUpdateInformation) {
this.$emit('valueChanged', parameterData); this.$emit('valueChanged', parameterData);
}, },

View file

@ -519,6 +519,9 @@ export default mixins(
}, },
mounted () { mounted () {
this.setNodeValues(); this.setNodeValues();
this.$on('openSettings', () => {
this.openPanel = 'settings';
});
}, },
}); });
</script> </script>

View file

@ -1,5 +1,5 @@
<template> <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"/> <BinaryDataDisplay :windowVisible="binaryDataDisplayVisible" :displayData="binaryDataDisplayData" @close="closeBinaryDataDisplay"/>
<div :class="$style.header"> <div :class="$style.header">
@ -16,11 +16,8 @@
<font-awesome-icon icon="info-circle" :class="$style.infoIcon" /> <font-awesome-icon icon="info-circle" :class="$style.infoIcon" />
</n8n-tooltip> </n8n-tooltip>
</div> </div>
<div class="title-text"> <div>
<!-- <n8n-text :bold="true" v-if="dataCount < maxDisplayItems"> <!-- <div v-else class="title-text">
{{ $locale.baseText('runData.items') }}: {{ dataCount }}
</n8n-text>
<div v-else class="title-text">
<n8n-text :bold="true">{{ $locale.baseText('runData.items') }}:</n8n-text> <n8n-text :bold="true">{{ $locale.baseText('runData.items') }}:</n8n-text>
<span class="opts"> <span class="opts">
<n8n-select size="mini" v-model="maxDisplayItems" @click.stop> <n8n-select size="mini" v-model="maxDisplayItems" @click.stop>
@ -33,30 +30,31 @@
<!-- <n8n-text :bold="true" v-if="maxOutputIndex > 0"> <!-- <n8n-text :bold="true" v-if="maxOutputIndex > 0">
| {{ $locale.baseText('runData.output') }}: | {{ $locale.baseText('runData.output') }}:
</n8n-text> --> </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-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 v-for="option in (maxOutputIndex + 1)" :label="getOutputName(option-1)" :value="option -1" :key="option">
</n8n-option> </n8n-option>
</n8n-select> </n8n-select>
</span> </span> -->
<n8n-text :bold="true" v-if="maxRunIndex > 0"> <!-- <n8n-text :bold="true" v-if="maxRunIndex > 0">
| {{ $locale.baseText('runData.dataOfExecution') }}: | {{ $locale.baseText('runData.dataOfExecution') }}:
</n8n-text> </n8n-text> -->
<span class="opts"> <span class="opts">
<n8n-select v-if="maxRunIndex > 0" size="mini" v-model="runIndex" @click.stop> <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 v-for="option in (maxRunIndex + 1)" :label="option + '/' + (maxRunIndex+1)" :value="option-1" :key="option">
</n8n-option> </n8n-option>
</n8n-select> </n8n-select>
</span> </span>
</div> </div>
<div v-if="hasNodeRun && !hasRunError" class="title-data-display-selector" @click.stop> <div v-if="hasNodeRun && !hasRunError" class="title-data-display-selector" @click.stop>
<n8n-radio-buttons <n8n-radio-buttons
v-model="displayMode" v-model="displayMode"
:options="buttons" :options="buttons"
/> />
</div> </div>
<div v-if="hasNodeRun && !hasRunError && displayMode === 'json' && state.path !== deselectedPlaceholder" class="select-button"> <div v-if="hasNodeRun && !hasRunError && displayMode === 'json' && state.path !== deselectedPlaceholder" class="select-button">
<el-dropdown trigger="click" @command="handleCopyClick"> <el-dropdown trigger="click" @command="handleCopyClick">
<span class="el-dropdown-link"> <span class="el-dropdown-link">
@ -76,53 +74,60 @@
</el-dropdown> </el-dropdown>
</div> </div>
</div> </div>
<div class="data-display-content">
<span v-if="node && workflowRunData !== null && workflowRunData.hasOwnProperty(node.name)"> <div v-if="!hasNodeRun" :class="$style.center">
<div v-if="workflowRunData[node.name][runIndex].error" class="error-display"> <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" /> <NodeErrorView :error="workflowRunData[node.name][runIndex].error" />
</div> </div>
<span v-else>
<div v-if="showData === false" class="too-much-data">
<h3>
{{ $locale.baseText('runData.nodeReturnedALargeAmountOfData') }}
</h3>
<div class="text"> <div v-else-if="hasNodeRun && jsonData && jsonData.length === 0" :class="$style.center">
<span v-html="$locale.baseText( <n8n-text :bold="true">{{ $locale.baseText('node.output.noOutputData.title') }}</n8n-text>
'runData.theNodeContains', <n8n-text>
{ {{ $locale.baseText('node.output.noOutputData.message') }}
interpolate: { <a @click="openSettings">{{ $locale.baseText('node.output.noOutputData.message.settings') }}</a>
numberOfKb: parseInt(dataSize/1024).toLocaleString() {{ $locale.baseText('node.output.noOutputData.message.settingsOption') }}
} </n8n-text>
}
)"></span>
</div> </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 <n8n-button
icon="eye" type="outline"
:label="$locale.baseText('runData.displayDataAnyway')" :label="$locale.baseText('node.output.tooMuchData.showDataAnyway')"
@click="displayMode = 'table';showData = true;" @click="showData = true"
/> />
</div> </div>
<div v-else-if="['json', 'table'].includes(displayMode)">
<div v-if="jsonData.length === 0" class="no-data"> <div v-else-if="hasNodeRun && displayMode === 'table' && tableData && tableData.columns && tableData.columns.length === 0" :class="$style.center">
{{ $locale.baseText('runData.noTextDataFound') }} <n8n-text align="center" tag="div">{{ $locale.baseText('runData.entriesExistButThey') }}</n8n-text>
</div> </div>
<div v-else-if="displayMode === 'table'">
<div v-if="tableData !== null && tableData.columns.length === 0" class="no-data"> <div v-else-if="hasNodeRun && displayMode === 'table' && tableData" :class="$style.dataDisplay">
{{ $locale.baseText('runData.entriesExistButThey') }} <n8n-text tag="div">
</div> {{ dataCount }} {{ $locale.baseText(dataCount === 1 ? 'node.output.item' : 'node.output.items') }}
<table v-else-if="tableData !== null"> </n8n-text>
<table :class="$style.table">
<tr> <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>
<tr v-for="(row, index1) in tableData.data" :key="index1"> <tr v-for="(row, index1) in tableData.data" :key="index1">
<td v-for="(data, index2) in row" :key="index2">{{ [null, undefined].includes(data) ? '&nbsp;' : data }}</td> <td v-for="(data, index2) in row" :key="index2">{{ [null, undefined].includes(data) ? '&nbsp;' : data }}</td>
</tr> </tr>
</table> </table>
</div> </div>
<div v-else-if="hasNodeRun && displayMode === 'json'" :class="$style.dataDisplay">
<vue-json-pretty <vue-json-pretty
v-else-if="displayMode === 'json'"
:data="jsonData" :data="jsonData"
:deep="10" :deep="10"
v-model="state.path" v-model="state.path"
@ -136,12 +141,12 @@
class="json-data" class="json-data"
/> />
</div> </div>
<div v-else-if="displayMode === 'binary'">
<div v-if="binaryData.length === 0" class="no-data"> <div v-else-if="displayMode === 'binary' && binaryData.length === 0">
{{ $locale.baseText('runData.noBinaryDataFound') }} <n8n-text align="center" tag="div">{{ $locale.baseText('runData.noBinaryDataFound') }}</n8n-text>
</div> </div>
<div v-else> <div v-else-if="displayMode === 'binary'">
<div v-for="(binaryDataEntry, index) in binaryData" :key="index"> <div v-for="(binaryDataEntry, index) in binaryData" :key="index">
<div class="binary-data-row-index"> <div class="binary-data-row-index">
<div class="binary-data-cell-index"> <div class="binary-data-cell-index">
@ -175,24 +180,13 @@
<div class="binary-data-show-data-button-wrapper"> <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)" /> <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>
</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> </template>
<script lang="ts"> <script lang="ts">
@ -364,6 +358,9 @@ export default mixins(
return inputData.length; return inputData.length;
}, },
dataSizeInMB(): string {
return (this.dataSize / 1024 / 1000).toLocaleString();
},
maxOutputIndex (): number { maxOutputIndex (): number {
if (this.node === null) { if (this.node === null) {
return 0; return 0;
@ -437,6 +434,9 @@ export default mixins(
}, },
}, },
methods: { methods: {
openSettings() {
this.$emit('openSettings');
},
init() { init() {
// Reset the selected output index every time another node gets selected // Reset the selected output index every time another node gets selected
this.outputIndex = 0; this.outputIndex = 0;
@ -659,6 +659,31 @@ export default mixins(
color: var(--color-foreground-dark); 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 { .title {
text-transform: uppercase; text-transform: uppercase;
color: var(--color-text-light); color: var(--color-text-light);
@ -683,26 +708,48 @@ export default mixins(
flex-grow: 1; flex-grow: 1;
} }
} }
</style>
<style lang="scss"> .dataDisplay {
.run-data-view {
.data-display-content {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
top: 50px; top: 60px;
left: 0; left: 16px;
right: 0; right: 0;
overflow-y: auto; overflow-y: auto;
line-height: 1.5; line-height: 1.5;
word-break: normal; word-break: normal;
font-size: var(--font-size-s);
> * {
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 { .binary-data-row {
display: inline-flex; display: inline-flex;
padding: 0.5em 1em; padding: 0.5em 1em;
font-size: var(--font-size-2xs);
.binary-data-cell { .binary-data-cell {
display: inline-block; display: inline-block;
@ -747,6 +794,7 @@ export default mixins(
.binary-data-row-index { .binary-data-row-index {
display: block; display: block;
padding: 1em 1em 0.25em 1em; padding: 1em 1em 0.25em 1em;
font-size: var(--font-size-2xs);
.binary-data-cell-index { .binary-data-cell-index {
display: inline-block; display: inline-block;
@ -762,95 +810,4 @@ export default mixins(
} }
} }
.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> </style>

View file

@ -748,7 +748,7 @@
"ms": "ms", "ms": "ms",
"noBinaryDataFound": "No binary data found", "noBinaryDataFound": "No binary data found",
"noData": "No data", "noData": "No data",
"noTextDataFound": "No text data found", "": "No text data found",
"nodeReturnedALargeAmountOfData": "Node returned a large amount of data", "nodeReturnedALargeAmountOfData": "Node returned a large amount of data",
"output": "Output", "output": "Output",
"showBinaryData": "Show Binary Data", "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.hint": "Executes this {nodeName} node after executing any previous nodes that have not yet returned data",
"node.execute.executeNode": "Execute node", "node.execute.executeNode": "Execute node",
"node.execute.executing": "Executing", "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.workflowImportError": "Could not import workflow",
"openWorkflow.workflowNotFoundError": "Could not find workflow", "openWorkflow.workflowNotFoundError": "Could not find workflow",
"settings": "Settings", "settings": "Settings",