fsanyoto commited on
Commit
91616ab
Β·
verified Β·
1 Parent(s): 30feec0

Deploy AIOS web (React glide grid + FastAPI slice)

Browse files
Files changed (3) hide show
  1. RELEASES.json +1 -1
  2. VERSION +1 -1
  3. web/src/customer-grid/display.ts +50 -0
RELEASES.json CHANGED
@@ -1,5 +1,5 @@
1
  {
2
- "current": "4c54929",
3
  "releases": [
4
  {
5
  "version": "v29",
 
1
  {
2
+ "current": "b9a3041",
3
  "releases": [
4
  {
5
  "version": "v29",
VERSION CHANGED
@@ -1 +1 @@
1
- 4c54929
 
1
+ b9a3041
web/src/customer-grid/display.ts CHANGED
@@ -437,6 +437,53 @@ export function codePreview(v: CellValue): string {
437
  return n > 1 ? `${first} +${n - 1} more` : first;
438
  }
439
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
440
  /** One compact line for a json cell. See the note above for why each case reads as it does. */
441
  export function jsonPreview(v: CellValue): string {
442
  const raw = String(v ?? "").trim();
@@ -471,6 +518,9 @@ export function jsonPreview(v: CellValue): string {
471
  return shown.posts.length === 0
472
  ? "No posts"
473
  : `${shown.posts.length} post${shown.posts.length === 1 ? "" : "s"}`;
 
 
 
474
  if (Array.isArray(value))
475
  return value.length === 0 ? "[]" : `[…] ${value.length} item${value.length === 1 ? "" : "s"}`;
476
  if (value !== null && typeof value === "object") {
 
437
  return n > 1 ? `${first} +${n - 1} more` : first;
438
  }
439
 
440
+ /**
441
+ * ⭐⭐ W37-T14 / T15 β€” THE TWO SHAPES WAVE 37 ADDED, READ AS WHAT THEY ARE.
442
+ *
443
+ * β›” FOUND BY QA ON THE DEPLOYED BUILD, not by a gate: `1.5BOPP`'s Units cell rendered
444
+ * **`[…] 2 items`** and its Tier prices cell the same way, because both are `type: "json"` and
445
+ * both fell through to the generic array branch below. The server was serving the right data the
446
+ * whole time β€” `[{name:"SLEEVE",qty:12},{name:"Master",qty:144}]` β€” and the grid said nothing
447
+ * about it. A column whose entire job is to show which units a SKU sells in, showing a count of
448
+ * items, is the [[permitted-is-not-answerable]] shape in the RENDER layer.
449
+ *
450
+ * ⚠ KEYED ON THE SHAPE, NEVER ON THE COLUMN KEY. A key test (`field.key === "units"`) would
451
+ * miss the same document on a user database, on a rollup, or under any rename β€” and this file
452
+ * has no access to the field anyway. Both shapes are exact: EVERY element must be an object
453
+ * carrying exactly the pair, so an unrelated array of objects still falls through to the generic
454
+ * branch and is not silently relabelled.
455
+ *
456
+ * ⚠ `Γ—` is U+00D7 MULTIPLICATION SIGN and `Β·` is U+00B7 MIDDLE DOT β€” neither is an em or en
457
+ * dash, so this copy is inside standing rule 2 rather than an exception to it.
458
+ */
459
+ function namedPairList(value: unknown): string | null {
460
+ if (!Array.isArray(value) || value.length === 0) return null;
461
+ const rows = value as Record<string, unknown>[];
462
+ const every = (a: string, b: string) =>
463
+ rows.every(
464
+ (r) =>
465
+ r !== null &&
466
+ typeof r === "object" &&
467
+ !Array.isArray(r) &&
468
+ typeof r[a] === "string" &&
469
+ typeof r[b] === "number",
470
+ );
471
+ // W37-T15 β€” units of measure: the NAME and its conversion factor, which is the whole point.
472
+ if (every("name", "qty"))
473
+ return rows.map((r) => `${String(r.name)} Γ—${trimNum(r.qty as number)}`).join(" Β· ");
474
+ // W37-T14 β€” the pricelists that really price this SKU today, each with its price.
475
+ if (every("pricelist", "unit_price"))
476
+ return rows
477
+ .map((r) => `${String(r.pricelist)} $${numberText(r.unit_price as number, { decimals: 2 })}`)
478
+ .join(" Β· ");
479
+ return null;
480
+ }
481
+
482
+ /** `12` not `12.0`, and `1.5` kept β€” a conversion factor is a count far more often than not. */
483
+ function trimNum(n: number): string {
484
+ return Number.isFinite(n) ? String(Number(n.toFixed(4))) : String(n);
485
+ }
486
+
487
  /** One compact line for a json cell. See the note above for why each case reads as it does. */
488
  export function jsonPreview(v: CellValue): string {
489
  const raw = String(v ?? "").trim();
 
518
  return shown.posts.length === 0
519
  ? "No posts"
520
  : `${shown.posts.length} post${shown.posts.length === 1 ? "" : "s"}`;
521
+ // ⭐ W37-T14/T15 β€” the two known shapes read as themselves; anything else keeps the old count.
522
+ const pairs = namedPairList(value);
523
+ if (pairs) return clip(pairs, 60);
524
  if (Array.isArray(value))
525
  return value.length === 0 ? "[]" : `[…] ${value.length} item${value.length === 1 ? "" : "s"}`;
526
  if (value !== null && typeof value === "object") {