mirror of
https://github.com/Abdulazizzn/n8n-enterprise-unlocked.git
synced 2025-12-17 18:12:04 +00:00
134 lines
3.7 KiB
Vue
134 lines
3.7 KiB
Vue
<template>
|
|
<n8n-card v-if="worker" :class="$style.cardLink">
|
|
<template #header>
|
|
<n8n-heading
|
|
tag="h2"
|
|
bold
|
|
:class="stale ? [$style.cardHeading, $style.stale] : [$style.cardHeading]"
|
|
data-test-id="worker-card-name"
|
|
>
|
|
Name: {{ worker.workerId }} ({{ worker.hostname }}) <br />
|
|
Average Load: {{ averageWorkerLoadFromLoadsAsString(worker.loadAvg ?? [0]) }} | Free Memory:
|
|
{{ memAsGb(worker.freeMem).toFixed(2) }}GB / {{ memAsGb(worker.totalMem).toFixed(2) }}GB
|
|
{{ stale ? ' (stale)' : '' }}
|
|
</n8n-heading>
|
|
</template>
|
|
<div :class="$style.cardDescription">
|
|
<n8n-text color="text-light" size="small" :class="$style.container">
|
|
<span
|
|
>{{ $locale.baseText('workerList.item.lastUpdated') }} {{ secondsSinceLastUpdateString }}s
|
|
ago | n8n-Version: {{ worker.version }} | Architecture: {{ worker.arch }} (
|
|
{{ worker.platform }}) | Uptime: {{ upTime(worker.uptime) }}</span
|
|
>
|
|
<WorkerJobAccordion :items="worker.runningJobsSummary" />
|
|
<WorkerNetAccordion :items="sortedWorkerInterfaces" />
|
|
<WorkerChartsAccordion :worker-id="worker.workerId" />
|
|
</n8n-text>
|
|
</div>
|
|
<template #append>
|
|
<div ref="cardActions" :class="$style.cardActions">
|
|
<!-- For future Worker actions -->
|
|
</div>
|
|
</template>
|
|
</n8n-card>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { useOrchestrationStore } from '@/stores/orchestration.store';
|
|
import type { IPushDataWorkerStatusPayload } from '@/Interface';
|
|
import { computed, onMounted, onBeforeUnmount, ref } from 'vue';
|
|
import { averageWorkerLoadFromLoadsAsString, memAsGb } from '../../utils/workerUtils';
|
|
import WorkerJobAccordion from './WorkerJobAccordion.ee.vue';
|
|
import WorkerNetAccordion from './WorkerNetAccordion.ee.vue';
|
|
import WorkerChartsAccordion from './WorkerChartsAccordion.ee.vue';
|
|
|
|
let interval: NodeJS.Timer;
|
|
|
|
const orchestrationStore = useOrchestrationStore();
|
|
|
|
const props = defineProps<{
|
|
workerId: string;
|
|
}>();
|
|
|
|
const secondsSinceLastUpdateString = ref<string>('0');
|
|
const stale = ref<boolean>(false);
|
|
|
|
const worker = computed((): IPushDataWorkerStatusPayload | undefined => {
|
|
return orchestrationStore.getWorkerStatus(props.workerId);
|
|
});
|
|
|
|
const sortedWorkerInterfaces = computed(
|
|
() => worker.value?.interfaces.toSorted((a, b) => a.family.localeCompare(b.family)) ?? [],
|
|
);
|
|
|
|
function upTime(seconds: number): string {
|
|
const days = Math.floor(seconds / (3600 * 24));
|
|
seconds -= days * 3600 * 24;
|
|
const hrs = Math.floor(seconds / 3600);
|
|
seconds -= hrs * 3600;
|
|
const mnts = Math.floor(seconds / 60);
|
|
seconds -= mnts * 60;
|
|
return `${days}d ${hrs}h ${mnts}m ${Math.floor(seconds)}s`;
|
|
}
|
|
|
|
onMounted(() => {
|
|
interval = setInterval(() => {
|
|
const lastUpdated = orchestrationStore.getWorkerLastUpdated(props.workerId);
|
|
if (!lastUpdated) {
|
|
return;
|
|
}
|
|
const secondsSinceLastUpdate = Math.ceil((Date.now() - lastUpdated) / 1000);
|
|
stale.value = secondsSinceLastUpdate > 10;
|
|
secondsSinceLastUpdateString.value = secondsSinceLastUpdate.toFixed(0);
|
|
}, 500);
|
|
});
|
|
|
|
onBeforeUnmount(() => {
|
|
clearInterval(interval);
|
|
});
|
|
</script>
|
|
|
|
<style lang="scss" module>
|
|
.container {
|
|
width: 100%;
|
|
}
|
|
|
|
.cardLink {
|
|
transition: box-shadow 0.3s ease;
|
|
cursor: pointer;
|
|
padding: 0;
|
|
align-items: stretch;
|
|
|
|
&:hover {
|
|
box-shadow: 0 2px 8px rgba(#441c17, 0.1);
|
|
}
|
|
}
|
|
|
|
.cardHeading {
|
|
font-size: var(--font-size-s);
|
|
word-break: break-word;
|
|
padding: var(--spacing-s) 0 0 var(--spacing-s);
|
|
}
|
|
|
|
.stale {
|
|
opacity: 0.5;
|
|
}
|
|
|
|
.cardDescription {
|
|
min-height: 19px;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 0 var(--spacing-s) var(--spacing-s);
|
|
}
|
|
|
|
.cardActions {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: center;
|
|
align-items: center;
|
|
align-self: stretch;
|
|
padding: 0 var(--spacing-s) 0 0;
|
|
cursor: default;
|
|
}
|
|
</style>
|