Files
Automata/packages/editor-ui/src/components/WorkerList.ee.vue
Michael Auerswald cbc690907f feat(editor): Adds a EE view to show worker details and job status (#7600)
This change expands on the command channel communication introduced
lately between the main instance(s) and the workers. The frontend gets a
new menu entry "Workers" which will, when opened, trigger a regular call
to getStatus from the workers. The workers then respond via their
response channel to the backend, which then pushes the status to the
frontend.
This introduces the use of ChartJS for metrics.
This feature is still in MVP state and thus disabled by default for the
moment.
2023-11-10 23:48:31 +01:00

131 lines
3.6 KiB
Vue

<template>
<div>
<PushConnectionTracker class="actions"></PushConnectionTracker>
<div :class="$style.workerListHeader">
<n8n-heading tag="h1" size="2xlarge">{{ pageTitle }}</n8n-heading>
</div>
<div v-if="isMounting">
<n8n-loading :class="$style.tableLoader" variant="custom" />
</div>
<div v-else>
<div v-if="workerIds.length === 0">{{ $locale.baseText('workerList.empty') }}</div>
<div v-else>
<div v-for="workerId in workerIds" :key="workerId" :class="$style.card">
<WorkerCard :workerId="workerId" data-test-id="worker-card" />
</div>
</div>
</div>
</div>
</template>
<script lang="ts">
import { defineComponent } from 'vue';
import { mapStores } from 'pinia';
import { externalHooks } from '@/mixins/externalHooks';
import PushConnectionTracker from '@/components/PushConnectionTracker.vue';
import { genericHelpers } from '@/mixins/genericHelpers';
import { executionHelpers } from '@/mixins/executionsHelpers';
import { useI18n, useToast } from '@/composables';
import type { IPushDataWorkerStatusPayload } from '@/Interface';
import type { ExecutionStatus } from 'n8n-workflow';
import { useUIStore } from '@/stores/ui.store';
import { useOrchestrationStore } from '../stores/orchestration.store';
import { setPageTitle } from '@/utils';
import { pushConnection } from '../mixins/pushConnection';
import WorkerCard from './Workers/WorkerCard.ee.vue';
// eslint-disable-next-line import/no-default-export
export default defineComponent({
name: 'WorkerList',
mixins: [pushConnection, externalHooks, genericHelpers, executionHelpers],
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/naming-convention
components: { PushConnectionTracker, WorkerCard },
props: {
autoRefreshEnabled: {
type: Boolean,
default: true,
},
},
setup() {
const i18n = useI18n();
return {
i18n,
...useToast(),
};
},
data() {
return {
isMounting: true,
};
},
mounted() {
setPageTitle(`n8n - ${this.pageTitle}`);
this.isMounting = false;
},
beforeMount() {
if (window.Cypress !== undefined) {
return;
}
this.pushConnect();
this.orchestrationManagerStore.startWorkerStatusPolling();
},
beforeUnmount() {
if (window.Cypress !== undefined) {
return;
}
this.orchestrationManagerStore.stopWorkerStatusPolling();
this.pushDisconnect();
},
computed: {
...mapStores(useUIStore, useOrchestrationStore),
combinedWorkers(): IPushDataWorkerStatusPayload[] {
const returnData: IPushDataWorkerStatusPayload[] = [];
for (const workerId in this.orchestrationManagerStore.workers) {
returnData.push(this.orchestrationManagerStore.workers[workerId]);
}
return returnData;
},
workerIds(): string[] {
return Object.keys(this.orchestrationManagerStore.workers);
},
pageTitle() {
return this.i18n.baseText('workerList.pageTitle');
},
},
methods: {
averageLoadAvg(loads: number[]) {
return (loads.reduce((prev, curr) => prev + curr, 0) / loads.length).toFixed(2);
},
getStatus(payload: IPushDataWorkerStatusPayload): ExecutionStatus {
if (payload.runningJobsSummary.length > 0) {
return 'running';
} else {
return 'success';
}
},
getRowClass(payload: IPushDataWorkerStatusPayload): string {
return [this.$style.execRow, this.$style[this.getStatus(payload)]].join(' ');
},
},
});
</script>
<style module lang="scss">
.workerListHeader {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: var(--spacing-s);
}
.card {
margin-bottom: var(--spacing-s);
}
.tableLoader {
width: 100%;
height: 48px;
margin-bottom: var(--spacing-2xs);
}
</style>