@bongos/core 1.21.38 → 1.21.39

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.
@@ -34,8 +34,6 @@
34
34
  // the seat is drawn empty and says so, and the rule is the building's own
35
35
  // matters' rule, else the design's default, named as the default
36
36
  // (holderOf()).
37
- // * On the table here: the docket's matters at this building. Each row opens
38
- // the short card (GovStreet.cardFor(); task 1004528 makes it act).
39
37
  // * The record: the building's history (docket.history: rulings, amendments,
40
38
  // sign-offs, releases, payouts) and its matters, filed by month, one drawer
41
39
  // a month, newest first.
@@ -176,7 +174,7 @@
176
174
  // key one of the nine civic keys
177
175
  // b the building, in civicInfo()'s shape: { group, name, holds, seats,
178
176
  // who, rule, how, cap, growth, floors: [{ name, line, count, status,
179
- // lines }], record: [{ label, items }], onFile, table: [rows], annex }
177
+ // lines }], record: [{ label, items }], onFile, annex }
180
178
  // st { floor, drawer, picks, vacant, reviewHeld, evening }
181
179
  // Everything the prototype's template binds, as data, plus `selFloor` and
182
180
  // `selDrawer`. The geometry is the prototype's to the pixel.
@@ -261,7 +259,6 @@
261
259
  : { key: s, init: s, bg: T.seatFor.bg, fg: T.seatFor.fg, border: 'none' };
262
260
  const g = City.glyph(b.rule, 9, 9, 16);
263
261
  const pct = Math.round(occ / cap * 100);
264
- const table = Array.isArray(b.table) ? b.table : [];
265
262
  const f = b.floors[selFloor];
266
263
  const quietWord = f && QUIET[f.status] !== undefined ? ' · ' + (f.status === 'proposed' ? 'proposed' : QUIET[f.status]) : '';
267
264
  return {
@@ -269,7 +266,6 @@
269
266
  seats: b.seats.map(seatOf), whoText: b.who, gf: g.fill, gl: g.line, howText: b.how,
270
267
  fill: pct, fillColor: pct >= 80 ? '#fb9569' : T.line,
271
268
  growth: (vacant ? 'Not built yet. ' : occ + ' of ' + cap + ' floors in use. ') + b.growth,
272
- hasTable: table.length > 0, table: table,
273
269
  openKicker: 'floor ' + (selFloor + 1) + (f && f.status === 'pending' ? ' · being decided' : quietWord),
274
270
  sym: f ? Object.assign(symbolPath(floorSymbol(f.name)), { c: '#fb9569' }) : { d: '', f: '', c: 'none' },
275
271
  flipA: ((st.picks || 0) % 2) === 0, flipB: ((st.picks || 0) % 2) === 1,
@@ -528,11 +524,6 @@
528
524
  if (!vacant && spec[2] && spec[2].held) fl.name = spec[2].held;
529
525
  return fl;
530
526
  });
531
- const order = { needs: 0, moving: 1, settled: 2 };
532
- const table = matters.slice().sort((a, b) => order[stateOf(a)] - order[stateOf(b)]).map((m) => {
533
- const s = stateOf(m), when = S.whenWord(m.deadline, c.now);
534
- return { key: String(m.id), matter: String(m.id), label: String(m.title || m.short || ''), status: s === 'needs' ? 'needs you' + (when ? ' · ' + when : '') : s === 'moving' ? 'moving' + (when ? ' · ' + when : '') : (when || 'settled'), state: s, color: s === 'needs' ? 'accent' : 'ink' };
535
- });
536
527
  const history = docket && Array.isArray(docket.history) ? docket.history.filter((x) => x && x.building === key) : [];
537
528
  const record = recordOf(matters, c.now, history);
538
529
  return {
@@ -541,7 +532,7 @@
541
532
  growth: vacant ? plan.vacantGrowth : plan.growth,
542
533
  floors: floors, record: record,
543
534
  onFile: !docket ? 'the docket could not be read just now' : matters.length ? matters.length + (matters.length === 1 ? ' matter' : ' matters') + ' on the docket' + (history.length ? ' · ' + history.length + ' on the record' : '') : history.length ? history.length + ' on the record' : 'nothing on file yet',
544
- table: table, annex: !vacant && floors.length >= plan.cap ? plan.annex : null, vacant: vacant,
535
+ annex: !vacant && floors.length >= plan.cap ? plan.annex : null, vacant: vacant,
545
536
  };
546
537
  }
547
538
 
@@ -558,9 +549,8 @@
558
549
  const docket = o.docket && Array.isArray(o.docket.matters) ? o.docket : null;
559
550
  const evening = !!docket && !(docket.counts && Number(docket.counts.needs) > 0);
560
551
  const bv = buildingView(T, o.key, b, { floor: o.floor, drawer: o.drawer, picks: o.picks, vacant: b.vacant, reviewHeld: !b.vacant, evening: evening, cleared: o.cleared });
561
- bv.table = bv.table.map((r) => Object.assign({}, r, { color: r.color === 'accent' ? T.accentText : T.ink }));
562
552
  bv.key = o.key; bv.mode = mode; bv.vacant = b.vacant;
563
- bv.label = b.name + ' in section: ' + b.floors.length + ' of ' + bv.cap + ' floors in use' + (bv.hasTable ? ', ' + bv.table.length + ' on the table' : '') + '.';
553
+ bv.label = b.name + ' in section: ' + b.floors.length + ' of ' + bv.cap + ' floors in use.';
564
554
  return bv;
565
555
  }
566
556
 
@@ -195,7 +195,7 @@ html[data-fullscreen="on"] .street-top { padding-right: 184px; }
195
195
  on the hall's tokens. Under 900 px the artboard gives way to a column: the
196
196
  drawing in its own sideways strip, the panel below it. */
197
197
  .inside { position: absolute; inset: 0; display: flex; overflow-x: auto; overflow-y: auto; background: var(--bg); }
198
- .inside[hidden], .inside-annex[hidden], .inside-dhead[hidden], .inside-legend[hidden], .inside-table[hidden], .inside-open[hidden], .inside-note[hidden], .inside-panel[hidden], .inside-more[hidden] { display: none; }
198
+ .inside[hidden], .inside-annex[hidden], .inside-dhead[hidden], .inside-legend[hidden], .inside-open[hidden], .inside-note[hidden], .inside-panel[hidden], .inside-more[hidden] { display: none; }
199
199
  .inside-sizer { position: relative; margin: auto; flex: none; overflow: hidden; }
200
200
  .inside-board { position: absolute; left: 0; top: 0; width: 1440px; height: 708px; transform-origin: 0 0; transform: scale(var(--inside-scale, 1)); color: var(--ink); }
201
201
  .inside-head { position: absolute; left: 32px; top: 16px; display: flex; align-items: center; gap: 16px; z-index: 2; }
@@ -265,10 +265,6 @@ html[data-fullscreen="on"] .street-top { padding-right: 184px; }
265
265
  .inside-meter__fill { height: 6px; width: 0; background: color-mix(in srgb, var(--ink) 30%, var(--bg)); }
266
266
  .inside-meter__fill--full { background: var(--accent); }
267
267
  .inside-meter__line { font-size: 13px; color: var(--ink-soft); line-height: 1.45; }
268
- .inside-table { display: flex; flex-direction: column; gap: 8px; }
269
- .inside-row { display: flex; justify-content: space-between; align-items: center; gap: 12px; width: 100%; background: none; border: 0; border-top: 1px solid var(--street-rule); padding: 10px 0; cursor: pointer; font-family: var(--font-body); font-size: 15px; text-align: left; color: var(--ink); }
270
- .inside-row--needs { color: var(--street-accent-text); }
271
- .inside-row__status { font-size: 12.5px; color: var(--ink-faint); white-space: nowrap; }
272
268
 
273
269
  /* the chosen floor, its sign large; the block re-enters on every pick */
274
270
  .inside-open { display: flex; flex-direction: column; gap: 10px; }
@@ -362,7 +358,7 @@ html[data-fullscreen="on"] .street-top { padding-right: 184px; }
362
358
  .inside-ditem { display: flex; justify-content: space-between; gap: 14px; padding: 8px 0; border-top: 1px solid var(--street-rule); font-size: 14px; line-height: 1.4; }
363
359
  .inside-ditem__meta { color: var(--ink-faint); white-space: nowrap; }
364
360
 
365
- .inside-back:focus-visible, .inside-textbtn:focus-visible, .inside-row:focus-visible, .inside-drawer:focus-visible, .inside-item:focus-visible, .inside-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
361
+ .inside-back:focus-visible, .inside-textbtn:focus-visible, .inside-drawer:focus-visible, .inside-item:focus-visible, .inside-more:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
366
362
  .inside-floor:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; }
367
363
  .inside-name:focus { outline: none; }
368
364
  .inside-name:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
@@ -166,10 +166,6 @@
166
166
  <span class="inside-meter__line" id="insideGrowth"></span>
167
167
  </div>
168
168
  </div>
169
- <div class="inside-table" id="insideTableWrap" hidden>
170
- <span class="street-label">on the table here</span>
171
- <div id="insideTable"></div>
172
- </div>
173
169
  <div class="inside-open" id="insideOpenA"></div>
174
170
  <div class="inside-open" id="insideOpenB" hidden></div>
175
171
  <div class="inside-record">
@@ -493,19 +493,6 @@
493
493
  var fill = $('insideFill');
494
494
  if (fill) { fill.style.width = bv.fill + '%'; fill.className = 'inside-meter__fill' + (bv.fill >= 80 ? ' inside-meter__fill--full' : ''); }
495
495
  setText('insideGrowth', bv.growth);
496
- show('insideTableWrap', bv.hasTable);
497
- var table = $('insideTable'); clear(table);
498
- bv.table.forEach(function (r) {
499
- var b = node('button', 'inside-row' + (r.state === 'needs' ? ' inside-row--needs' : ''));
500
- b.setAttribute('type', 'button');
501
- b.setAttribute('data-matter', r.matter);
502
- b.setAttribute('aria-controls', 'streetCard');
503
- b.setAttribute('aria-expanded', view.open === r.matter ? 'true' : 'false');
504
- b.appendChild(node('span', 'inside-row__label', r.label));
505
- b.appendChild(node('span', 'inside-row__status', r.status));
506
- b.addEventListener('click', function () { openCard(r.matter, b); });
507
- if (table) table.appendChild(b);
508
- });
509
496
  // the chosen floor: two blocks that take turns, so the block re-enters on every pick
510
497
  var on = $(bv.flipA ? 'insideOpenA' : 'insideOpenB'), off = $(bv.flipA ? 'insideOpenB' : 'insideOpenA');
511
498
  if (off) { off.hidden = true; clear(off); }
@@ -1104,12 +1091,10 @@
1104
1091
  // The pins were redrawn, so focus goes back to the new button for the same matter.
1105
1092
  if (restore !== false && was && was.getAttribute) {
1106
1093
  var key = was.getAttribute('data-matter');
1107
- // the pins and the table rows were redrawn: focus the new control for the same matter
1094
+ // the pins were redrawn: focus the new pin for the same matter
1108
1095
  // .children is an HTMLCollection, which concat does not spread: copy it first
1109
1096
  var list = function (id) { var el = $(id); return el && el.children ? Array.prototype.slice.call(el.children) : []; };
1110
- var pins = list('streetPins');
1111
- var rows = list('insideTable');
1112
- var pool = view.inside ? [].concat(rows, pins) : [].concat(pins, rows);
1097
+ var pool = list('streetPins');
1113
1098
  for (var i = 0; i < pool.length; i++) {
1114
1099
  if (pool[i].getAttribute('data-matter') === key) { if (pool[i].focus) pool[i].focus(); break; }
1115
1100
  }
@@ -21,12 +21,12 @@ Built 1:1 on `buildingView()` and `districtView()` of the same prototype. The in
21
21
  Files: `street-inside.js` (`window.GovInside`, node-require-safe, pure): the prototype's `crown()`, `workItem()`, `floorSymbol()`, `symbolPath()` (all forty symbols) and the section drawing itself, verbatim, plus the real-data adapters. `street.js` builds the nodes; `street.css` carries the interior's styles under the `inside-` prefix.
22
22
 
23
23
  - **The building in section.** Every storey a real floor (slab, cut walls with glazing, three lamps, a partition with a doorway, the framed sign with the floor's symbol, its name and state lettered on the wall, its count, its level number), dark empty floors up to the building's capacity, the crown per building, the lift in its shaft, the orange frame and orange sign on the chosen floor, and the annex lot once the building is full. An unheld Review is the dashed ghost (`GovStreet.reviewHeldOf()`, so the street and the interior agree).
24
- - **The right panel.** Name and what it holds, who holds it (seat chips), how it decides (the rule glyph), **change how this works**, the fill meter with its growth line, on the table here, the chosen floor with its sign large, and the record as monthly filing drawers.
24
+ - **The right panel.** Name and what it holds, who holds it (seat chips), how it decides (the rule glyph), **change how this works**, the fill meter with its growth line, the chosen floor with its sign large, and the record as monthly filing drawers.
25
25
  - **Floors are the prototype's structure; a number appears only when the docket holds it.** `GovInside.PLAN` keeps each building's floors, order and capacity. A floor bound to a docket source shows that source's open matters at this building (count, line, needs you, the lines); one bound to a reading shows its figure; Planning's Goals floor counts the open goals. Every other floor says "not recorded yet" on the wall, lettered faint, with no number. A source that is off, coming, not yours or unreadable says which, never a figure. Filling every floor with real data is task 1004527, through `floorFor()` and `PLAN`.
26
26
  - **Who holds it.** The docket names no holders yet (task 1004529), so the seat is an empty dashed chip and says "who holds it is not set on this project yet". The rule is the one the building's open matters are decided by, else the design's default, which the words call "by default". `holderOf()` reads a docket building's `holders` / `rule` / `who` first, so 1004529 lands without touching the drawing.
27
27
  - **The lift and the flip.** The lift is one node kept across draws, so picking a floor slides it by a CSS transform transition; the chosen floor's block is two blocks that take turns (`flipA` / `flipB`), so it re-enters on every pick. Both are dead under reduced motion.
28
28
  - **Change how this works** is present and honest: pressed, it says drafting an amendment from here is not built yet (task 1004530 wires it).
29
- - **On the table here** rows open the same short card a pin opens, through `openCard()`; Escape gives focus back to the row.
29
+ - **No "on the table here" list.** The prototype's list of the building's open matters was removed on the owner's direction (task 1004565): the floor desks carry every matter as an actionable row, so the list was duplication. Inside a building a matter is its desk row; the short card opens from the street's pins.
30
30
  - **Districts.** The goal's tasks (`GET /tasks?goal_id=N`, read once per goal): shape from the discipline (tower engineer, studio artist, glass front UI, pavilion ideator; none is a tower), stage from the status (backlog and blocked a staked plot, ready a slab, active a scaffold, completed and confirmed built with a flag, shipped lit), label the kind; height from the estimate. Up to ten stand on the road, work in flight first; the rest are counted with a link to the goal. Each one opens its task.
31
31
  - **Narrow.** Under 900 px the board becomes a column: the drawing in its own sideways strip (never scaled under 0.6, so a floor stays a 24 px target), then the panel.
32
32
 
package/package-lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.21.38",
3
+ "version": "1.21.39",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bongos/core",
9
- "version": "1.21.38",
9
+ "version": "1.21.39",
10
10
  "license": "AGPL-3.0-or-later",
11
11
  "dependencies": {
12
12
  "express": "^4.21.2",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bongos/core",
3
- "version": "1.21.38",
3
+ "version": "1.21.39",
4
4
  "description": "Cloud Bongos — the AI-first build platform core (GDS + platform surfaces + module system), installed as a versioned dependency (ADR 0108).",
5
5
  "license": "AGPL-3.0-or-later",
6
6
  "main": "src/platform-server.js",
@@ -8992,5 +8992,11 @@
8992
8992
  "id": "1004564",
8993
8993
  "text": "If you put something up for a vote and nobody has voted yet, you can now withdraw it with one tap on your desk. Once anyone votes, it stays with the vote. A small database change makes \"withdrawn\" a valid way for a sitting to"
8994
8994
  }
8995
+ ],
8996
+ "1.21.39": [
8997
+ {
8998
+ "id": "1004565",
8999
+ "text": "Inside each building on the governor street, the separate \"on the table here\" list is gone. The floor desks already show every matter as a row you can act on, so the list only repeated them. The rest of the building panel look"
9000
+ }
8995
9001
  ]
8996
9002
  }
package/src/module-api.js CHANGED
@@ -75,7 +75,7 @@ const { responsibilityFor, ROLE_RESPONSIBILITIES } = require('./role-responsibil
75
75
  // MAJOR (see allowBoxScope below): passes the request through untouched.
76
76
  function deprecatedNoopMiddleware(_req, _res, next) { next(); }
77
77
 
78
- const CORE_VERSION = '1.21.38'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
78
+ const CORE_VERSION = '1.21.39'; // CI auto-patch carrier (ADR 0161); changelog: docs/module-api-changelog.md
79
79
 
80
80
  // A namespaced logger so a module's log lines are attributable + consistent.
81
81
  // Usage: const log = api.logger('discord'); log.info('mounted');
@@ -218,7 +218,7 @@ test('a source that is off, coming, not yours or unreadable never shows a number
218
218
  const none = I.civicInfo('release', { docket: null, now: NOW });
219
219
  assert.ok(none.floors.every((f) => f.count === '' && f.status !== 'ok' && f.status !== 'pending'), 'no docket: no numbers anywhere');
220
220
  assert.equal(none.onFile, 'the docket could not be read just now');
221
- assert.deepEqual(none.table, []);
221
+ assert.deepEqual(none.record, [], 'no docket: nothing filed');
222
222
  });
223
223
 
224
224
  test('a floor bound to a reading shows its figure and line when live; Planning counts the open goals', () => {
@@ -237,12 +237,12 @@ test('a floor bound to a reading shows its figure and line when live; Planning c
237
237
  assert.ok(m.texts.some((t) => t.v === '5' && t.s === 20), 'only open goals are counted on the wall');
238
238
  });
239
239
 
240
- test('on the table: the building\'s matters, needs first; each row names the matter it opens', () => {
241
- const ms = [matter({ id: 'board:1', source: 'board', building: 'charter', state: 'moving', title: 'B', deadline: '2026-10-04T09:00:00.000Z' }), matter({ id: 'board:2', source: 'board', building: 'charter', state: 'needs', title: 'A', deadline: '2026-10-02T20:00:00.000Z' }), matter({ id: 'blockers:3' })];
240
+ test('no separate list of matters: the floor desks carry every matter, so the model keeps no table (task 1004565)', () => {
241
+ const ms = [matter({ id: 'board:1', source: 'board', building: 'charter', state: 'moving', title: 'B' }), matter({ id: 'board:2', source: 'board', building: 'charter', state: 'needs', title: 'A' })];
242
242
  const m = I.buildingModel({ key: 'charter', docket: docket(ms), mode: 'light', now: NOW });
243
- assert.deepEqual(m.table.map((r) => [r.matter, r.label, r.status, r.state]), [['board:2', 'A', 'needs you · today', 'needs'], ['board:1', 'B', 'moving · sun', 'moving']]);
244
- assert.equal(m.table[0].color, S.theme('light').accentText);
245
- assert.ok(m.hasTable);
243
+ assert.ok(!('table' in m) && !('hasTable' in m), 'no table fields on the model');
244
+ assert.doesNotMatch(m.label, /on the table/, 'the building\'s label no longer counts a table');
245
+ assert.match(m.label, /floors in use\.$/);
246
246
  });
247
247
 
248
248
  test('the record files the building\'s matters by the month each was opened, newest drawer first', () => {
@@ -524,7 +524,8 @@ const FEEDS = (ms, extra = {}) => ({
524
524
 
525
525
  test('the markup carries the interior: one persistent lift, two flip blocks, the panel and the back link', () => {
526
526
  const html = read('street.html').replace(/<!--[\s\S]*?-->/g, '');
527
- for (const id of ['streetInside', 'insideBack', 'insideSvg', 'insideFloors', 'insideLift', 'insideAnnex', 'insidePanel', 'insideName', 'insideAmend', 'insideAmendNote', 'insideFill', 'insideTable', 'insideOpenA', 'insideOpenB', 'insideDrawers', 'insideDrawerItems', 'insideDName', 'insideLegend', 'insideItems']) assert.match(html, new RegExp(`id="${id}"`), id);
527
+ for (const id of ['streetInside', 'insideBack', 'insideSvg', 'insideFloors', 'insideLift', 'insideAnnex', 'insidePanel', 'insideName', 'insideAmend', 'insideAmendNote', 'insideFill', 'insideOpenA', 'insideOpenB', 'insideDrawers', 'insideDrawerItems', 'insideDName', 'insideLegend', 'insideItems']) assert.match(html, new RegExp(`id="${id}"`), id);
528
+ assert.doesNotMatch(html, /insideTable|on the table here/i, 'the "on the table here" list is gone (task 1004565)');
528
529
  assert.equal((html.match(/<h1\b/g) || []).length, 1, 'the street keeps its one h1; the interior names are h2');
529
530
  assert.match(html, /<section class="inside" id="streetInside"[^>]*hidden>/, 'hidden until an address names a building or a district');
530
531
  assert.match(html, /<button type="button" class="inside-textbtn" id="insideAmend"/);
@@ -539,8 +540,7 @@ test('a building address draws the interior in place of the street, from the doc
539
540
  assert.equal(p.byId.get('insideFloors').children.length, 7, 'a button per floor in use');
540
541
  assert.equal(p.byId.get('insideFloors').children[4].attrs['aria-pressed'], 'true', 'the floor being decided is chosen');
541
542
  assert.equal(p.byId.get('insideLift').style.transform, 'translateY(-208px)');
542
- assert.equal(p.byId.get('insideTable').children.length, 1);
543
- assert.equal(p.byId.get('insideTable').children[0].className, 'inside-row inside-row--needs');
543
+ assert.equal(p.byId.get('insideTable'), undefined, 'no separate list of matters');
544
544
  assert.equal(p.byId.get('insideSeats').children[0].className, 'inside-seat inside-seat--open');
545
545
  assert.equal(p.focused.el, null, 'a page opened at the address keeps the browser\'s own start');
546
546
  p.location.hash = '#building=rules';
@@ -575,15 +575,17 @@ test('picking a floor moves the SAME lift node and re-enters the chosen block; d
575
575
  assert.match(p.byId.get('insideAmendNote').textContent, /could not be read/);
576
576
  });
577
577
 
578
- test('a table row opens the short card; Escape gives focus back to the row; back to the street returns to the door', async () => {
578
+ test('a matter is a desk row: its name opens it in place; back to the street returns to the door', async () => {
579
579
  const ms = [matter({ id: 'board:1', source: 'board', building: 'charter', state: 'needs', title: '<b>x</b>' })];
580
580
  const p = await bootPage({ hash: '#building=charter', feeds: FEEDS(ms) });
581
- p.byId.get('insideTable').children[0].fire('click');
582
- assert.equal(p.byId.get('streetCard').hidden, false);
583
- assert.equal(p.byId.get('streetCardTitle').textContent, '<b>x</b>', 'docket text lands as text');
584
- p.fireWin('keydown', { key: 'Escape', preventDefault() {} });
585
- assert.equal(p.byId.get('streetCard').hidden, true);
586
- assert.equal(p.focused.el.attrs['data-matter'], 'board:1', 'focus goes back to the row');
581
+ const desk = () => (p.byId.get('insideOpenA').hidden ? p.byId.get('insideOpenB') : p.byId.get('insideOpenA'));
582
+ const find = (el, pred) => { if (pred(el)) return el; for (const c of el.children) { const hit = find(c, pred); if (hit) return hit; } return null; };
583
+ const nameOf = () => find(desk(), (el) => el.attrs && el.attrs['data-matter'] === 'board:1');
584
+ assert.ok(nameOf(), 'the desk carries the matter as a row');
585
+ assert.equal(nameOf().attrs['aria-expanded'], 'false');
586
+ nameOf().fire('click');
587
+ assert.equal(nameOf().attrs['aria-expanded'], 'true', 'the row opens in place');
588
+ assert.equal(p.byId.get('streetCard').hidden, true, 'no card is needed inside: the desk acts');
587
589
  p.byId.get('insideBack').fire('click');
588
590
  assert.deepEqual(p.history, ['/builders/street']);
589
591
  assert.equal(p.byId.get('streetInside').hidden, true);