@bongos/core 1.19.484 → 1.19.486
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 +102 -52
- package/clients/bongos-client/README.md +1 -1
- package/clients/bongos-client/bongos-client.global.js +6 -0
- package/clients/bongos-client/index.cjs +6 -0
- package/clients/bongos-client/index.d.ts +7 -0
- package/clients/bongos-client/index.mjs +6 -0
- package/docs/adr/0232-rot-is-derived-not-swept-and-water-is-the-only-new-verb.md +155 -0
- package/docs/adr/README.md +1 -0
- package/docs/api/openapi.json +147 -3
- package/docs/api-reference.md +7 -4
- package/docs/copy-inventory.md +169 -178
- package/docs/copy-registry.json +295 -405
- package/docs/file-map.md +1 -1
- package/docs/module-api-changelog.md +4 -0
- package/migrations/core_231_project_settings_and_attention_water.sql +163 -0
- package/modules/dev-box/app/src/vendor/bongos-client.cjs +6 -0
- package/modules/hall-ui/public/goal-inbox.js +119 -1
- package/modules/hall-ui/public/not-ready.html +14 -10
- package/modules/hall-ui/public/not-ready.states.json +14 -0
- package/modules/hall-ui/public/pair.css +17 -67
- package/modules/hall-ui/public/pair.html +8 -1
- package/modules/hall-ui/public/pair.states.json +14 -0
- package/modules/hall-ui/public/panel.css +333 -0
- package/modules/hall-ui/public/profile.css +85 -0
- package/modules/hall-ui/public/profile.html +12 -5
- package/modules/hall-ui/public/profile.states.json +15 -0
- package/modules/hall-ui/public/settings.css +119 -336
- package/modules/hall-ui/public/settings.html +28 -19
- package/modules/hall-ui/public/settings.js +44 -35
- package/modules/hall-ui/public/settings.states.json +16 -0
- package/modules/hall-ui/public/style.css +5 -2
- package/modules/lifecycle/module.json +2 -1
- package/modules/lifecycle/rot.js +210 -0
- package/modules/lifecycle/routes/rot.js +160 -0
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/scripts/gds/fitness-checks-vocabulary.js +0 -1
- package/scripts/gds/fitness.js +9 -0
- package/src/bongos/project-settings.js +193 -0
- package/src/module-api.js +29 -1
- package/tests/hall_settings_world.mjs +274 -0
- package/tests/join_application_note.mjs +7 -15
- package/tests/module-scope-map.mjs +1 -1
- package/tests/module_api.mjs +1 -0
- package/tests/rot_inbox.mjs +532 -0
- package/modules/hall-ui/public/my-projects.css +0 -62
- package/modules/hall-ui/public/my-projects.html +0 -73
- package/modules/hall-ui/public/my-projects.js +0 -153
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
// my-projects.js — the signed-in builder's cross-project view (ADR 0141 §3, task
|
|
2
|
-
// #1002112). Fetches /api/gds/my-projects (session cookie, same-origin) and renders
|
|
3
|
-
// owned + building-on lists with self-service leave, plus a join-by-origin form
|
|
4
|
-
// whose application is one click plus an optional note (task 1002330).
|
|
5
|
-
// All network values are rendered via textContent — never innerHTML.
|
|
6
|
-
(function () {
|
|
7
|
-
'use strict';
|
|
8
|
-
var ownedEl = document.getElementById('owned');
|
|
9
|
-
var buildingEl = document.getElementById('building');
|
|
10
|
-
var joinBtn = document.getElementById('join-btn');
|
|
11
|
-
var joinInput = document.getElementById('join-origin');
|
|
12
|
-
var joinNoteInput = document.getElementById('join-note'); // the applicant's own words (optional)
|
|
13
|
-
var joinStatus = document.getElementById('join-status'); // what the project answered
|
|
14
|
-
|
|
15
|
-
function el(tag, cls) { var e = document.createElement(tag); if (cls) e.className = cls; return e; }
|
|
16
|
-
|
|
17
|
-
function safeOriginHost(origin) {
|
|
18
|
-
try {
|
|
19
|
-
var u = new URL(String(origin));
|
|
20
|
-
return (u.protocol === 'https:' || u.protocol === 'http:') ? u.host : null;
|
|
21
|
-
} catch (_) { return null; }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function renderList(container, items, opts) {
|
|
25
|
-
container.textContent = '';
|
|
26
|
-
if (!items || items.length === 0) {
|
|
27
|
-
var p = el('p', 'empty');
|
|
28
|
-
p.textContent = opts.emptyText;
|
|
29
|
-
container.appendChild(p);
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
items.forEach(function (m) {
|
|
33
|
-
var row = el('div', 'row');
|
|
34
|
-
var meta = el('div', 'meta');
|
|
35
|
-
var name = el('div', 'name');
|
|
36
|
-
name.textContent = m.name || m.client_id;
|
|
37
|
-
meta.appendChild(name);
|
|
38
|
-
var host = safeOriginHost(m.origin);
|
|
39
|
-
if (host) {
|
|
40
|
-
var o = el('div', 'origin');
|
|
41
|
-
o.textContent = host;
|
|
42
|
-
meta.appendChild(o);
|
|
43
|
-
}
|
|
44
|
-
row.appendChild(meta);
|
|
45
|
-
if (m.membership_kind === 'owner') {
|
|
46
|
-
var pill = el('span', 'owner-pill');
|
|
47
|
-
pill.textContent = 'owner';
|
|
48
|
-
row.appendChild(pill);
|
|
49
|
-
}
|
|
50
|
-
if (opts.leavable) {
|
|
51
|
-
var btn = el('button', 'btn-ghost');
|
|
52
|
-
btn.type = 'button';
|
|
53
|
-
btn.textContent = 'Leave';
|
|
54
|
-
btn.addEventListener('click', function () { leave(m.client_id, row, btn); });
|
|
55
|
-
row.appendChild(btn);
|
|
56
|
-
}
|
|
57
|
-
container.appendChild(row);
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function leave(clientId, row, btn) {
|
|
62
|
-
btn.disabled = true;
|
|
63
|
-
btn.textContent = 'Leaving…';
|
|
64
|
-
fetch('/api/gds/my-projects/' + encodeURIComponent(clientId) + '/leave', { method: 'POST' })
|
|
65
|
-
.then(function (r) { return r.ok ? r.json() : Promise.reject(); })
|
|
66
|
-
.then(function () { row.remove(); })
|
|
67
|
-
.catch(function () { btn.disabled = false; btn.textContent = 'Leave'; });
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function resolveInvite(clientId, accept, row, btns) {
|
|
71
|
-
btns.forEach(function (b) { b.disabled = true; });
|
|
72
|
-
fetch('/api/gds/my-projects/invites/' + encodeURIComponent(clientId) + '/' + (accept ? 'accept' : 'decline'), { method: 'POST' })
|
|
73
|
-
.then(function (r) { return r.ok ? r.json() : Promise.reject(); })
|
|
74
|
-
.then(function () { row.remove(); if (accept) load(); loadInvites(); })
|
|
75
|
-
.catch(function () { btns.forEach(function (b) { b.disabled = false; }); });
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function loadInvites() {
|
|
79
|
-
var section = document.getElementById('invites-section');
|
|
80
|
-
var container = document.getElementById('invites');
|
|
81
|
-
fetch('/api/gds/my-projects/invites', { headers: { Accept: 'application/json' } })
|
|
82
|
-
.then(function (r) { return r.ok ? r.json() : Promise.reject(); })
|
|
83
|
-
.then(function (data) {
|
|
84
|
-
var invites = (data && data.invites) || [];
|
|
85
|
-
if (invites.length === 0) { section.hidden = true; return; }
|
|
86
|
-
container.textContent = '';
|
|
87
|
-
invites.forEach(function (inv) {
|
|
88
|
-
var row = el('div', 'row');
|
|
89
|
-
var meta = el('div', 'meta');
|
|
90
|
-
var name = el('div', 'name');
|
|
91
|
-
name.textContent = inv.name || inv.client_id;
|
|
92
|
-
meta.appendChild(name);
|
|
93
|
-
var host = safeOriginHost(inv.origin);
|
|
94
|
-
if (host) { var o = el('div', 'origin'); o.textContent = host; meta.appendChild(o); }
|
|
95
|
-
row.appendChild(meta);
|
|
96
|
-
var accept = el('button', 'btn-ghost'); accept.type = 'button'; accept.textContent = 'Accept';
|
|
97
|
-
var decline = el('button', 'btn-ghost'); decline.type = 'button'; decline.textContent = 'Decline';
|
|
98
|
-
accept.addEventListener('click', function () { resolveInvite(inv.client_id, true, row, [accept, decline]); });
|
|
99
|
-
decline.addEventListener('click', function () { resolveInvite(inv.client_id, false, row, [accept, decline]); });
|
|
100
|
-
row.appendChild(accept); row.appendChild(decline);
|
|
101
|
-
container.appendChild(row);
|
|
102
|
-
});
|
|
103
|
-
section.hidden = false;
|
|
104
|
-
})
|
|
105
|
-
.catch(function () { section.hidden = true; });
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function load() {
|
|
109
|
-
fetch('/api/gds/my-projects', { headers: { Accept: 'application/json' } })
|
|
110
|
-
.then(function (r) { return r.ok ? r.json() : Promise.reject(); })
|
|
111
|
-
.then(function (data) {
|
|
112
|
-
renderList(ownedEl, data.owned, { emptyText: 'You don’t own any projects yet.', leavable: false });
|
|
113
|
-
renderList(buildingEl, data.building, { emptyText: 'You’re not building on any other projects yet.', leavable: true });
|
|
114
|
-
})
|
|
115
|
-
.catch(function () {
|
|
116
|
-
ownedEl.textContent = ''; buildingEl.textContent = '';
|
|
117
|
-
var p = el('p', 'empty'); p.textContent = 'Couldn’t load your projects right now.';
|
|
118
|
-
buildingEl.appendChild(p);
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
joinBtn.addEventListener('click', function () {
|
|
123
|
-
var origin = (joinInput.value || '').trim();
|
|
124
|
-
if (!origin) { joinStatus.textContent = 'Enter a project URL.'; return; }
|
|
125
|
-
var note = (joinNoteInput.value || '').trim();
|
|
126
|
-
joinBtn.disabled = true;
|
|
127
|
-
joinStatus.textContent = 'Requesting…';
|
|
128
|
-
fetch('/api/gds/my-projects/join', {
|
|
129
|
-
method: 'POST',
|
|
130
|
-
headers: { 'Content-Type': 'application/json' },
|
|
131
|
-
/* note is omitted entirely when blank — an application with nothing written
|
|
132
|
-
is still an application (task 1002330). */
|
|
133
|
-
body: JSON.stringify(note ? { origin: origin, note: note } : { origin: origin }),
|
|
134
|
-
})
|
|
135
|
-
.then(function (r) { return r.json().then(function (b) { return { ok: r.ok, body: b }; }); })
|
|
136
|
-
.then(function (res) {
|
|
137
|
-
joinBtn.disabled = false;
|
|
138
|
-
if (res.ok && res.body && res.body.message) {
|
|
139
|
-
joinStatus.textContent = res.body.message;
|
|
140
|
-
/* a door refusal rides a 200 (task 1003044): keep the address AND the
|
|
141
|
-
note the applicant wrote, and don't repaint as if a request went out */
|
|
142
|
-
var refused = res.body.status === 'invite_only' || res.body.status === 'open_enrollment' || res.body.status === 'members_only';
|
|
143
|
-
if (!refused) { joinInput.value = ''; joinNoteInput.value = ''; load(); }
|
|
144
|
-
}
|
|
145
|
-
else if (res.body && res.body.error && res.body.error.code === 'unknown_project') { joinStatus.textContent = 'That project isn’t on the platform.'; }
|
|
146
|
-
else { joinStatus.textContent = 'Could not request access right now.'; }
|
|
147
|
-
})
|
|
148
|
-
.catch(function () { joinBtn.disabled = false; joinStatus.textContent = 'Could not request access right now.'; });
|
|
149
|
-
});
|
|
150
|
-
|
|
151
|
-
load();
|
|
152
|
-
loadInvites();
|
|
153
|
-
}());
|