@wix/himalaya-cli 0.860.0 → 0.862.0

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.
@@ -181,11 +181,22 @@ function subjectLabelOf(m: SemanticModelSummary): string {
181
181
  * renders as a dash rather than as 0. `formatNumber` and not `toLocaleString`,
182
182
  * which is ECMA-402 and absent on QuickJS-ng (watchOS/Wear OS).
183
183
  */
184
+ /**
185
+ * The one placeholder a cell falls back to when there is nothing to render.
186
+ *
187
+ * Named, because two things depend on it meaning exactly one thing: `cellText`
188
+ * produces it, and `runQuery` asks whether the server's total came back as it —
189
+ * which is how "the owner asked for a total and got a dash" is told apart from
190
+ * "the server answered". Spelling it twice let those two drift apart once
191
+ * already.
192
+ */
193
+ const DASH = "\u2014";
194
+
184
195
  function cellText(v: SemanticValue | undefined): string {
185
- if (!v) return "—";
196
+ if (!v) return DASH;
186
197
  if (v.formatted !== undefined && v.formatted !== "") return v.formatted;
187
198
  const raw = v.value;
188
- if (raw === null || raw === undefined) return "—";
199
+ if (raw === null || raw === undefined) return DASH;
189
200
  if (typeof raw === "number") return formatNumber(raw);
190
201
  if (typeof raw === "boolean") return raw ? "Yes" : "No";
191
202
  if (typeof raw === "string") return raw;
@@ -387,6 +398,23 @@ async function runQuery(s: ReportState, days: number): Promise<ReportState | Dec
387
398
  ? copyParam("ownerReport.missingFields", "No data returned for: ") + result.missingFields.join(", ")
388
399
  : "";
389
400
 
401
+ // Did the SERVER actually answer with a total for the measure asked for?
402
+ // This is NOT the same question as "is a totals row on screen": the row is
403
+ // rendered as a dash when the owner asked and nothing came back, and a dash
404
+ // is a placeholder, not an answer. Keeping the two apart is what stops a
405
+ // placeholder from counting as content — see `hideTable`/`noEmpty` below.
406
+ //
407
+ // A zero is unaffected: `cellText` formats it as "0", not as the dash, and a
408
+ // zero total is a real answer that must keep the table up.
409
+ // Asked of `cellText` rather than re-derived: a `SemanticValue` is an OBJECT
410
+ // even when it carries `value: null`, so a nullish check on the entry itself
411
+ // calls a valueless total an answer. `cellText` already owns the decision of
412
+ // what counts as showable, down to `formatted: ""`, so the question is simply
413
+ // whether it produced the placeholder.
414
+ const serverTotal = result.totals?.[s.measureName];
415
+ const totalText = cellText(serverTotal);
416
+ const answeredTotal = totalText !== DASH;
417
+
390
418
  // `noTotals` is the owner's REQUEST and stays theirs; only they change it.
391
419
  // When they asked and the server sent no total, that is reported as a dash —
392
420
  // an absent number the owner asked for must be visible, not silently dropped
@@ -395,9 +423,12 @@ async function runQuery(s: ReportState, days: number): Promise<ReportState | Dec
395
423
  ? null
396
424
  : {
397
425
  dimension: copyParam("ownerReport.totalsLabel", "Total"),
398
- measure: result.totals ? cellText(result.totals[s.measureName]) : "—",
426
+ measure: totalText,
399
427
  };
400
428
 
429
+ // Is there anything to READ? Rows, or a total the server actually sent.
430
+ const hasContent = rows.length > 0 || answeredTotal;
431
+
401
432
  const out: ReportState = {
402
433
  ...s,
403
434
  status: "ready",
@@ -405,16 +436,22 @@ async function runQuery(s: ReportState, days: number): Promise<ReportState | Dec
405
436
  + `${s.measureLabel} ${copyParam("ownerReport.by", "by")} ${s.dimensionLabel}`,
406
437
  rows,
407
438
  totals,
408
- rowCount: rows.length > 0
409
- ? `${result.paging.count || rows.length} ${copyParam("ownerReport.rows", "rows")}`
410
- : "",
439
+ // A zero count is stated, not left blank. Silence beside a caption reads
440
+ // as "still loading" — the ambiguity this screen removes everywhere else —
441
+ // so "0 rows" says the query ran and came back with nothing.
442
+ rowCount: `${rows.length > 0 ? result.paging.count || rows.length : 0} ${copyParam("ownerReport.rows", "rows")}`,
411
443
  missingFields: gap,
412
444
  noGap: gap === "",
413
- // Rows OR totals. The API can answer `results: []` WITH a `totals` object
414
- // — the SDK has a test for exactly that shape — and gating on rows alone
415
- // hid the server's total and put "Nothing to show" over it. Opting into
416
- // Show total would then have thrown away the only answer that came back.
417
- hideTable: rows.length === 0 && !totals,
445
+ // Rows OR a total the SERVER sent. The API can answer `results: []` WITH a
446
+ // `totals` object — the SDK has a test for exactly that shape — and gating
447
+ // on rows alone hid the server's total and put "Nothing to show" over it.
448
+ //
449
+ // But it must be `answeredTotal`, not `totals`: `totals` is non-null for
450
+ // the whole time the owner has Show total on, INCLUDING when the answer is
451
+ // the "—" placeholder. Gating on it meant an empty result with the toggle
452
+ // on rendered a table whose only row was `Total —`, and the empty state
453
+ // could never fire while the toggle was on. Two states each correct alone.
454
+ hideTable: !hasContent,
418
455
  notLoading: true,
419
456
  notErrored: true,
420
457
  hideContent: false,
@@ -423,10 +460,10 @@ async function runQuery(s: ReportState, days: number): Promise<ReportState | Dec
423
460
  // It is NOT conflated with a dropped field: the SDK reports no
424
461
  // `missingFields` when nothing came back at all, precisely because the two
425
462
  // are indistinguishable there, so this arm never accuses a field.
426
- noEmpty: rows.length > 0 || totals !== null,
427
- emptyText: rows.length === 0 && !totals
428
- ? copyParam("ownerReport.empty", "No data for this range.")
429
- : "",
463
+ noEmpty: hasContent,
464
+ emptyText: hasContent
465
+ ? ""
466
+ : copyParam("ownerReport.empty", "No data for this range."),
430
467
  // Carried through untouched: see the totals comment above.
431
468
  noTotals: s.noTotals,
432
469
  error: "",