mirror of
https://github.com/maziggy/bambuddy.git
synced 2026-10-21 01:57:41 +02:00
fix(queue): say when an unscheduled item runs instead of calling it ASAP (issue #3018)
The print dialog offers ASAP, Queue and Schedule. ASAP and Queue differ only in where the item is inserted, and neither is stored on the item -- scheduleType is a frontend-only concept, and grep finds no "asap" anywhere in the backend. So the queue's time column had nothing to read but scheduled_time, and labelled every unscheduled item "ASAP": the name of the one mode the user may well have chosen against. Someone who picked Queue then watched their row appear as ASAP and start immediately, and concluded Bambuddy had overridden them. Two reporters wrote that same sentence thirteen months apart, and #2557 was closed as A2L-specific after the first of them -- kilrah replied there with an X1C before filing this. The column answers when an item runs, so it now says that. The key is renamed whenFree rather than just retranslated: left called asap, the next translator puts ASAP back. The dispatch is unchanged, because it was right. A print scheduled for later does not reserve the printer until then; an unscheduled item behind it uses the idle printer rather than leaving an X1C dark until 6 AM. Two of the new tests pin that, so it does not get "fixed" later on the strength of a report like this one. What genuinely could not answer the question was the queue's own log. Its per-printer line called every entry in busy_printers "not available" -- but that set holds both printers that cannot take work and printers the pass has just claimed for some, which are opposite facts. It also read printer state at logging time rather than at the decision, so #3018's bundle carries Queue: printer 1 not available — connected=True, state=IDLE, ... Launching 1 upload(s) (pool 0/4 in flight) Starting queue item 18 a printer reported unavailable, evidence that it was available, and a dispatch to it, in three consecutive lines. It is the first line anyone greps for "why did my item not go out". Each of the nine sites that removes a printer from a pass now records why, and the summary reports a claim as a reservation and everything else as an obstruction with its reason. The live fields stay, since a bundle reader wants them next, but are labelled as read now rather than offered as the cause. print_scheduler.py:1210 already documented that these two meanings differ -- the dispatching_printers snapshot exists for it. This carries that distinction into the log.
This commit is contained in:
@@ -457,6 +457,29 @@ describe('QueuePage', () => {
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('tells an unscheduled item when it runs, without naming a dispatch mode', async () => {
|
||||
// ASAP and Queue differ only in where the item is inserted; neither is
|
||||
// stored on it, so this column cannot tell them apart. Labelling every
|
||||
// unscheduled item "ASAP" made a Queue choice look overridden, which is
|
||||
// what both #2557 and #3018 opened on.
|
||||
server.use(
|
||||
http.get('/api/v1/queue/', () => {
|
||||
return HttpResponse.json([
|
||||
{ ...mockQueueItems[0], archive_name: 'Queued Print', scheduled_time: null },
|
||||
]);
|
||||
}),
|
||||
);
|
||||
|
||||
render(<QueuePage />);
|
||||
|
||||
const name = await screen.findByText('Queued Print');
|
||||
const row = name.closest('.group') as HTMLElement;
|
||||
|
||||
expect(row).not.toBeNull();
|
||||
expect(within(row).getByText('When a printer is free')).toBeInTheDocument();
|
||||
expect(within(row).queryByText('ASAP')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('does not render a dangling ETA for an invalid duration', async () => {
|
||||
server.use(
|
||||
http.get('/api/v1/queue/', () => {
|
||||
|
||||
@@ -1489,7 +1489,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: 'Fertigstellungszeit, wenn dieser Auftrag jetzt starten würde',
|
||||
asap: 'Sofort',
|
||||
whenFree: 'Sobald ein Drucker frei ist',
|
||||
overdue: 'Überfällig',
|
||||
now: 'Jetzt',
|
||||
lessThanMinute: 'In weniger als einer Minute',
|
||||
|
||||
@@ -1505,7 +1505,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: 'Completion time if this job started now',
|
||||
asap: 'ASAP',
|
||||
whenFree: 'When a printer is free',
|
||||
overdue: 'Overdue',
|
||||
now: 'Now',
|
||||
lessThanMinute: 'In less than a minute',
|
||||
|
||||
@@ -1489,7 +1489,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: 'Hora de finalización si este trabajo comenzara ahora',
|
||||
asap: 'Lo antes posible',
|
||||
whenFree: 'Cuando haya una impresora libre',
|
||||
overdue: 'Atrasada',
|
||||
now: 'Ahora',
|
||||
lessThanMinute: 'En menos de un minuto',
|
||||
|
||||
@@ -1489,7 +1489,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: 'Heure de fin si cette tâche démarrait maintenant',
|
||||
asap: 'Dès que possible',
|
||||
whenFree: 'Dès qu\'une imprimante est libre',
|
||||
overdue: 'En retard',
|
||||
now: 'Maintenant',
|
||||
lessThanMinute: 'Dans moins d\'une minute',
|
||||
|
||||
@@ -1489,7 +1489,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: 'Orario di completamento se questo lavoro iniziasse ora',
|
||||
asap: 'ASAP',
|
||||
whenFree: 'Quando una stampante è libera',
|
||||
overdue: 'Scaduto',
|
||||
now: 'Ora',
|
||||
lessThanMinute: 'Tra meno di un minuto',
|
||||
|
||||
@@ -1488,7 +1488,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: 'このジョブを今開始した場合の完了予定時刻',
|
||||
asap: '即時',
|
||||
whenFree: 'プリンターが空き次第',
|
||||
overdue: '期限超過',
|
||||
now: '今すぐ',
|
||||
lessThanMinute: '1分以内',
|
||||
|
||||
@@ -1418,7 +1418,7 @@ export default {
|
||||
},
|
||||
time: {
|
||||
etaIfStartedNow: '이 작업을 지금 시작할 경우의 완료 예정 시각',
|
||||
asap: '즉시',
|
||||
whenFree: '프린터가 사용 가능해지면',
|
||||
overdue: '기한 초과',
|
||||
now: '지금',
|
||||
lessThanMinute: '1분 이내',
|
||||
|
||||
@@ -1505,7 +1505,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: 'Voltooiingstijd als deze taak nu zou starten',
|
||||
asap: 'Zo snel mogelijk',
|
||||
whenFree: 'Zodra een printer vrij is',
|
||||
overdue: 'Te laat',
|
||||
now: 'Nu',
|
||||
lessThanMinute: 'Binnen een minuut',
|
||||
|
||||
@@ -1489,7 +1489,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: 'Horário de conclusão se este trabalho começasse agora',
|
||||
asap: 'ASAP',
|
||||
whenFree: 'Quando uma impressora estiver livre',
|
||||
overdue: 'Atrasado',
|
||||
now: 'Agora',
|
||||
lessThanMinute: 'Em menos de um minuto',
|
||||
|
||||
@@ -1428,7 +1428,7 @@ export default {
|
||||
},
|
||||
time: {
|
||||
etaIfStartedNow: "Время завершения, если запустить это задание сейчас",
|
||||
asap: "Как можно скорее",
|
||||
whenFree: "Когда принтер освободится",
|
||||
overdue: "Просрочено",
|
||||
now: "Сейчас",
|
||||
lessThanMinute: "Меньше чем через минуту",
|
||||
|
||||
@@ -1489,7 +1489,7 @@ export default {
|
||||
// Zaman
|
||||
time: {
|
||||
etaIfStartedNow: 'Bu iş şimdi başlatılırsa tamamlanma saati',
|
||||
asap: 'ASAP',
|
||||
whenFree: 'Bir yazıcı boşaldığında',
|
||||
overdue: 'Gecikmiş',
|
||||
now: 'Şimdi',
|
||||
lessThanMinute: 'Bir dakikadan az',
|
||||
|
||||
@@ -1504,7 +1504,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: "Час завершення, якщо запустити це завдання зараз",
|
||||
asap: "Якнайшвидше",
|
||||
whenFree: "Коли принтер звільниться",
|
||||
overdue: "Прострочено",
|
||||
now: "Зараз",
|
||||
lessThanMinute: "Менше ніж за хвилину",
|
||||
|
||||
@@ -1489,7 +1489,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: '若此任务现在开始的预计完成时间',
|
||||
asap: '尽快',
|
||||
whenFree: '有空闲打印机时',
|
||||
overdue: '已逾期',
|
||||
now: '现在',
|
||||
lessThanMinute: '不到一分钟',
|
||||
|
||||
@@ -1489,7 +1489,7 @@ export default {
|
||||
// Time
|
||||
time: {
|
||||
etaIfStartedNow: '若此工作現在開始的預計完成時間',
|
||||
asap: '儘快',
|
||||
whenFree: '有空閒印表機時',
|
||||
overdue: '已逾期',
|
||||
now: '現在',
|
||||
lessThanMinute: '不到一分鐘',
|
||||
|
||||
@@ -664,11 +664,18 @@ function SortableQueueItem({
|
||||
{isPending && !item.manual_start && (
|
||||
<span className="flex items-center gap-1.5">
|
||||
<Clock className="w-3.5 h-3.5" />
|
||||
{/* An item with no scheduled time used to render as "ASAP", which is the
|
||||
name of a dispatch mode the user may well not have picked -- ASAP and
|
||||
Queue differ only in insert position, and neither is stored on the
|
||||
item, so the two are indistinguishable here. Someone who chose Queue
|
||||
saw their row labelled ASAP and read it as Bambuddy overriding them
|
||||
(#2557, #3018). This column answers "when does it run", so it now says
|
||||
that instead of borrowing a mode name. */}
|
||||
{item.scheduled_time
|
||||
? ((parseUTCDate(item.scheduled_time)?.getTime() ?? 0) - Date.now() < -60000
|
||||
? t?.('queue.time.overdue') ?? 'Overdue'
|
||||
: formatRelativeTime(item.scheduled_time, timeFormat, t))
|
||||
: t?.('queue.time.asap') ?? 'ASAP'}
|
||||
: t?.('queue.time.whenFree') ?? 'When a printer is free'}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user