refactor header

This commit is contained in:
Mutasem 2022-03-28 19:03:54 +02:00
parent 865b795733
commit 56f02b3362
8 changed files with 277 additions and 73 deletions

View file

@ -0,0 +1,57 @@
<template>
<label role="radio" tabindex="-1" :class="$style.container" aria-checked="true">
<input type="radio" tabindex="-1" autocomplete="off" :class="$style.input" :value="value">
<div :class="{[$style.button]: true, [$style.active]: active}" @click="$emit('click')">{{ label }}</div>
</label>
</template>
<script lang="ts">
export default {
name: 'n8n-radio-button',
props: {
label: {
type: String,
required: true,
},
value: {
type: String,
required: true,
},
active: {
type: Boolean,
default: false,
},
},
};
</script>
<style lang="scss" module>
.container {
display: inline-block;
outline: 0;
position: relative;
}
.input {
opacity: 0;
outline: 0;
z-index: -1;
position: absolute;
}
.button {
border-radius: 0;
padding: var(--spacing-2xs) 15px;
font-size: var(--font-size-2xs);
border-radius: var(--border-radius-base);
font-weight: var(--font-weight-bold);
color: var(--color-text-base);
cursor: pointer;
transition: background-color 0.2s ease;
}
.active {
background-color: var(--color-foreground-xlight);
color: var(--color-text-dark);
}
</style>

View file

@ -0,0 +1,51 @@
import N8nRadioButtons from './RadioButtons.vue';
import { action } from '@storybook/addon-actions';
export default {
title: 'Atoms/RadioButtons',
component: N8nRadioButtons,
argTypes: {
},
parameters: {
backgrounds: { default: '--color-background-xlight' },
},
};
const methods = {
onInput: action('input'),
};
const Template = (args, { argTypes }) => ({
props: Object.keys(argTypes),
components: {
N8nRadioButtons,
},
template:
`<n8n-radio-buttons v-model="val" v-bind="$props" @input="onInput">
</n8n-radio-buttons>`,
methods,
data() {
return {
val: '',
};
},
});
export const Example = Template.bind({});
Example.args = {
options: [
{
label: 'Test',
value: 'test',
},
{
label: 'World',
value: 'world',
},
{
label: 'Hello',
value: 'hello',
},
],
};

View file

@ -0,0 +1,49 @@
<template>
<div role="radiogroup" :class="$style.radioGroup">
<RadioButton
v-for="option in options"
:key="option.value"
v-bind="option"
:active="value === option.value"
@click="(e) => onClick(option.value, e)"
/>
</div>
</template>
<script lang="ts">
import RadioButton from './RadioButton';
export default {
name: 'n8n-radio-buttons',
props: {
value: {
type: String,
},
options: {
},
},
components: {
RadioButton,
},
methods: {
onClick(value) {
this.$emit('input', value);
},
},
};
</script>
<style lang="scss" module>
.radioGroup {
display: inline-block;
line-height: 1;
vertical-align: middle;
font-size: 0;
background-color: var(--color-foreground-base);
padding: var(--spacing-5xs);
border-radius: var(--border-radius-base);
}
</style>

View file

@ -0,0 +1,3 @@
import N8nRadioButtons from './RadioButtons.vue';
export default N8nRadioButtons;

View file

@ -53,6 +53,7 @@ import N8nMenu from './N8nMenu';
import N8nMenuItem from './N8nMenuItem';
import N8nLink from './N8nLink';
import N8nOption from './N8nOption';
import N8nRadioButtons from './N8nRadioButtons';
import N8nSelect from './N8nSelect';
import N8nSpinner from './N8nSpinner';
import N8nSquareButton from './N8nSquareButton';
@ -87,6 +88,7 @@ export {
N8nMenu,
N8nMenuItem,
N8nOption,
N8nRadioButtons,
N8nSelect,
N8nSpinner,
N8nSquareButton,

View file

@ -285,8 +285,8 @@
);
--color-background-light-h: 220;
--color-background-light-s: 27.3%;
--color-background-light-l: 97.8%;
--color-background-light-s: 60%;
--color-background-light-l: 99%;
--color-background-light: hsl(
var(--color-background-light-h),
var(--color-background-light-s),

View file

@ -1,10 +1,23 @@
<template>
<div class="run-data-view" v-loading="workflowRunning">
<div :class="['run-data-view', $style.container]" v-loading="workflowRunning">
<BinaryDataDisplay :windowVisible="binaryDataDisplayVisible" :displayData="binaryDataDisplayData" @close="closeBinaryDataDisplay"/>
<div class="header">
<div :class="$style.header">
<div>
<span :class="$style.title">{{ $locale.baseText('runData.output') }}</span>
<n8n-tooltip
v-if="runMetadata"
placement="right"
>
<div slot="content">
<n8n-text :bold="true" size="small">{{ $locale.baseText('runData.startTime') + ':' }}</n8n-text> {{runMetadata.startTime}}<br/>
<n8n-text :bold="true" size="small">{{ $locale.baseText('runData.executionTime') + ':' }}</n8n-text> {{runMetadata.executionTime}} {{ $locale.baseText('runData.ms') }}
</div>
<font-awesome-icon icon="info-circle" :class="$style.infoIcon" />
</n8n-tooltip>
</div>
<div class="title-text">
<n8n-text :bold="true" v-if="dataCount < maxDisplayItems">
<!-- <n8n-text :bold="true" v-if="dataCount < maxDisplayItems">
{{ $locale.baseText('runData.items') }}: {{ dataCount }}
</n8n-text>
<div v-else class="title-text">
@ -15,20 +28,11 @@
</n8n-select>
</span>/
<n8n-text :bold="true">{{ dataCount }}</n8n-text>
</div>
<n8n-tooltip
v-if="runMetadata"
placement="right"
>
<div slot="content">
<n8n-text :bold="true" size="small">{{ $locale.baseText('runData.startTime') + ':' }}</n8n-text> {{runMetadata.startTime}}<br/>
<n8n-text :bold="true" size="small">{{ $locale.baseText('runData.executionTime') + ':' }}</n8n-text> {{runMetadata.executionTime}} {{ $locale.baseText('runData.ms') }}
</div>
<font-awesome-icon icon="info-circle" class="primary-color" />
</n8n-tooltip>
<n8n-text :bold="true" v-if="maxOutputIndex > 0">
</div> -->
<!-- <n8n-text :bold="true" v-if="maxOutputIndex > 0">
| {{ $locale.baseText('runData.output') }}:
</n8n-text>
</n8n-text> -->
<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">
@ -48,13 +52,12 @@
</div>
<div v-if="hasNodeRun && !hasRunError" class="title-data-display-selector" @click.stop>
<el-radio-group v-model="displayMode" size="mini">
<el-radio-button :label="$locale.baseText('runData.json')" :disabled="showData === false"></el-radio-button>
<el-radio-button :label="$locale.baseText('runData.table')"></el-radio-button>
<el-radio-button :label="$locale.baseText('runData.binary')" v-if="binaryData.length !== 0"></el-radio-button>
</el-radio-group>
<n8n-radio-buttons
v-model="displayMode"
:options="buttons"
/>
</div>
<div v-if="hasNodeRun && !hasRunError && displayMode === $locale.baseText('runData.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">
<span class="el-dropdown-link">
<n8n-icon-button :title="$locale.baseText('runData.copyToClipboard')" icon="copy" />
@ -98,14 +101,14 @@
<n8n-button
icon="eye"
:label="$locale.baseText('runData.displayDataAnyway')"
@click="displayMode = $locale.baseText('runData.table');showData = true;"
@click="displayMode = 'table';showData = true;"
/>
</div>
<div v-else-if="[$locale.baseText('runData.json'), $locale.baseText('runData.table')].includes(displayMode)">
<div v-else-if="['json', 'table'].includes(displayMode)">
<div v-if="jsonData.length === 0" class="no-data">
{{ $locale.baseText('runData.noTextDataFound') }}
</div>
<div v-else-if="displayMode === $locale.baseText('runData.table')">
<div v-else-if="displayMode === 'table'">
<div v-if="tableData !== null && tableData.columns.length === 0" class="no-data">
{{ $locale.baseText('runData.entriesExistButThey') }}
</div>
@ -119,7 +122,7 @@
</table>
</div>
<vue-json-pretty
v-else-if="displayMode === $locale.baseText('runData.json')"
v-else-if="displayMode === 'json'"
:data="jsonData"
:deep="10"
v-model="state.path"
@ -133,7 +136,7 @@
class="json-data"
/>
</div>
<div v-else-if="displayMode === $locale.baseText('runData.binary')">
<div v-else-if="displayMode === 'binary'">
<div v-if="binaryData.length === 0" class="no-data">
{{ $locale.baseText('runData.noBinaryDataFound') }}
</div>
@ -249,7 +252,7 @@ export default mixins(
binaryDataPreviewActive: false,
dataSize: 0,
deselectedPlaceholder,
displayMode: this.$locale.baseText('runData.table'),
displayMode: 'table',
state: {
value: '' as object | number | string,
path: deselectedPlaceholder,
@ -269,6 +272,19 @@ export default mixins(
this.init();
},
computed: {
buttons(): {label: string, value: string}[] {
const defaults = [
{ label: this.$locale.baseText('runData.json'), value: 'json'},
{ label: this.$locale.baseText('runData.table'), value: 'table'},
];
if (this.binaryData.length) {
return [ ...defaults,
{ label: this.$locale.baseText('runData.binary'), value: 'binary'},
];
}
return defaults;
},
hasNodeRun(): boolean {
return Boolean(this.node && this.workflowRunData && this.workflowRunData.hasOwnProperty(this.node.name));
},
@ -426,10 +442,10 @@ export default mixins(
this.outputIndex = 0;
this.maxDisplayItems = 25;
this.refreshDataSize();
if (this.displayMode === this.$locale.baseText('runData.binary')) {
if (this.displayMode === 'binary') {
this.closeBinaryDataDisplay();
if (this.binaryData.length === 0) {
this.displayMode = this.$locale.baseText('runData.table');
this.displayMode = 'table';
}
}
},
@ -638,13 +654,40 @@ export default mixins(
});
</script>
<style lang="scss">
<style lang="scss" module>
.infoIcon {
color: var(--color-foreground-dark);
}
.run-data-view {
.title {
text-transform: uppercase;
color: var(--color-text-light);
letter-spacing: 3px;
font-weight: var(--font-weight-bold);
margin-right: var(--spacing-2xs);
}
.container {
position: relative;
width: 100%;
height: 100%;
background-color: #f9f9f9;
background-color: var(--color-background-light);
padding: var(--spacing-s) var(--spacing-s) 0 var(--spacing-s);
}
.header {
display: flex;
align-items: center;
> *:first-child {
flex-grow: 1;
}
}
</style>
<style lang="scss">
.run-data-view {
.data-display-content {
position: absolute;
@ -767,50 +810,47 @@ export default mixins(
}
}
.header {
padding-top: 10px;
padding-left: 10px;
// .header {
// display: flex;
// align-items: center;
// height: 40px;
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;
// }
.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;
.title-text {
display: inline-flex;
align-items: center;
// > * {
// margin-right: 2px;
// }
// }
> * {
margin-right: 2px;
}
}
// .title-data-display-selector {
// position: absolute;
// left: calc(50% - 105px);
// width: 210px;
// display: inline-block;
// text-align: center;
.title-data-display-selector {
position: absolute;
left: calc(50% - 105px);
width: 210px;
display: inline-block;
text-align: center;
// .entry.active {
// font-weight: bold;
// }
// }
.entry.active {
font-weight: bold;
}
}
.opts {
width: 80px;
z-index: 1;
}
}
// .opts {
// width: 80px;
// z-index: 1;
// }
// }
}
</style>

View file

@ -61,6 +61,7 @@ import {
N8nMenu,
N8nMenuItem,
N8nOption,
N8nRadioButtons,
N8nSelect,
N8nSpinner,
N8nFormInputs,
@ -97,6 +98,7 @@ Vue.use(N8nMenuItem);
Vue.use(N8nOption);
Vue.use(N8nSelect);
Vue.use(N8nSpinner);
Vue.use(N8nRadioButtons);
Vue.component('n8n-square-button', N8nSquareButton);
Vue.use(N8nTags);
Vue.use(N8nTag);