@bongos/core 1.19.115 → 1.19.117
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 +39 -24
- package/clients/bongos-client/index.d.ts +2 -2
- package/docs/api/openapi.json +6 -0
- package/docs/api-reference.md +2 -2
- package/modules/platform-identity/migrations/platform_identity_006_project_type.sql +23 -0
- package/modules/platform-identity/platform-identity.js +20 -10
- package/modules/platform-identity/routes/projects.js +2 -0
- package/modules/platform-identity/tests/platform-identity.mjs +14 -0
- package/modules/provisioning/migrations/provisioning_007_project_type.sql +24 -0
- package/modules/provisioning/provisioning.js +17 -5
- package/modules/provisioning/routes/provisioning.js +14 -0
- package/modules/provisioning/tests/provisioning.mjs +7 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/public-landing/assets/cosmos.css +5 -1
- package/public-landing/projects.html +150 -34
- package/scripts/gds/provision.js +3 -1
- package/scripts/gds/seed-bv1-profile-page-tasks.js +161 -0
- package/src/module-api.js +5 -1
- package/tests/cosmos_token_contrast.mjs +7 -0
- package/tests/projects_hub.mjs +42 -11
|
@@ -178,6 +178,13 @@ const PAIRS = [
|
|
|
178
178
|
// alone do not cover them
|
|
179
179
|
['?view=new .ghrow .priv 11px', 'var(--ink-soft)', 'color-mix(in srgb,var(--ink) 8%,var(--bg-deep))', 4.5],
|
|
180
180
|
['--on-ok on an --ok fill', 'var(--on-ok)', 'var(--ok)', 4.5],
|
|
181
|
+
// the wizard's per-type description card (task 1002772): heading ink is a
|
|
182
|
+
// 40%-accent ink mix over the card's own 9%-accent tint — one row per type
|
|
183
|
+
['typeCard heading · game', 'color-mix(in srgb,var(--accent) 40%,var(--ink))', 'color-mix(in srgb,var(--accent) 9%,var(--bg-card))', 4.5],
|
|
184
|
+
['typeCard heading · research', 'color-mix(in srgb,var(--sea) 40%,var(--ink))', 'color-mix(in srgb,var(--sea) 9%,var(--bg-card))', 4.5],
|
|
185
|
+
['typeCard heading · business', 'color-mix(in srgb,var(--terracotta) 40%,var(--ink))', 'color-mix(in srgb,var(--terracotta) 9%,var(--bg-card))', 4.5],
|
|
186
|
+
['typeCard heading · non-profit', 'color-mix(in srgb,var(--gold-soft) 40%,var(--ink))', 'color-mix(in srgb,var(--gold-soft) 9%,var(--bg-card))', 4.5],
|
|
187
|
+
['typeCard heading · not-sure', 'color-mix(in srgb,var(--rule-soft) 40%,var(--ink))', 'color-mix(in srgb,var(--rule-soft) 9%,var(--bg-card))', 4.5],
|
|
181
188
|
['?view=new input ::placeholder', 'var(--ink-faint)', CARD, 4.5],
|
|
182
189
|
['?view=new .ghlist .hint on deep', 'var(--ink-faint)', 'var(--bg-deep)', 4.5],
|
|
183
190
|
['--chrome-accent wordmark', 'var(--chrome-accent)', 'var(--page-bg)', 4.5],
|
package/tests/projects_hub.mjs
CHANGED
|
@@ -228,11 +228,37 @@ test('/create is absorbed — the wizard lives here and the route only redirects
|
|
|
228
228
|
const server = fs.readFileSync(path.join(ROOT, 'src', 'platform-server.js'), 'utf8');
|
|
229
229
|
assert.match(server, /res\.redirect\(302, '\/projects\?view=new'/,
|
|
230
230
|
'/create must 302 into the hub (302, not 301: the URL is an OAuth return target in the wild)');
|
|
231
|
-
for (const id of ['panel-gate', 'panel-name', 'panel-home', 'panel-address', 'panel-review', 'panel-done']) {
|
|
231
|
+
for (const id of ['panel-gate', 'panel-name', 'panel-type', 'panel-home', 'panel-address', 'panel-review', 'panel-done']) {
|
|
232
232
|
assert.match(HUB, new RegExp(`id="${id}"`), `the wizard's ${id} ships as real markup (C7)`);
|
|
233
233
|
}
|
|
234
234
|
});
|
|
235
235
|
|
|
236
|
+
test('the wizard step indices stay coupled — data-next lands one past its own panel (task 1002772)', () => {
|
|
237
|
+
// The whole renumbering turns on validateStep(next - 1): a form's data-next
|
|
238
|
+
// must sit inside panels[next - 1], or the validator guards the wrong step.
|
|
239
|
+
const pm = SCRIPT.match(/var panels = \{([^}]*)\}/);
|
|
240
|
+
assert.ok(pm, 'the panels map must exist');
|
|
241
|
+
const map = {};
|
|
242
|
+
for (const m of pm[1].matchAll(/(\d+):\s*'([a-z-]+)'/g)) map[Number(m[1])] = m[2];
|
|
243
|
+
const nexts = [...HUB.matchAll(/data-next="(\d+)"/g)];
|
|
244
|
+
assert.ok(nexts.length >= 4, 'every wizard form declares its next step');
|
|
245
|
+
for (const m of nexts) {
|
|
246
|
+
const before = HUB.slice(0, m.index);
|
|
247
|
+
const sec = before.lastIndexOf('id="panel-');
|
|
248
|
+
assert.ok(sec !== -1, 'a data-next form lives inside a panel');
|
|
249
|
+
const id = HUB.slice(sec + 4).match(/^(panel-[a-z]+)/)[1];
|
|
250
|
+
assert.equal(id, map[Number(m[1]) - 1],
|
|
251
|
+
`data-next="${m[1]}" must live in panels[${Number(m[1]) - 1}] — validateStep(next-1) guards that panel`);
|
|
252
|
+
}
|
|
253
|
+
for (const m of HUB.matchAll(/data-back="(\d+)"/g)) {
|
|
254
|
+
assert.ok(map[Number(m[1])], `data-back="${m[1]}" must point at a mapped panel`);
|
|
255
|
+
}
|
|
256
|
+
// the rail numbers every step except the gate and the done panel
|
|
257
|
+
const beats = [...HUB.matchAll(/data-step="(\d+)"/g)].map((x) => Number(x[1]));
|
|
258
|
+
assert.equal(Math.max.apply(null, beats), Object.keys(map).length - 2,
|
|
259
|
+
'the rail shows every numbered step except gate and done');
|
|
260
|
+
});
|
|
261
|
+
|
|
236
262
|
test('the absorbed wizard sheds its two URL landmines — /gate/ and the whole-query strip', () => {
|
|
237
263
|
// create.html carried a document-level Escape that navigated to the retired
|
|
238
264
|
// /gate/ (a 404 the href-only guard above cannot see: it was a
|
|
@@ -475,18 +501,21 @@ test('the row keeps its own Open link working underneath the card', () => {
|
|
|
475
501
|
The mock's columns shipped whole — Project / Builders / Type / Tags / Status
|
|
476
502
|
— but three of them rendered an em dash for every row, forever, because the
|
|
477
503
|
public projection carries four fields and Type/Tags are not in the catalog
|
|
478
|
-
schema at all. A header promising a column is a claim like any other.
|
|
504
|
+
schema at all. A header promising a column is a claim like any other.
|
|
505
|
+
Builders and Runs came back with a source in task 1002771; Type came back in
|
|
506
|
+
task 1002772 when a project began DECLARING it at creation — a nullable
|
|
507
|
+
declared field, so an em dash now means "not declared", never a guess. ── */
|
|
479
508
|
|
|
480
|
-
test('
|
|
509
|
+
test('every table column has a source — Type is declared, never guessed', () => {
|
|
481
510
|
const thead = (HUB.match(/<thead>([\s\S]*?)<\/thead>/) || [, ''])[1];
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
assert.doesNotMatch(thead, />Type</, 'Type has no source until a project declares it');
|
|
485
|
-
// Builders and Runs came back in task 1002771 WITH a source behind them
|
|
511
|
+
assert.match(thead, />Type</, 'Type has a source now: the project declares it at creation (task 1002772)');
|
|
512
|
+
assert.match(SCRIPT, /typeHtml\(p\.type\)/, 'the Type cell must read the declared field through the one formatter');
|
|
486
513
|
assert.match(thead, />Builders</);
|
|
487
514
|
assert.match(thead, />Runs</);
|
|
488
515
|
assert.match(SCRIPT, /p\.builders/, 'the Builders cell must read real data');
|
|
489
516
|
assert.match(SCRIPT, /tagsHtml\(p\.tags\)/, 'the Runs cell must read real data');
|
|
517
|
+
// the wizard files the declaration with the create — the source end of the pipe
|
|
518
|
+
assert.match(SCRIPT, /type: state\.projType/, 'the create request carries the declared type');
|
|
490
519
|
});
|
|
491
520
|
|
|
492
521
|
test('header and body agree on the column count', () => {
|
|
@@ -509,11 +538,13 @@ test('no sort control is offered for a column that cannot sort', () => {
|
|
|
509
538
|
}
|
|
510
539
|
});
|
|
511
540
|
|
|
512
|
-
test('
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
assert.ok(COSMOS.includes(live), `${live} styles a column that now renders real data`);
|
|
541
|
+
test('every live column keeps its styling — .colType included since task 1002772', () => {
|
|
542
|
+
for (const live of ['.tbl .num', '.tbl .tags', '.colTags', '.colType', '.typeTag']) {
|
|
543
|
+
assert.ok(COSMOS.includes(live), `${live} styles a column that renders real data`);
|
|
516
544
|
}
|
|
545
|
+
// the type tag is its own vocabulary: not the relationship .pill, not the
|
|
546
|
+
// liveness .chip — two different facts must not wear the same chrome
|
|
547
|
+
assert.doesNotMatch(SCRIPT, /typeHtml[\s\S]{0,80}?class="pill"/, 'type must not wear the relationship pill');
|
|
517
548
|
});
|
|
518
549
|
|
|
519
550
|
/* ── Real Builders + Runs (task 1002771) ────────────────────────────────────
|