mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
fix(editor): Insights design review 3 (no-changelog) (#14520)
This commit is contained in:
committed by
GitHub
parent
5826ff2cec
commit
e54f450a9d
@@ -29,6 +29,7 @@ export const generateLineChartOptions = (
|
||||
{
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
animation: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: false,
|
||||
@@ -115,6 +116,7 @@ export const generateBarChartOptions = (
|
||||
{
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
animation: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
display: true,
|
||||
@@ -126,6 +128,7 @@ export const generateBarChartOptions = (
|
||||
boxHeight: 8,
|
||||
borderRadius: 2,
|
||||
useBorderRadius: true,
|
||||
color: colorTextLight.value,
|
||||
},
|
||||
},
|
||||
tooltip: {
|
||||
|
||||
@@ -91,56 +91,64 @@ watch(
|
||||
|
||||
<template>
|
||||
<div :class="$style.insightsView">
|
||||
<N8nHeading bold tag="h2" size="xlarge">
|
||||
{{ i18n.baseText('insights.dashboard.title') }}
|
||||
</N8nHeading>
|
||||
<div>
|
||||
<InsightsSummary
|
||||
v-if="insightsStore.isSummaryEnabled"
|
||||
:summary="insightsStore.summary.state"
|
||||
:loading="insightsStore.summary.isLoading"
|
||||
:class="$style.insightsBanner"
|
||||
/>
|
||||
<div v-if="insightsStore.isInsightsEnabled" :class="$style.insightsContent">
|
||||
<div :class="$style.insightsChartWrapper">
|
||||
<template v-if="insightsStore.charts.isLoading"> loading </template>
|
||||
<component
|
||||
:is="chartComponents[props.insightType]"
|
||||
v-else
|
||||
:type="props.insightType"
|
||||
:data="insightsStore.charts.state"
|
||||
/>
|
||||
</div>
|
||||
<div :class="$style.insightsTableWrapper">
|
||||
<InsightsTableWorkflows
|
||||
v-model:sort-by="sortTableBy"
|
||||
:data="insightsStore.table.state"
|
||||
:loading="insightsStore.table.isLoading"
|
||||
@update:options="fetchPaginatedTableData"
|
||||
/>
|
||||
<div :class="$style.insightsContainer">
|
||||
<N8nHeading bold tag="h2" size="xlarge">
|
||||
{{ i18n.baseText('insights.dashboard.title') }}
|
||||
</N8nHeading>
|
||||
<div>
|
||||
<InsightsSummary
|
||||
v-if="insightsStore.isSummaryEnabled"
|
||||
:summary="insightsStore.summary.state"
|
||||
:loading="insightsStore.summary.isLoading"
|
||||
:class="$style.insightsBanner"
|
||||
/>
|
||||
<div v-if="insightsStore.isInsightsEnabled" :class="$style.insightsContent">
|
||||
<div :class="$style.insightsChartWrapper">
|
||||
<template v-if="insightsStore.charts.isLoading"> loading </template>
|
||||
<component
|
||||
:is="chartComponents[props.insightType]"
|
||||
v-else
|
||||
:type="props.insightType"
|
||||
:data="insightsStore.charts.state"
|
||||
/>
|
||||
</div>
|
||||
<div :class="$style.insightsTableWrapper">
|
||||
<InsightsTableWorkflows
|
||||
v-model:sort-by="sortTableBy"
|
||||
:data="insightsStore.table.state"
|
||||
:loading="insightsStore.table.isLoading"
|
||||
@update:options="fetchPaginatedTableData"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<InsightsPaywall v-else data-test-id="insights-dashboard-unlicensed" />
|
||||
</div>
|
||||
<InsightsPaywall v-else data-test-id="insights-dashboard-unlicensed" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" module>
|
||||
.insightsView {
|
||||
padding: var(--spacing-l) var(--spacing-2xl);
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 30px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.insightsContainer {
|
||||
width: 100%;
|
||||
max-width: var(--content-container-width);
|
||||
padding: var(--spacing-l) var(--spacing-2xl);
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.insightsBanner {
|
||||
padding-bottom: 0;
|
||||
|
||||
ul {
|
||||
border-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
import { VIEWS } from '@/constants';
|
||||
import {
|
||||
INSIGHT_IMPACT_TYPES,
|
||||
@@ -10,7 +11,6 @@ import type { InsightsSummary } from '@n8n/api-types';
|
||||
import { smartDecimal } from '@n8n/utils/number/smartDecimal';
|
||||
import { computed, ref, useCssModule } from 'vue';
|
||||
import { useRoute } from 'vue-router';
|
||||
import { useTelemetry } from '@/composables/useTelemetry';
|
||||
|
||||
const props = defineProps<{
|
||||
summary: InsightsSummaryDisplay;
|
||||
@@ -62,61 +62,65 @@ const trackTabClick = (insightType: keyof InsightsSummary) => {
|
||||
|
||||
<template>
|
||||
<div :class="$style.insights">
|
||||
<N8nLoading v-if="loading" :class="$style.loading" :cols="5" />
|
||||
<ul v-else data-test-id="insights-summary-tabs">
|
||||
<li
|
||||
v-for="{ id, value, deviation, deviationUnit, unit, to } in summaryWithRouteLocations"
|
||||
:key="id"
|
||||
:data-test-id="`insights-summary-tab-${id}`"
|
||||
>
|
||||
<router-link :to="to" :exact-active-class="$style.activeTab" @click="trackTabClick(id)">
|
||||
<strong>
|
||||
<N8nTooltip placement="bottom" :disabled="id !== 'timeSaved'">
|
||||
<template #content>
|
||||
{{ i18n.baseText('insights.banner.title.timeSaved.tooltip') }}
|
||||
</template>
|
||||
{{ summaryTitles[id] }}
|
||||
</N8nTooltip>
|
||||
</strong>
|
||||
<small :class="$style.days">{{
|
||||
i18n.baseText('insights.lastNDays', { interpolate: { count: lastNDays } })
|
||||
}}</small>
|
||||
<span v-if="value === 0 && id === 'timeSaved'" :class="$style.empty">
|
||||
<em>--</em>
|
||||
<small>
|
||||
<N8nTooltip placement="bottom">
|
||||
<ul data-test-id="insights-summary-tabs">
|
||||
<N8nLoading v-if="loading" :class="$style.loading" :cols="5" />
|
||||
<template v-else>
|
||||
<li
|
||||
v-for="{ id, value, deviation, deviationUnit, unit, to } in summaryWithRouteLocations"
|
||||
:key="id"
|
||||
:data-test-id="`insights-summary-tab-${id}`"
|
||||
>
|
||||
<router-link :to="to" :exact-active-class="$style.activeTab" @click="trackTabClick(id)">
|
||||
<strong>
|
||||
<N8nTooltip placement="bottom" :disabled="id !== 'timeSaved'">
|
||||
<template #content>
|
||||
<i18n-t keypath="insights.banner.timeSaved.tooltip">
|
||||
<template #link>
|
||||
<a href="#">{{
|
||||
i18n.baseText('insights.banner.timeSaved.tooltip.link.text')
|
||||
}}</a>
|
||||
</template>
|
||||
</i18n-t>
|
||||
{{ i18n.baseText('insights.banner.title.timeSaved.tooltip') }}
|
||||
</template>
|
||||
<N8nIcon :class="$style.icon" icon="info-circle" />
|
||||
{{ summaryTitles[id] }}
|
||||
</N8nTooltip>
|
||||
</small>
|
||||
</span>
|
||||
<span v-else>
|
||||
<em
|
||||
>{{ smartDecimal(value).toLocaleString('en-US') }} <i>{{ unit }}</i></em
|
||||
>
|
||||
<small v-if="deviation !== null" :class="getImpactStyle(id, deviation)">
|
||||
<N8nIcon
|
||||
:class="[$style.icon, getImpactStyle(id, deviation)]"
|
||||
:icon="deviation === 0 ? 'caret-right' : deviation > 0 ? 'caret-up' : 'caret-down'"
|
||||
/>
|
||||
<N8nTooltip placement="bottom" :disabled="id !== 'failureRate'">
|
||||
<template #content>
|
||||
{{ i18n.baseText('insights.banner.failureRate.deviation.tooltip') }}
|
||||
</template>
|
||||
{{ smartDecimal(Math.abs(deviation)).toLocaleString('en-US') }}{{ deviationUnit }}
|
||||
</N8nTooltip>
|
||||
</small>
|
||||
</span>
|
||||
</router-link>
|
||||
</li>
|
||||
</strong>
|
||||
<small :class="$style.days">{{
|
||||
i18n.baseText('insights.lastNDays', { interpolate: { count: lastNDays } })
|
||||
}}</small>
|
||||
<span v-if="value === 0 && id === 'timeSaved'" :class="$style.empty">
|
||||
<em>--</em>
|
||||
<small>
|
||||
<N8nTooltip placement="bottom">
|
||||
<template #content>
|
||||
<i18n-t keypath="insights.banner.timeSaved.tooltip">
|
||||
<template #link>
|
||||
<a href="#">{{
|
||||
i18n.baseText('insights.banner.timeSaved.tooltip.link.text')
|
||||
}}</a>
|
||||
</template>
|
||||
</i18n-t>
|
||||
</template>
|
||||
<N8nIcon :class="$style.icon" icon="info-circle" />
|
||||
</N8nTooltip>
|
||||
</small>
|
||||
</span>
|
||||
<span v-else>
|
||||
<em
|
||||
>{{ smartDecimal(value).toLocaleString('en-US') }} <i>{{ unit }}</i></em
|
||||
>
|
||||
<small v-if="deviation !== null" :class="getImpactStyle(id, deviation)">
|
||||
<N8nIcon
|
||||
:class="[$style.icon, getImpactStyle(id, deviation)]"
|
||||
:icon="
|
||||
deviation === 0 ? 'caret-right' : deviation > 0 ? 'caret-up' : 'caret-down'
|
||||
"
|
||||
/>
|
||||
<N8nTooltip placement="bottom" :disabled="id !== 'failureRate'">
|
||||
<template #content>
|
||||
{{ i18n.baseText('insights.banner.failureRate.deviation.tooltip') }}
|
||||
</template>
|
||||
{{ smartDecimal(Math.abs(deviation)).toLocaleString('en-US') }}{{ deviationUnit }}
|
||||
</N8nTooltip>
|
||||
</small>
|
||||
</span>
|
||||
</router-link>
|
||||
</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
@@ -222,7 +226,6 @@ const trackTabClick = (insightType: keyof InsightsSummary) => {
|
||||
gap: var(--spacing-5xs);
|
||||
|
||||
i {
|
||||
color: var(--color-text-light);
|
||||
font-size: 22px;
|
||||
font-style: normal;
|
||||
}
|
||||
@@ -268,13 +271,13 @@ const trackTabClick = (insightType: keyof InsightsSummary) => {
|
||||
|
||||
.loading {
|
||||
display: flex;
|
||||
min-height: 91px;
|
||||
align-self: stretch;
|
||||
align-items: stretch;
|
||||
|
||||
> div {
|
||||
margin: 0;
|
||||
height: auto;
|
||||
border-radius: inherit;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { generateBarChartOptions } from '@/features/insights/chartjs.utils';
|
||||
import { DATE_FORMAT_MASK } from '@/features/insights/insights.constants';
|
||||
import type { InsightsByTime, InsightsSummaryType } from '@n8n/api-types';
|
||||
import { smartDecimal } from '@n8n/utils/number/smartDecimal';
|
||||
import { useCssVar } from '@vueuse/core';
|
||||
import type { ChartData } from 'chart.js';
|
||||
import dateformat from 'dateformat';
|
||||
import { computed } from 'vue';
|
||||
import { Bar } from 'vue-chartjs';
|
||||
import type { ChartData } from 'chart.js';
|
||||
import { useCssVar } from '@vueuse/core';
|
||||
import dateformat from 'dateformat';
|
||||
import type { InsightsByTime, InsightsSummaryType } from '@n8n/api-types';
|
||||
import { generateBarChartOptions } from '@/features/insights/chartjs.utils';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { smartDecimal } from '@n8n/utils/number/smartDecimal';
|
||||
import { DATE_FORMAT_MASK } from '@/features/insights/insights.constants';
|
||||
|
||||
const props = defineProps<{
|
||||
data: InsightsByTime[];
|
||||
@@ -46,7 +46,7 @@ const chartData = computed<ChartData<'bar'>>(() => {
|
||||
labels,
|
||||
datasets: [
|
||||
{
|
||||
label: i18n.baseText('insights.banner.title.failed'),
|
||||
label: i18n.baseText('insights.chart.failed'),
|
||||
data,
|
||||
backgroundColor: colorPrimary.value,
|
||||
},
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<script lang="ts" setup>
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { generateBarChartOptions } from '@/features/insights/chartjs.utils';
|
||||
import { DATE_FORMAT_MASK } from '@/features/insights/insights.constants';
|
||||
import type { InsightsByTime, InsightsSummaryType } from '@n8n/api-types';
|
||||
import { useCssVar } from '@vueuse/core';
|
||||
import type { ChartData } from 'chart.js';
|
||||
import dateformat from 'dateformat';
|
||||
import { computed } from 'vue';
|
||||
import { Bar } from 'vue-chartjs';
|
||||
import type { ChartData } from 'chart.js';
|
||||
import { useCssVar } from '@vueuse/core';
|
||||
import dateformat from 'dateformat';
|
||||
import type { InsightsByTime, InsightsSummaryType } from '@n8n/api-types';
|
||||
import { generateBarChartOptions } from '@/features/insights/chartjs.utils';
|
||||
import { useI18n } from '@/composables/useI18n';
|
||||
import { DATE_FORMAT_MASK } from '@/features/insights/insights.constants';
|
||||
|
||||
const props = defineProps<{
|
||||
data: InsightsByTime[];
|
||||
@@ -21,8 +21,7 @@ const chartOptions = computed(() =>
|
||||
generateBarChartOptions({
|
||||
plugins: {
|
||||
tooltip: {
|
||||
itemSort: (a) =>
|
||||
a.dataset.label === i18n.baseText('insights.banner.title.succeeded') ? -1 : 1,
|
||||
itemSort: (a) => (a.dataset.label === i18n.baseText('insights.chart.succeeded') ? -1 : 1),
|
||||
},
|
||||
},
|
||||
}),
|
||||
@@ -43,12 +42,12 @@ const chartData = computed<ChartData<'bar'>>(() => {
|
||||
labels,
|
||||
datasets: [
|
||||
{
|
||||
label: i18n.baseText('insights.banner.title.failed'),
|
||||
label: i18n.baseText('insights.chart.failed'),
|
||||
data: failedData,
|
||||
backgroundColor: colorPrimary.value,
|
||||
},
|
||||
{
|
||||
label: i18n.baseText('insights.banner.title.succeeded'),
|
||||
label: i18n.baseText('insights.chart.succeeded'),
|
||||
data: succeededData,
|
||||
backgroundColor: '#3E999F',
|
||||
},
|
||||
|
||||
@@ -3083,12 +3083,13 @@
|
||||
"insights.banner.timeSaved.tooltip.link.text": "add time estimates",
|
||||
"insights.banner.title.total": "Prod. executions",
|
||||
"insights.banner.title.failed": "Failed prod. executions",
|
||||
"insights.banner.title.succeeded": "Successful prod. executions",
|
||||
"insights.banner.title.failureRate": "Failure rate",
|
||||
"insights.banner.title.timeSaved": "Time saved",
|
||||
"insights.banner.title.timeSavedDailyAverage": "Time saved daily avg.",
|
||||
"insights.banner.title.averageRunTime": "Run time (avg.)",
|
||||
"insights.dashboard.title": "Insights",
|
||||
"insights.banner.title.timeSaved.tooltip": "Total time saved calculated from your estimated time savings per execution across all workflows",
|
||||
"insights.banner.failureRate.deviation.tooltip": "Percentage point change from previous period"
|
||||
"insights.banner.failureRate.deviation.tooltip": "Percentage point change from previous period",
|
||||
"insights.chart.failed": "Failed",
|
||||
"insights.chart.succeeded": "Successful"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user