dsh-xray 0.7.0 → 0.7.1

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.
Files changed (2) hide show
  1. package/lib/client.js +25 -10
  2. package/package.json +1 -1
package/lib/client.js CHANGED
@@ -21,15 +21,24 @@ window.__ModuleLoader__.load({
21
21
  '.xray-sub{color:var(--dsw-alias-label-tertiary);margin:0 0 14px;font-size:12px}',
22
22
  '.xray-nav{display:flex;gap:6px;flex-wrap:wrap;margin-bottom:12px}',
23
23
  '.xray-nav button{font:inherit;font-size:12px;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-bg-layer-3);border:1px solid var(--dsw-alias-border-l2);border-radius:6px;padding:4px 10px;cursor:pointer}',
24
- '.xray-nav button.active{color:#fff;background:var(--dsw-alias-brand-primary);border-color:var(--dsw-alias-brand-primary)}',
24
+ '.xray-nav button:hover{background:var(--dsw-alias-interactive-bg-hover)}',
25
+ // active view: the host's own tab-active family (state-business-*) —
26
+ // visible in both themes, unlike brand-primary which resolves to
27
+ // near-white in dark mode (white-on-white active buttons).
28
+ '.xray-nav button.active{color:var(--dsw-alias-state-business-primary);background:var(--dsw-alias-state-business-tertiary);border-color:var(--dsw-alias-state-business-primary);font-weight:600}',
29
+ // min-height pads the short views (summary is 4 rows, deps dozens) so
30
+ // switching between them moves the layout as little as possible;
31
+ // .xray-stale dims outgoing content while the next payload is in flight.
32
+ '.xray-body{min-height:320px}',
33
+ '.xray-stale{opacity:.45;transition:opacity .15s;pointer-events:none}',
25
34
  '.xray-table{border-collapse:collapse;width:100%;margin-top:6px}',
26
35
  '.xray-table th,.xray-table td{text-align:left;padding:4px 10px;border-bottom:1px solid var(--dsw-alias-border-l2);vertical-align:top}',
27
36
  '.xray-table th{color:var(--dsw-alias-label-tertiary);font-weight:normal}',
28
37
  '.xray-num{text-align:right}',
29
- '.xray-warn{color:var(--dsw-alias-label-error)}',
30
- '.xray-ok{color:var(--dsw-alias-label-success,#7ee787)}',
38
+ '.xray-warn{color:var(--dsw-alias-state-error-primary,#f85149)}',
39
+ '.xray-ok{color:var(--dsw-alias-state-success-primary,#3fb950)}',
31
40
  '.xray-muted{color:var(--dsw-alias-label-tertiary)}',
32
- '.xray-bar{background:var(--dsw-alias-brand-primary);height:10px;border-radius:2px;display:inline-block}',
41
+ '.xray-bar{background:var(--dsw-alias-state-business-primary);height:10px;border-radius:2px;display:inline-block}',
33
42
  '.xray-h3{font-size:13px;font-weight:600;margin:14px 0 4px}',
34
43
  ].join('\n');
35
44
  if (
@@ -260,11 +269,13 @@ window.__ModuleLoader__.load({
260
269
  // `for` stamps which view the payload belongs to: a click flips `view`
261
270
  // synchronously while `state` still carries the previous view's data —
262
271
  // rendering that mismatch with the new renderer throws and unmounts
263
- // the whole tab. Mismatch renders as loading instead.
272
+ // the whole tab. During the switch the previous view's content stays
273
+ // up (dimmed) and is replaced in one paint when the payload lands, so
274
+ // the layout changes once per click instead of collapsing to a
275
+ // one-line loading row and re-expanding.
264
276
  const [state, setState] = react.useState({ phase: 'loading', for: 'summary' });
265
277
  react.useEffect(() => {
266
278
  let alive = true;
267
- setState({ phase: 'loading', for: view });
268
279
  fetch(`/xray/api/${view}`)
269
280
  .then(async (res) => {
270
281
  if (!res.ok) throw new Error(await res.text());
@@ -285,15 +296,18 @@ window.__ModuleLoader__.load({
285
296
  alive = false;
286
297
  };
287
298
  }, [view]);
299
+ // Render whatever payload we HAVE (state.for), not the view the user
300
+ // just requested — the stale content keeps the scaffold stable while
301
+ // the fresh payload is in flight.
302
+ const settled = state.phase !== 'loading';
288
303
  let body;
289
- if (state.for !== view || state.phase === 'loading')
290
- body = h('p', { className: 'xray-muted' }, `loading ${view}…`);
304
+ if (!settled) body = h('p', { className: 'xray-muted' }, `loading ${view}…`);
291
305
  else if (state.phase === 'error') body = h('p', { className: 'xray-warn' }, state.message);
292
306
  else {
293
307
  // A diagnostic surface must never take itself down on one bad
294
308
  // payload: render the failure, keep the tab and its nav alive.
295
309
  try {
296
- body = renderers[view](state.data);
310
+ body = renderers[state.for](state.data);
297
311
  } catch (err) {
298
312
  body = h(
299
313
  'p',
@@ -302,6 +316,7 @@ window.__ModuleLoader__.load({
302
316
  );
303
317
  }
304
318
  }
319
+ const stale = settled && state.for !== view;
305
320
  return h(
306
321
  'div',
307
322
  { className: 'xray-panel' },
@@ -317,7 +332,7 @@ window.__ModuleLoader__.load({
317
332
  ),
318
333
  ),
319
334
  ),
320
- body,
335
+ h('div', { className: stale ? 'xray-body xray-stale' : 'xray-body' }, body),
321
336
  );
322
337
  }
323
338
  //#endregion
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-xray",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
4
4
  "description": "X-ray for your DeepSeek Harness — see what's actually loaded, why, and what it costs you.",
5
5
  "repository": {
6
6
  "type": "git",