@yuneta/gobj-ui 7.23.175 → 7.23.177

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.
@@ -76272,21 +76272,6 @@ function traffic_iso(value) {
76272
76272
  return null;
76273
76273
  }
76274
76274
  }
76275
- /************************************************************
76276
- * Clip a string for inline display (full text kept elsewhere).
76277
- ************************************************************/
76278
- function traffic_clip(s, n) {
76279
- s = String(s);
76280
- return s.length > n ? s.slice(0, n) + "…" : s;
76281
- }
76282
- /************************************************************
76283
- * A scalar rendered as a short inline token (for summaries).
76284
- ************************************************************/
76285
- function traffic_scalar_text(v) {
76286
- if (v === null) return "null";
76287
- if (typeof v === "string") return traffic_clip(v, 40);
76288
- return String(v);
76289
- }
76290
76275
  function dir_class(dir) {
76291
76276
  return dir === 2 ? "dir-in" : dir === 3 ? "dir-err" : "dir-out";
76292
76277
  }
@@ -76299,9 +76284,11 @@ function dir_arrow(dir) {
76299
76284
  function dev_num(key, def) {
76300
76285
  return Number((0, _yuneta_gobj_js.kw_get_local_storage_value)(key, def === void 0 ? 0 : def, false));
76301
76286
  }
76302
- function dev_view() {
76303
- let v = (0, _yuneta_gobj_js.kw_get_local_storage_value)("dev_view_mode", "detailed", false);
76304
- return v === "compact" || v === "name" || v === "full" ? v : "detailed";
76287
+ function dev_traffic_view() {
76288
+ return (0, _yuneta_gobj_js.kw_get_local_storage_value)("dev_traffic_view", "collapsed", false) === "expanded" ? "expanded" : "collapsed";
76289
+ }
76290
+ function dev_traces_payload() {
76291
+ return dev_num("dev_traces_payload", 1) ? 1 : 0;
76305
76292
  }
76306
76293
  var SIMPLE_MACH_DEFAULT = 1;
76307
76294
  var SIMPLE_MACH_KEY = "dev_mach_simple";
@@ -76319,10 +76306,21 @@ function console_traffic(title, jn, direction, size) {
76319
76306
  let event = jn && jn.event ? String(jn.event) : "(no event)";
76320
76307
  let kw = jn && jn.kw && typeof jn.kw === "object" ? jn.kw : jn;
76321
76308
  let color = direction === 2 ? "#16a34a" : direction === 3 ? "#dc2626" : "#2563eb";
76322
- window.console.log("%c" + dir_arrow(direction) + " " + (title ? "[" + title + "] " : "") + event + (size ? " (" + size + "b)" : ""), "color:" + color, kw);
76309
+ let head = "%c" + dir_arrow(direction) + " " + (title ? "[" + title + "] " : "") + event + (size ? " (" + size + "b)" : "");
76310
+ if (dev_traffic_view() === "expanded") {
76311
+ let text;
76312
+ try {
76313
+ text = JSON.stringify(full_sections(kw), null, 4);
76314
+ } catch (err) {
76315
+ text = String(kw);
76316
+ }
76317
+ window.console.log(head, "color:" + color, "\n" + text);
76318
+ return;
76319
+ }
76320
+ window.console.log(head, "color:" + color, kw);
76323
76321
  }
76324
- function set_view(v) {
76325
- (0, _yuneta_gobj_js.kw_set_local_storage_value)("dev_view_mode", v);
76322
+ function set_traffic_view(v) {
76323
+ (0, _yuneta_gobj_js.kw_set_local_storage_value)("dev_traffic_view", v === "expanded" ? "expanded" : "collapsed");
76326
76324
  rerender_all();
76327
76325
  refresh_dev_chrome();
76328
76326
  }
@@ -76348,12 +76346,12 @@ function build_filter_ctx() {
76348
76346
  inc: dev_num("dev_filter_in", 1),
76349
76347
  err: dev_num("dev_filter_err", 1),
76350
76348
  search: SEARCH_TEXT,
76351
- view: dev_view()
76349
+ payload: dev_traces_payload()
76352
76350
  };
76353
76351
  }
76354
76352
  function entry_hidden(e, ctx) {
76355
76353
  if (e.kind === "log") {
76356
- if (e.level === "json" && (ctx.view === "name" || ctx.view === "compact")) return true;
76354
+ if (e.level === "json" && !ctx.payload) return true;
76357
76355
  return !!(ctx.search && e.hay.indexOf(ctx.search) < 0);
76358
76356
  }
76359
76357
  if (e.dir === 1 && !ctx.out) return true;
@@ -76433,17 +76431,15 @@ function ensure_dev_style() {
76433
76431
  .YDEV_TITLE_MAIN { font-weight: 700; }
76434
76432
  .YDEV_TITLE_SUB { opacity: 0.7; font-size: 12px; }
76435
76433
  /* -------- entries (shared) -------- */
76436
- .TRAFFIC_ENTRY, .TRAFFIC_LINE, .TRAFFIC_NAME {
76434
+ .TRAFFIC_ENTRY {
76437
76435
  border-left: 3px solid #94a3b8; border-radius: 3px;
76438
76436
  font-family: "DejaVu Sans Mono", monospace, consolas, monaco; font-size: 13px;
76439
76437
  background: rgba(0,0,0,0.02);
76440
76438
  }
76441
76439
  .TRAFFIC_ENTRY { margin: 6px 0; padding: 4px 8px; line-height: 1.55; }
76442
- .TRAFFIC_LINE { margin: 2px 0; padding: 2px 8px; display: flex; align-items: baseline; gap: 8px; }
76443
- .TRAFFIC_NAME { margin: 1px 0; padding: 1px 8px; display: flex; align-items: baseline; gap: 8px; background: transparent; }
76444
- .TRAFFIC_ENTRY.dir-out, .TRAFFIC_LINE.dir-out, .TRAFFIC_NAME.dir-out { border-left-color: #2563eb; }
76445
- .TRAFFIC_ENTRY.dir-in, .TRAFFIC_LINE.dir-in, .TRAFFIC_NAME.dir-in { border-left-color: #059669; }
76446
- .TRAFFIC_ENTRY.dir-err, .TRAFFIC_LINE.dir-err, .TRAFFIC_NAME.dir-err { border-left-color: #dc2626; }
76440
+ .TRAFFIC_ENTRY.dir-out { border-left-color: #2563eb; }
76441
+ .TRAFFIC_ENTRY.dir-in { border-left-color: #059669; }
76442
+ .TRAFFIC_ENTRY.dir-err { border-left-color: #dc2626; }
76447
76443
  .TRAFFIC_HEADER { display: flex; align-items: baseline; gap: 8px; }
76448
76444
  .TRAFFIC_ARROW { font-weight: 700; }
76449
76445
  .TRAFFIC_EVENT { font-weight: 700; }
@@ -76451,9 +76447,13 @@ function ensure_dev_style() {
76451
76447
  .dir-out .TRAFFIC_ARROW, .dir-out .TRAFFIC_EVENT { color: #2563eb; }
76452
76448
  .dir-in .TRAFFIC_ARROW, .dir-in .TRAFFIC_EVENT { color: #059669; }
76453
76449
  .dir-err .TRAFFIC_ARROW, .dir-err .TRAFFIC_EVENT { color: #dc2626; }
76454
- .TRAFFIC_SUMMARY { opacity: 0.6; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto; min-width: 0; }
76455
76450
  .TRAFFIC_META { margin-left: auto; opacity: 0.6; font-size: 11px; white-space: nowrap; }
76456
- .TRAFFIC_ENTRY:hover .TRAFFIC_KW { margin: 2px 0 0 16px; }
76451
+ /* The indent of a nested block is NOT a hover effect: it used to be given
76452
+ only on .TRAFFIC_ENTRY:hover, so moving the cursor across the log made
76453
+ every payload under it jump 16px sideways and reflow. A payload being
76454
+ read must not move because the pointer passed over it.
76455
+ (No backticks in here: this stylesheet is a template literal.) */
76456
+ .TRAFFIC_KW { margin: 2px 0 0 16px; }
76457
76457
  .TRAFFIC_FULL { margin: 4px 0 0 16px; padding: 6px 8px; font-family: monospace; font-size: 11px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; background: rgba(0,0,0,0.04); border-radius: 4px; overflow-x: auto; }
76458
76458
  .TRAFFIC_ROW { display: flex; gap: 6px; align-items: baseline; }
76459
76459
  .TRAFFIC_BULLET { opacity: 0.45; flex: 0 0 auto; }
@@ -76484,10 +76484,10 @@ details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
76484
76484
  :root[data-theme="dark"] .YDEV_BAR, :root[data-theme="dark"] .YDEV_STATS { background: rgba(255,255,255,0.04); }
76485
76485
  :root[data-theme="dark"] .YDEV_SEP { background: rgba(255,255,255,0.14); }
76486
76486
  :root[data-theme="dark"] .YDEV_CHIP, :root[data-theme="dark"] .YDEV_SEG, :root[data-theme="dark"] .YDEV_SEARCH { border-color: rgba(255,255,255,0.2); }
76487
- :root[data-theme="dark"] .TRAFFIC_ENTRY, :root[data-theme="dark"] .TRAFFIC_LINE { background: rgba(255,255,255,0.03); }
76488
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-out, :root[data-theme="dark"] .TRAFFIC_LINE.dir-out, :root[data-theme="dark"] .TRAFFIC_NAME.dir-out { border-left-color: #60a5fa; }
76489
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-in, :root[data-theme="dark"] .TRAFFIC_LINE.dir-in, :root[data-theme="dark"] .TRAFFIC_NAME.dir-in { border-left-color: #34d399; }
76490
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-err, :root[data-theme="dark"] .TRAFFIC_LINE.dir-err, :root[data-theme="dark"] .TRAFFIC_NAME.dir-err { border-left-color: #f87171; }
76487
+ :root[data-theme="dark"] .TRAFFIC_ENTRY { background: rgba(255,255,255,0.03); }
76488
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-out { border-left-color: #60a5fa; }
76489
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-in { border-left-color: #34d399; }
76490
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-err { border-left-color: #f87171; }
76491
76491
  :root[data-theme="dark"] .dir-out .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-out .TRAFFIC_EVENT { color: #60a5fa; }
76492
76492
  :root[data-theme="dark"] .dir-in .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-in .TRAFFIC_EVENT { color: #34d399; }
76493
76493
  :root[data-theme="dark"] .dir-err .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-err .TRAFFIC_EVENT { color: #f87171; }
@@ -76567,6 +76567,29 @@ function traffic_scalar_row(key, value) {
76567
76567
  ]
76568
76568
  ];
76569
76569
  }
76570
+ var PREVIEW_MAX_KEYS = 4;
76571
+ var PREVIEW_MAX_CHARS = 90;
76572
+ var PREVIEW_MAX_VALUE = 28;
76573
+ function preview_scalar(v) {
76574
+ if (v === null) return "null";
76575
+ if (typeof v === "string") return "\"" + (v.length > PREVIEW_MAX_VALUE ? v.slice(0, PREVIEW_MAX_VALUE) + "…" : v) + "\"";
76576
+ if (typeof v === "object") return Array.isArray(v) ? "[…]" : "{…}";
76577
+ return String(v);
76578
+ }
76579
+ function object_preview(obj, count) {
76580
+ let keys = Object.keys(obj);
76581
+ let parts = [];
76582
+ let used = 0;
76583
+ for (let k of keys) {
76584
+ if (parts.length >= PREVIEW_MAX_KEYS) break;
76585
+ let part = k + ": " + preview_scalar(obj[k]);
76586
+ if (parts.length > 0 && used + part.length > PREVIEW_MAX_CHARS) break;
76587
+ parts.push(part);
76588
+ used += part.length + 2;
76589
+ }
76590
+ if (parts.length < count) parts.push("…");
76591
+ return "{" + parts.join(", ") + "}";
76592
+ }
76570
76593
  /************************************************************
76571
76594
  * One field of any type. Scalars → a bullet row; objects and
76572
76595
  * arrays → a collapsed <details> so metadata / nested payloads
@@ -76597,7 +76620,7 @@ function traffic_value_node(key, value) {
76597
76620
  ]
76598
76621
  ]
76599
76622
  ];
76600
- let hint = is_arr ? `[${count}]` : `{${count}}`;
76623
+ let hint = is_arr ? `[${count}]` : object_preview(value, count);
76601
76624
  return [
76602
76625
  "details",
76603
76626
  { class: "TRAFFIC_NEST" },
@@ -76617,7 +76640,10 @@ function traffic_value_node(key, value) {
76617
76640
  ],
76618
76641
  [
76619
76642
  "span",
76620
- { class: "TRAFFIC_NEST_HINT" },
76643
+ {
76644
+ class: "TRAFFIC_NEST_HINT",
76645
+ title: `${count}`
76646
+ },
76621
76647
  hint
76622
76648
  ]
76623
76649
  ]
@@ -76657,24 +76683,6 @@ function event_spans(e) {
76657
76683
  ]);
76658
76684
  return spans;
76659
76685
  }
76660
- function compact_summary(kw) {
76661
- if (!kw) return "";
76662
- let parts = [];
76663
- if ("result" in kw) parts.push("result=" + traffic_scalar_text(kw.result));
76664
- if (typeof kw.comment === "string" && kw.comment) parts.push(traffic_clip(kw.comment, 80));
76665
- if (!parts.length) {
76666
- let n = 0;
76667
- for (let k of Object.keys(kw)) {
76668
- if (k === "command") continue;
76669
- let v = kw[k];
76670
- if (v === null || typeof v !== "object") {
76671
- parts.push(k + "=" + traffic_scalar_text(v));
76672
- if (++n >= 3) break;
76673
- }
76674
- }
76675
- }
76676
- return traffic_clip(parts.join(" · "), 140);
76677
- }
76678
76686
  function render_detailed(e) {
76679
76687
  let head = event_spans(e);
76680
76688
  head.push([
@@ -76765,43 +76773,6 @@ function render_full(e) {
76765
76773
  children
76766
76774
  ]);
76767
76775
  }
76768
- function render_compact(e) {
76769
- let kids = event_spans(e);
76770
- kids.push([
76771
- "span",
76772
- { class: "TRAFFIC_SUMMARY" },
76773
- compact_summary(e.kw)
76774
- ]);
76775
- kids.push([
76776
- "span",
76777
- { class: "TRAFFIC_META" },
76778
- `${traffic_size(e.size)} · ${e.ts}`
76779
- ]);
76780
- return (0, _yuneta_gobj_js.createElement2)([
76781
- "div",
76782
- {
76783
- class: "TRAFFIC_LINE " + dir_class(e.dir),
76784
- title: e.title
76785
- },
76786
- kids
76787
- ]);
76788
- }
76789
- function render_name(e) {
76790
- let kids = event_spans(e);
76791
- kids.push([
76792
- "span",
76793
- { class: "TRAFFIC_META" },
76794
- e.ts
76795
- ]);
76796
- return (0, _yuneta_gobj_js.createElement2)([
76797
- "div",
76798
- {
76799
- class: "TRAFFIC_NAME " + dir_class(e.dir),
76800
- title: e.title
76801
- },
76802
- kids
76803
- ]);
76804
- }
76805
76776
  function render_log(e) {
76806
76777
  let $row = (0, _yuneta_gobj_js.createElement2)([
76807
76778
  "div",
@@ -76833,10 +76804,7 @@ function render_log(e) {
76833
76804
  }
76834
76805
  function render_entry(e) {
76835
76806
  if (e.kind === "log") return render_log(e);
76836
- let view = dev_view();
76837
- if (view === "full") return render_full(e);
76838
- if (view === "compact") return render_compact(e);
76839
- if (view === "name") return render_name(e);
76807
+ if (dev_traffic_view() === "expanded") return render_full(e);
76840
76808
  return render_detailed(e);
76841
76809
  }
76842
76810
  /******************************
@@ -76959,7 +76927,6 @@ function info_traffic(title, msg, direction, size) {
76959
76927
  return;
76960
76928
  }
76961
76929
  let route = dev_route();
76962
- if (route !== "window") console_traffic(title, jn, direction, size);
76963
76930
  let event = jn && jn.event ? String(jn.event) : "(no event)";
76964
76931
  let kw = jn && jn.kw && typeof jn.kw === "object" ? jn.kw : null;
76965
76932
  let command = kw && typeof kw.command === "string" ? kw.command : "";
@@ -76982,10 +76949,12 @@ function info_traffic(title, msg, direction, size) {
76982
76949
  $node: null
76983
76950
  };
76984
76951
  push_entry(entry);
76952
+ let hidden = entry_hidden(entry, build_filter_ctx());
76953
+ if (route !== "window" && !hidden) console_traffic(title, jn, direction, size);
76985
76954
  let logger = document.getElementById("developer-traffic-logger");
76986
76955
  if (!logger || route === "console") return;
76987
76956
  ensure_dev_style();
76988
- if (!entry_hidden(entry, build_filter_ctx())) {
76957
+ if (!hidden) {
76989
76958
  let node = render_entry(entry);
76990
76959
  entry.$node = node;
76991
76960
  let ph = logger.querySelector(".YDEV_EMPTY");
@@ -77148,7 +77117,7 @@ function refresh_dev_chrome() {
77148
77117
  $b.textContent = key === "automata" && v > 0 ? label + " " + v : label;
77149
77118
  $b.classList.toggle("is-active", v > 0);
77150
77119
  });
77151
- let view = dev_view();
77120
+ let view = dev_traffic_view();
77152
77121
  document.querySelectorAll(".YDEV_SEG_BTN[data-view]").forEach(($b) => {
77153
77122
  $b.classList.toggle("is-active", $b.getAttribute("data-view") === view);
77154
77123
  });
@@ -77157,7 +77126,7 @@ function refresh_dev_chrome() {
77157
77126
  $b.classList.toggle("is-active", $b.getAttribute("data-output") === route);
77158
77127
  });
77159
77128
  let $eg = document.getElementById("ydev-expand-grp");
77160
- if ($eg) $eg.style.display = view === "full" ? "" : "none";
77129
+ if ($eg) $eg.style.display = view === "expanded" ? "" : "none";
77161
77130
  document.querySelectorAll(".YDEV_CHIP[data-expand]").forEach(($b) => {
77162
77131
  $b.classList.toggle("is-active", full_show($b.getAttribute("data-expand")));
77163
77132
  });
@@ -77167,6 +77136,9 @@ function refresh_dev_chrome() {
77167
77136
  document.querySelectorAll(".YDEV_CHIP[data-toggle=\"automata-simple\"]").forEach(($b) => {
77168
77137
  $b.classList.toggle("is-active", !!dev_simple_mach());
77169
77138
  });
77139
+ document.querySelectorAll(".YDEV_CHIP[data-toggle=\"traces-payload\"]").forEach(($b) => {
77140
+ $b.classList.toggle("is-active", !!dev_traces_payload());
77141
+ });
77170
77142
  update_stats();
77171
77143
  }
77172
77144
  function traffic_to_text() {
@@ -77249,18 +77221,46 @@ function build_control_bar() {
77249
77221
  refresh_dev_chrome();
77250
77222
  } }
77251
77223
  ];
77224
+ let traces_payload = [
77225
+ "button",
77226
+ {
77227
+ class: "YDEV_CHIP",
77228
+ "data-toggle": "traces-payload",
77229
+ type: "button",
77230
+ title: (0, i18next.t)("show the payload of the traces"),
77231
+ "data-i18n-title": "show the payload of the traces",
77232
+ "data-i18n": "payload",
77233
+ "aria-label": (0, i18next.t)("payload"),
77234
+ "data-i18n-aria-label": "payload"
77235
+ },
77236
+ (0, i18next.t)("payload"),
77237
+ { click: (ev) => {
77238
+ ev.stopPropagation();
77239
+ (0, _yuneta_gobj_js.kw_set_local_storage_value)("dev_traces_payload", dev_traces_payload() ? 0 : 1);
77240
+ rerender_all();
77241
+ refresh_dev_chrome();
77242
+ } }
77243
+ ];
77244
+ let VIEW_TITLES = {
77245
+ collapsed: "traffic payload folded",
77246
+ expanded: "traffic payload laid out"
77247
+ };
77252
77248
  let mk_view = (v, label) => [
77253
77249
  "button",
77254
77250
  {
77255
77251
  class: "YDEV_SEG_BTN",
77256
77252
  "data-view": v,
77253
+ type: "button",
77254
+ title: (0, i18next.t)(VIEW_TITLES[v]),
77255
+ "data-i18n-title": VIEW_TITLES[v],
77257
77256
  "data-i18n": label,
77258
- type: "button"
77257
+ "aria-label": (0, i18next.t)(label),
77258
+ "data-i18n-aria-label": label
77259
77259
  },
77260
77260
  (0, i18next.t)(label),
77261
77261
  { click: (ev) => {
77262
77262
  ev.stopPropagation();
77263
- set_view(v);
77263
+ set_traffic_view(v);
77264
77264
  } }
77265
77265
  ];
77266
77266
  let view_seg = [
@@ -77269,12 +77269,7 @@ function build_control_bar() {
77269
77269
  class: "YDEV_SEG",
77270
77270
  id: "ydev-seg"
77271
77271
  },
77272
- [
77273
- mk_view("detailed", "detailed"),
77274
- mk_view("full", "expanded"),
77275
- mk_view("compact", "compact"),
77276
- mk_view("name", "name only")
77277
- ]
77272
+ [mk_view("collapsed", "collapsed"), mk_view("expanded", "expanded")]
77278
77273
  ];
77279
77274
  let OUT_TITLES = {
77280
77275
  window: "dev window only",
@@ -77465,7 +77460,11 @@ function build_control_bar() {
77465
77460
  "div",
77466
77461
  { class: "YDEV_BAR" },
77467
77462
  [
77468
- grp("traces", [...trace_chips, simple_mach]),
77463
+ grp("traces", [
77464
+ ...trace_chips,
77465
+ simple_mach,
77466
+ traces_payload
77467
+ ]),
77469
77468
  sep(),
77470
77469
  grp("output", [output_seg]),
77471
77470
  sep(),
@@ -76267,21 +76267,6 @@ function traffic_iso(value) {
76267
76267
  return null;
76268
76268
  }
76269
76269
  }
76270
- /************************************************************
76271
- * Clip a string for inline display (full text kept elsewhere).
76272
- ************************************************************/
76273
- function traffic_clip(s, n) {
76274
- s = String(s);
76275
- return s.length > n ? s.slice(0, n) + "…" : s;
76276
- }
76277
- /************************************************************
76278
- * A scalar rendered as a short inline token (for summaries).
76279
- ************************************************************/
76280
- function traffic_scalar_text(v) {
76281
- if (v === null) return "null";
76282
- if (typeof v === "string") return traffic_clip(v, 40);
76283
- return String(v);
76284
- }
76285
76270
  function dir_class(dir) {
76286
76271
  return dir === 2 ? "dir-in" : dir === 3 ? "dir-err" : "dir-out";
76287
76272
  }
@@ -76294,9 +76279,11 @@ function dir_arrow(dir) {
76294
76279
  function dev_num(key, def) {
76295
76280
  return Number(kw_get_local_storage_value(key, def === void 0 ? 0 : def, false));
76296
76281
  }
76297
- function dev_view() {
76298
- let v = kw_get_local_storage_value("dev_view_mode", "detailed", false);
76299
- return v === "compact" || v === "name" || v === "full" ? v : "detailed";
76282
+ function dev_traffic_view() {
76283
+ return kw_get_local_storage_value("dev_traffic_view", "collapsed", false) === "expanded" ? "expanded" : "collapsed";
76284
+ }
76285
+ function dev_traces_payload() {
76286
+ return dev_num("dev_traces_payload", 1) ? 1 : 0;
76300
76287
  }
76301
76288
  var SIMPLE_MACH_DEFAULT = 1;
76302
76289
  var SIMPLE_MACH_KEY = "dev_mach_simple";
@@ -76314,10 +76301,21 @@ function console_traffic(title, jn, direction, size) {
76314
76301
  let event = jn && jn.event ? String(jn.event) : "(no event)";
76315
76302
  let kw = jn && jn.kw && typeof jn.kw === "object" ? jn.kw : jn;
76316
76303
  let color = direction === 2 ? "#16a34a" : direction === 3 ? "#dc2626" : "#2563eb";
76317
- window.console.log("%c" + dir_arrow(direction) + " " + (title ? "[" + title + "] " : "") + event + (size ? " (" + size + "b)" : ""), "color:" + color, kw);
76304
+ let head = "%c" + dir_arrow(direction) + " " + (title ? "[" + title + "] " : "") + event + (size ? " (" + size + "b)" : "");
76305
+ if (dev_traffic_view() === "expanded") {
76306
+ let text;
76307
+ try {
76308
+ text = JSON.stringify(full_sections(kw), null, 4);
76309
+ } catch (err) {
76310
+ text = String(kw);
76311
+ }
76312
+ window.console.log(head, "color:" + color, "\n" + text);
76313
+ return;
76314
+ }
76315
+ window.console.log(head, "color:" + color, kw);
76318
76316
  }
76319
- function set_view(v) {
76320
- kw_set_local_storage_value("dev_view_mode", v);
76317
+ function set_traffic_view(v) {
76318
+ kw_set_local_storage_value("dev_traffic_view", v === "expanded" ? "expanded" : "collapsed");
76321
76319
  rerender_all();
76322
76320
  refresh_dev_chrome();
76323
76321
  }
@@ -76343,12 +76341,12 @@ function build_filter_ctx() {
76343
76341
  inc: dev_num("dev_filter_in", 1),
76344
76342
  err: dev_num("dev_filter_err", 1),
76345
76343
  search: SEARCH_TEXT,
76346
- view: dev_view()
76344
+ payload: dev_traces_payload()
76347
76345
  };
76348
76346
  }
76349
76347
  function entry_hidden(e, ctx) {
76350
76348
  if (e.kind === "log") {
76351
- if (e.level === "json" && (ctx.view === "name" || ctx.view === "compact")) return true;
76349
+ if (e.level === "json" && !ctx.payload) return true;
76352
76350
  return !!(ctx.search && e.hay.indexOf(ctx.search) < 0);
76353
76351
  }
76354
76352
  if (e.dir === 1 && !ctx.out) return true;
@@ -76428,17 +76426,15 @@ function ensure_dev_style() {
76428
76426
  .YDEV_TITLE_MAIN { font-weight: 700; }
76429
76427
  .YDEV_TITLE_SUB { opacity: 0.7; font-size: 12px; }
76430
76428
  /* -------- entries (shared) -------- */
76431
- .TRAFFIC_ENTRY, .TRAFFIC_LINE, .TRAFFIC_NAME {
76429
+ .TRAFFIC_ENTRY {
76432
76430
  border-left: 3px solid #94a3b8; border-radius: 3px;
76433
76431
  font-family: "DejaVu Sans Mono", monospace, consolas, monaco; font-size: 13px;
76434
76432
  background: rgba(0,0,0,0.02);
76435
76433
  }
76436
76434
  .TRAFFIC_ENTRY { margin: 6px 0; padding: 4px 8px; line-height: 1.55; }
76437
- .TRAFFIC_LINE { margin: 2px 0; padding: 2px 8px; display: flex; align-items: baseline; gap: 8px; }
76438
- .TRAFFIC_NAME { margin: 1px 0; padding: 1px 8px; display: flex; align-items: baseline; gap: 8px; background: transparent; }
76439
- .TRAFFIC_ENTRY.dir-out, .TRAFFIC_LINE.dir-out, .TRAFFIC_NAME.dir-out { border-left-color: #2563eb; }
76440
- .TRAFFIC_ENTRY.dir-in, .TRAFFIC_LINE.dir-in, .TRAFFIC_NAME.dir-in { border-left-color: #059669; }
76441
- .TRAFFIC_ENTRY.dir-err, .TRAFFIC_LINE.dir-err, .TRAFFIC_NAME.dir-err { border-left-color: #dc2626; }
76435
+ .TRAFFIC_ENTRY.dir-out { border-left-color: #2563eb; }
76436
+ .TRAFFIC_ENTRY.dir-in { border-left-color: #059669; }
76437
+ .TRAFFIC_ENTRY.dir-err { border-left-color: #dc2626; }
76442
76438
  .TRAFFIC_HEADER { display: flex; align-items: baseline; gap: 8px; }
76443
76439
  .TRAFFIC_ARROW { font-weight: 700; }
76444
76440
  .TRAFFIC_EVENT { font-weight: 700; }
@@ -76446,9 +76442,13 @@ function ensure_dev_style() {
76446
76442
  .dir-out .TRAFFIC_ARROW, .dir-out .TRAFFIC_EVENT { color: #2563eb; }
76447
76443
  .dir-in .TRAFFIC_ARROW, .dir-in .TRAFFIC_EVENT { color: #059669; }
76448
76444
  .dir-err .TRAFFIC_ARROW, .dir-err .TRAFFIC_EVENT { color: #dc2626; }
76449
- .TRAFFIC_SUMMARY { opacity: 0.6; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto; min-width: 0; }
76450
76445
  .TRAFFIC_META { margin-left: auto; opacity: 0.6; font-size: 11px; white-space: nowrap; }
76451
- .TRAFFIC_ENTRY:hover .TRAFFIC_KW { margin: 2px 0 0 16px; }
76446
+ /* The indent of a nested block is NOT a hover effect: it used to be given
76447
+ only on .TRAFFIC_ENTRY:hover, so moving the cursor across the log made
76448
+ every payload under it jump 16px sideways and reflow. A payload being
76449
+ read must not move because the pointer passed over it.
76450
+ (No backticks in here: this stylesheet is a template literal.) */
76451
+ .TRAFFIC_KW { margin: 2px 0 0 16px; }
76452
76452
  .TRAFFIC_FULL { margin: 4px 0 0 16px; padding: 6px 8px; font-family: monospace; font-size: 11px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; background: rgba(0,0,0,0.04); border-radius: 4px; overflow-x: auto; }
76453
76453
  .TRAFFIC_ROW { display: flex; gap: 6px; align-items: baseline; }
76454
76454
  .TRAFFIC_BULLET { opacity: 0.45; flex: 0 0 auto; }
@@ -76479,10 +76479,10 @@ details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
76479
76479
  :root[data-theme="dark"] .YDEV_BAR, :root[data-theme="dark"] .YDEV_STATS { background: rgba(255,255,255,0.04); }
76480
76480
  :root[data-theme="dark"] .YDEV_SEP { background: rgba(255,255,255,0.14); }
76481
76481
  :root[data-theme="dark"] .YDEV_CHIP, :root[data-theme="dark"] .YDEV_SEG, :root[data-theme="dark"] .YDEV_SEARCH { border-color: rgba(255,255,255,0.2); }
76482
- :root[data-theme="dark"] .TRAFFIC_ENTRY, :root[data-theme="dark"] .TRAFFIC_LINE { background: rgba(255,255,255,0.03); }
76483
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-out, :root[data-theme="dark"] .TRAFFIC_LINE.dir-out, :root[data-theme="dark"] .TRAFFIC_NAME.dir-out { border-left-color: #60a5fa; }
76484
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-in, :root[data-theme="dark"] .TRAFFIC_LINE.dir-in, :root[data-theme="dark"] .TRAFFIC_NAME.dir-in { border-left-color: #34d399; }
76485
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-err, :root[data-theme="dark"] .TRAFFIC_LINE.dir-err, :root[data-theme="dark"] .TRAFFIC_NAME.dir-err { border-left-color: #f87171; }
76482
+ :root[data-theme="dark"] .TRAFFIC_ENTRY { background: rgba(255,255,255,0.03); }
76483
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-out { border-left-color: #60a5fa; }
76484
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-in { border-left-color: #34d399; }
76485
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-err { border-left-color: #f87171; }
76486
76486
  :root[data-theme="dark"] .dir-out .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-out .TRAFFIC_EVENT { color: #60a5fa; }
76487
76487
  :root[data-theme="dark"] .dir-in .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-in .TRAFFIC_EVENT { color: #34d399; }
76488
76488
  :root[data-theme="dark"] .dir-err .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-err .TRAFFIC_EVENT { color: #f87171; }
@@ -76562,6 +76562,29 @@ function traffic_scalar_row(key, value) {
76562
76562
  ]
76563
76563
  ];
76564
76564
  }
76565
+ var PREVIEW_MAX_KEYS = 4;
76566
+ var PREVIEW_MAX_CHARS = 90;
76567
+ var PREVIEW_MAX_VALUE = 28;
76568
+ function preview_scalar(v) {
76569
+ if (v === null) return "null";
76570
+ if (typeof v === "string") return "\"" + (v.length > PREVIEW_MAX_VALUE ? v.slice(0, PREVIEW_MAX_VALUE) + "…" : v) + "\"";
76571
+ if (typeof v === "object") return Array.isArray(v) ? "[…]" : "{…}";
76572
+ return String(v);
76573
+ }
76574
+ function object_preview(obj, count) {
76575
+ let keys = Object.keys(obj);
76576
+ let parts = [];
76577
+ let used = 0;
76578
+ for (let k of keys) {
76579
+ if (parts.length >= PREVIEW_MAX_KEYS) break;
76580
+ let part = k + ": " + preview_scalar(obj[k]);
76581
+ if (parts.length > 0 && used + part.length > PREVIEW_MAX_CHARS) break;
76582
+ parts.push(part);
76583
+ used += part.length + 2;
76584
+ }
76585
+ if (parts.length < count) parts.push("…");
76586
+ return "{" + parts.join(", ") + "}";
76587
+ }
76565
76588
  /************************************************************
76566
76589
  * One field of any type. Scalars → a bullet row; objects and
76567
76590
  * arrays → a collapsed <details> so metadata / nested payloads
@@ -76592,7 +76615,7 @@ function traffic_value_node(key, value) {
76592
76615
  ]
76593
76616
  ]
76594
76617
  ];
76595
- let hint = is_arr ? `[${count}]` : `{${count}}`;
76618
+ let hint = is_arr ? `[${count}]` : object_preview(value, count);
76596
76619
  return [
76597
76620
  "details",
76598
76621
  { class: "TRAFFIC_NEST" },
@@ -76612,7 +76635,10 @@ function traffic_value_node(key, value) {
76612
76635
  ],
76613
76636
  [
76614
76637
  "span",
76615
- { class: "TRAFFIC_NEST_HINT" },
76638
+ {
76639
+ class: "TRAFFIC_NEST_HINT",
76640
+ title: `${count}`
76641
+ },
76616
76642
  hint
76617
76643
  ]
76618
76644
  ]
@@ -76652,24 +76678,6 @@ function event_spans(e) {
76652
76678
  ]);
76653
76679
  return spans;
76654
76680
  }
76655
- function compact_summary(kw) {
76656
- if (!kw) return "";
76657
- let parts = [];
76658
- if ("result" in kw) parts.push("result=" + traffic_scalar_text(kw.result));
76659
- if (typeof kw.comment === "string" && kw.comment) parts.push(traffic_clip(kw.comment, 80));
76660
- if (!parts.length) {
76661
- let n = 0;
76662
- for (let k of Object.keys(kw)) {
76663
- if (k === "command") continue;
76664
- let v = kw[k];
76665
- if (v === null || typeof v !== "object") {
76666
- parts.push(k + "=" + traffic_scalar_text(v));
76667
- if (++n >= 3) break;
76668
- }
76669
- }
76670
- }
76671
- return traffic_clip(parts.join(" · "), 140);
76672
- }
76673
76681
  function render_detailed(e) {
76674
76682
  let head = event_spans(e);
76675
76683
  head.push([
@@ -76760,43 +76768,6 @@ function render_full(e) {
76760
76768
  children
76761
76769
  ]);
76762
76770
  }
76763
- function render_compact(e) {
76764
- let kids = event_spans(e);
76765
- kids.push([
76766
- "span",
76767
- { class: "TRAFFIC_SUMMARY" },
76768
- compact_summary(e.kw)
76769
- ]);
76770
- kids.push([
76771
- "span",
76772
- { class: "TRAFFIC_META" },
76773
- `${traffic_size(e.size)} · ${e.ts}`
76774
- ]);
76775
- return createElement2([
76776
- "div",
76777
- {
76778
- class: "TRAFFIC_LINE " + dir_class(e.dir),
76779
- title: e.title
76780
- },
76781
- kids
76782
- ]);
76783
- }
76784
- function render_name(e) {
76785
- let kids = event_spans(e);
76786
- kids.push([
76787
- "span",
76788
- { class: "TRAFFIC_META" },
76789
- e.ts
76790
- ]);
76791
- return createElement2([
76792
- "div",
76793
- {
76794
- class: "TRAFFIC_NAME " + dir_class(e.dir),
76795
- title: e.title
76796
- },
76797
- kids
76798
- ]);
76799
- }
76800
76771
  function render_log(e) {
76801
76772
  let $row = createElement2([
76802
76773
  "div",
@@ -76828,10 +76799,7 @@ function render_log(e) {
76828
76799
  }
76829
76800
  function render_entry(e) {
76830
76801
  if (e.kind === "log") return render_log(e);
76831
- let view = dev_view();
76832
- if (view === "full") return render_full(e);
76833
- if (view === "compact") return render_compact(e);
76834
- if (view === "name") return render_name(e);
76802
+ if (dev_traffic_view() === "expanded") return render_full(e);
76835
76803
  return render_detailed(e);
76836
76804
  }
76837
76805
  /******************************
@@ -76954,7 +76922,6 @@ function info_traffic(title, msg, direction, size) {
76954
76922
  return;
76955
76923
  }
76956
76924
  let route = dev_route();
76957
- if (route !== "window") console_traffic(title, jn, direction, size);
76958
76925
  let event = jn && jn.event ? String(jn.event) : "(no event)";
76959
76926
  let kw = jn && jn.kw && typeof jn.kw === "object" ? jn.kw : null;
76960
76927
  let command = kw && typeof kw.command === "string" ? kw.command : "";
@@ -76977,10 +76944,12 @@ function info_traffic(title, msg, direction, size) {
76977
76944
  $node: null
76978
76945
  };
76979
76946
  push_entry(entry);
76947
+ let hidden = entry_hidden(entry, build_filter_ctx());
76948
+ if (route !== "window" && !hidden) console_traffic(title, jn, direction, size);
76980
76949
  let logger = document.getElementById("developer-traffic-logger");
76981
76950
  if (!logger || route === "console") return;
76982
76951
  ensure_dev_style();
76983
- if (!entry_hidden(entry, build_filter_ctx())) {
76952
+ if (!hidden) {
76984
76953
  let node = render_entry(entry);
76985
76954
  entry.$node = node;
76986
76955
  let ph = logger.querySelector(".YDEV_EMPTY");
@@ -77143,7 +77112,7 @@ function refresh_dev_chrome() {
77143
77112
  $b.textContent = key === "automata" && v > 0 ? label + " " + v : label;
77144
77113
  $b.classList.toggle("is-active", v > 0);
77145
77114
  });
77146
- let view = dev_view();
77115
+ let view = dev_traffic_view();
77147
77116
  document.querySelectorAll(".YDEV_SEG_BTN[data-view]").forEach(($b) => {
77148
77117
  $b.classList.toggle("is-active", $b.getAttribute("data-view") === view);
77149
77118
  });
@@ -77152,7 +77121,7 @@ function refresh_dev_chrome() {
77152
77121
  $b.classList.toggle("is-active", $b.getAttribute("data-output") === route);
77153
77122
  });
77154
77123
  let $eg = document.getElementById("ydev-expand-grp");
77155
- if ($eg) $eg.style.display = view === "full" ? "" : "none";
77124
+ if ($eg) $eg.style.display = view === "expanded" ? "" : "none";
77156
77125
  document.querySelectorAll(".YDEV_CHIP[data-expand]").forEach(($b) => {
77157
77126
  $b.classList.toggle("is-active", full_show($b.getAttribute("data-expand")));
77158
77127
  });
@@ -77162,6 +77131,9 @@ function refresh_dev_chrome() {
77162
77131
  document.querySelectorAll(".YDEV_CHIP[data-toggle=\"automata-simple\"]").forEach(($b) => {
77163
77132
  $b.classList.toggle("is-active", !!dev_simple_mach());
77164
77133
  });
77134
+ document.querySelectorAll(".YDEV_CHIP[data-toggle=\"traces-payload\"]").forEach(($b) => {
77135
+ $b.classList.toggle("is-active", !!dev_traces_payload());
77136
+ });
77165
77137
  update_stats();
77166
77138
  }
77167
77139
  function traffic_to_text() {
@@ -77244,18 +77216,46 @@ function build_control_bar() {
77244
77216
  refresh_dev_chrome();
77245
77217
  } }
77246
77218
  ];
77219
+ let traces_payload = [
77220
+ "button",
77221
+ {
77222
+ class: "YDEV_CHIP",
77223
+ "data-toggle": "traces-payload",
77224
+ type: "button",
77225
+ title: t("show the payload of the traces"),
77226
+ "data-i18n-title": "show the payload of the traces",
77227
+ "data-i18n": "payload",
77228
+ "aria-label": t("payload"),
77229
+ "data-i18n-aria-label": "payload"
77230
+ },
77231
+ t("payload"),
77232
+ { click: (ev) => {
77233
+ ev.stopPropagation();
77234
+ kw_set_local_storage_value("dev_traces_payload", dev_traces_payload() ? 0 : 1);
77235
+ rerender_all();
77236
+ refresh_dev_chrome();
77237
+ } }
77238
+ ];
77239
+ let VIEW_TITLES = {
77240
+ collapsed: "traffic payload folded",
77241
+ expanded: "traffic payload laid out"
77242
+ };
77247
77243
  let mk_view = (v, label) => [
77248
77244
  "button",
77249
77245
  {
77250
77246
  class: "YDEV_SEG_BTN",
77251
77247
  "data-view": v,
77248
+ type: "button",
77249
+ title: t(VIEW_TITLES[v]),
77250
+ "data-i18n-title": VIEW_TITLES[v],
77252
77251
  "data-i18n": label,
77253
- type: "button"
77252
+ "aria-label": t(label),
77253
+ "data-i18n-aria-label": label
77254
77254
  },
77255
77255
  t(label),
77256
77256
  { click: (ev) => {
77257
77257
  ev.stopPropagation();
77258
- set_view(v);
77258
+ set_traffic_view(v);
77259
77259
  } }
77260
77260
  ];
77261
77261
  let view_seg = [
@@ -77264,12 +77264,7 @@ function build_control_bar() {
77264
77264
  class: "YDEV_SEG",
77265
77265
  id: "ydev-seg"
77266
77266
  },
77267
- [
77268
- mk_view("detailed", "detailed"),
77269
- mk_view("full", "expanded"),
77270
- mk_view("compact", "compact"),
77271
- mk_view("name", "name only")
77272
- ]
77267
+ [mk_view("collapsed", "collapsed"), mk_view("expanded", "expanded")]
77273
77268
  ];
77274
77269
  let OUT_TITLES = {
77275
77270
  window: "dev window only",
@@ -77460,7 +77455,11 @@ function build_control_bar() {
77460
77455
  "div",
77461
77456
  { class: "YDEV_BAR" },
77462
77457
  [
77463
- grp("traces", [...trace_chips, simple_mach]),
77458
+ grp("traces", [
77459
+ ...trace_chips,
77460
+ simple_mach,
77461
+ traces_payload
77462
+ ]),
77464
77463
  sep(),
77465
77464
  grp("output", [output_seg]),
77466
77465
  sep(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yuneta/gobj-ui",
3
- "version": "7.23.175",
3
+ "version": "7.23.177",
4
4
  "type": "module",
5
5
  "main": "dist/gobj-ui.cjs.js",
6
6
  "module": "dist/gobj-ui.es.js",
package/src/yui_dev.js CHANGED
@@ -79,13 +79,14 @@ const TRAFFIC_TS_FIELDS = {
79
79
  * kept here so it can be copied:
80
80
  *
81
81
  * automata, both, browser console only, clear,
82
- * clear captured traffic, compact, console, copied, copy,
83
- * copy visible traffic to clipboard, creation, data, detailed,
82
+ * clear captured traffic, collapsed, console, copied, copy,
83
+ * copy visible traffic to clipboard, creation, data,
84
84
  * dev window and browser console, dev window only, developer,
85
85
  * clear the filter, errors, expand, expanded, filter events / payload,
86
86
  * find, i18n,
87
87
  * i18next debug output, incoming, log, machine trace shape,
88
- * metadata, name only, outgoing, output, periodic, schema, show,
88
+ * metadata, outgoing, output, payload, periodic, schema, show,
89
+ * show the payload of the traces,
89
90
  * show this section in the expanded view, simple mach,
90
91
  * start / stop, subscriptions,
91
92
  * trace every event of every automaton,
@@ -94,7 +95,8 @@ const TRAFFIC_TS_FIELDS = {
94
95
  * trace the messages to and from the backend,
95
96
  * trace the periodic timer event,
96
97
  * trace the start and stop of gobjs,
97
- * traces, traffic, view, window, yuno monitor
98
+ * traces, traffic, traffic payload folded,
99
+ * traffic payload laid out, view, window, yuno monitor
98
100
  *
99
101
  * wattyzer and the yunovatios GUIs carry them; check a new consumer
100
102
  * against this list, and confirm it by DUMPING the window. */
@@ -168,29 +170,6 @@ function traffic_iso(value)
168
170
  }
169
171
  }
170
172
 
171
- /************************************************************
172
- * Clip a string for inline display (full text kept elsewhere).
173
- ************************************************************/
174
- function traffic_clip(s, n)
175
- {
176
- s = String(s);
177
- return s.length > n ? s.slice(0, n) + "…" : s;
178
- }
179
-
180
- /************************************************************
181
- * A scalar rendered as a short inline token (for summaries).
182
- ************************************************************/
183
- function traffic_scalar_text(v)
184
- {
185
- if(v === null) {
186
- return "null";
187
- }
188
- if(typeof v === "string") {
189
- return traffic_clip(v, 40);
190
- }
191
- return String(v);
192
- }
193
-
194
173
  function dir_class(dir)
195
174
  {
196
175
  return (dir === 2) ? "dir-in" : (dir === 3) ? "dir-err" : "dir-out";
@@ -212,10 +191,33 @@ function dev_num(key, def)
212
191
  return Number(kw_get_local_storage_value(key, (def === undefined ? 0 : def), false));
213
192
  }
214
193
 
215
- function dev_view()
194
+ /* TRAFFIC and TRACES are two FEEDS, and each carries its own controls.
195
+ *
196
+ * They used to share one selector, and it steered the wrong one: the four
197
+ * view modes rewrote the traffic -- down to a bare event name -- while the
198
+ * trace lines ignored them altogether. Someone who ticks Traffic alone to
199
+ * read what is going to the backend got a list of event names, and the one
200
+ * feed whose shape they might want to change did not change.
201
+ *
202
+ * Both feeds can be on at once, so neither control may borrow the other's:
203
+ * the traffic's lives in the VIEW group, the traces' in the TRACES row,
204
+ * beside the chip that picks the machine-trace shape.
205
+ *
206
+ * The traffic payload is ALWAYS there; the view says whether it is folded.
207
+ * The old `dev_view_mode` key is left where it is and simply stops being
208
+ * read (same as SIMPLE_MACH_KEY below). */
209
+ function dev_traffic_view()
210
+ {
211
+ let v = kw_get_local_storage_value("dev_traffic_view", "collapsed", false);
212
+ return (v === "expanded") ? "expanded" : "collapsed";
213
+ }
214
+
215
+ /* Whether the trace's PAYLOAD lines (level `json`: the kw a trace dumps
216
+ * with ev_kw, or a publication) are shown. Default ON, which is what the
217
+ * old default view showed. */
218
+ function dev_traces_payload()
216
219
  {
217
- let v = kw_get_local_storage_value("dev_view_mode", "detailed", false);
218
- return (v === "compact" || v === "name" || v === "full") ? v : "detailed";
220
+ return dev_num("dev_traces_payload", 1) ? 1 : 0;
219
221
  }
220
222
 
221
223
  /* Which SHAPE the machine trace is written in — the two the C kernel
@@ -268,23 +270,38 @@ function apply_console_route()
268
270
 
269
271
  /* Emit one inter-event traffic line to the browser console (routes
270
272
  * "console" and "both"). gobj-js only knows about framework logs, not this
271
- * traffic feed, so the console mirror is produced here. */
273
+ * traffic feed, so the console mirror is produced here.
274
+ *
275
+ * It follows the VIEW, because the window and the console are two sinks of
276
+ * ONE feed and may not disagree about what they are showing: `expanded`
277
+ * prints the payload laid out, `collapsed` hands the object to the console
278
+ * and lets it fold it. The same promise the log filter made in 7.23.33 --
279
+ * one rule, two sinks -- which the traffic half had never kept. */
272
280
  function console_traffic(title, jn, direction, size)
273
281
  {
274
282
  let event = (jn && jn.event) ? String(jn.event) : "(no event)";
275
283
  let kw = (jn && jn.kw && typeof jn.kw === "object") ? jn.kw : jn;
276
284
  let color = (direction === 2) ? "#16a34a" : (direction === 3) ? "#dc2626" : "#2563eb";
277
- window.console.log(
278
- "%c" + dir_arrow(direction) + " " + (title ? "[" + title + "] " : "") + event +
279
- (size ? " (" + size + "b)" : ""),
280
- "color:" + color,
281
- kw
282
- );
285
+ let head = "%c" + dir_arrow(direction) + " " + (title ? "[" + title + "] " : "") + event +
286
+ (size ? " (" + size + "b)" : "");
287
+
288
+ if(dev_traffic_view() === "expanded") {
289
+ let text;
290
+ try {
291
+ text = JSON.stringify(full_sections(kw), null, 4);
292
+ } catch(err) {
293
+ text = String(kw);
294
+ }
295
+ window.console.log(head, "color:" + color, "\n" + text);
296
+ return;
297
+ }
298
+
299
+ window.console.log(head, "color:" + color, kw);
283
300
  }
284
301
 
285
- function set_view(v)
302
+ function set_traffic_view(v)
286
303
  {
287
- kw_set_local_storage_value("dev_view_mode", v);
304
+ kw_set_local_storage_value("dev_traffic_view", (v === "expanded") ? "expanded" : "collapsed");
288
305
  rerender_all();
289
306
  refresh_dev_chrome();
290
307
  }
@@ -320,7 +337,7 @@ function build_filter_ctx()
320
337
  inc: dev_num("dev_filter_in", 1),
321
338
  err: dev_num("dev_filter_err", 1),
322
339
  search: SEARCH_TEXT,
323
- view: dev_view(),
340
+ payload: dev_traces_payload(),
324
341
  };
325
342
  }
326
343
 
@@ -328,9 +345,11 @@ function entry_hidden(e, ctx)
328
345
  {
329
346
  if(e.kind === "log") {
330
347
  /* A `json` line is a PAYLOAD (the kw the trace dumps with ev_kw or a
331
- * publication): the Compact and Name only views promise one line
332
- * per message, so they leave it out. Its level says what it is. */
333
- if(e.level === "json" && (ctx.view === "name" || ctx.view === "compact")) {
348
+ * publication), and the TRACES row says whether those are wanted.
349
+ * It used to hang off the traffic view, which is another feed's
350
+ * control: turning the traffic into names silently took the
351
+ * traces' payloads away with it. */
352
+ if(e.level === "json" && !ctx.payload) {
334
353
  return true;
335
354
  }
336
355
  /* Mirrored console logs respect the search box only — not the
@@ -432,17 +451,15 @@ function ensure_dev_style()
432
451
  .YDEV_TITLE_MAIN { font-weight: 700; }
433
452
  .YDEV_TITLE_SUB { opacity: 0.7; font-size: 12px; }
434
453
  /* -------- entries (shared) -------- */
435
- .TRAFFIC_ENTRY, .TRAFFIC_LINE, .TRAFFIC_NAME {
454
+ .TRAFFIC_ENTRY {
436
455
  border-left: 3px solid #94a3b8; border-radius: 3px;
437
456
  font-family: "DejaVu Sans Mono", monospace, consolas, monaco; font-size: 13px;
438
457
  background: rgba(0,0,0,0.02);
439
458
  }
440
459
  .TRAFFIC_ENTRY { margin: 6px 0; padding: 4px 8px; line-height: 1.55; }
441
- .TRAFFIC_LINE { margin: 2px 0; padding: 2px 8px; display: flex; align-items: baseline; gap: 8px; }
442
- .TRAFFIC_NAME { margin: 1px 0; padding: 1px 8px; display: flex; align-items: baseline; gap: 8px; background: transparent; }
443
- .TRAFFIC_ENTRY.dir-out, .TRAFFIC_LINE.dir-out, .TRAFFIC_NAME.dir-out { border-left-color: #2563eb; }
444
- .TRAFFIC_ENTRY.dir-in, .TRAFFIC_LINE.dir-in, .TRAFFIC_NAME.dir-in { border-left-color: #059669; }
445
- .TRAFFIC_ENTRY.dir-err, .TRAFFIC_LINE.dir-err, .TRAFFIC_NAME.dir-err { border-left-color: #dc2626; }
460
+ .TRAFFIC_ENTRY.dir-out { border-left-color: #2563eb; }
461
+ .TRAFFIC_ENTRY.dir-in { border-left-color: #059669; }
462
+ .TRAFFIC_ENTRY.dir-err { border-left-color: #dc2626; }
446
463
  .TRAFFIC_HEADER { display: flex; align-items: baseline; gap: 8px; }
447
464
  .TRAFFIC_ARROW { font-weight: 700; }
448
465
  .TRAFFIC_EVENT { font-weight: 700; }
@@ -450,9 +467,13 @@ function ensure_dev_style()
450
467
  .dir-out .TRAFFIC_ARROW, .dir-out .TRAFFIC_EVENT { color: #2563eb; }
451
468
  .dir-in .TRAFFIC_ARROW, .dir-in .TRAFFIC_EVENT { color: #059669; }
452
469
  .dir-err .TRAFFIC_ARROW, .dir-err .TRAFFIC_EVENT { color: #dc2626; }
453
- .TRAFFIC_SUMMARY { opacity: 0.6; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1 1 auto; min-width: 0; }
454
470
  .TRAFFIC_META { margin-left: auto; opacity: 0.6; font-size: 11px; white-space: nowrap; }
455
- .TRAFFIC_ENTRY:hover .TRAFFIC_KW { margin: 2px 0 0 16px; }
471
+ /* The indent of a nested block is NOT a hover effect: it used to be given
472
+ only on .TRAFFIC_ENTRY:hover, so moving the cursor across the log made
473
+ every payload under it jump 16px sideways and reflow. A payload being
474
+ read must not move because the pointer passed over it.
475
+ (No backticks in here: this stylesheet is a template literal.) */
476
+ .TRAFFIC_KW { margin: 2px 0 0 16px; }
456
477
  .TRAFFIC_FULL { margin: 4px 0 0 16px; padding: 6px 8px; font-family: monospace; font-size: 11px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; background: rgba(0,0,0,0.04); border-radius: 4px; overflow-x: auto; }
457
478
  .TRAFFIC_ROW { display: flex; gap: 6px; align-items: baseline; }
458
479
  .TRAFFIC_BULLET { opacity: 0.45; flex: 0 0 auto; }
@@ -483,10 +504,10 @@ details.TRAFFIC_NEST > summary::-webkit-details-marker { display: none; }
483
504
  :root[data-theme="dark"] .YDEV_BAR, :root[data-theme="dark"] .YDEV_STATS { background: rgba(255,255,255,0.04); }
484
505
  :root[data-theme="dark"] .YDEV_SEP { background: rgba(255,255,255,0.14); }
485
506
  :root[data-theme="dark"] .YDEV_CHIP, :root[data-theme="dark"] .YDEV_SEG, :root[data-theme="dark"] .YDEV_SEARCH { border-color: rgba(255,255,255,0.2); }
486
- :root[data-theme="dark"] .TRAFFIC_ENTRY, :root[data-theme="dark"] .TRAFFIC_LINE { background: rgba(255,255,255,0.03); }
487
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-out, :root[data-theme="dark"] .TRAFFIC_LINE.dir-out, :root[data-theme="dark"] .TRAFFIC_NAME.dir-out { border-left-color: #60a5fa; }
488
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-in, :root[data-theme="dark"] .TRAFFIC_LINE.dir-in, :root[data-theme="dark"] .TRAFFIC_NAME.dir-in { border-left-color: #34d399; }
489
- :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-err, :root[data-theme="dark"] .TRAFFIC_LINE.dir-err, :root[data-theme="dark"] .TRAFFIC_NAME.dir-err { border-left-color: #f87171; }
507
+ :root[data-theme="dark"] .TRAFFIC_ENTRY { background: rgba(255,255,255,0.03); }
508
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-out { border-left-color: #60a5fa; }
509
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-in { border-left-color: #34d399; }
510
+ :root[data-theme="dark"] .TRAFFIC_ENTRY.dir-err { border-left-color: #f87171; }
490
511
  :root[data-theme="dark"] .dir-out .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-out .TRAFFIC_EVENT { color: #60a5fa; }
491
512
  :root[data-theme="dark"] .dir-in .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-in .TRAFFIC_EVENT { color: #34d399; }
492
513
  :root[data-theme="dark"] .dir-err .TRAFFIC_ARROW, :root[data-theme="dark"] .dir-err .TRAFFIC_EVENT { color: #f87171; }
@@ -554,6 +575,67 @@ function traffic_scalar_row(key, value)
554
575
  ]];
555
576
  }
556
577
 
578
+ /* What a FOLDED object says about itself, the way a browser console says it:
579
+ * its first fields rather than a count. `{5}` is true and tells the reader
580
+ * nothing -- a list of twelve column descriptors was twelve identical `{5}`,
581
+ * and finding the one for `tags` meant opening them one at a time. The
582
+ * console prints `Object { header: "id", fillspace: 18, … }` and that is the
583
+ * idea copied here.
584
+ *
585
+ * Strings are QUOTED, unlike the expanded rows: in one line of several
586
+ * fields the quotes are what separate a value from the next key.
587
+ * A nested container is not entered -- it says `{…}` / `[…]` -- because a
588
+ * preview that recursed would be as long as the thing it previews.
589
+ *
590
+ * The count is not lost: it stays in the tooltip, for an object whose first
591
+ * fields do not fit. */
592
+ const PREVIEW_MAX_KEYS = 4;
593
+ const PREVIEW_MAX_CHARS = 90;
594
+ const PREVIEW_MAX_VALUE = 28;
595
+
596
+ function preview_scalar(v)
597
+ {
598
+ if(v === null) {
599
+ return "null";
600
+ }
601
+ if(typeof v === "string") {
602
+ let text = (v.length > PREVIEW_MAX_VALUE) ?
603
+ v.slice(0, PREVIEW_MAX_VALUE) + "…" : v;
604
+ return '"' + text + '"';
605
+ }
606
+ if(typeof v === "object") {
607
+ return Array.isArray(v) ? "[…]" : "{…}";
608
+ }
609
+ return String(v);
610
+ }
611
+
612
+ function object_preview(obj, count)
613
+ {
614
+ let keys = Object.keys(obj);
615
+ let parts = [];
616
+ let used = 0;
617
+
618
+ for(let k of keys) {
619
+ if(parts.length >= PREVIEW_MAX_KEYS) {
620
+ break;
621
+ }
622
+ let part = k + ": " + preview_scalar(obj[k]);
623
+ /* Stop at the width, but never with an empty preview: one field
624
+ too wide still says more than a number. */
625
+ if(parts.length > 0 && used + part.length > PREVIEW_MAX_CHARS) {
626
+ break;
627
+ }
628
+ parts.push(part);
629
+ used += part.length + 2;
630
+ }
631
+
632
+ if(parts.length < count) {
633
+ parts.push("…");
634
+ }
635
+
636
+ return "{" + parts.join(", ") + "}";
637
+ }
638
+
557
639
  /************************************************************
558
640
  * One field of any type. Scalars → a bullet row; objects and
559
641
  * arrays → a collapsed <details> so metadata / nested payloads
@@ -575,12 +657,12 @@ function traffic_value_node(key, value)
575
657
  ]];
576
658
  }
577
659
 
578
- let hint = is_arr ? `[${count}]` : `{${count}}`;
660
+ let hint = is_arr ? `[${count}]` : object_preview(value, count);
579
661
  return ['details', {class: 'TRAFFIC_NEST'}, [
580
662
  ['summary', {}, [
581
663
  ['span', {class: 'TRAFFIC_BULLET'}, '▸'],
582
664
  ['span', {class: 'TRAFFIC_NEST_KEY'}, key],
583
- ['span', {class: 'TRAFFIC_NEST_HINT'}, hint],
665
+ ['span', {class: 'TRAFFIC_NEST_HINT', title: `${count}`}, hint],
584
666
  ]],
585
667
  ['div', {class: 'TRAFFIC_KW'}, traffic_bullets(value)],
586
668
  ]];
@@ -620,36 +702,6 @@ function event_spans(e)
620
702
  return spans;
621
703
  }
622
704
 
623
- /* One-line summary of the kw for the compact view. */
624
- function compact_summary(kw)
625
- {
626
- if(!kw) {
627
- return "";
628
- }
629
- let parts = [];
630
- if("result" in kw) {
631
- parts.push("result=" + traffic_scalar_text(kw.result));
632
- }
633
- if(typeof kw.comment === "string" && kw.comment) {
634
- parts.push(traffic_clip(kw.comment, 80));
635
- }
636
- if(!parts.length) {
637
- let n = 0;
638
- for(let k of Object.keys(kw)) {
639
- if(k === "command") {
640
- continue;
641
- }
642
- let v = kw[k];
643
- if(v === null || typeof v !== "object") {
644
- parts.push(k + "=" + traffic_scalar_text(v));
645
- if(++n >= 3) {
646
- break;
647
- }
648
- }
649
- }
650
- }
651
- return traffic_clip(parts.join(" · "), 140);
652
- }
653
705
 
654
706
  function render_detailed(e)
655
707
  {
@@ -726,21 +778,6 @@ function render_full(e)
726
778
  return createElement2(['div', {class: 'TRAFFIC_ENTRY ' + dir_class(e.dir), title: e.title}, children]);
727
779
  }
728
780
 
729
- function render_compact(e)
730
- {
731
- let kids = event_spans(e);
732
- kids.push(['span', {class: 'TRAFFIC_SUMMARY'}, compact_summary(e.kw)]);
733
- kids.push(['span', {class: 'TRAFFIC_META'}, `${traffic_size(e.size)} · ${e.ts}`]);
734
- return createElement2(['div', {class: 'TRAFFIC_LINE ' + dir_class(e.dir), title: e.title}, kids]);
735
- }
736
-
737
- function render_name(e)
738
- {
739
- let kids = event_spans(e);
740
- kids.push(['span', {class: 'TRAFFIC_META'}, e.ts]);
741
- return createElement2(['div', {class: 'TRAFFIC_NAME ' + dir_class(e.dir), title: e.title}, kids]);
742
- }
743
-
744
781
  /* A mirrored framework log line (error/warning/info/debug/msg). */
745
782
  function render_log(e)
746
783
  {
@@ -769,21 +806,18 @@ function render_log(e)
769
806
  return $row;
770
807
  }
771
808
 
809
+ /* A TRAFFIC entry always shows its payload -- folded (`collapsed`, the
810
+ * bullets) or laid out (`expanded`, the JSON). A trace line is written by
811
+ * the runtime and is painted as it comes; what shapes it is the TRACES row
812
+ * (the machine-trace format chip and the payload chip), not this. */
772
813
  function render_entry(e)
773
814
  {
774
815
  if(e.kind === "log") {
775
816
  return render_log(e);
776
817
  }
777
- let view = dev_view();
778
- if(view === "full") {
818
+ if(dev_traffic_view() === "expanded") {
779
819
  return render_full(e);
780
820
  }
781
- if(view === "compact") {
782
- return render_compact(e);
783
- }
784
- if(view === "name") {
785
- return render_name(e);
786
- }
787
821
  return render_detailed(e);
788
822
  }
789
823
 
@@ -976,11 +1010,6 @@ function info_traffic(title, msg, direction, size)
976
1010
 
977
1011
  let route = dev_route();
978
1012
 
979
- /* Console side (routes "console" / "both"). */
980
- if(route !== "window") {
981
- console_traffic(title, jn, direction, size);
982
- }
983
-
984
1013
  let event = (jn && jn.event) ? String(jn.event) : "(no event)";
985
1014
  let kw = (jn && jn.kw && typeof jn.kw === "object") ? jn.kw : null;
986
1015
  let command = (kw && typeof kw.command === "string") ? kw.command : "";
@@ -1000,6 +1029,19 @@ function info_traffic(title, msg, direction, size)
1000
1029
 
1001
1030
  push_entry(entry);
1002
1031
 
1032
+ /* ONE rule, two sinks. The filter used to be asked by the window only,
1033
+ * and the console printed the very line the window had just hidden:
1034
+ * hide the outgoing half, or type something in FIND, and the traffic
1035
+ * went on arriving in the pane beside it. The answer is computed once,
1036
+ * here, and both sinks obey it. */
1037
+ let hidden = entry_hidden(entry, build_filter_ctx());
1038
+
1039
+ /* Console side (routes "console" / "both"), which has no window to
1040
+ * depend on: it prints whether or not the monitor is mounted. */
1041
+ if(route !== "window" && !hidden) {
1042
+ console_traffic(title, jn, direction, size);
1043
+ }
1044
+
1003
1045
  /* Window side: the entry is buffered above whatever happens, so the
1004
1046
  * window shows what arrived before it was opened. Painted only when the
1005
1047
  * window is mounted and not routed to the console only. */
@@ -1009,7 +1051,7 @@ function info_traffic(title, msg, direction, size)
1009
1051
  }
1010
1052
  ensure_dev_style();
1011
1053
 
1012
- if(!entry_hidden(entry, build_filter_ctx())) {
1054
+ if(!hidden) {
1013
1055
  let node = render_entry(entry);
1014
1056
  entry.$node = node;
1015
1057
  /* Drop the "no traffic yet" placeholder before the first row. */
@@ -1231,7 +1273,7 @@ function refresh_dev_chrome()
1231
1273
  $b.classList.toggle('is-active', v > 0);
1232
1274
  });
1233
1275
 
1234
- let view = dev_view();
1276
+ let view = dev_traffic_view();
1235
1277
  document.querySelectorAll('.YDEV_SEG_BTN[data-view]').forEach(($b) => {
1236
1278
  $b.classList.toggle('is-active', $b.getAttribute('data-view') === view);
1237
1279
  });
@@ -1245,7 +1287,7 @@ function refresh_dev_chrome()
1245
1287
  * the group only there, and reflect each toggle's persisted state. */
1246
1288
  let $eg = document.getElementById('ydev-expand-grp');
1247
1289
  if($eg) {
1248
- $eg.style.display = (view === 'full') ? '' : 'none';
1290
+ $eg.style.display = (view === 'expanded') ? '' : 'none';
1249
1291
  }
1250
1292
  document.querySelectorAll('.YDEV_CHIP[data-expand]').forEach(($b) => {
1251
1293
  $b.classList.toggle('is-active', full_show($b.getAttribute('data-expand')));
@@ -1259,6 +1301,10 @@ function refresh_dev_chrome()
1259
1301
  $b.classList.toggle('is-active', !!dev_simple_mach());
1260
1302
  });
1261
1303
 
1304
+ document.querySelectorAll('.YDEV_CHIP[data-toggle="traces-payload"]').forEach(($b) => {
1305
+ $b.classList.toggle('is-active', !!dev_traces_payload());
1306
+ });
1307
+
1262
1308
  update_stats();
1263
1309
  }
1264
1310
 
@@ -1356,19 +1402,48 @@ function build_control_bar()
1356
1402
  }
1357
1403
  }];
1358
1404
 
1359
- let mk_view = (v, label) => ['button', {class: 'YDEV_SEG_BTN', 'data-view': v,
1360
- 'data-i18n': label, type: 'button'}, t(label), {
1405
+ /* The TRACES feed's payload: the `json` lines a trace dumps (an ev_kw,
1406
+ * a publication). It used to be taken away by the TRAFFIC view being
1407
+ * set to names -- another feed's control -- so nothing said where the
1408
+ * payloads had gone. Here it says it. */
1409
+ let traces_payload = ['button', {
1410
+ class: 'YDEV_CHIP', 'data-toggle': 'traces-payload', type: 'button',
1411
+ title: t('show the payload of the traces'),
1412
+ 'data-i18n-title': 'show the payload of the traces',
1413
+ 'data-i18n': 'payload',
1414
+ 'aria-label': t('payload'), 'data-i18n-aria-label': 'payload',
1415
+ }, t('payload'), {
1416
+ click: (ev) => {
1417
+ ev.stopPropagation();
1418
+ kw_set_local_storage_value("dev_traces_payload", dev_traces_payload() ? 0 : 1);
1419
+ rerender_all();
1420
+ refresh_dev_chrome();
1421
+ }
1422
+ }];
1423
+
1424
+ /* The TRAFFIC feed's own control, and it only says how much room its
1425
+ * payload takes: the payload is always there. What shapes a TRACE is
1426
+ * in the TRACES row (the machine-trace chip and `payload`), because
1427
+ * both feeds can be on at once and neither may steer the other. */
1428
+ let VIEW_TITLES = {
1429
+ collapsed: 'traffic payload folded',
1430
+ expanded: 'traffic payload laid out',
1431
+ };
1432
+ let mk_view = (v, label) => ['button', {
1433
+ class: 'YDEV_SEG_BTN', 'data-view': v, type: 'button',
1434
+ title: t(VIEW_TITLES[v]), 'data-i18n-title': VIEW_TITLES[v],
1435
+ 'data-i18n': label,
1436
+ 'aria-label': t(label), 'data-i18n-aria-label': label,
1437
+ }, t(label), {
1361
1438
  click: (ev) => {
1362
1439
  ev.stopPropagation();
1363
- set_view(v);
1440
+ set_traffic_view(v);
1364
1441
  }
1365
1442
  }];
1366
1443
 
1367
1444
  let view_seg = ['div', {class: 'YDEV_SEG', id: 'ydev-seg'}, [
1368
- mk_view('detailed', 'detailed'),
1369
- mk_view('full', 'expanded'),
1370
- mk_view('compact', 'compact'),
1371
- mk_view('name', 'name only'),
1445
+ mk_view('collapsed', 'collapsed'),
1446
+ mk_view('expanded', 'expanded'),
1372
1447
  ]];
1373
1448
 
1374
1449
  /* Output routing: send traffic + all logs + automata to the dev window,
@@ -1394,8 +1469,8 @@ function build_control_bar()
1394
1469
  mk_out('both', 'both'),
1395
1470
  ]];
1396
1471
 
1397
- /* Expanded-view section toggles (only meaningful in the 'full' view;
1398
- * the group is shown/hidden by refresh_dev_chrome). */
1472
+ /* Expanded-view section toggles (only meaningful in the 'expanded'
1473
+ * traffic view; the group is shown/hidden by refresh_dev_chrome). */
1399
1474
  /* The title says WHAT it does and not which section: composing
1400
1475
  * `'Show ' + label + '...'` gives a string that is no i18n key, so
1401
1476
  * it could never re-translate -- and the button's own label is the
@@ -1497,7 +1572,7 @@ function build_control_bar()
1497
1572
  let sep = () => ['span', {class: 'YDEV_SEP'}, ''];
1498
1573
 
1499
1574
  return createElement2(['div', {class: 'YDEV_BAR'}, [
1500
- grp('traces', [...trace_chips, simple_mach]), sep(),
1575
+ grp('traces', [...trace_chips, simple_mach, traces_payload]), sep(),
1501
1576
  grp('output', [output_seg]), sep(),
1502
1577
  grp('view', [view_seg]), expand_grp, sep(),
1503
1578
  grp('show', dir_chips), sep(),