@andrian.yablonskyy/thub-coordinator 1.1.10 → 1.1.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@andrian.yablonskyy/thub-coordinator",
3
- "version": "1.1.10",
3
+ "version": "1.1.11",
4
4
  "description": "TestHub Coordinator — job queue, resource registry, scheduler, heartbeat monitor, log/artifact store and web dashboard",
5
5
  "main": "src/server.js",
6
6
  "engines": {
@@ -56,7 +56,7 @@
56
56
  }
57
57
 
58
58
  .resource-capabilities {
59
- font-size: 0.75rem;
59
+ font-size: 0.875rem;
60
60
  }
61
61
 
62
62
  /* An overlay inside a modal (e.g. "Import to config"'s review note on the
@@ -340,3 +340,21 @@ test('Labels tab: in effect at once, sent to the Client as its next config revis
340
340
  const old = register(services, 'lab-old-30', { configFile: null });
341
341
  assert.throws(() => services.registry.setClientLabels(old, ['x'], { by: 'x' }), /too old/);
342
342
  });
343
+
344
+ test('runner card: capabilities have their own tab, next to Details', async (t) => {
345
+ const { base, services, admin } = await start(t),
346
+ { resourceId } = services.registry.registerAuto({
347
+ clientId: 'hw8', name: 'lab-hw-08', type: 'hw', labels: [],
348
+ capabilities: { hw: { stlinks: [{ index: 1, path: '/dev/thub/dut1-stlink', present: false }], uarts: [], usbs: [] } }
349
+ }),
350
+ html = await (await fetch(`${base}/runners`, { headers: { cookie: admin } })).text(),
351
+ card = html.slice(html.indexOf(`id="resource-card-${resourceId}"`)),
352
+ details = card.slice(card.indexOf(`id="rc-${resourceId}-details"`), card.indexOf(`id="rc-${resourceId}-caps"`)),
353
+ caps = card.slice(card.indexOf(`id="rc-${resourceId}-caps"`)),
354
+ // The tab right after Details.
355
+ tabs = [...card.slice(0, card.indexOf('</ul>')).matchAll(/<button class="nav-link[^"]*" id="rc-[^"]*-(\w+)-tab"/g)].map((m) => m[1]);
356
+ assert.deepEqual(tabs.slice(0, 2), ['details', 'caps']);
357
+ assert.doesNotMatch(details, />Capabilities</); // no longer a Details row
358
+ assert.match(caps, new RegExp(`^id="rc-${resourceId}-caps"[^>]*data-live="rc-caps-${resourceId}"`)); // updates live
359
+ assert.match(caps, /\/dev\/thub\/dut1-stlink<\/code><span class="badge text-bg-danger[^"]*"[^>]*>missing/);
360
+ });
@@ -47,7 +47,7 @@
47
47
  +code('HW machine').
48
48
  sudo systemctl restart thub-client@client
49
49
  ls -l /dev/thub/
50
- li Check the runner card's #[strong Capabilities]: each configured device must be present (a missing one is flagged).
50
+ li Check the runner card's #[strong Capabilities] tab: each configured device must be present (a missing one is flagged).
51
51
  li Your job's #[code --command] flashes the board. The Client never flashes by itself; it passes the ST-Link serials and the downloaded files in the environment (#[a(href="#env") Environment variables]).
52
52
  +code('A typical HW job').
53
53
  thub run --type hw --label board:nucleo-f401re \
@@ -121,4 +121,4 @@
121
121
  td Files written to #[code /work] stay owned by the Client user, so the workspace can be cleaned up.
122
122
  +note('info').
123
123
  Docker access is effectively root access on that host. The Client host must have Docker and the service user must be in the
124
- #[code docker] group. The runner card's #[strong Capabilities] show whether a Client can use Docker, and why not.
124
+ #[code docker] group. The runner card's #[strong Capabilities] tab shows whether a Client can use Docker, and why not.
@@ -298,8 +298,9 @@ mixin resourceCard(r, groupsById, returnTo)
298
298
  //- data-config-root: where public/js/client-config.js tracks unsaved
299
299
  //- changes (⚠ on the config tabs).
300
300
  .modal-body.pt-2(data-config-root)
301
- //- Details: what the Client is and reports. Then its config tabs
302
- //- (client-config.pug; read-only for viewers), then its USB devices.
301
+ //- Details: what the Client is and reports; Capabilities: what it can
302
+ //- drive. Then its config tabs (client-config.pug; read-only for
303
+ //- viewers), then its USB devices.
303
304
  ul.nav.nav-tabs.mb-3(role="tablist")
304
305
  li.nav-item(role="presentation")
305
306
  button.nav-link.active(
@@ -311,6 +312,16 @@ mixin resourceCard(r, groupsById, returnTo)
311
312
  aria-controls=`rc-${r.id}-details`
312
313
  aria-selected="true"
313
314
  ) Details
315
+ li.nav-item(role="presentation")
316
+ button.nav-link(
317
+ id=`rc-${r.id}-caps-tab`
318
+ type="button"
319
+ role="tab"
320
+ data-bs-toggle="tab"
321
+ data-bs-target=`#rc-${r.id}-caps`
322
+ aria-controls=`rc-${r.id}-caps`
323
+ aria-selected="false"
324
+ ) Capabilities
314
325
  +configTabItems(r)
315
326
  li.nav-item(role="presentation")
316
327
  button.nav-link(
@@ -326,6 +337,11 @@ mixin resourceCard(r, groupsById, returnTo)
326
337
  .tab-content
327
338
  .tab-pane.fade.show.active(id=`rc-${r.id}-details` role="tabpanel" aria-labelledby=`rc-${r.id}-details-tab` tabindex="0" data-live=`rc-details-${r.id}`)
328
339
  +resourceDetails(r, groupsById, returnTo, local, external)
340
+ //- Live too: a Client that restarts reports them again.
341
+ .tab-pane.fade(id=`rc-${r.id}-caps` role="tabpanel" aria-labelledby=`rc-${r.id}-caps-tab` tabindex="0" data-live=`rc-caps-${r.id}`)
342
+ p.small.text-body-secondary.mb-2 What the Client reported it can drive at its last start, checked against its host.
343
+ .resource-capabilities
344
+ +capabilitiesList(r.capabilities)
329
345
  +configPanes(r, returnTo, groupsById)
330
346
  .tab-pane.fade.thub-usb-pane(id=`rc-${r.id}-usb` role="tabpanel" aria-labelledby=`rc-${r.id}-usb-tab` tabindex="0")
331
347
  +usbScanPane(r)
@@ -496,9 +512,6 @@ mixin resourceDetails(r, groupsById, returnTo, local, external)
496
512
  data-bs-toggle="tooltip"
497
513
  data-bs-title="The address the Coordinator last saw this Client connect from"
498
514
  ) external
499
- dt.col-sm-4 Capabilities
500
- dd.col-sm-8.resource-capabilities
501
- +capabilitiesList(r.capabilities)
502
515
  dt.col-sm-4 Labels
503
516
  dd.col-sm-8
504
517
  if r.labels.length