@morscherlab/mint-sdk 1.4.0-beta.18 → 1.4.0-beta.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/JobsStatusTray.vue.d.ts +4 -0
- package/dist/composables/useJobCenter.d.ts +32 -2
- package/dist/{data-BIiV4kKw.js → data-DBnmeBZX.js} +2 -2
- package/dist/{data-BIiV4kKw.js.map → data-DBnmeBZX.js.map} +1 -1
- package/dist/data.js +2 -2
- package/dist/index.js +3 -3
- package/dist/{install-Dg-Z6ze5.js → install-C5psB1H0.js} +3 -3
- package/dist/{install-Dg-Z6ze5.js.map → install-C5psB1H0.js.map} +1 -1
- package/dist/install.js +1 -1
- package/dist/{runtime-cHv1phcc.js → runtime-CoHhBP10.js} +23 -4
- package/dist/runtime-CoHhBP10.js.map +1 -0
- package/dist/runtime.d.ts +1 -1
- package/dist/runtime.js +2 -2
- package/dist/styles.css +4 -0
- package/dist/useRealtime-C3whhVvb.js +508 -0
- package/dist/useRealtime-C3whhVvb.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/components/JobsStatusTray.test.ts +242 -6
- package/src/__tests__/composables/useJobCenter.test.ts +39 -0
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +1 -0
- package/src/components/JobsStatusTray.story.vue +20 -1
- package/src/components/JobsStatusTray.vue +145 -40
- package/src/composables/useJobCenter.ts +63 -2
- package/src/runtime.ts +2 -0
- package/src/styles/components/jobs-status-tray.css +5 -0
- package/dist/runtime-cHv1phcc.js.map +0 -1
- package/dist/useRealtime-BW02xy4Z.js +0 -398
- package/dist/useRealtime-BW02xy4Z.js.map +0 -1
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
import { mount } from '@vue/test-utils'
|
|
1
|
+
import { flushPromises, mount } from '@vue/test-utils'
|
|
2
2
|
import { describe, expect, it, vi } from 'vitest'
|
|
3
|
-
import { defineComponent, h, nextTick } from 'vue'
|
|
3
|
+
import { defineComponent, h, nextTick, shallowRef } from 'vue'
|
|
4
4
|
|
|
5
|
+
import BaseModal from '../../components/BaseModal.vue'
|
|
5
6
|
import JobsStatusTray from '../../components/JobsStatusTray.vue'
|
|
6
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
useJobCenter,
|
|
9
|
+
type PluginJobCenterSource,
|
|
10
|
+
type UseJobCenterOptions,
|
|
11
|
+
type UseJobCenterReturn,
|
|
12
|
+
} from '../../composables/useJobCenter'
|
|
7
13
|
import type { JobState, JobStateInput, JobStatus } from '../../types/jobs'
|
|
8
14
|
|
|
9
15
|
function job(status: JobStatus, id: string = status): JobStateInput {
|
|
@@ -43,17 +49,24 @@ function job(status: JobStatus, id: string = status): JobStateInput {
|
|
|
43
49
|
async function openTray(options: {
|
|
44
50
|
source: PluginJobCenterSource
|
|
45
51
|
slots?: Record<string, (props: { job: JobState }) => unknown>
|
|
52
|
+
confirm?: InstanceType<typeof JobsStatusTray>['$props']['confirm']
|
|
53
|
+
rowJob?: UseJobCenterOptions['rowJob']
|
|
54
|
+
/** Run real transitions, so a leaving dialog stays in the DOM for a frame. */
|
|
55
|
+
transitions?: boolean
|
|
46
56
|
}) {
|
|
47
57
|
const Host = defineComponent({
|
|
48
58
|
setup() {
|
|
49
|
-
const center = useJobCenter({ source: options.source, loadOnMount: false })
|
|
59
|
+
const center = useJobCenter({ source: options.source, loadOnMount: false, rowJob: options.rowJob })
|
|
50
60
|
return () => [
|
|
51
61
|
h('button', { class: 'opener', onClick: center.toggle }, 'Jobs'),
|
|
52
|
-
h(JobsStatusTray, { center, teleportTo: false }, options.slots),
|
|
62
|
+
h(JobsStatusTray, { center, teleportTo: false, confirm: options.confirm }, options.slots),
|
|
53
63
|
]
|
|
54
64
|
},
|
|
55
65
|
})
|
|
56
|
-
const wrapper = mount(Host, {
|
|
66
|
+
const wrapper = mount(Host, {
|
|
67
|
+
attachTo: document.body,
|
|
68
|
+
global: options.transitions ? { stubs: { transition: false } } : {},
|
|
69
|
+
})
|
|
57
70
|
const opener = wrapper.get('.opener')
|
|
58
71
|
;(opener.element as HTMLElement).focus()
|
|
59
72
|
await opener.trigger('click')
|
|
@@ -255,4 +268,227 @@ describe('JobsStatusTray', () => {
|
|
|
255
268
|
wrapper.unmount()
|
|
256
269
|
})
|
|
257
270
|
})
|
|
271
|
+
|
|
272
|
+
it('should draw a row from the center row view when a rowJob option overrides it', async () => {
|
|
273
|
+
const wrapper = await openTray({
|
|
274
|
+
source: { jobs: [{ ...job('awaiting_input', 'A-1'), can_cancel: true }], cancel: vi.fn(async () => undefined) },
|
|
275
|
+
rowJob: row => (row.status === 'awaiting_input' ? { status: 'running', percent: 40, message: 'Decoding in the browser' } : null),
|
|
276
|
+
})
|
|
277
|
+
const row = wrapper.get('.mint-jobs-tray__row')
|
|
278
|
+
|
|
279
|
+
expect({
|
|
280
|
+
section: wrapper.get('[data-section="active"]').text().replace(/\s+/g, ' '),
|
|
281
|
+
status: row.attributes('data-status'),
|
|
282
|
+
tinted: row.classes('mint-jobs-tray__row--awaiting-input'),
|
|
283
|
+
icon: row.get('[role="img"]').attributes('aria-label'),
|
|
284
|
+
value: row.get('.mint-jobs-tray__value').text(),
|
|
285
|
+
progress: row.get('[role="progressbar"]').attributes('aria-valuenow'),
|
|
286
|
+
detail: row.get('.mint-jobs-tray__detail').text(),
|
|
287
|
+
cancel: row.find('[aria-label="Cancel Job A-1"]').exists(),
|
|
288
|
+
}).toEqual({
|
|
289
|
+
section: 'Active · 1',
|
|
290
|
+
status: 'awaiting_input',
|
|
291
|
+
tinted: false,
|
|
292
|
+
icon: 'Running',
|
|
293
|
+
value: '40%',
|
|
294
|
+
progress: '40',
|
|
295
|
+
detail: 'Decoding in the browser',
|
|
296
|
+
cancel: true,
|
|
297
|
+
})
|
|
298
|
+
})
|
|
299
|
+
|
|
300
|
+
it('should mount no confirm dialog when confirm is off', async () => {
|
|
301
|
+
const wrapper = await openTray({ source: { jobs: [job('completed')], delete: vi.fn(async () => true) } })
|
|
302
|
+
expect(wrapper.findComponent(BaseModal).exists()).toBe(false)
|
|
303
|
+
wrapper.unmount()
|
|
304
|
+
})
|
|
305
|
+
|
|
306
|
+
it('should keep the tray open when an inner handler prevents the Escape default', async () => {
|
|
307
|
+
const wrapper = await openTray({
|
|
308
|
+
source: { jobs: [job('running', 'R-1')] },
|
|
309
|
+
slots: {
|
|
310
|
+
'job-actions': () => h('input', {
|
|
311
|
+
class: 'inner',
|
|
312
|
+
onKeydown: (event: KeyboardEvent) => { if (event.key === 'Escape') event.preventDefault() },
|
|
313
|
+
}),
|
|
314
|
+
},
|
|
315
|
+
})
|
|
316
|
+
const inner = wrapper.get('.inner').element as HTMLElement
|
|
317
|
+
inner.focus()
|
|
318
|
+
|
|
319
|
+
inner.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true, cancelable: true }))
|
|
320
|
+
await nextTick()
|
|
321
|
+
|
|
322
|
+
expect(wrapper.find('.mint-jobs-tray__panel').exists()).toBe(true)
|
|
323
|
+
wrapper.unmount()
|
|
324
|
+
})
|
|
325
|
+
|
|
326
|
+
it('should leave focus on the page when a job update arrives while nothing in the tray is focused', async () => {
|
|
327
|
+
const jobs = shallowRef([job('running', 'R-1')])
|
|
328
|
+
const wrapper = await openTray({ source: { jobs } })
|
|
329
|
+
;(document.activeElement as HTMLElement).blur()
|
|
330
|
+
|
|
331
|
+
jobs.value = [job('completed', 'R-1')]
|
|
332
|
+
await nextTick()
|
|
333
|
+
await nextTick()
|
|
334
|
+
|
|
335
|
+
expect(document.activeElement).toBe(document.body)
|
|
336
|
+
wrapper.unmount()
|
|
337
|
+
})
|
|
338
|
+
|
|
339
|
+
it('should focus the panel when the focused row leaves the list while the tray is open', async () => {
|
|
340
|
+
const jobs = shallowRef([job('completed', 'C-1'), job('completed', 'C-2')])
|
|
341
|
+
const wrapper = await openTray({ source: { jobs, delete: vi.fn(async () => true) } })
|
|
342
|
+
;(wrapper.get('[aria-label="Delete Job C-1"]').element as HTMLElement).focus()
|
|
343
|
+
|
|
344
|
+
jobs.value = [job('completed', 'C-2')]
|
|
345
|
+
await nextTick()
|
|
346
|
+
await nextTick()
|
|
347
|
+
|
|
348
|
+
expect(document.activeElement).toBe(wrapper.get('.mint-jobs-tray__panel').element)
|
|
349
|
+
wrapper.unmount()
|
|
350
|
+
})
|
|
351
|
+
|
|
352
|
+
describe('confirmation', () => {
|
|
353
|
+
const dialog = () => document.body.querySelector<HTMLElement>('.mint-modal [role="dialog"], .mint-modal__container')
|
|
354
|
+
|
|
355
|
+
function confirmSource() {
|
|
356
|
+
return {
|
|
357
|
+
jobs: [{ ...job('running', 'R-1'), can_cancel: true }, job('completed', 'C-1'), job('failed', 'F-1')],
|
|
358
|
+
cancel: vi.fn(async () => undefined),
|
|
359
|
+
delete: vi.fn(async () => true),
|
|
360
|
+
clear: vi.fn(async () => 2),
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
const triggers = {
|
|
364
|
+
cancel: '[aria-label="Cancel Job R-1"]',
|
|
365
|
+
delete: '[aria-label="Delete Job C-1"]',
|
|
366
|
+
clear: '[data-section="finished"] .mint-jobs-tray__section-action',
|
|
367
|
+
} as const
|
|
368
|
+
|
|
369
|
+
it.each([
|
|
370
|
+
['cancel', true, 'Job R-1'],
|
|
371
|
+
['delete', { delete: true }, 'Job C-1'],
|
|
372
|
+
['clear', { clear: true }, '2 finished jobs'],
|
|
373
|
+
] as const)('should run %s only after the confirm dialog is confirmed when confirm is %o', async (kind, confirm, named) => {
|
|
374
|
+
const source = confirmSource()
|
|
375
|
+
const wrapper = await openTray({ source, confirm })
|
|
376
|
+
|
|
377
|
+
await wrapper.get(triggers[kind]).trigger('click')
|
|
378
|
+
await nextTick()
|
|
379
|
+
const shown = dialog()
|
|
380
|
+
const before = source[kind].mock.calls.length
|
|
381
|
+
const confirmButton = [...shown!.querySelectorAll('button')].at(-1)!
|
|
382
|
+
confirmButton.click()
|
|
383
|
+
await flushPromises()
|
|
384
|
+
|
|
385
|
+
expect([shown?.textContent?.includes(named), before, source[kind].mock.calls.length]).toEqual([true, 0, 1])
|
|
386
|
+
wrapper.unmount()
|
|
387
|
+
})
|
|
388
|
+
|
|
389
|
+
it.each([
|
|
390
|
+
['off', undefined],
|
|
391
|
+
['set for another action', { delete: true }],
|
|
392
|
+
] as const)('should cancel at once without a dialog when confirm is %s', async (_case, confirm) => {
|
|
393
|
+
const source = confirmSource()
|
|
394
|
+
const wrapper = await openTray({ source, confirm })
|
|
395
|
+
|
|
396
|
+
await wrapper.get(triggers.cancel).trigger('click')
|
|
397
|
+
await flushPromises()
|
|
398
|
+
|
|
399
|
+
expect([dialog(), source.cancel.mock.calls.length]).toEqual([null, 1])
|
|
400
|
+
wrapper.unmount()
|
|
401
|
+
})
|
|
402
|
+
|
|
403
|
+
it('should run the action once when Confirm is clicked twice while the dialog fades out', async () => {
|
|
404
|
+
const source = confirmSource()
|
|
405
|
+
const wrapper = await openTray({ source, confirm: true, transitions: true })
|
|
406
|
+
await wrapper.get(triggers.clear).trigger('click')
|
|
407
|
+
await nextTick()
|
|
408
|
+
const confirmButton = [...dialog()!.querySelectorAll('button')].at(-1)!
|
|
409
|
+
|
|
410
|
+
confirmButton.click()
|
|
411
|
+
confirmButton.click()
|
|
412
|
+
await flushPromises()
|
|
413
|
+
|
|
414
|
+
expect([confirmButton.isConnected, source.clear.mock.calls.length]).toEqual([true, 1])
|
|
415
|
+
await vi.waitFor(() => expect(dialog()).toBeNull())
|
|
416
|
+
wrapper.unmount()
|
|
417
|
+
})
|
|
418
|
+
|
|
419
|
+
it('should close only the dialog when Escape is pressed in it', async () => {
|
|
420
|
+
const source = confirmSource()
|
|
421
|
+
const wrapper = await openTray({ source, confirm: true })
|
|
422
|
+
await wrapper.get(triggers.delete).trigger('click')
|
|
423
|
+
await nextTick()
|
|
424
|
+
|
|
425
|
+
dialog()!.dispatchEvent(new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }))
|
|
426
|
+
await flushPromises()
|
|
427
|
+
|
|
428
|
+
expect([dialog(), wrapper.find('.mint-jobs-tray__panel').exists(), source.delete.mock.calls.length])
|
|
429
|
+
.toEqual([null, true, 0])
|
|
430
|
+
wrapper.unmount()
|
|
431
|
+
})
|
|
432
|
+
|
|
433
|
+
it('should ask again with the new count when the finished jobs change before Confirm', async () => {
|
|
434
|
+
const jobs = shallowRef([job('completed', 'C-1'), job('failed', 'F-1')])
|
|
435
|
+
const clear = vi.fn(async () => 3)
|
|
436
|
+
const wrapper = await openTray({ source: { jobs, clear }, confirm: true })
|
|
437
|
+
await wrapper.get(triggers.clear).trigger('click')
|
|
438
|
+
await nextTick()
|
|
439
|
+
|
|
440
|
+
jobs.value = [...jobs.value, job('cancelled', 'X-1')]
|
|
441
|
+
await nextTick()
|
|
442
|
+
;[...dialog()!.querySelectorAll('button')].at(-1)!.click()
|
|
443
|
+
await flushPromises()
|
|
444
|
+
const asked = [dialog()?.textContent?.includes('3 finished jobs'), clear.mock.calls.length]
|
|
445
|
+
;[...dialog()!.querySelectorAll('button')].at(-1)!.click()
|
|
446
|
+
await flushPromises()
|
|
447
|
+
|
|
448
|
+
expect([...asked, dialog(), clear.mock.calls.length]).toEqual([true, 0, null, 1])
|
|
449
|
+
wrapper.unmount()
|
|
450
|
+
})
|
|
451
|
+
|
|
452
|
+
it.each([
|
|
453
|
+
['delete', 'the job is gone', [] as JobStateInput[]],
|
|
454
|
+
['cancel', 'the job finished', [{ ...job('completed', 'R-1'), can_cancel: true }]],
|
|
455
|
+
['delete', 'the job is no longer deletable', [{ ...job('completed', 'C-1'), can_delete: false }]],
|
|
456
|
+
] as const)('should close the %s dialog without acting when %s before Confirm', async (kind, _case, next) => {
|
|
457
|
+
const source = { ...confirmSource(), jobs: shallowRef<JobStateInput[]>(confirmSource().jobs) }
|
|
458
|
+
const wrapper = await openTray({ source, confirm: true })
|
|
459
|
+
await wrapper.get(triggers[kind]).trigger('click')
|
|
460
|
+
await nextTick()
|
|
461
|
+
|
|
462
|
+
source.jobs.value = [...next]
|
|
463
|
+
await nextTick()
|
|
464
|
+
;[...dialog()!.querySelectorAll('button')].at(-1)!.click()
|
|
465
|
+
await flushPromises()
|
|
466
|
+
|
|
467
|
+
expect([dialog(), source[kind].mock.calls.length]).toEqual([null, 0])
|
|
468
|
+
wrapper.unmount()
|
|
469
|
+
})
|
|
470
|
+
|
|
471
|
+
it('should drop the pending action when the job source changes while the dialog is open', async () => {
|
|
472
|
+
const first = confirmSource()
|
|
473
|
+
const second = confirmSource()
|
|
474
|
+
const current = shallowRef<PluginJobCenterSource>(first)
|
|
475
|
+
const Host = defineComponent({
|
|
476
|
+
setup() {
|
|
477
|
+
const center = useJobCenter({ source: current, loadOnMount: false })
|
|
478
|
+
center.open()
|
|
479
|
+
return () => h(JobsStatusTray, { center, teleportTo: false, confirm: true })
|
|
480
|
+
},
|
|
481
|
+
})
|
|
482
|
+
const wrapper = mount(Host, { attachTo: document.body })
|
|
483
|
+
await nextTick()
|
|
484
|
+
await wrapper.get(triggers.delete).trigger('click')
|
|
485
|
+
await nextTick()
|
|
486
|
+
|
|
487
|
+
current.value = second
|
|
488
|
+
await nextTick()
|
|
489
|
+
|
|
490
|
+
expect([dialog(), first.delete.mock.calls.length, second.delete.mock.calls.length]).toEqual([null, 0, 0])
|
|
491
|
+
wrapper.unmount()
|
|
492
|
+
})
|
|
493
|
+
})
|
|
258
494
|
})
|
|
@@ -423,6 +423,21 @@ describe('useJobCenter top-bar chip', () => {
|
|
|
423
423
|
}).toEqual({ baseline: null, later: { status: 'failed', label: '1 failed' }, stored: ['old'] })
|
|
424
424
|
})
|
|
425
425
|
|
|
426
|
+
it.each<[string, TopBarJob | null, TopBarJob]>([
|
|
427
|
+
['use the override', { status: 'completed', label: 'Saved to the experiment' },
|
|
428
|
+
{ status: 'completed', label: 'Saved to the experiment' }],
|
|
429
|
+
['keep the default', null, { status: 'completed', label: 'r completed' }],
|
|
430
|
+
])('should %s for the held job when the topBarJob option returns that value', async (_case, override, expected) => {
|
|
431
|
+
const jobs = shallowRef([job('running', 'r')])
|
|
432
|
+
const topBarJob = vi.fn((shown: { status: JobStatus }) => (shown.status === 'completed' ? override : null))
|
|
433
|
+
const { tray } = mountComposable({ source: { jobs }, loadOnMount: false, topBarJob })
|
|
434
|
+
|
|
435
|
+
jobs.value = [job('completed', 'r')]
|
|
436
|
+
await nextTick()
|
|
437
|
+
|
|
438
|
+
expect(tray.topBarJob.value).toEqual(expected)
|
|
439
|
+
})
|
|
440
|
+
|
|
426
441
|
it('should hold a just-completed job for 6 s and select it on click when nothing else runs', async () => {
|
|
427
442
|
vi.useFakeTimers()
|
|
428
443
|
const jobs = shallowRef([job('running', 'r')])
|
|
@@ -501,3 +516,27 @@ describe('useJobCenter top-bar chip', () => {
|
|
|
501
516
|
expect(tray.completedCount.value).toBe(2)
|
|
502
517
|
})
|
|
503
518
|
})
|
|
519
|
+
|
|
520
|
+
describe('useJobCenter row view', () => {
|
|
521
|
+
const awaiting = job('awaiting_input', 'a')
|
|
522
|
+
const running = job('running', 'r')
|
|
523
|
+
|
|
524
|
+
it.each<[string, JobStateInput, UseJobCenterOptions['rowJob'], ReturnType<ReturnType<typeof useJobCenter>['rowView']>]>([
|
|
525
|
+
['absent', running, undefined, { status: 'running', percent: 42, message: 'running' }],
|
|
526
|
+
['null', awaiting, () => null,
|
|
527
|
+
{ status: 'awaiting_input', percent: null, message: 'Waiting for external input' }],
|
|
528
|
+
['a status and percent', awaiting, () => ({ status: 'running', percent: 40 }),
|
|
529
|
+
{ status: 'running', percent: 40, message: 'Waiting for external input' }],
|
|
530
|
+
['a message only', running, () => ({ message: 'Decoding 3/8' }),
|
|
531
|
+
{ status: 'running', percent: 42, message: 'Decoding 3/8' }],
|
|
532
|
+
['undefined and null fields', running, () => ({ status: null, percent: undefined, message: null }),
|
|
533
|
+
{ status: 'running', percent: 42, message: 'running' }],
|
|
534
|
+
['a status only', running, () => ({ status: 'awaiting_input' }),
|
|
535
|
+
{ status: 'awaiting_input', percent: 42, message: 'running' }],
|
|
536
|
+
['a null percent', running, () => ({ percent: null }),
|
|
537
|
+
{ status: 'running', percent: null, message: 'running' }],
|
|
538
|
+
])('should resolve the row view from the job when the row override is %s', (_case, input, rowJob, expected) => {
|
|
539
|
+
const { tray } = mountComposable({ source: { jobs: [input] }, loadOnMount: false, rowJob })
|
|
540
|
+
expect(tray.rowView(tray.jobs.value[0]!)).toEqual(expected)
|
|
541
|
+
})
|
|
542
|
+
})
|
|
@@ -63,11 +63,18 @@ const TrayDemo = defineComponent({
|
|
|
63
63
|
jobs: { type: Array as PropType<JobStateInput[]>, required: true },
|
|
64
64
|
title: { type: String, default: undefined },
|
|
65
65
|
open: Boolean,
|
|
66
|
+
confirm: Boolean,
|
|
67
|
+
/** Show the awaiting-input job as a browser decode, as LEAF does. */
|
|
68
|
+
decode: Boolean,
|
|
66
69
|
},
|
|
67
70
|
setup(props) {
|
|
68
71
|
// One source object: a new source identity resets the just-completed hold.
|
|
69
72
|
const center = useJobCenter({
|
|
70
73
|
source: { jobs: () => props.jobs, cancel: cancelJob, delete: deleteJob },
|
|
74
|
+
rowJob: row => (props.decode && row.status === 'awaiting_input'
|
|
75
|
+
? { status: 'running', percent: 62, message: 'Decoding in the browser · 5/8' }
|
|
76
|
+
: null),
|
|
77
|
+
topBarJob: shown => (shown.status === 'completed' ? { status: 'completed', label: `Saved to ${shown.experiment_id}` } : null),
|
|
71
78
|
})
|
|
72
79
|
onMounted(() => { if (props.open) center.open() })
|
|
73
80
|
return () => [
|
|
@@ -79,7 +86,7 @@ const TrayDemo = defineComponent({
|
|
|
79
86
|
jobsPanelId: center.panelId,
|
|
80
87
|
onJobClick: () => center.handleTopBarClick(openJob),
|
|
81
88
|
}),
|
|
82
|
-
h(JobsStatusTray, { center, title: props.title, onSelect: openJob }, {
|
|
89
|
+
h(JobsStatusTray, { center, title: props.title, confirm: props.confirm, onSelect: openJob }, {
|
|
83
90
|
'job-actions': ({ job: row }: { job: JobState }) => row.status === 'completed'
|
|
84
91
|
? h('button', { type: 'button', class: 'mint-jobs-tray__section-action', onClick: () => openJob(row) }, 'Open')
|
|
85
92
|
: null,
|
|
@@ -109,6 +116,8 @@ function initState() {
|
|
|
109
116
|
percent: 37,
|
|
110
117
|
finished: false,
|
|
111
118
|
open: true,
|
|
119
|
+
confirm: false,
|
|
120
|
+
decode: false,
|
|
112
121
|
}
|
|
113
122
|
}
|
|
114
123
|
</script>
|
|
@@ -123,6 +132,8 @@ function initState() {
|
|
|
123
132
|
:jobs="playgroundJobs(state.percent, state.finished)"
|
|
124
133
|
:title="state.title"
|
|
125
134
|
:open="state.open"
|
|
135
|
+
:confirm="state.confirm"
|
|
136
|
+
:decode="state.decode"
|
|
126
137
|
/>
|
|
127
138
|
</div>
|
|
128
139
|
</template>
|
|
@@ -131,9 +142,17 @@ function initState() {
|
|
|
131
142
|
<HstSlider v-model="state.percent" title="Running percent" :min="0" :max="100" />
|
|
132
143
|
<HstCheckbox v-model="state.finished" title="Running job completed (6 s chip)" />
|
|
133
144
|
<HstCheckbox v-model="state.open" title="Open on mount" />
|
|
145
|
+
<HstCheckbox v-model="state.confirm" title="Confirm cancel, delete and clear" />
|
|
146
|
+
<HstCheckbox v-model="state.decode" title="Row override: J-104 as a browser decode" />
|
|
134
147
|
</template>
|
|
135
148
|
</Variant>
|
|
136
149
|
|
|
150
|
+
<Variant title="Confirm and row override">
|
|
151
|
+
<div style="min-height: 560px;">
|
|
152
|
+
<TrayDemo :jobs="playgroundJobs(37, false)" open confirm decode />
|
|
153
|
+
</div>
|
|
154
|
+
</Variant>
|
|
155
|
+
|
|
137
156
|
<Variant title="Awaiting input">
|
|
138
157
|
<div style="min-height: 560px;">
|
|
139
158
|
<TrayDemo :jobs="[job('awaiting_input', 'J-301')]" open />
|