mirror of
https://github.com/tdurieux/anonymous_github.git
synced 2026-09-21 01:40:42 +02:00
refactor: migrate the frontend from AngularJS to Vue 3
This commit is contained in:
@@ -5,13 +5,13 @@
|
||||
<h1 class="paper-page-title">Queues</h1>
|
||||
<div class="q-header-actions">
|
||||
<div class="q-range-btns">
|
||||
<button class="btn btn-sm" ng-class="{active: range == '1h'}" ng-click="setRange('1h')">1h</button>
|
||||
<button class="btn btn-sm" ng-class="{active: range == '6h'}" ng-click="setRange('6h')">6h</button>
|
||||
<button class="btn btn-sm" ng-class="{active: range == '24h'}" ng-click="setRange('24h')">24h</button>
|
||||
<button class="btn btn-sm" ng-class="{active: range == '7d'}" ng-click="setRange('7d')">7d</button>
|
||||
<button class="btn btn-sm" :class="{active: range == '1h'}" @click="setRange('1h')">1h</button>
|
||||
<button class="btn btn-sm" :class="{active: range == '6h'}" @click="setRange('6h')">6h</button>
|
||||
<button class="btn btn-sm" :class="{active: range == '24h'}" @click="setRange('24h')">24h</button>
|
||||
<button class="btn btn-sm" :class="{active: range == '7d'}" @click="setRange('7d')">7d</button>
|
||||
</div>
|
||||
<button class="btn btn-sm" ng-click="pauseAll()">Pause all</button>
|
||||
<button class="btn btn-sm btn-dark" ng-click="drainSelected()">Drain {{selectedQueue}}</button>
|
||||
<button class="btn btn-sm" @click="pauseAll()">Pause all</button>
|
||||
<button class="btn btn-sm btn-dark" @click="drainSelected()">Drain {{ selectedQueue }}</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -26,25 +26,25 @@
|
||||
|
||||
<!-- Queue overview cards -->
|
||||
<div class="q-cards">
|
||||
<div class="q-card" ng-repeat="q in queueList" ng-class="{selected: selectedQueue == q.key, paused: q.paused}" ng-click="selectQueue(q.key)">
|
||||
<div class="q-card" v-for="(q, index) in queueList" :class="{selected: selectedQueue == q?.key, paused: q?.paused}" @click="selectQueue(q.key)">
|
||||
<div class="q-card-head">
|
||||
<span class="q-dot" ng-class="{'q-dot-red': q.paused || q.counts.failed > 0}"></span>
|
||||
<span class="q-card-name" ng-bind="q.label"></span>
|
||||
<span class="q-dot" :class="{'q-dot-red': q?.paused || q?.counts?.failed > 0}"></span>
|
||||
<span class="q-card-name" v-text="q?.label"></span>
|
||||
</div>
|
||||
<div class="q-card-count" ng-bind="(q.counts.waiting || 0) + (q.counts.active || 0) + (q.counts.delayed || 0)"></div>
|
||||
<div class="q-card-count" v-text="(q?.counts?.waiting || 0) + (q?.counts?.active || 0) + (q?.counts?.delayed || 0)"></div>
|
||||
<div class="q-card-sub">
|
||||
<span>waiting · {{q.counts.active || 0}} active</span>
|
||||
<div class="q-card-bar" ng-if="q.counts.active">
|
||||
<div class="q-card-bar-fill" ng-style="{width: (q.counts.active / ((q.counts.waiting || 0) + (q.counts.active || 0) + (q.counts.delayed || 0) || 1) * 100) + '%'}"></div>
|
||||
<span>waiting · {{ q?.counts?.active || 0 }} active</span>
|
||||
<div class="q-card-bar" v-if="q?.counts?.active">
|
||||
<div class="q-card-bar-fill" :style="{width: (q?.counts?.active / ((q?.counts?.waiting || 0) + (q?.counts?.active || 0) + (q?.counts?.delayed || 0) || 1) * 100) + '%'}"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Detail: throughput chart + stats panel -->
|
||||
<div class="q-detail" ng-if="selectedStats">
|
||||
<div class="q-detail" v-if="selectedStats">
|
||||
<div class="q-throughput">
|
||||
<div class="q-section-label">{{selectedQueue}}·throughput <span class="q-section-right"><span class="q-legend-completed">●</span> completed <span class="q-legend-failed">●</span> failed <span class="q-legend-exec">- -</span> avg time · {{range | uppercase}}</span></div>
|
||||
<div class="q-section-label">{{ selectedQueue }}·throughput <span class="q-section-right"><span class="q-legend-completed">●</span> completed <span class="q-legend-failed">●</span> failed <span class="q-legend-exec">- -</span> avg time · {{ fmt?.uppercase(range) }}</span></div>
|
||||
<div class="q-chart-wrap">
|
||||
<canvas id="q-throughput-chart" height="180"></canvas>
|
||||
<div id="q-chart-tooltip" class="q-chart-tooltip" style="display:none;"></div>
|
||||
@@ -52,67 +52,67 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="q-stats-panel">
|
||||
<div class="q-section-label">{{selectedQueue}}·stats</div>
|
||||
<div class="q-section-label">{{ selectedQueue }}·stats</div>
|
||||
<div class="q-stats-grid">
|
||||
<div class="q-stat">
|
||||
<div class="q-stat-label">WAITING</div>
|
||||
<div class="q-stat-value" ng-bind="selectedStats.counts.waiting || 0"></div>
|
||||
<div class="q-stat-value" v-text="selectedStats?.counts?.waiting || 0"></div>
|
||||
</div>
|
||||
<div class="q-stat">
|
||||
<div class="q-stat-label">ACTIVE</div>
|
||||
<div class="q-stat-value" ng-bind="selectedStats.counts.active || 0"></div>
|
||||
<div class="q-stat-value" v-text="selectedStats?.counts?.active || 0"></div>
|
||||
</div>
|
||||
<div class="q-stat">
|
||||
<div class="q-stat-label">COMPLETED (24H)</div>
|
||||
<div class="q-stat-value" ng-bind="selectedStats.completed24h | number"></div>
|
||||
<div class="q-stat-value" v-text="fmt?.number(selectedStats?.completed24h)"></div>
|
||||
</div>
|
||||
<div class="q-stat">
|
||||
<div class="q-stat-label">FAILED (24H)</div>
|
||||
<div class="q-stat-value" ng-bind="selectedStats.failed24h || 0"></div>
|
||||
<div class="q-stat-value" v-text="selectedStats?.failed24h || 0"></div>
|
||||
</div>
|
||||
<div class="q-stat">
|
||||
<div class="q-stat-label">DELAYED</div>
|
||||
<div class="q-stat-value" ng-bind="selectedStats.counts.delayed || 0"></div>
|
||||
<div class="q-stat-value" v-text="selectedStats?.counts?.delayed || 0"></div>
|
||||
</div>
|
||||
<div class="q-stat">
|
||||
<div class="q-stat-label">WORKERS</div>
|
||||
<div class="q-stat-value" ng-bind="selectedStats.workers || 0"></div>
|
||||
<div class="q-stat-value" v-text="selectedStats?.workers || 0"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="q-stats-actions">
|
||||
<button class="btn btn-sm" ng-click="togglePause()">{{selectedStats.paused ? 'Resume' : 'Pause'}}</button>
|
||||
<button class="btn btn-sm" ng-click="retryFailed()" ng-disabled="!selectedStats.counts.failed">Retry failed</button>
|
||||
<button class="btn btn-sm" ng-click="emptyQueue()">Empty</button>
|
||||
<button class="btn btn-sm" @click="togglePause()">{{ selectedStats?.paused ? 'Resume' : 'Pause' }}</button>
|
||||
<button class="btn btn-sm" @click="retryFailed()" :disabled="!selectedStats?.counts?.failed">Retry failed</button>
|
||||
<button class="btn btn-sm" @click="emptyQueue()">Empty</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="q-toast-error" ng-if="actionError" ng-click="actionError = null">
|
||||
<i class="fas fa-exclamation-circle"></i> {{actionError}}
|
||||
<div class="q-toast-error" v-if="actionError" @click="actionError = null">
|
||||
<i class="fas fa-exclamation-circle"></i> {{ actionError }}
|
||||
</div>
|
||||
|
||||
<!-- Jobs table -->
|
||||
<div class="q-jobs">
|
||||
<div class="q-jobs-header">
|
||||
<div class="q-section-label">ALL JOBS · {{selectedQueue | uppercase}}</div>
|
||||
<div class="q-section-label">ALL JOBS · {{ fmt?.uppercase(selectedQueue) }}</div>
|
||||
<div class="q-state-filters">
|
||||
<label class="q-state-toggle" ng-repeat="s in allStates">
|
||||
<input type="checkbox" ng-model="stateFilter[s]" />
|
||||
<span class="q-state-chip q-state-{{s}}">{{s}}</span>
|
||||
<label class="q-state-toggle" v-for="(s, index) in allStates">
|
||||
<input type="checkbox" v-field="{ state: viewState, set: value => { stateFilter[s] = value }, value: stateFilter[s], form: null, options: {} }">
|
||||
<span :class=""q-state-chip q-state-" + (s)">{{ s }}</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="q-search-row">
|
||||
<input type="search" class="form-control" placeholder="Search by job/repo id…" ng-model="query.search" autocomplete="off" />
|
||||
<input type="search" class="form-control" placeholder="Search by job/repo id…" autocomplete="off" v-field="{ state: viewState, set: value => { query.search = value }, value: query?.search, form: null, options: {} }">
|
||||
<label class="q-auto-refresh">
|
||||
<input type="checkbox" ng-model="query.autoRefresh" />
|
||||
<input type="checkbox" v-field="{ state: viewState, set: value => { query.autoRefresh = value }, value: query?.autoRefresh, form: null, options: {} }">
|
||||
Auto-refresh
|
||||
</label>
|
||||
<button class="btn btn-sm" type="button" ng-click="refreshNow()" title="Refresh now"><i class="fas fa-sync"></i></button>
|
||||
<button class="btn btn-sm" type="button" title="Refresh now" @click="refreshNow()"><i class="fas fa-sync"></i></button>
|
||||
</div>
|
||||
|
||||
<table class="q-table" ng-if="filteredJobs().length > 0">
|
||||
<table class="q-table" v-if="filteredJobs().length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>STATE</th>
|
||||
@@ -124,90 +124,90 @@
|
||||
<th></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody ng-repeat="job in filteredJobs()">
|
||||
<tr ng-class="{'q-row-failed': job._state == 'failed', 'q-row-expanded': expanded[job.id]}" ng-click="toggleJob(job)" style="cursor:pointer;">
|
||||
<tbody v-for="(job, index) in filteredJobs()">
|
||||
<tr style="cursor:pointer;" :class="{'q-row-failed': job?._state == 'failed', 'q-row-expanded': expanded[job?.id]}" @click="toggleJob(job)">
|
||||
<td class="q-cell-state">
|
||||
<span class="q-state-badge q-state-{{job._state}}" ng-bind="job._state"></span>
|
||||
<span class="q-delay-hint" ng-if="job._state == 'delayed' && job.delayUntil" ng-bind="delayCountdown(job.delayUntil)"></span>
|
||||
<span v-text="job?._state" :class=""q-state-badge q-state-" + (job?._state)"></span>
|
||||
<span class="q-delay-hint" v-if="job?._state == 'delayed' && job?.delayUntil" v-text="delayCountdown(job?.delayUntil)"></span>
|
||||
</td>
|
||||
<td class="q-cell-id">
|
||||
<i class="fas fa-chevron-right q-chevron" ng-class="{'q-chevron-open': expanded[job.id]}"></i>
|
||||
<a target="_blank" ng-href="/r/{{job.id}}" ng-click="$event.stopPropagation()" ng-bind="'job:' + (job.id | limitTo:6)"></a>
|
||||
<i class="fas fa-chevron-right q-chevron" :class="{'q-chevron-open': expanded[job?.id]}"></i>
|
||||
<a target="_blank" v-text="'job:' + fmt.limitTo(job?.id, 6)" @click="$event.stopPropagation()" :href="safeUrl("/r/" + (job?.id))"></a>
|
||||
</td>
|
||||
<td class="q-cell-payload">
|
||||
<span ng-bind="job.name || 'anonymize'"></span>
|
||||
<span class="q-payload-detail" ng-if="job.data.repoId && job.data.repoId !== job.name"> · {{job.data.repoId}}</span>
|
||||
<span v-text="job?.name || 'anonymize'"></span>
|
||||
<span class="q-payload-detail" v-if="job?.data?.repoId && job?.data?.repoId !== job?.name"> · {{ job?.data?.repoId }}</span>
|
||||
</td>
|
||||
<td class="q-cell-num" ng-bind="job.attemptsMade || 1"></td>
|
||||
<td class="q-cell-num" ng-bind="jobDuration(job)"></td>
|
||||
<td class="q-cell-num" v-text="job?.attemptsMade || 1"></td>
|
||||
<td class="q-cell-num" v-text="jobDuration(job)"></td>
|
||||
<td class="q-cell-progress">
|
||||
<div class="q-progress-wrap" ng-if="jobProgressPct(job) !== null">
|
||||
<div class="q-progress-bar" ng-style="{'--pct': jobProgressPct(job) + '%'}"></div>
|
||||
<span class="q-progress-label" ng-bind="jobProgressPct(job) + '%'"></span>
|
||||
<div class="q-progress-wrap" v-if="jobProgressPct(job) !== null">
|
||||
<div class="q-progress-bar" :style="{'--pct': jobProgressPct(job) + '%'}"></div>
|
||||
<span class="q-progress-label" v-text="jobProgressPct(job) + '%'"></span>
|
||||
</div>
|
||||
</td>
|
||||
<td class="q-cell-actions">
|
||||
<button class="btn btn-sm" ng-click="retryJob(job); $event.stopPropagation()" title="Retry" ng-if="job._state == 'failed'"><i class="fas fa-sync"></i></button>
|
||||
<button class="btn btn-sm" ng-click="removeJob(job); $event.stopPropagation()" title="Remove"><i class="fas fa-trash-alt"></i></button>
|
||||
<button class="btn btn-sm" title="Retry" v-if="job?._state == 'failed'" @click="retryJob(job); $event.stopPropagation()"><i class="fas fa-sync"></i></button>
|
||||
<button class="btn btn-sm" title="Remove" @click="removeJob(job); $event.stopPropagation()"><i class="fas fa-trash-alt"></i></button>
|
||||
</td>
|
||||
</tr>
|
||||
<tr class="q-detail-row" ng-if="expanded[job.id]">
|
||||
<tr class="q-detail-row" v-if="expanded[job?.id]">
|
||||
<td colspan="7">
|
||||
<div class="q-job-detail">
|
||||
<div class="q-job-detail-grid">
|
||||
<div class="q-job-detail-item">
|
||||
<span class="q-job-detail-label">JOB ID</span>
|
||||
<span class="q-job-detail-value"><a target="_blank" ng-href="/r/{{job.id}}" ng-bind="job.id"></a></span>
|
||||
<span class="q-job-detail-value"><a target="_blank" v-text="job?.id" :href="safeUrl("/r/" + (job?.id))"></a></span>
|
||||
</div>
|
||||
<div class="q-job-detail-item">
|
||||
<span class="q-job-detail-label">STATE</span>
|
||||
<span class="q-job-detail-value"><span class="q-state-badge q-state-{{job._state}}" ng-bind="job._state"></span></span>
|
||||
<span class="q-job-detail-value"><span v-text="job?._state" :class=""q-state-badge q-state-" + (job?._state)"></span></span>
|
||||
</div>
|
||||
<div class="q-job-detail-item" ng-if="job.data.repoId">
|
||||
<div class="q-job-detail-item" v-if="job?.data?.repoId">
|
||||
<span class="q-job-detail-label">REPO ID</span>
|
||||
<span class="q-job-detail-value" ng-bind="job.data.repoId"></span>
|
||||
<span class="q-job-detail-value" v-text="job?.data?.repoId"></span>
|
||||
</div>
|
||||
<div class="q-job-detail-item" ng-if="job.timestamp">
|
||||
<div class="q-job-detail-item" v-if="job?.timestamp">
|
||||
<span class="q-job-detail-label">CREATED</span>
|
||||
<span class="q-job-detail-value" ng-bind="humanTime(job.timestamp)"></span>
|
||||
<span class="q-job-detail-value" v-text="humanTime(job?.timestamp)"></span>
|
||||
</div>
|
||||
<div class="q-job-detail-item" ng-if="job._state == 'delayed' && job.delayUntil">
|
||||
<div class="q-job-detail-item" v-if="job?._state == 'delayed' && job?.delayUntil">
|
||||
<span class="q-job-detail-label">RETRY AT</span>
|
||||
<span class="q-job-detail-value">{{humanTime(job.delayUntil)}} ({{delayCountdown(job.delayUntil)}})</span>
|
||||
<span class="q-job-detail-value">{{ humanTime(job?.delayUntil) }} ({{ delayCountdown(job?.delayUntil) }})</span>
|
||||
</div>
|
||||
<div class="q-job-detail-item" ng-if="job.processedOn">
|
||||
<div class="q-job-detail-item" v-if="job?.processedOn">
|
||||
<span class="q-job-detail-label">PROCESSED</span>
|
||||
<span class="q-job-detail-value" ng-bind="humanTime(job.processedOn)"></span>
|
||||
<span class="q-job-detail-value" v-text="humanTime(job?.processedOn)"></span>
|
||||
</div>
|
||||
<div class="q-job-detail-item" ng-if="job.finishedOn">
|
||||
<div class="q-job-detail-item" v-if="job?.finishedOn">
|
||||
<span class="q-job-detail-label">FINISHED</span>
|
||||
<span class="q-job-detail-value" ng-bind="humanTime(job.finishedOn)"></span>
|
||||
<span class="q-job-detail-value" v-text="humanTime(job?.finishedOn)"></span>
|
||||
</div>
|
||||
<div class="q-job-detail-item" ng-if="job.attemptsMade">
|
||||
<div class="q-job-detail-item" v-if="job?.attemptsMade">
|
||||
<span class="q-job-detail-label">ATTEMPTS</span>
|
||||
<span class="q-job-detail-value" ng-bind="job.attemptsMade"></span>
|
||||
<span class="q-job-detail-value" v-text="job?.attemptsMade"></span>
|
||||
</div>
|
||||
<div class="q-job-detail-item" ng-if="job.progress && job.progress.status">
|
||||
<div class="q-job-detail-item" v-if="job?.progress && job?.progress?.status">
|
||||
<span class="q-job-detail-label">STATUS</span>
|
||||
<span class="q-job-detail-value" ng-bind="job.progress.status"></span>
|
||||
<span class="q-job-detail-value" v-text="job?.progress?.status"></span>
|
||||
</div>
|
||||
<div class="q-job-detail-item" ng-if="jobProgressPct(job) !== null">
|
||||
<div class="q-job-detail-item" v-if="jobProgressPct(job) !== null">
|
||||
<span class="q-job-detail-label">PROGRESS</span>
|
||||
<span class="q-job-detail-value" ng-bind="jobProgressPct(job) + '%'"></span>
|
||||
<span class="q-job-detail-value" v-text="jobProgressPct(job) + '%'"></span>
|
||||
</div>
|
||||
</div>
|
||||
<div ng-if="job.failedReason" class="q-job-detail-error">
|
||||
<div class="q-job-detail-error" v-if="job?.failedReason">
|
||||
<span class="q-job-detail-label">ERROR</span>
|
||||
<div class="q-error-reason" ng-bind="job.failedReason"></div>
|
||||
<div class="q-error-reason" v-text="job?.failedReason"></div>
|
||||
</div>
|
||||
<div ng-if="job.stacktrace.length">
|
||||
<div v-if="job?.stacktrace?.length">
|
||||
<span class="q-job-detail-label">STACKTRACE</span>
|
||||
<pre ng-repeat="stack in job.stacktrace track by $index" class="q-error-stack"><code ng-bind="stack"></code></pre>
|
||||
<pre class="q-error-stack" v-for="(stack, index) in job?.stacktrace" :key="index"><code v-text="stack"></code></pre>
|
||||
</div>
|
||||
<div class="q-job-detail-actions">
|
||||
<button class="btn btn-sm" ng-click="retryJob(job)" ng-if="job._state == 'failed'"><i class="fas fa-sync"></i> Retry</button>
|
||||
<button class="btn btn-sm" ng-click="removeJob(job)"><i class="fas fa-trash-alt"></i> Remove</button>
|
||||
<a class="btn btn-sm" target="_blank" ng-href="/r/{{job.id}}"><i class="fas fa-external-link-alt"></i> View repo</a>
|
||||
<button class="btn btn-sm" v-if="job?._state == 'failed'" @click="retryJob(job)"><i class="fas fa-sync"></i> Retry</button>
|
||||
<button class="btn btn-sm" @click="removeJob(job)"><i class="fas fa-trash-alt"></i> Remove</button>
|
||||
<a class="btn btn-sm" target="_blank" :href="safeUrl("/r/" + (job?.id))"><i class="fas fa-external-link-alt"></i> View repo</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
@@ -215,10 +215,10 @@
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="paper-table-empty" ng-if="filteredJobs().length == 0" style="border:1px solid var(--border-color);border-radius:10px;background:var(--paper-card);">
|
||||
<div class="paper-table-empty" style="border:1px solid var(--border-color);border-radius:10px;background:var(--paper-card);" v-if="filteredJobs().length == 0">
|
||||
<i class="fas fa-check-circle"></i>
|
||||
<span ng-if="!query.search">No jobs in the {{selectedQueue}} queue.</span>
|
||||
<span ng-if="query.search">No jobs match the current filters.</span>
|
||||
<span v-if="!query?.search">No jobs in the {{ selectedQueue }} queue.</span>
|
||||
<span v-if="query?.search">No jobs match the current filters.</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user