Spaces:
Paused
Paused
| <template> | |
| <Settings :title="$t('admin.settings.queue.queue')" :description="$t('admin.settings.queue.desc')"> | |
| <template #headerActions> | |
| <div v-if="queueInfo"> | |
| <div class="flex items-center gap-2"> | |
| <Button | |
| v-if="queueInfo.paused" | |
| :text="$t('admin.settings.queue.resume')" | |
| start-icon="play" | |
| @click="resumeQueue" | |
| /> | |
| <Button v-else :text="$t('admin.settings.queue.pause')" start-icon="pause" @click="pauseQueue" /> | |
| <Icon | |
| :name="queueInfo.paused ? 'pause' : 'play'" | |
| class="h-6 w-6" | |
| :class="{ | |
| 'text-wp-error-100': queueInfo.paused, | |
| 'text-wp-text-100': !queueInfo.paused, | |
| }" | |
| /> | |
| </div> | |
| </div> | |
| </template> | |
| <div class="flex flex-col"> | |
| <AdminQueueStats :stats="queueInfo?.stats" /> | |
| <div v-if="tasks.length > 0" class="flex flex-col"> | |
| <p class="mt-6 mb-2 text-xl">{{ $t('admin.settings.queue.tasks') }}</p> | |
| <ListItem | |
| v-for="task in tasks" | |
| :key="task.id" | |
| class="bg-wp-background-200! dark:bg-wp-background-200! mb-2 flex-col items-center gap-4" | |
| > | |
| <div | |
| class="border-wp-background-400 dark:border-wp-background-100 flex w-full items-center justify-between gap-2 border-b pb-2" | |
| > | |
| <div | |
| class="flex items-center gap-2" | |
| :title=" | |
| task.status === 'pending' | |
| ? $t('admin.settings.queue.task_pending') | |
| : task.status === 'running' | |
| ? $t('admin.settings.queue.task_running') | |
| : $t('admin.settings.queue.task_waiting_on_deps') | |
| " | |
| > | |
| <Icon | |
| :name=" | |
| task.status === 'pending' | |
| ? 'status-pending' | |
| : task.status === 'running' | |
| ? 'status-running' | |
| : 'status-declined' | |
| " | |
| :class="{ | |
| 'text-wp-error-100': task.status === 'waiting_on_deps', | |
| 'text-wp-state-info-100': task.status === 'running', | |
| 'text-wp-state-neutral-100': task.status === 'pending', | |
| }" | |
| /> | |
| <span>{{ task.name }}</span> | |
| </div> | |
| <div class="ml-auto flex items-center gap-2"> | |
| <span class="flex gap-2"> | |
| <Badge v-if="task.agent_name" :label="$t('admin.settings.queue.agent')" :value="task.agent_name" /> | |
| <Badge | |
| v-if="task.dependencies" | |
| :label="$t('admin.settings.queue.waiting_for')" | |
| :value="task.dependencies.join(', ')" | |
| /> | |
| </span> | |
| </div> | |
| <div class="ml-2 flex items-center gap-2"> | |
| <IconButton | |
| v-if="task.pipeline_number" | |
| icon="chevron-right" | |
| :title="$t('repo.pipeline.view')" | |
| class="h-8 w-8" | |
| :to="{ | |
| name: 'repo-pipeline', | |
| params: { repoId: task.repo_id, pipelineId: task.pipeline_number, stepId: task.pid }, | |
| }" | |
| /> | |
| </div> | |
| </div> | |
| <div class="flex w-full flex-wrap gap-2"> | |
| <template v-for="(value, label) in task.labels"> | |
| <Badge v-if="value" :key="label" :label="label.toString()" :value="value" /> | |
| </template> | |
| </div> | |
| </ListItem> | |
| </div> | |
| </div> | |
| </Settings> | |
| </template> | |
| <script lang="ts" setup> | |
| import { computed, ref } from 'vue'; | |
| import { useI18n } from 'vue-i18n'; | |
| import AdminQueueStats from '~/components/admin/settings/queue/AdminQueueStats.vue'; | |
| import Badge from '~/components/atomic/Badge.vue'; | |
| import Button from '~/components/atomic/Button.vue'; | |
| import Icon from '~/components/atomic/Icon.vue'; | |
| import IconButton from '~/components/atomic/IconButton.vue'; | |
| import ListItem from '~/components/atomic/ListItem.vue'; | |
| import Settings from '~/components/layout/Settings.vue'; | |
| import useApiClient from '~/compositions/useApiClient'; | |
| import { useInterval } from '~/compositions/useInterval'; | |
| import useNotifications from '~/compositions/useNotifications'; | |
| import { useWPTitle } from '~/compositions/useWPTitle'; | |
| import type { QueueInfo } from '~/lib/api/types'; | |
| const apiClient = useApiClient(); | |
| const notifications = useNotifications(); | |
| const { t } = useI18n(); | |
| const queueInfo = ref<QueueInfo>(); | |
| const tasks = computed(() => { | |
| const _tasks = []; | |
| if (queueInfo.value?.running) { | |
| _tasks.push(...queueInfo.value.running.map((task) => ({ ...task, status: 'running' }))); | |
| } | |
| if (queueInfo.value?.pending) { | |
| _tasks.push(...queueInfo.value.pending.map((task) => ({ ...task, status: 'pending' }))); | |
| } | |
| if (queueInfo.value?.waiting_on_deps) { | |
| _tasks.push(...queueInfo.value.waiting_on_deps.map((task) => ({ ...task, status: 'waiting_on_deps' }))); | |
| } | |
| return _tasks | |
| .map((task) => ({ | |
| ...task, | |
| labels: Object.fromEntries(Object.entries(task.labels).filter(([key]) => key !== 'org-id')), | |
| })) | |
| .toSorted((a, b) => a.id - b.id); | |
| }); | |
| async function loadQueueInfo() { | |
| queueInfo.value = await apiClient.getQueueInfo(); | |
| } | |
| async function pauseQueue() { | |
| await apiClient.pauseQueue(); | |
| await loadQueueInfo(); | |
| notifications.notify({ | |
| title: t('admin.settings.queue.paused'), | |
| type: 'success', | |
| }); | |
| } | |
| async function resumeQueue() { | |
| await apiClient.resumeQueue(); | |
| await loadQueueInfo(); | |
| notifications.notify({ | |
| title: t('admin.settings.queue.resumed'), | |
| type: 'success', | |
| }); | |
| } | |
| useInterval(loadQueueInfo, 5 * 1000); | |
| useWPTitle(computed(() => [t('admin.settings.queue.queue'), t('admin.settings.settings')])); | |
| </script> | |