mirror of
https://github.com/n8n-io/n8n.git
synced 2024-12-25 12:44:07 -08:00
feat(editor): Separate node output execution tooltip from status icon (#11196)
This commit is contained in:
parent
321d6deef1
commit
cd15e959c7
|
@ -23,6 +23,7 @@ describe('Manual partial execution', () => {
|
||||||
canvas.actions.openNode('Webhook1');
|
canvas.actions.openNode('Webhook1');
|
||||||
|
|
||||||
ndv.getters.nodeRunSuccessIndicator().should('exist');
|
ndv.getters.nodeRunSuccessIndicator().should('exist');
|
||||||
|
ndv.getters.nodeRunTooltipIndicator().should('exist');
|
||||||
ndv.getters.outputRunSelector().should('not.exist'); // single run
|
ndv.getters.outputRunSelector().should('not.exist'); // single run
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -133,9 +133,10 @@ describe('NDV', () => {
|
||||||
"An expression here won't work because it uses .item and n8n can't figure out the matching item.",
|
"An expression here won't work because it uses .item and n8n can't figure out the matching item.",
|
||||||
);
|
);
|
||||||
ndv.getters.nodeRunErrorIndicator().should('be.visible');
|
ndv.getters.nodeRunErrorIndicator().should('be.visible');
|
||||||
|
ndv.getters.nodeRunTooltipIndicator().should('be.visible');
|
||||||
// The error details should be hidden behind a tooltip
|
// The error details should be hidden behind a tooltip
|
||||||
ndv.getters.nodeRunErrorIndicator().should('not.contain', 'Start Time');
|
ndv.getters.nodeRunTooltipIndicator().should('not.contain', 'Start Time');
|
||||||
ndv.getters.nodeRunErrorIndicator().should('not.contain', 'Execution Time');
|
ndv.getters.nodeRunTooltipIndicator().should('not.contain', 'Execution Time');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should save workflow using keyboard shortcut from NDV', () => {
|
it('should save workflow using keyboard shortcut from NDV', () => {
|
||||||
|
@ -617,8 +618,10 @@ describe('NDV', () => {
|
||||||
// Should not show run info before execution
|
// Should not show run info before execution
|
||||||
ndv.getters.nodeRunSuccessIndicator().should('not.exist');
|
ndv.getters.nodeRunSuccessIndicator().should('not.exist');
|
||||||
ndv.getters.nodeRunErrorIndicator().should('not.exist');
|
ndv.getters.nodeRunErrorIndicator().should('not.exist');
|
||||||
|
ndv.getters.nodeRunTooltipIndicator().should('not.exist');
|
||||||
ndv.getters.nodeExecuteButton().click();
|
ndv.getters.nodeExecuteButton().click();
|
||||||
ndv.getters.nodeRunSuccessIndicator().should('exist');
|
ndv.getters.nodeRunSuccessIndicator().should('exist');
|
||||||
|
ndv.getters.nodeRunTooltipIndicator().should('exist');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should properly show node execution indicator for multiple nodes', () => {
|
it('should properly show node execution indicator for multiple nodes', () => {
|
||||||
|
@ -630,6 +633,7 @@ describe('NDV', () => {
|
||||||
// Manual tigger node should show success indicator
|
// Manual tigger node should show success indicator
|
||||||
workflowPage.actions.openNode('When clicking ‘Test workflow’');
|
workflowPage.actions.openNode('When clicking ‘Test workflow’');
|
||||||
ndv.getters.nodeRunSuccessIndicator().should('exist');
|
ndv.getters.nodeRunSuccessIndicator().should('exist');
|
||||||
|
ndv.getters.nodeRunTooltipIndicator().should('exist');
|
||||||
// Code node should show error
|
// Code node should show error
|
||||||
ndv.getters.backToCanvas().click();
|
ndv.getters.backToCanvas().click();
|
||||||
workflowPage.actions.openNode('Code');
|
workflowPage.actions.openNode('Code');
|
||||||
|
|
|
@ -130,8 +130,9 @@ export class NDV extends BasePage {
|
||||||
codeEditorFullscreenButton: () => cy.getByTestId('code-editor-fullscreen-button'),
|
codeEditorFullscreenButton: () => cy.getByTestId('code-editor-fullscreen-button'),
|
||||||
codeEditorDialog: () => cy.getByTestId('code-editor-fullscreen'),
|
codeEditorDialog: () => cy.getByTestId('code-editor-fullscreen'),
|
||||||
codeEditorFullscreen: () => this.getters.codeEditorDialog().find('.cm-content'),
|
codeEditorFullscreen: () => this.getters.codeEditorDialog().find('.cm-content'),
|
||||||
nodeRunSuccessIndicator: () => cy.getByTestId('node-run-info-success'),
|
nodeRunTooltipIndicator: () => cy.getByTestId('node-run-info'),
|
||||||
nodeRunErrorIndicator: () => cy.getByTestId('node-run-info-danger'),
|
nodeRunSuccessIndicator: () => cy.getByTestId('node-run-status-success'),
|
||||||
|
nodeRunErrorIndicator: () => cy.getByTestId('node-run-status-danger'),
|
||||||
nodeRunErrorMessage: () => cy.getByTestId('node-error-message'),
|
nodeRunErrorMessage: () => cy.getByTestId('node-error-message'),
|
||||||
nodeRunErrorDescription: () => cy.getByTestId('node-error-description'),
|
nodeRunErrorDescription: () => cy.getByTestId('node-error-description'),
|
||||||
fixedCollectionParameter: (paramName: string) =>
|
fixedCollectionParameter: (paramName: string) =>
|
||||||
|
|
|
@ -2,12 +2,24 @@
|
||||||
import type { Placement } from 'element-plus';
|
import type { Placement } from 'element-plus';
|
||||||
import { computed } from 'vue';
|
import { computed } from 'vue';
|
||||||
|
|
||||||
|
import type { IconColor } from 'n8n-design-system/types/icon';
|
||||||
|
|
||||||
import N8nIcon from '../N8nIcon';
|
import N8nIcon from '../N8nIcon';
|
||||||
import N8nTooltip from '../N8nTooltip';
|
import N8nTooltip from '../N8nTooltip';
|
||||||
|
|
||||||
const THEME = ['info', 'info-light', 'warning', 'danger', 'success'] as const;
|
const THEME = ['info', 'info-light', 'warning', 'danger', 'success'] as const;
|
||||||
const TYPE = ['note', 'tooltip'] as const;
|
const TYPE = ['note', 'tooltip'] as const;
|
||||||
|
|
||||||
|
const ICON_MAP = {
|
||||||
|
info: 'info-circle',
|
||||||
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||||
|
'info-light': 'info-circle',
|
||||||
|
warning: 'exclamation-triangle',
|
||||||
|
danger: 'exclamation-triangle',
|
||||||
|
success: 'check-circle',
|
||||||
|
} as const;
|
||||||
|
type IconMap = typeof ICON_MAP;
|
||||||
|
|
||||||
interface InfoTipProps {
|
interface InfoTipProps {
|
||||||
theme?: (typeof THEME)[number];
|
theme?: (typeof THEME)[number];
|
||||||
type?: (typeof TYPE)[number];
|
type?: (typeof TYPE)[number];
|
||||||
|
@ -23,39 +35,11 @@ const props = withDefaults(defineProps<InfoTipProps>(), {
|
||||||
tooltipPlacement: 'top',
|
tooltipPlacement: 'top',
|
||||||
});
|
});
|
||||||
|
|
||||||
const iconData = computed((): { icon: string; color: string } => {
|
const iconData = computed<{ icon: IconMap[keyof IconMap]; color: IconColor }>(() => {
|
||||||
switch (props.theme) {
|
return {
|
||||||
case 'info':
|
icon: ICON_MAP[props.theme],
|
||||||
return {
|
color: props.theme === 'info' || props.theme === 'info-light' ? 'text-base' : props.theme,
|
||||||
icon: 'info-circle',
|
} as const;
|
||||||
color: '--color-text-light)',
|
|
||||||
};
|
|
||||||
case 'info-light':
|
|
||||||
return {
|
|
||||||
icon: 'info-circle',
|
|
||||||
color: 'var(--color-foreground-dark)',
|
|
||||||
};
|
|
||||||
case 'warning':
|
|
||||||
return {
|
|
||||||
icon: 'exclamation-triangle',
|
|
||||||
color: 'var(--color-warning)',
|
|
||||||
};
|
|
||||||
case 'danger':
|
|
||||||
return {
|
|
||||||
icon: 'exclamation-triangle',
|
|
||||||
color: 'var(--color-danger)',
|
|
||||||
};
|
|
||||||
case 'success':
|
|
||||||
return {
|
|
||||||
icon: 'check-circle',
|
|
||||||
color: 'var(--color-success)',
|
|
||||||
};
|
|
||||||
default:
|
|
||||||
return {
|
|
||||||
icon: 'info-circle',
|
|
||||||
color: '--color-text-light)',
|
|
||||||
};
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
@ -69,14 +53,16 @@ const iconData = computed((): { icon: string; color: string } => {
|
||||||
[$style.bold]: bold,
|
[$style.bold]: bold,
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
|
<!-- Note that the branching is required to support displaying
|
||||||
|
the slot either in the tooltip of the icon or following it -->
|
||||||
<N8nTooltip
|
<N8nTooltip
|
||||||
v-if="type === 'tooltip'"
|
v-if="type === 'tooltip'"
|
||||||
:placement="tooltipPlacement"
|
:placement="tooltipPlacement"
|
||||||
:popper-class="$style.tooltipPopper"
|
:popper-class="$style.tooltipPopper"
|
||||||
:disabled="type !== 'tooltip'"
|
:disabled="type !== 'tooltip'"
|
||||||
>
|
>
|
||||||
<span :class="$style.iconText" :style="{ color: iconData.color }">
|
<span :class="$style.iconText">
|
||||||
<N8nIcon :icon="iconData.icon" />
|
<N8nIcon :icon="iconData.icon" :color="iconData.color" />
|
||||||
</span>
|
</span>
|
||||||
<template #content>
|
<template #content>
|
||||||
<span>
|
<span>
|
||||||
|
@ -85,7 +71,7 @@ const iconData = computed((): { icon: string; color: string } => {
|
||||||
</template>
|
</template>
|
||||||
</N8nTooltip>
|
</N8nTooltip>
|
||||||
<span v-else :class="$style.iconText">
|
<span v-else :class="$style.iconText">
|
||||||
<N8nIcon :icon="iconData.icon" />
|
<N8nIcon :icon="iconData.icon" :color="iconData.color" />
|
||||||
<span>
|
<span>
|
||||||
<slot />
|
<slot />
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,9 +1,16 @@
|
||||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`N8nInfoTip > should render correctly as note 1`] = `"<div class="n8n-info-tip infoTip info note bold"><span class="iconText"><span class="n8n-text compact size-medium regular n8n-icon n8n-icon"><!----></span><span>Need help doing something?<a href="/docs" target="_blank">Open docs</a></span></span></div>"`;
|
exports[`N8nInfoTip > should render correctly as note 1`] = `
|
||||||
|
"<div class="n8n-info-tip infoTip info note bold">
|
||||||
|
<!-- Note that the branching is required to support displaying
|
||||||
|
the slot either in the tooltip of the icon or following it --><span class="iconText"><span class="n8n-text text-base compact size-medium regular n8n-icon n8n-icon"><!----></span><span>Need help doing something?<a href="/docs" target="_blank">Open docs</a></span></span>
|
||||||
|
</div>"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`N8nInfoTip > should render correctly as tooltip 1`] = `
|
exports[`N8nInfoTip > should render correctly as tooltip 1`] = `
|
||||||
"<div class="n8n-info-tip infoTip info tooltip bold"><span class="iconText el-tooltip__trigger el-tooltip__trigger"><span class="n8n-text compact size-medium regular n8n-icon n8n-icon"><!----></span></span>
|
"<div class="n8n-info-tip infoTip info tooltip bold">
|
||||||
|
<!-- Note that the branching is required to support displaying
|
||||||
|
the slot either in the tooltip of the icon or following it --><span class="iconText el-tooltip__trigger el-tooltip__trigger"><span class="n8n-text text-base compact size-medium regular n8n-icon n8n-icon"><!----></span></span>
|
||||||
<!--teleport start-->
|
<!--teleport start-->
|
||||||
<!--teleport end-->
|
<!--teleport end-->
|
||||||
</div>"
|
</div>"
|
||||||
|
|
|
@ -50,27 +50,38 @@ const runMetadata = computed(() => {
|
||||||
"
|
"
|
||||||
></span>
|
></span>
|
||||||
</n8n-info-tip>
|
</n8n-info-tip>
|
||||||
<n8n-info-tip
|
<div v-else-if="runMetadata" :class="$style.tooltipRow">
|
||||||
v-else-if="runMetadata"
|
<n8n-info-tip type="note" :theme="theme" :data-test-id="`node-run-status-${theme}`" />
|
||||||
type="tooltip"
|
<n8n-info-tip
|
||||||
:theme="theme"
|
type="tooltip"
|
||||||
:data-test-id="`node-run-info-${theme}`"
|
theme="info"
|
||||||
tooltip-placement="right"
|
:data-test-id="`node-run-info`"
|
||||||
>
|
tooltip-placement="right"
|
||||||
<div>
|
>
|
||||||
<n8n-text :bold="true" size="small"
|
<div>
|
||||||
>{{
|
<n8n-text :bold="true" size="small"
|
||||||
runTaskData?.error
|
>{{
|
||||||
? i18n.baseText('runData.executionStatus.failed')
|
runTaskData?.error
|
||||||
: i18n.baseText('runData.executionStatus.success')
|
? i18n.baseText('runData.executionStatus.failed')
|
||||||
}} </n8n-text
|
: i18n.baseText('runData.executionStatus.success')
|
||||||
><br />
|
}} </n8n-text
|
||||||
<n8n-text :bold="true" size="small">{{ i18n.baseText('runData.startTime') + ':' }}</n8n-text>
|
><br />
|
||||||
{{ runMetadata.startTime }}<br />
|
<n8n-text :bold="true" size="small">{{
|
||||||
<n8n-text :bold="true" size="small">{{
|
i18n.baseText('runData.startTime') + ':'
|
||||||
i18n.baseText('runData.executionTime') + ':'
|
}}</n8n-text>
|
||||||
}}</n8n-text>
|
{{ runMetadata.startTime }}<br />
|
||||||
{{ runMetadata.executionTime }} {{ i18n.baseText('runData.ms') }}
|
<n8n-text :bold="true" size="small">{{
|
||||||
</div>
|
i18n.baseText('runData.executionTime') + ':'
|
||||||
</n8n-info-tip>
|
}}</n8n-text>
|
||||||
|
{{ runMetadata.executionTime }} {{ i18n.baseText('runData.ms') }}
|
||||||
|
</div>
|
||||||
|
</n8n-info-tip>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss" module>
|
||||||
|
.tooltipRow {
|
||||||
|
display: flex;
|
||||||
|
column-gap: var(--spacing-4xs);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
Loading…
Reference in a new issue