@bongos/core 1.21.113 → 1.21.115
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.
- package/.bongos-core.json +608 -188
- package/.claude/skills/ask-for-help/SKILL.md +1 -1
- package/.claude/skills/bongos-feedback/SKILL.md +1 -1
- package/.claude/skills/builder-sequence/SKILL.md +1 -1
- package/.claude/skills/builder-ship/SKILL.md +1 -0
- package/GOVERNMENT.md +128 -11
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +28 -0
- package/clients/bongos-client/index.cjs +28 -0
- package/clients/bongos-client/index.d.ts +45 -2
- package/clients/bongos-client/index.mjs +28 -0
- package/docs/adr/0372-an-ask-is-stored-per-docket-matter-and-the-server-refuses-slop.md +33 -0
- package/docs/adr/0373-an-ai-session-files-a-blocker-with-an-ask.md +31 -0
- package/docs/adr/0374-a-building-lead-is-a-held-position-appointed-by-a-people-matter.md +30 -0
- package/docs/adr/0375-who-may-build-without-a-vote-comes-from-the-form-of-government.md +38 -0
- package/docs/adr/0376-every-ask-is-routed-to-a-real-seat-on-the-server.md +30 -0
- package/docs/adr/0377-governance-is-a-held-position-read-on-me.md +24 -0
- package/docs/adr/0378-a-leads-build-outs-are-rows-built-at-once-or-by-a-passed-vote.md +33 -0
- package/docs/adr/0379-the-treasury-is-pots-per-goal-a-reserve-and-borrowing-over-real-spend.md +32 -0
- package/docs/adr/0380-a-strictness-preset-is-a-bundle-of-laws-switched-by-one-laws-vote.md +26 -0
- package/docs/adr/README.md +10 -1
- package/docs/api/openapi.json +989 -87
- package/docs/api-reference.md +18 -4
- package/docs/copy-inventory.md +709 -626
- package/docs/copy-registry.json +1673 -858
- package/docs/file-map.md +2 -1
- package/docs/module-api-changelog.md +4 -0
- package/docs/packs/engineer.md +2 -1
- package/docs/page-inventory.json +91 -6
- package/docs/page-readings.json +4875 -4748
- package/modules/builder-settings/law-locks.js +202 -0
- package/modules/builder-settings/routes/settings.js +66 -6
- package/modules/builder-settings/settings.js +7 -0
- package/modules/discord/ship-broadcast.js +22 -13
- package/modules/government/asks-db.js +54 -0
- package/modules/government/asks.js +269 -0
- package/modules/government/board-idea-reads.js +68 -0
- package/modules/government/board.js +21 -57
- package/modules/government/build-rights.js +148 -0
- package/modules/government/buildouts.js +160 -0
- package/modules/government/counts.js +81 -0
- package/modules/government/db.js +242 -0
- package/modules/government/decision-board.js +234 -8
- package/modules/government/decision-rules.js +2 -0
- package/modules/government/docket.js +114 -6
- package/modules/government/law-board.js +131 -0
- package/modules/government/laws.js +241 -0
- package/modules/government/leads.js +170 -0
- package/modules/government/migrations/government_027_laws.sql +143 -0
- package/modules/government/migrations/government_028_asks.sql +57 -0
- package/modules/government/migrations/government_029_leads.sql +135 -0
- package/modules/government/migrations/government_030_buildouts.sql +111 -0
- package/modules/government/migrations/government_031_treasury.sql +107 -0
- package/modules/government/module.json +2 -1
- package/modules/government/pollers/treasury-borrow.js +62 -0
- package/modules/government/positions.js +107 -0
- package/modules/government/presets.js +149 -0
- package/modules/government/routes/government.js +425 -2
- package/modules/government/routing.js +154 -0
- package/modules/government/treasury-db.js +166 -0
- package/modules/government/treasury.js +241 -0
- package/modules/hall-ui/public/atlas.html +2 -2
- package/modules/hall-ui/public/blockers.html +2 -2
- package/modules/hall-ui/public/board-room.html +2 -2
- package/modules/hall-ui/public/board-room.js +2 -0
- package/modules/hall-ui/public/city-draw.js +604 -11
- package/modules/hall-ui/public/city.css +157 -1
- package/modules/hall-ui/public/city.html +37 -7
- package/modules/hall-ui/public/city.js +441 -21
- package/modules/hall-ui/public/city.states.json +110 -5
- package/modules/hall-ui/public/collab.html +2 -2
- package/modules/hall-ui/public/commands.html +2 -2
- package/modules/hall-ui/public/copy-desk.html +2 -2
- package/modules/hall-ui/public/craft-mode.js +112 -29
- package/modules/hall-ui/public/deploy.html +2 -2
- package/modules/hall-ui/public/diagram-viewer.css +12 -0
- package/modules/hall-ui/public/diagram-viewer.js +4 -0
- package/modules/hall-ui/public/diagrams.html +2 -2
- package/modules/hall-ui/public/drachmae.html +2 -2
- package/modules/hall-ui/public/fleet.html +2 -2
- package/modules/hall-ui/public/gate.html +2 -2
- package/modules/hall-ui/public/goal-map.html +2 -2
- package/modules/hall-ui/public/goals.html +2 -2
- package/modules/hall-ui/public/gov-feeds.js +141 -0
- package/modules/hall-ui/public/gov-living.js +1002 -0
- package/modules/hall-ui/public/gov-positions.js +97 -0
- package/modules/hall-ui/public/government.html +2 -2
- package/modules/hall-ui/public/hall-render.js +3 -0
- package/modules/hall-ui/public/idea.html +2 -2
- package/modules/hall-ui/public/ideas.html +2 -2
- package/modules/hall-ui/public/index.html +3 -3
- package/modules/hall-ui/public/modules.html +2 -2
- package/modules/hall-ui/public/my-agents.css +334 -0
- package/modules/hall-ui/public/my-agents.html +72 -0
- package/modules/hall-ui/public/my-agents.js +603 -0
- package/modules/hall-ui/public/my-agents.states.json +37 -0
- package/modules/hall-ui/public/primer.html +2 -2
- package/modules/hall-ui/public/profile-connections.js +40 -28
- package/modules/hall-ui/public/profile.html +2 -2
- package/modules/hall-ui/public/project-settings.html +2 -2
- package/modules/hall-ui/public/ranks.html +2 -2
- package/modules/hall-ui/public/roadmap.html +2 -2
- package/modules/hall-ui/public/room.css +8 -0
- package/modules/hall-ui/public/roster.html +2 -2
- package/modules/hall-ui/public/sessions.html +2 -2
- package/modules/hall-ui/public/settings.html +2 -2
- package/modules/hall-ui/public/shell.js +116 -16
- package/modules/hall-ui/public/street-card.js +18 -1
- package/modules/hall-ui/public/street-deck.css +299 -0
- package/modules/hall-ui/public/street-deck.js +1145 -0
- package/modules/hall-ui/public/street-depth.js +712 -0
- package/modules/hall-ui/public/street-desk.js +5 -2
- package/modules/hall-ui/public/street-draw.js +109 -16
- package/modules/hall-ui/public/street-inside.js +137 -22
- package/modules/hall-ui/public/street-office.js +705 -0
- package/modules/hall-ui/public/street.css +161 -11
- package/modules/hall-ui/public/street.html +41 -11
- package/modules/hall-ui/public/street.js +78 -66
- package/modules/hall-ui/public/street.states.json +129 -21
- package/modules/hall-ui/public/studio.html +2 -2
- package/modules/hall-ui/public/style.css +5 -1
- package/modules/hall-ui/public/task.html +2 -2
- package/modules/hall-ui/public/thinking.html +2 -2
- package/modules/hall-ui/public/tweak-editor.html +2 -2
- package/modules/hall-ui/public/watch.html +2 -2
- package/modules/hall-ui/public/watch.js +14 -1
- package/modules/hall-ui/public/work.html +2 -2
- package/modules/hall-ui/records/living-city.md +57 -0
- package/modules/hall-ui/records/my-agents.md +21 -0
- package/modules/hall-ui/records/oversight-family.md +1 -0
- package/modules/hall-ui/records/profile-connections.md +10 -0
- package/modules/hall-ui/records/reading-rooms.md +2 -0
- package/modules/ideas/routes/blockers.js +92 -3
- package/modules/lifecycle/module.json +2 -1
- package/modules/lifecycle/moving.js +17 -1
- package/modules/lifecycle/routes/moving.js +6 -0
- package/modules/lifecycle/routes/project-settings.js +23 -0
- package/modules/onboarding/approval-broadcast.js +8 -0
- package/modules/onboarding/routes/access-requests.js +16 -6
- package/modules/platform-identity/connections.js +13 -2
- package/modules/platform-identity/routes/connections.js +7 -1
- package/modules/public-landing/public/account-private.states.json +2 -2
- package/modules/public-landing/public/account.html +65 -5
- package/modules/public-landing/public/account.states.json +3 -3
- package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.jpg.json +1 -1
- package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp +0 -0
- package/modules/public-landing/public/assets/world/r2-bongos-chrome-b.webp.json +13 -0
- package/modules/public-landing/public/assets/world/r2-chrome-blob-one.jpg.json +1 -1
- package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp +0 -0
- package/modules/public-landing/public/assets/world/r2-chrome-blob-one.webp.json +13 -0
- package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.jpg.json +1 -1
- package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp +0 -0
- package/modules/public-landing/public/assets/world/r2-chrome-blobs-set.webp.json +13 -0
- package/modules/public-landing/public/assets/world.css +4 -4
- package/modules/public-landing/public/connections-empty.states.json +14 -0
- package/modules/public-landing/public/connections-inactive.states.json +14 -0
- package/modules/public-landing/public/connections.html +450 -0
- package/modules/public-landing/public/connections.probes.json +414 -0
- package/modules/public-landing/public/connections.states.json +17 -0
- package/modules/public-landing/public/contact.html +2 -2
- package/modules/public-landing/public/guild.html +2 -2
- package/modules/public-landing/public/index.html +2 -2
- package/modules/public-landing/public/invitations.html +2 -2
- package/modules/public-landing/public/privacy.html +2 -2
- package/modules/public-landing/public/projects-hall-live.states.json +0 -5
- package/modules/public-landing/public/projects.html +169 -6
- package/modules/public-landing/public/projects.probes.json +10 -6
- package/modules/public-landing/public/projects.states.json +13 -13
- package/modules/public-landing/public/terms.html +2 -2
- package/modules/ui-design/kit/fixtures/connections-empty.json +12 -0
- package/modules/ui-design/kit/fixtures/connections-inactive.json +7 -0
- package/modules/ui-design/kit/fixtures/connections.json +22 -0
- package/modules/ui-design/kit/serve.js +95 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +128 -0
- package/scripts/discord/README.md +8 -5
- package/scripts/discord/post.js +12 -1
- package/scripts/gds/artifact-audit.js +20 -3
- package/scripts/gds/ask.js +164 -0
- package/scripts/gds/autobongos-verify.js +21 -2
- package/scripts/gds/government-walk.js +638 -4
- package/scripts/gds/pulse.js +9 -6
- package/scripts/gds/ship-escalation.js +22 -3
- package/scripts/gds/ship-finish.js +5 -4
- package/scripts/gds/ship-merge-gate.js +18 -6
- package/scripts/hall-preview/README.md +41 -1
- package/scripts/hall-preview/pref-writes.js +140 -0
- package/scripts/hall-preview/refresh-fixtures.js +101 -7
- package/scripts/hall-preview/scrub-identity.js +366 -7
- package/scripts/hall-preview/server.js +27 -1
- package/scripts/render-diagrams.sh +4 -2
- package/src/bongos/auth-idp.js +6 -1
- package/src/bongos/project-settings.js +41 -0
- package/src/bongos/route-rank-check.js +27 -0
- package/src/bongos/routes/me.js +68 -7
- package/src/bongos/serve-internal.js +5 -1
- package/src/module-api.js +7 -1
- package/src/platform-server.js +10 -0
- package/tests/application_lifecycle.mjs +47 -5
- package/tests/conductor_main_e2e.mjs +21 -0
- package/tests/connections_api.mjs +18 -0
- package/tests/craft_mode_nav.mjs +5 -3
- package/tests/craft_mode_tallies.mjs +52 -16
- package/tests/discord_approvals.mjs +11 -0
- package/tests/discord_channels.mjs +20 -0
- package/tests/fixtures/gov-seated.mjs +64 -0
- package/tests/fixtures/government-ask-cards.json +1284 -0
- package/tests/government_act_alone_buildings.mjs +1 -0
- package/tests/government_agent_asks.mjs +322 -0
- package/tests/government_asks.mjs +408 -0
- package/tests/government_build_rights.mjs +253 -0
- package/tests/government_buildouts.mjs +382 -0
- package/tests/government_counts.mjs +143 -0
- package/tests/government_decision_rules.mjs +5 -1
- package/tests/government_laws.mjs +488 -0
- package/tests/government_laws_session.mjs +321 -0
- package/tests/government_leads.mjs +375 -0
- package/tests/government_positions.mjs +127 -0
- package/tests/government_presets.mjs +215 -0
- package/tests/government_routes.mjs +8 -1
- package/tests/government_routing.mjs +118 -0
- package/tests/government_seed.mjs +5 -0
- package/tests/government_treasury.mjs +394 -0
- package/tests/governor_docket.mjs +26 -2
- package/tests/hall_buildouts.mjs +208 -0
- package/tests/hall_city.mjs +14 -6
- package/tests/hall_city_living.mjs +617 -0
- package/tests/hall_gov_counts.mjs +336 -0
- package/tests/hall_gov_living.mjs +636 -0
- package/tests/hall_gov_real_site.mjs +655 -0
- package/tests/hall_matter_card.mjs +6 -1
- package/tests/hall_my_agents.mjs +481 -0
- package/tests/hall_nav.mjs +107 -4
- package/tests/hall_page_gate_map.mjs +4 -0
- package/tests/hall_preview_governor_fixtures.mjs +30 -3
- package/tests/hall_preview_scrub.mjs +59 -1
- package/tests/hall_preview_security.mjs +169 -0
- package/tests/hall_reading_world.mjs +44 -0
- package/tests/hall_roster_world.mjs +6 -2
- package/tests/hall_street.mjs +18 -2
- package/tests/hall_street_amend.mjs +1 -1
- package/tests/hall_street_deck.mjs +609 -0
- package/tests/hall_street_depth.mjs +559 -0
- package/tests/hall_street_desk.mjs +1 -1
- package/tests/hall_street_inside.mjs +29 -5
- package/tests/hall_tweak_editor.mjs +4 -1
- package/tests/hub_account_page.mjs +94 -3
- package/tests/hub_connections_page.mjs +507 -0
- package/tests/hub_invite_badge.mjs +1 -1
- package/tests/idp_device_exchange.mjs +18 -0
- package/tests/landing_legal_pages.mjs +8 -5
- package/tests/landing_page.mjs +23 -4
- package/tests/nav_permission_atoms.mjs +4 -1
- package/tests/profile_connections_ui.mjs +88 -25
- package/tests/projects_hub.mjs +15 -0
- package/tests/projects_hub_pre_uat.mjs +4 -2
- package/tests/render_check.mjs +2 -2
- package/tests/ship_broadcast_routing.mjs +57 -16
- package/tests/ship_broadcast_server.mjs +40 -7
- package/tests/ship_merge_gate.mjs +19 -0
- package/tests/ui_design_kit.mjs +2 -2
- package/tests/watch_applications_queue.mjs +23 -0
- package/tests/wizard_physics.mjs +1 -1
- package/tests/wizard_physics_more.mjs +133 -0
|
@@ -73,6 +73,28 @@ const floorRow = (key, over = {}) => ({ key, building: key.split('.')[0], status
|
|
|
73
73
|
|
|
74
74
|
// ── the drawing is the prototype's ───────────────────────────────────────────
|
|
75
75
|
|
|
76
|
+
// The one place the hall departs from the prototype's section (task 1004718): the
|
|
77
|
+
// chosen floor lit in the prototype's warm wash, salmon frame, salmon sign and
|
|
78
|
+
// salmon level number, which spends salmon on a floor that may need nothing.
|
|
79
|
+
// The hall lights it in ink. inked() turns the prototype's chosen floor into
|
|
80
|
+
// the hall's, colour for colour and nothing else, so every shape, path and
|
|
81
|
+
// position still has to match the prototype exactly.
|
|
82
|
+
const INKED = {
|
|
83
|
+
dark: { '#2b2219': '#202025', '#ffd9a8': '#e6e6ea', 'rgba(255,217,168,0.10)': 'rgba(255,255,255,0.07)', 'rgba(255,214,170,0.55)': 'rgba(220,224,240,0.40)', ink: '#ffffff' },
|
|
84
|
+
light: { '#fdf0e2': '#ebeaee', '#f0a86a': '#55565a', 'rgba(240,168,106,0.12)': 'rgba(23,24,26,0.06)', 'rgba(240,168,106,0.45)': 'rgba(23,24,26,0.22)', ink: '#17181a' },
|
|
85
|
+
};
|
|
86
|
+
function inked(view, mode) {
|
|
87
|
+
const M = INKED[mode], accentText = S.theme(mode).accentText;
|
|
88
|
+
const v = j(view);
|
|
89
|
+
v.shapes = v.shapes.map((s) => Object.assign(s, {
|
|
90
|
+
f: M[s.f] || s.f,
|
|
91
|
+
s: s.s === '#fb9569' && s.dash === 'none' && s.w === 1.5 ? M.ink : s.s,
|
|
92
|
+
}));
|
|
93
|
+
v.texts = v.texts.map((t) => (/^\d\d$/.test(t.v) && t.c === accentText ? Object.assign(t, { c: M.ink }) : t));
|
|
94
|
+
v.syms = v.syms.map((s) => (s.c === '#fb9569' ? Object.assign(s, { c: M.ink }) : s));
|
|
95
|
+
return v;
|
|
96
|
+
}
|
|
97
|
+
|
|
76
98
|
const SECTION_KEYS = ['kicker', 'name', 'holds', 'whoText', 'howText', 'seats', 'fill', 'fillColor', 'growth', 'openKicker', 'sym', 'flipA', 'flipB', 'openTitle', 'openLines', 'drawerItems', 'onFile', 'shapes', 'texts', 'syms', 'lift', 'hasAnnex', 'annex'];
|
|
77
99
|
|
|
78
100
|
test('every building in section is the prototype\'s, to the path, in both modes, before and after a pick', () => {
|
|
@@ -81,7 +103,7 @@ test('every building in section is the prototype\'s, to the path, in both modes,
|
|
|
81
103
|
for (const st of [{}, { reviewHeld: true, floor: 1, drawer: 1, picks: 3 }, { floor: 99, drawer: 7, picks: 2 }]) {
|
|
82
104
|
for (const key of S.CIVIC_KEYS) {
|
|
83
105
|
const p = proto(mode, { view: key, ...st });
|
|
84
|
-
const want = p.buildingView(p.theme(mode), key, p.matters());
|
|
106
|
+
const want = inked(p.buildingView(p.theme(mode), key, p.matters()), mode);
|
|
85
107
|
const vacant = key === 'review' && !p.state.reviewHeld;
|
|
86
108
|
const got = I.buildingView(S.theme(mode), key, p.civicInfo(key), { floor: p.state.floor, drawer: p.state.drawer, picks: p.state.picks, vacant, reviewHeld: p.state.reviewHeld, evening: false });
|
|
87
109
|
for (const k of SECTION_KEYS) assert.deepEqual(j(got[k]), j(want[k]), `${mode} ${key} ${JSON.stringify(st)} ${k}`);
|
|
@@ -385,9 +407,11 @@ test('the lift runs to the chosen floor, and the chosen block flips on every pic
|
|
|
385
407
|
assert.equal(b.selFloor, 7, 'a pick past the top is the top floor');
|
|
386
408
|
assert.deepEqual([b.flipA, b.flipB], [true, false]);
|
|
387
409
|
assert.ok(b.floors[7].selected && !b.floors[2].selected);
|
|
388
|
-
|
|
389
|
-
assert.
|
|
390
|
-
assert.ok(a.
|
|
410
|
+
// the chosen floor is framed and signed in ink: salmon is only what needs you (task 1004718)
|
|
411
|
+
assert.ok(a.shapes.some((s) => s.s === '#ffffff' && s.w === 1.5 && s.dash === 'none'), 'the ink frame');
|
|
412
|
+
assert.ok(!a.shapes.some((s) => s.s === '#fb9569' && s.dash === 'none'), 'no solid salmon frame');
|
|
413
|
+
assert.equal(a.syms[2].c, '#ffffff', 'and the ink sign on the chosen floor only');
|
|
414
|
+
assert.ok(a.syms.filter((s, i) => i !== 2).every((s) => s.c !== '#ffffff' && s.c !== '#fb9569'));
|
|
391
415
|
});
|
|
392
416
|
|
|
393
417
|
// ── districts ──────────────────────────────────────────────────────────────
|
|
@@ -508,7 +532,7 @@ async function bootPage({ hash = '', feeds = {}, innerWidth = 1440 } = {}) {
|
|
|
508
532
|
};
|
|
509
533
|
const ctx = vm.createContext({ window, document, fetch, Promise, Math, String, Number, Array, Object, JSON, Date, console, encodeURIComponent, decodeURIComponent, isNaN, isFinite, Map });
|
|
510
534
|
ctx.globalThis = ctx;
|
|
511
|
-
for (const f of ['city-draw.js', 'street-draw.js', 'street-card.js', 'street-inside.js', 'street-desk.js', 'street.js']) vm.runInContext(read(f), ctx);
|
|
535
|
+
for (const f of ['city-draw.js', 'street-draw.js', 'street-card.js', 'street-inside.js', 'street-depth.js', 'street-desk.js', 'street.js']) vm.runInContext(read(f), ctx);
|
|
512
536
|
await window.GovStreetPage.ready;
|
|
513
537
|
await new Promise((r) => setTimeout(r, 0));
|
|
514
538
|
const fireWin = (t, e) => (listeners[t] || []).forEach((fn) => fn(e));
|
|
@@ -651,7 +651,10 @@ try {
|
|
|
651
651
|
assert.match(HTML, /<body data-page="tweak-editor"[^>]*data-fullscreen-switch/);
|
|
652
652
|
assert.equal((HTML.match(/<h1\b/g) || []).length, 1);
|
|
653
653
|
assert.ok(HTML.indexOf('tweak-editor-lib.js') < HTML.indexOf('tweak-editor.js?'), 'the lib loads first');
|
|
654
|
-
|
|
654
|
+
// the page carries the shell's current cache-bust, the one every hall page carries
|
|
655
|
+
// (read off the index, so a bump of the shell's stamp moves this pin with it)
|
|
656
|
+
const stamp = /shell\.js\?v=([\w.-]+)/.exec(fs.readFileSync(path.join(ROOT, 'modules/hall-ui/public/index.html'), 'utf8'))[1];
|
|
657
|
+
assert.ok(HTML.includes('shell.js?v=' + stamp), 'shell.js?v=' + stamp);
|
|
655
658
|
assert.equal(/fonts\.googleapis\.com\/css/.test(HTML), false);
|
|
656
659
|
for (const id of ['tw-bar', 'tw-counter', 'tw-open', 'tw-open-more', 'tw-divider', 'tw-openwrap', 'tw-open-menu', 'tw-open-tab', 'tw-open-split', 'tw-frame', 'tw-frame-view', 'tw-split-close', 'tw-download', 'tw-upload', 'tw-file', 'tw-submit', 'tw-paper', 'tw-doc', 'tw-notice', 'tw-done', 'tw-take', 'tw-pick', 'tw-picks', 'tw-refused', 'tw-refused-title', 'tw-refused-list', 'tw-refused-next', 'tw-refused-download', 'tw-refused-close']) {
|
|
657
660
|
assert.ok(new RegExp(`id="${id}"`).test(HTML), `#${id} is in the markup`);
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
// the builders/status hosts, and never on a child instance;
|
|
15
15
|
// 5. the hall's side: the two privacy sections are gone, one link-out row
|
|
16
16
|
// remains, and its hub origin is a bare https origin or nothing;
|
|
17
|
+
// 7. the guild notice (task 1004260, ADR 0337 D4.4): under Private and under
|
|
18
|
+
// Hide, for the choice as it stands, the sentence that a guild counts your
|
|
19
|
+
// numbers and a link to each of your guilds' own switch — never the switch;
|
|
17
20
|
// 6. the bar (task 1004455): the hub's own bar and two bands rather than a
|
|
18
21
|
// header of its own — the same markup as projects.html, cosmos.css's rules,
|
|
19
22
|
// no map search, links into /projects, Account as the current place — and
|
|
@@ -81,7 +84,7 @@ test('the script builds no markup from strings, and the controls are real markup
|
|
|
81
84
|
test('the door returns here, and the page calls only its own-scoped routes', () => {
|
|
82
85
|
assert.match(PAGE, /href="\/api\/bongos\/auth\/web\/start\?return=\/account&repos=1"/, 'sign-in lands back on /account, asking for repo access once (task 1004549)');
|
|
83
86
|
const calls = [...SCRIPT.matchAll(/request\('(GET|PATCH|POST)', '([^']+)'/g)].map((m) => `${m[1]} ${m[2]}`);
|
|
84
|
-
assert.deepEqual([...new Set(calls)].sort(), ['GET /me/cross-project', 'PATCH /me/cross-project', 'PATCH /me/handle', 'PATCH /me/profile', 'GET /my-projects', 'POST /my-projects/'].sort());
|
|
87
|
+
assert.deepEqual([...new Set(calls)].sort(), ['GET /me/cross-project', 'PATCH /me/cross-project', 'PATCH /me/handle', 'PATCH /me/profile', 'GET /my-projects', 'POST /my-projects/', 'GET /me/guilds'].sort());
|
|
85
88
|
// the bar's two calls live in the shared asset: the identity read and sign out
|
|
86
89
|
const barCalls = [...BAR.matchAll(/fetch\(API \+ '([^']+)', \{ method: '(GET|POST)'/g)].map((m) => `${m[2]} ${m[1]}`);
|
|
87
90
|
assert.deepEqual(barCalls.sort(), ['GET /me', 'POST /auth/logout']);
|
|
@@ -134,7 +137,7 @@ test('the bands say what the hub’s say and lead into /projects; Account is the
|
|
|
134
137
|
['Your projects', '/projects?view=mine'], ['New project', '/projects?view=new'],
|
|
135
138
|
], 'this page has no views of its own, so every item names /projects in full');
|
|
136
139
|
assert.deepEqual(bandLinks(bandOf(PAGE, 'menuProfile')), [
|
|
137
|
-
['My projects', '/projects?view=mine'], ['Invitations', '/invitations'], ['Account', '/account'], ['Sign out', '/api/bongos/auth/logout'],
|
|
140
|
+
['My projects', '/projects?view=mine'], ['Invitations', '/invitations'], ['Connections', '/connections'], ['Account', '/account'], ['Sign out', '/api/bongos/auth/logout'],
|
|
138
141
|
]);
|
|
139
142
|
assert.deepEqual(PAGE.match(/<a [^>]*aria-current="page"[^>]*>[^<]+/g), ['<a class="bandT" href="/account" aria-current="page">Account']);
|
|
140
143
|
});
|
|
@@ -488,7 +491,7 @@ test('the section ships inside the signed-in body, last, as a list with an empty
|
|
|
488
491
|
test('signed in: the list is read once, after the account, and each row names its project and host with its own Leave', async () => {
|
|
489
492
|
const dom = boot(building(BUILDING));
|
|
490
493
|
await settle();
|
|
491
|
-
assert.deepEqual(dom.calls.filter((c) => c.method === 'GET' && c.path !== '/me').map((c) => c.path), ['/me/cross-project', '/my-projects']);
|
|
494
|
+
assert.deepEqual(dom.calls.filter((c) => c.method === 'GET' && c.path !== '/me').map((c) => c.path), ['/me/cross-project', '/my-projects', '/me/guilds']);
|
|
492
495
|
assert.equal(dom.els.get('buildingLoading').hidden, true);
|
|
493
496
|
assert.equal(dom.els.get('buildingEmpty').hidden, true);
|
|
494
497
|
const rows = rowsOf(dom);
|
|
@@ -566,6 +569,94 @@ test('/projects keeps no copy: the mine view points here, and nothing there read
|
|
|
566
569
|
assert.match(SCRIPT, /if \(target && typeof target\.scrollIntoView === 'function'\) target\.scrollIntoView\(\);/, 'and #aBuilding lands on the section once the body shows');
|
|
567
570
|
});
|
|
568
571
|
|
|
572
|
+
// ── 3c. the guilds that count your numbers (task 1004260, ADR 0337 D4.4) ─────
|
|
573
|
+
// Every guild counts a member's numbers in its rounded totals unless they leave
|
|
574
|
+
// them out on that guild's page — a private account and a hidden record included.
|
|
575
|
+
// So Private and Hide each say so, for the choice as it stands, and list the
|
|
576
|
+
// builder's guilds with a link to each one's switch. The switch is the guild
|
|
577
|
+
// page's: this page reads GET /me/guilds and writes nothing to a guild.
|
|
578
|
+
|
|
579
|
+
const GUILDS = [
|
|
580
|
+
{ slug: 'forge-crew', name: 'Forge Crew', visibility: 'public', membership_kind: 'member', shown_publicly: false, counted_in_totals: true },
|
|
581
|
+
{ slug: 'night-shift', name: 'Night Shift', visibility: 'unlisted', membership_kind: 'owner', shown_publicly: false, counted_in_totals: false },
|
|
582
|
+
];
|
|
583
|
+
const GUILD_PAGE = fs.readFileSync(path.join(LANDING, 'guild.html'), 'utf8').replace(/\r\n/g, '\n');
|
|
584
|
+
const withGuilds = (rows, acct = ACCOUNT) => (m, p) => {
|
|
585
|
+
if (m === 'GET' && p === '/me/cross-project') return { status: 200, data: acct() };
|
|
586
|
+
if (m === 'GET' && p === '/me/guilds') return rows ? { status: 200, data: { guilds: rows, count: rows.length } } : { status: 500, data: null };
|
|
587
|
+
return m === 'GET' ? { status: 500, data: null } : { status: 200, data: {} };
|
|
588
|
+
};
|
|
589
|
+
const guildLinks = (dom, key) => dom.els.get(key + 'GuildList').children.map((li) => ({
|
|
590
|
+
href: li.children[0].href, name: li.children[0].textContent, state: li.children[1].textContent,
|
|
591
|
+
}));
|
|
592
|
+
|
|
593
|
+
test('the notice ships hidden under each choice, as real markup, and the guild page is the only place a switch lives', () => {
|
|
594
|
+
for (const key of ['vis', 'record']) {
|
|
595
|
+
assert.match(PAGE, new RegExp(`<div class="aGuilds" id="${key}Guilds" hidden><p class="aWhat" id="${key}GuildsWhat"></p><ul class="aGuildList" id="${key}GuildList"></ul></div>`));
|
|
596
|
+
}
|
|
597
|
+
assert.ok(PAGE.indexOf('id="visGuilds"') < PAGE.indexOf('id="recLabel"'), 'under the profile-page choice, before recruiters');
|
|
598
|
+
assert.ok(PAGE.indexOf('id="recordGuilds"') > PAGE.indexOf('name="record" value="hide"'), 'under the show/hide choice');
|
|
599
|
+
assert.doesNotMatch(SCRIPT, /counted_in_totals:|\/membership|name="counted"/, 'no switch drawn or written here');
|
|
600
|
+
});
|
|
601
|
+
|
|
602
|
+
test('the notice speaks the guild page’s words: rounded to a band, counted weekly, never shown on its own', () => {
|
|
603
|
+
for (const words of ['They are never shown on their own: only inside totals rounded down to a band (10+, 20+, 50+ …) and counted once a week. ']) {
|
|
604
|
+
assert.ok(GUILD_PAGE.includes(words) && SCRIPT.includes(words), `"${words}" on both pages`);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
test('public and shown: no notice; picking Private or Hide shows it under that choice alone, before any save', async () => {
|
|
609
|
+
const dom = boot(withGuilds(GUILDS));
|
|
610
|
+
await settle();
|
|
611
|
+
assert.equal(dom.els.get('visGuilds').hidden, true, 'a public page says nothing about guilds');
|
|
612
|
+
assert.equal(dom.els.get('recordGuilds').hidden, true);
|
|
613
|
+
dom.pick('visibility', 'private');
|
|
614
|
+
assert.equal(dom.els.get('visGuilds').hidden, false);
|
|
615
|
+
assert.equal(dom.els.get('recordGuilds').hidden, true, 'only the choice that applies');
|
|
616
|
+
assert.equal(dom.text('visGuildsWhat'), 'Every guild you belong to counts your numbers in its rounded totals unless you leave them out — even while your profile page is private. ' +
|
|
617
|
+
'They are never shown on their own: only inside totals rounded down to a band (10+, 20+, 50+ …) and counted once a week. Each guild’s page has the switch:');
|
|
618
|
+
dom.pick('record', 'hide');
|
|
619
|
+
assert.equal(dom.els.get('recordGuilds').hidden, false);
|
|
620
|
+
assert.match(dom.text('recordGuildsWhat'), /unless you leave them out — even while your record is hidden\. /);
|
|
621
|
+
dom.pick('visibility', 'public');
|
|
622
|
+
assert.equal(dom.els.get('visGuilds').hidden, true, 'and goes again with the choice');
|
|
623
|
+
assert.equal(dom.calls.filter((c) => c.method !== 'GET').length, 0, 'picking sends nothing');
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
test('each guild links to its own page, with its current answer beside it', async () => {
|
|
627
|
+
const dom = boot(withGuilds([...GUILDS, { slug: 'a b', name: null, counted_in_totals: true }]));
|
|
628
|
+
await settle();
|
|
629
|
+
dom.pick('record', 'hide');
|
|
630
|
+
assert.deepEqual(guildLinks(dom, 'record'), [
|
|
631
|
+
{ href: '/g/forge-crew', name: 'Forge Crew', state: ' · counted' },
|
|
632
|
+
{ href: '/g/night-shift', name: 'Night Shift', state: ' · left out' },
|
|
633
|
+
{ href: '/g/a%20b', name: 'a b', state: ' · counted' },
|
|
634
|
+
], 'the slug is encoded, never spliced raw, and a missing name falls back to it');
|
|
635
|
+
});
|
|
636
|
+
|
|
637
|
+
test('a private, hidden account sees both notices on load; in no guild, neither', async () => {
|
|
638
|
+
const hiddenPrivate = () => ({ ...ACCOUNT(), account_visibility: 'private', hide_stats: true });
|
|
639
|
+
const dom = boot(withGuilds(GUILDS, hiddenPrivate));
|
|
640
|
+
await settle();
|
|
641
|
+
assert.equal(dom.els.get('visGuilds').hidden, false);
|
|
642
|
+
assert.equal(dom.els.get('recordGuilds').hidden, false);
|
|
643
|
+
assert.equal(guildLinks(dom, 'vis').length, 2);
|
|
644
|
+
const none = boot(withGuilds([], hiddenPrivate));
|
|
645
|
+
await settle();
|
|
646
|
+
assert.equal(none.els.get('visGuilds').hidden, true, 'no guild, nothing to say');
|
|
647
|
+
assert.equal(none.els.get('recordGuilds').hidden, true);
|
|
648
|
+
});
|
|
649
|
+
|
|
650
|
+
test('a failed guild read still says the sentence, with no list, and keeps the rest of the page', async () => {
|
|
651
|
+
const dom = boot(withGuilds(null));
|
|
652
|
+
await settle();
|
|
653
|
+
assert.equal(dom.els.get('acctBody').hidden, false);
|
|
654
|
+
dom.pick('visibility', 'private');
|
|
655
|
+
assert.equal(dom.els.get('visGuilds').hidden, false, 'not knowing your guilds is no reason to stay quiet');
|
|
656
|
+
assert.match(dom.text('visGuildsWhat'), /Each guild’s page has the switch\.$/);
|
|
657
|
+
assert.equal(dom.els.get('visGuildList').children.length, 0);
|
|
658
|
+
});
|
|
659
|
+
|
|
569
660
|
// ── 3b. the bar, executed (task 1004455) ─────────────────────────────────────
|
|
570
661
|
|
|
571
662
|
const ME = { builder: { id: '1', github_login: 'octocat', avatar_url: 'https://avatars.example/u/1' } };
|