@bongos/core 1.23.13 → 1.23.14
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 +27 -27
- package/docs/copy-inventory.md +77 -69
- package/docs/copy-registry.json +238 -165
- package/docs/module-api-changelog.md +2 -2
- package/docs/page-inventory.json +3 -2
- package/docs/page-readings.json +18 -18
- package/modules/copy-desk/page-status.js +2 -2
- package/modules/copy-desk/tests/copy_page_status.mjs +1 -1
- package/modules/hall-ui/public/approval-queue-lib.js +1 -1
- package/modules/hall-ui/public/approval-queue.css +26 -12
- package/modules/hall-ui/public/approval-queue.js +40 -16
- package/modules/hall-ui/public/studio-lib.js +5 -3
- package/modules/hall-ui/public/studio.html +8 -8
- package/modules/hall-ui/public/studio.js +25 -5
- package/modules/hall-ui/public/studio.states.json +54 -4
- package/modules/hall-ui/public/welcome-boot.js +62 -12
- package/package-lock.json +2 -2
- package/package.json +1 -1
- package/release-notes.json +9 -1
- package/src/module-api.js +1 -1
- package/tests/hall_approval_queue.mjs +33 -9
- package/tests/hall_studio_home.mjs +74 -7
- package/tests/welcome_boot_browser.mjs +45 -3
|
@@ -3241,7 +3241,7 @@ is load-bearing: the script throws rather than guess if it is missing, and
|
|
|
3241
3241
|
landed since 1.23.10 with no explicit bump. run 40552168441. (task 1002620)
|
|
3242
3242
|
1.23.12 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3243
3243
|
landed since 1.23.11 with no explicit bump. run 40583533060. (task 1002620)
|
|
3244
|
-
1.23.
|
|
3245
|
-
landed since 1.23.12 with no explicit bump. run
|
|
3244
|
+
1.23.14 — CI auto-patch (publish-on-merge, ADR 0161): carrier for merges
|
|
3245
|
+
landed since 1.23.12 with no explicit bump. run 40600119011. (task 1002620)
|
|
3246
3246
|
---------------------------------------------------------------------------
|
|
3247
3247
|
```
|
package/docs/page-inventory.json
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"pages": 47,
|
|
14
14
|
"surfaces": 3,
|
|
15
15
|
"with_states": 40,
|
|
16
|
-
"states":
|
|
16
|
+
"states": 343
|
|
17
17
|
},
|
|
18
18
|
"surfaces": [
|
|
19
19
|
{
|
|
@@ -1201,7 +1201,8 @@
|
|
|
1201
1201
|
"approvals-phone",
|
|
1202
1202
|
"approvals-note",
|
|
1203
1203
|
"approved",
|
|
1204
|
-
"sent-back"
|
|
1204
|
+
"sent-back",
|
|
1205
|
+
"approvals-page"
|
|
1205
1206
|
]
|
|
1206
1207
|
},
|
|
1207
1208
|
{
|
package/docs/page-readings.json
CHANGED
|
@@ -1380,8 +1380,8 @@
|
|
|
1380
1380
|
"surface": "builders",
|
|
1381
1381
|
"title": "Builders' Hall",
|
|
1382
1382
|
"states_read": ["home","standing","standing-karma","out","founding","genesis","decide","demo"],
|
|
1383
|
-
"files_hash": "
|
|
1384
|
-
"reading_hash": "
|
|
1383
|
+
"files_hash": "9ae2154234599eee",
|
|
1384
|
+
"reading_hash": "5f0fcdc8f240a233",
|
|
1385
1385
|
"counts": {"lines":110,"placed":56,"shared":10,"unplaced":44},
|
|
1386
1386
|
"omitted": {"data":102},
|
|
1387
1387
|
"notes": ["founding: an action failed (page.focus: Timeout 6000ms exceeded.); read as it stood"],
|
|
@@ -1391,7 +1391,7 @@
|
|
|
1391
1391
|
{"key":"L0003","section":"top bar","text":"Home","placement":"shared"},
|
|
1392
1392
|
{"key":"L0004","section":"top bar","text":"Welcome back, {…}.","placement":"shared","file":"modules/hall-ui/public/hall-render.js","line":596,"string_id":"0658f0358ffd"},
|
|
1393
1393
|
{"key":"L0005","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":540,"string_id":"eba610d25523"},
|
|
1394
|
-
{"key":"L0006","section":"top bar","text":"
|
|
1394
|
+
{"key":"L0006","section":"top bar","text":"Ctrl K","placement":"shared"},
|
|
1395
1395
|
{"key":"L0007","section":"top bar","text":"Building","placement":"shared"},
|
|
1396
1396
|
{"key":"L0008","section":"top bar","text":"Artistry","placement":"shared"},
|
|
1397
1397
|
{"key":"L0009","section":"top bar","text":"Ideating","placement":"shared"},
|
|
@@ -1472,7 +1472,7 @@
|
|
|
1472
1472
|
{"key":"L0084","section":"Achievements","text":"Won {…}","placement":"placed","file":"modules/hall-ui/public/builders.js","line":481,"string_id":"c5fd76a9e03d","state":"standing","occurrences":10},
|
|
1473
1473
|
{"key":"L0085","section":"Achievements","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9","state":"standing","occurrences":2},
|
|
1474
1474
|
{"key":"L0086","section":"footer","text":"Sign out","placement":"shared","file":"modules/hall-ui/public/shell.js","line":516,"string_id":"1883ad7f07fc","state":"standing","occurrences":2},
|
|
1475
|
-
{"key":"L0087","section":"Achievements","text":"core 1.23.
|
|
1475
|
+
{"key":"L0087","section":"Achievements","text":"core 1.23.12","placement":"unplaced","state":"standing"},
|
|
1476
1476
|
{"key":"L0088","section":"Achievements","text":"Skip","placement":"unplaced","state":"standing"},
|
|
1477
1477
|
{"key":"L0089","section":"Next up — ready to claim","text":"Next up — ready to claim","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":110,"string_id":"659d8256139c"},
|
|
1478
1478
|
{"key":"L0090","section":"Next up — ready to claim","text":"#1003412 · ~60m · 51 {…} est.","placement":"unplaced"},
|
|
@@ -1489,12 +1489,12 @@
|
|
|
1489
1489
|
{"key":"L0101","section":"Recently shipped","text":"{…} and {…}","placement":"placed","file":"modules/hall-ui/public/profile-nudge.js","line":77,"string_id":"56b00d773232","occurrences":2},
|
|
1490
1490
|
{"key":"L0102","section":"Recently shipped","text":"All your work →","placement":"placed","file":"modules/hall-ui/public/hall-widgets.js","line":118,"string_id":"b38c01691857"},
|
|
1491
1491
|
{"key":"L0103","section":"Recently shipped","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9"},
|
|
1492
|
-
{"key":"L0104","section":"Recently shipped","text":"core 1.23.
|
|
1493
|
-
{"key":"L0105","section":"Good morning, {…}","text":"Where do you want to start the day?","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":
|
|
1494
|
-
{"key":"L0106","section":"Good morning, {…}","text":"Start with your role","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":
|
|
1495
|
-
{"key":"L0107","section":"Good morning, {…}","text":"Pick today’s craft and go straight to its room.","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":
|
|
1496
|
-
{"key":"L0108","section":"Good morning, {…}","text":"Your home page","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":
|
|
1497
|
-
{"key":"L0109","section":"Good morning, {…}","text":"Your work, what needs you, and what shipped.","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":
|
|
1492
|
+
{"key":"L0104","section":"Recently shipped","text":"core 1.23.12","placement":"unplaced"},
|
|
1493
|
+
{"key":"L0105","section":"Good morning, {…}","text":"Where do you want to start the day?","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":170,"string_id":"0ec8d133f878","state":"founding"},
|
|
1494
|
+
{"key":"L0106","section":"Good morning, {…}","text":"Start with your role","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":172,"string_id":"58cef7963b6c","state":"founding"},
|
|
1495
|
+
{"key":"L0107","section":"Good morning, {…}","text":"Pick today’s craft and go straight to its room.","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":172,"string_id":"100e4665514d","state":"founding"},
|
|
1496
|
+
{"key":"L0108","section":"Good morning, {…}","text":"Your home page","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":173,"string_id":"2e6866532113","state":"founding"},
|
|
1497
|
+
{"key":"L0109","section":"Good morning, {…}","text":"Your work, what needs you, and what shipped.","placement":"placed","file":"modules/hall-ui/public/welcome-boot.js","line":173,"string_id":"e8d92c773db0","state":"founding"},
|
|
1498
1498
|
{"key":"L0110","section":"Recently shipped","text":"Skip","placement":"unplaced"}
|
|
1499
1499
|
]
|
|
1500
1500
|
},
|
|
@@ -3867,12 +3867,12 @@
|
|
|
3867
3867
|
"id": "builders:studio",
|
|
3868
3868
|
"surface": "builders",
|
|
3869
3869
|
"title": "Studio",
|
|
3870
|
-
"states_read": ["home","out","flow","flow-pick","status","words-offer","words-edit","reviews","full","full-back","approvals","approvals-before","approvals-phone","approvals-note","approved","sent-back"],
|
|
3871
|
-
"files_hash": "
|
|
3872
|
-
"reading_hash": "
|
|
3870
|
+
"states_read": ["home","out","flow","flow-pick","status","words-offer","words-edit","reviews","full","full-back","approvals","approvals-before","approvals-phone","approvals-note","approved","sent-back","approvals-page"],
|
|
3871
|
+
"files_hash": "e25ff80c76808d45",
|
|
3872
|
+
"reading_hash": "420a20ec8bb680bb",
|
|
3873
3873
|
"counts": {"lines":30,"placed":16,"shared":6,"unplaced":8},
|
|
3874
3874
|
"omitted": {"data":4},
|
|
3875
|
-
"notes": ["flow: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","flow-pick: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","status: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","words-offer: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","words-edit: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","reviews: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","full: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","full-back: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals-before: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals-phone: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals-note: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approved: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","sent-back: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood"],
|
|
3875
|
+
"notes": ["flow: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","flow-pick: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","status: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","words-offer: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","words-edit: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","reviews: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","full: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","full-back: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals-before: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals-phone: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals-note: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approved: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","sent-back: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood","approvals-page: an action failed (page.click: Timeout 6000ms exceeded.); read as it stood"],
|
|
3876
3876
|
"lines": [
|
|
3877
3877
|
{"key":"L0001","section":"skip link","text":"Skip to content","placement":"shared","file":"modules/hall-ui/public/shell.js","line":868,"string_id":"87cee78ca134"},
|
|
3878
3878
|
{"key":"L0002","section":"top bar","text":"Jump to…","placement":"shared","file":"modules/hall-ui/public/shell.js","line":540,"string_id":"eba610d25523"},
|
|
@@ -3884,15 +3884,15 @@
|
|
|
3884
3884
|
{"key":"L0008","section":"page top","text":"pages tweaked","placement":"placed","file":"modules/hall-ui/public/studio.html","line":89,"string_id":"271de72308a4"},
|
|
3885
3885
|
{"key":"L0009","section":"page top","text":"this week","placement":"placed","file":"modules/hall-ui/public/studio.html","line":91,"string_id":"130c3731ad83"},
|
|
3886
3886
|
{"key":"L0010","section":"Good evening.","text":"Good evening.","placement":"placed","file":"modules/hall-ui/public/studio.html","line":101,"string_id":"80fd51db38d7"},
|
|
3887
|
-
{"key":"L0011","section":"Good evening.","text":"{…}, on the {…} page, is where you left it. {…} of its {…} lines are yours so far.","placement":"placed","file":"modules/hall-ui/public/studio.js","line":
|
|
3887
|
+
{"key":"L0011","section":"Good evening.","text":"{…}, on the {…} page, is where you left it. {…} of its {…} lines are yours so far.","placement":"placed","file":"modules/hall-ui/public/studio.js","line":677,"string_id":"7763e6f28c67"},
|
|
3888
3888
|
{"key":"L0012","section":"Good evening.","text":"click any words here to rewrite them","placement":"placed","file":"modules/hall-ui/public/studio.html","line":103,"string_id":"8d46c902a9d5"},
|
|
3889
3889
|
{"key":"L0013","section":"Good evening.","text":"Resume","placement":"unplaced"},
|
|
3890
3890
|
{"key":"L0014","section":"Good evening.","text":"{…} of {…}","placement":"placed","file":"modules/hall-ui/public/sky-panel.js","line":120,"string_id":"73c1372b43d9","occurrences":2},
|
|
3891
|
-
{"key":"L0015","section":"Good evening.","text":"
|
|
3891
|
+
{"key":"L0015","section":"Good evening.","text":"Work through tweaks","placement":"placed","file":"modules/hall-ui/public/studio.html","line":123,"string_id":"51458d92e5bc"},
|
|
3892
3892
|
{"key":"L0016","section":"Good evening.","text":"next up: {…} — {…}","placement":"unplaced"},
|
|
3893
|
-
{"key":"L0017","section":"Good evening.","text":"
|
|
3893
|
+
{"key":"L0017","section":"Good evening.","text":"Approve and confirm tweaks","placement":"placed","file":"modules/hall-ui/public/studio.html","line":127,"string_id":"2bd592da42f8"},
|
|
3894
3894
|
{"key":"L0018","section":"Good evening.","text":"2 pages applied, waiting for you","placement":"unplaced"},
|
|
3895
|
-
{"key":"L0019","section":"Good evening.","text":"
|
|
3895
|
+
{"key":"L0019","section":"Good evening.","text":"Needs to be reviewed","placement":"placed","file":"modules/hall-ui/public/studio.html","line":131,"string_id":"dcff7dcecf55"},
|
|
3896
3896
|
{"key":"L0020","section":"Good evening.","text":"From the live site","placement":"placed","file":"modules/hall-ui/public/studio.html","line":137,"string_id":"edced5d528c3"},
|
|
3897
3897
|
{"key":"L0021","section":"Good evening.","text":"2 reviews from the live site","placement":"unplaced"},
|
|
3898
3898
|
{"key":"L0022","section":"Good evening.","text":"Builders hall · this session","placement":"placed","file":"modules/hall-ui/public/craft-mode.js","line":670,"string_id":"fd1903586e8e"},
|
|
@@ -306,7 +306,7 @@ function orderedSurfaces(inventory) {
|
|
|
306
306
|
// last update), and whether it has sat there too long. Waiting for review is
|
|
307
307
|
// the artist's own move and a draft is theirs to finish; a draft is never stuck,
|
|
308
308
|
// and a review is stuck only after 3 days (task 1004777, so its artist is told);
|
|
309
|
-
// a state the reads cannot name always needs
|
|
309
|
+
// a state the reads cannot name always needs to be reviewed.
|
|
310
310
|
// ---------------------------------------------------------------------------
|
|
311
311
|
|
|
312
312
|
const DAY_MS = 24 * 60 * 60 * 1000;
|
|
@@ -318,7 +318,7 @@ const IN_FLIGHT = Object.freeze({
|
|
|
318
318
|
// task 1004777: a review left 3 days is stuck too, so its artist is told on Home.
|
|
319
319
|
waiting_for_artist: { word: 'Waiting for your review', stuck_after: 3 * DAY_MS },
|
|
320
320
|
landing: { word: 'Approved, going live', stuck_after: DAY_MS },
|
|
321
|
-
unknown: { word: 'Needs
|
|
321
|
+
unknown: { word: 'Needs to be reviewed', stuck_after: 0 },
|
|
322
322
|
});
|
|
323
323
|
const IN_FLIGHT_ORDER = ['unknown', 'landing', 'applying', 'submitted', 'waiting_for_artist', 'writing', 'draft'];
|
|
324
324
|
|
|
@@ -259,7 +259,7 @@ await test('in_flight: every open round, its plain state, how long, and stuck wh
|
|
|
259
259
|
];
|
|
260
260
|
const out = status.composePages({ inventory, readings: null, tasks, now: NOW });
|
|
261
261
|
assert.deepEqual(out.in_flight.map((f) => [f.page_id, f.state, f.state_word, f.stuck]), [
|
|
262
|
-
['builders:f', 'unknown', 'Needs
|
|
262
|
+
['builders:f', 'unknown', 'Needs to be reviewed', true],
|
|
263
263
|
['landing:c', 'landing', 'Approved, going live', true],
|
|
264
264
|
['status:h', 'applying', 'Being applied', true],
|
|
265
265
|
['landing:a', 'submitted', 'Submitted, waiting to be applied', true],
|
|
@@ -90,7 +90,7 @@
|
|
|
90
90
|
|
|
91
91
|
// What the studio's quick action says under "Approval queue".
|
|
92
92
|
function doorDetail(count) {
|
|
93
|
-
if (count == null) return '
|
|
93
|
+
if (count == null) return 'tweaks waiting for your sign-off';
|
|
94
94
|
if (count === 0) return 'nothing waiting for you';
|
|
95
95
|
return `${plural(count, 'page', 'pages')} applied, waiting for you`;
|
|
96
96
|
}
|
|
@@ -150,12 +150,16 @@ html.aq-open { overflow: hidden; }
|
|
|
150
150
|
}
|
|
151
151
|
|
|
152
152
|
/* The page, and the words beside it. */
|
|
153
|
+
/* The words changed lead and the page is a look-if-you-want beneath them, so the
|
|
154
|
+
body is one column that scrolls as a whole. */
|
|
153
155
|
.aq-body {
|
|
154
156
|
flex-grow: 1;
|
|
155
157
|
min-height: 0;
|
|
156
158
|
min-width: 0;
|
|
157
159
|
display: flex;
|
|
158
|
-
|
|
160
|
+
flex-direction: column;
|
|
161
|
+
gap: 18px;
|
|
162
|
+
overflow-y: auto;
|
|
159
163
|
}
|
|
160
164
|
.aq-frame {
|
|
161
165
|
flex-grow: 1;
|
|
@@ -183,16 +187,15 @@ html.aq-open { overflow: hidden; }
|
|
|
183
187
|
color: var(--aq-paper-ink);
|
|
184
188
|
}
|
|
185
189
|
.aq-lines {
|
|
186
|
-
/* 300px, the artboard's, until the page beside it has shrunk; then down to 240. */
|
|
187
|
-
width: clamp(240px, 32%, 300px);
|
|
188
190
|
flex: none;
|
|
189
191
|
min-width: 0;
|
|
190
|
-
min-height: 0;
|
|
191
|
-
overflow-y: auto;
|
|
192
192
|
display: flex;
|
|
193
193
|
flex-direction: column;
|
|
194
194
|
gap: 16px;
|
|
195
195
|
}
|
|
196
|
+
.aq-peek { display: flex; flex-direction: column; gap: 12px; min-width: 0; flex: none; }
|
|
197
|
+
.aq-peek__bar { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
|
|
198
|
+
.aq-peek .aq-frame { flex-grow: 0; max-height: min(520px, 60vh); }
|
|
196
199
|
.aq-views { display: flex; flex-wrap: wrap; gap: 8px; }
|
|
197
200
|
.aq-lines__list {
|
|
198
201
|
list-style: none;
|
|
@@ -202,7 +205,16 @@ html.aq-open { overflow: hidden; }
|
|
|
202
205
|
flex-direction: column;
|
|
203
206
|
gap: 14px;
|
|
204
207
|
}
|
|
205
|
-
|
|
208
|
+
/* One changed line: what it was on the left, what it is now on the right. */
|
|
209
|
+
.aq-line {
|
|
210
|
+
display: grid;
|
|
211
|
+
grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
|
|
212
|
+
gap: 6px 24px;
|
|
213
|
+
padding-top: 14px;
|
|
214
|
+
border-top: 1px solid var(--aq-rule);
|
|
215
|
+
}
|
|
216
|
+
.aq-line__section, .aq-line__pinned { grid-column: 1 / -1; }
|
|
217
|
+
.aq-line__aside { grid-column: 1; grid-row: 2; }
|
|
206
218
|
.aq-line__section {
|
|
207
219
|
font-family: var(--aq-mono);
|
|
208
220
|
font-size: 11px;
|
|
@@ -210,7 +222,7 @@ html.aq-open { overflow: hidden; }
|
|
|
210
222
|
text-transform: uppercase;
|
|
211
223
|
color: var(--aq-ink-faint);
|
|
212
224
|
}
|
|
213
|
-
.aq-line__text { font-size:
|
|
225
|
+
.aq-line__text { grid-column: 2; grid-row: 2; font-size: 17px; line-height: 1.5; color: var(--aq-ink); overflow-wrap: anywhere; }
|
|
214
226
|
.aq-mark { background: var(--aq-mark); color: var(--aq-ink); border-radius: 4px; padding: 0 3px; }
|
|
215
227
|
/* A brand hole ({{productName}}) shown as the name it stands for: a fixed name
|
|
216
228
|
the artist did not write and cannot rewrite, so a quiet chip (task 1004381). */
|
|
@@ -224,7 +236,7 @@ html.aq-open { overflow: hidden; }
|
|
|
224
236
|
line-height: 1.35;
|
|
225
237
|
white-space: nowrap;
|
|
226
238
|
}
|
|
227
|
-
.aq-line__aside { font-size:
|
|
239
|
+
.aq-line__aside { font-size: 15px; line-height: 1.5; color: var(--aq-ink-faint); overflow-wrap: anywhere; }
|
|
228
240
|
.aq-line--refused .aq-line__aside { color: var(--aq-link); }
|
|
229
241
|
/* task 1004775: a test that still checks the old words. */
|
|
230
242
|
.aq-line__pinned { font-size: 13px; line-height: 1.45; color: var(--aq-link); overflow-wrap: anywhere; }
|
|
@@ -248,8 +260,9 @@ html.aq-open { overflow: hidden; }
|
|
|
248
260
|
min-height: 48px;
|
|
249
261
|
}
|
|
250
262
|
.aq-accent {
|
|
251
|
-
height:
|
|
252
|
-
padding: 0
|
|
263
|
+
height: 52px;
|
|
264
|
+
padding: 0 34px;
|
|
265
|
+
font-weight: 600;
|
|
253
266
|
border-radius: 999px;
|
|
254
267
|
cursor: pointer;
|
|
255
268
|
border: 0;
|
|
@@ -312,10 +325,11 @@ html.aq-open { overflow: hidden; }
|
|
|
312
325
|
.aq-title { order: 3; flex: 1 1 100%; }
|
|
313
326
|
.aq-head__gap { display: none; }
|
|
314
327
|
.aq-head .aq-flips { order: 4; }
|
|
315
|
-
.aq-body { flex-
|
|
328
|
+
.aq-body { flex-grow: 0; overflow: visible; }
|
|
329
|
+
.aq-line { grid-template-columns: minmax(0, 1fr); }
|
|
330
|
+
.aq-line__aside, .aq-line__text { grid-column: 1; grid-row: auto; }
|
|
316
331
|
.aq-frame { flex: none; max-height: 70vh; }
|
|
317
332
|
.aq-frame__note { padding: 40px 20px; }
|
|
318
|
-
.aq-lines { width: auto; overflow: visible; }
|
|
319
333
|
.aq-foot { flex-wrap: wrap; }
|
|
320
334
|
.aq-note { flex: 1 1 100%; }
|
|
321
335
|
.aq-hint { margin-left: 0; flex: 1 1 100%; white-space: normal; }
|
|
@@ -72,6 +72,7 @@
|
|
|
72
72
|
renders: new Map(), // task id -> render index, or 'loading' / 'failed'
|
|
73
73
|
outcome: new Map(), // task id -> { kind: 'approved'|'sent', line }
|
|
74
74
|
noteOpen: false,
|
|
75
|
+
peek: false, // the rendered page is a look-if-you-want, never the card
|
|
75
76
|
busy: false,
|
|
76
77
|
error: null,
|
|
77
78
|
opener: null,
|
|
@@ -133,7 +134,7 @@
|
|
|
133
134
|
if (!pick) {
|
|
134
135
|
return L.hasAnyRender(r)
|
|
135
136
|
? `<p class="aq-frame__note">No ${esc(state.view.phase)} render is attached to this page.</p>`
|
|
136
|
-
: '<p class="aq-frame__note">No render is attached to this page yet.
|
|
137
|
+
: '<p class="aq-frame__note">No render is attached to this page yet. The words above are what changed.</p>';
|
|
137
138
|
}
|
|
138
139
|
const name = L.displayTitle(item);
|
|
139
140
|
const alt = `${name}, ${state.view.phase}, ${pick.device}, ${pick.mode}`;
|
|
@@ -145,8 +146,9 @@
|
|
|
145
146
|
return H ? H.holesHtml(text, { cls: 'aq-hole' }) : esc(text);
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
// The card IS the words: each changed line, what it was beside what it is now.
|
|
148
150
|
function linesHtml(item) {
|
|
149
|
-
const rows = (item.lines || []).map((l) => L.lineRow(l,
|
|
151
|
+
const rows = (item.lines || []).map((l) => L.lineRow(l, 'after'));
|
|
150
152
|
if (!rows.length) return '<p class="aq-lines__none">This round changed no lines.</p>';
|
|
151
153
|
return `<ol class="aq-lines__list">${rows.map((r) => `
|
|
152
154
|
<li class="aq-line${r.refused ? ' aq-line--refused' : ''}">
|
|
@@ -170,20 +172,35 @@
|
|
|
170
172
|
if (!item.can_decide) {
|
|
171
173
|
return '<div class="aq-foot"><p class="aq-sealed">Only the artist who wrote this page, or another artist, can approve it or send it back.</p><span class="aq-hint">highlighted: the words you changed</span></div>';
|
|
172
174
|
}
|
|
173
|
-
const
|
|
174
|
-
const noPicture = r && r !== 'loading' && r !== 'failed' && !L.hasAnyRender(r);
|
|
175
|
-
const approve = `<button type="button" class="aq-accent" data-approve${state.busy || noPicture ? ' disabled' : ''}>approve and ship</button>`;
|
|
175
|
+
const approve = `<button type="button" class="aq-accent" data-approve${state.busy ? ' disabled' : ''}>Approve and ship</button>`;
|
|
176
176
|
const note = state.noteOpen
|
|
177
177
|
? `<div class="aq-note">
|
|
178
178
|
<label for="aq-note" class="aq-sr">What needs changing</label>
|
|
179
179
|
<input id="aq-note" class="aq-note__input" type="text" maxlength="${L.MAX_NOTE}" placeholder="The hero line is too long on a phone." autocomplete="off">
|
|
180
180
|
<button type="button" class="aq-ghost aq-ghost--send" data-send${state.busy ? ' disabled' : ''}>send</button>
|
|
181
181
|
</div>`
|
|
182
|
-
: `<button type="button" class="aq-ghost" data-open-note${state.busy ? ' disabled' : ''}>
|
|
182
|
+
: `<button type="button" class="aq-ghost" data-open-note${state.busy ? ' disabled' : ''}>Send it back</button>`;
|
|
183
183
|
const err = state.error ? `<p class="aq-error" role="alert">${esc(state.error)}</p>` : '';
|
|
184
184
|
return `<div class="aq-foot">${approve}${note}<span class="aq-hint">highlighted: the words you changed</span></div>${err}`;
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
// The page as the artist would see it: closed until asked for, because a
|
|
188
|
+
// picture that may not exist is no way to open a decision.
|
|
189
|
+
function peekHtml(item) {
|
|
190
|
+
if (!state.peek) {
|
|
191
|
+
return '<div class="aq-peek"><button type="button" class="aq-ghost aq-ghost--small" data-peek aria-expanded="false">See it on the page</button></div>';
|
|
192
|
+
}
|
|
193
|
+
return `<div class="aq-peek aq-peek--open">
|
|
194
|
+
<div class="aq-peek__bar">
|
|
195
|
+
<button type="button" class="aq-ghost aq-ghost--small" data-peek aria-expanded="true">Hide the page</button>
|
|
196
|
+
${pills('phase', L.PHASES, state.view.phase, 'Before or after')}
|
|
197
|
+
${pills('device', L.DEVICES, state.view.device, 'Desktop or phone')}
|
|
198
|
+
${pills('mode', L.MODES, state.view.mode, 'Light or dark')}
|
|
199
|
+
</div>
|
|
200
|
+
<div class="aq-frame" tabindex="0" aria-label="The page, rendered">${frameHtml(item)}</div>
|
|
201
|
+
</div>`;
|
|
202
|
+
}
|
|
203
|
+
|
|
187
204
|
// task 1004765: submitted rounds nobody has applied, below the reviewable
|
|
188
205
|
// pages. The server lists them apart; the panel only words them, and gives
|
|
189
206
|
// them no approve or send-back verb.
|
|
@@ -204,28 +221,26 @@
|
|
|
204
221
|
const item = current();
|
|
205
222
|
const close = '<button type="button" class="aq-close" data-close>close</button>';
|
|
206
223
|
if (!item) {
|
|
207
|
-
const words = state.loadError || (state.loaded ? 'Nothing is waiting for you. A page
|
|
224
|
+
const words = state.loadError || (state.loaded ? 'Nothing is waiting for you. A page shows up here once its tweaks have been applied and checked.' : 'Opening the Approval queue…');
|
|
208
225
|
dialog.innerHTML = `
|
|
209
226
|
<div class="aq-head"><span class="aq-eyebrow">approval queue</span><h2 class="aq-title" id="aq-title">${state.loaded ? 'Nothing waiting' : 'Approval queue'}</h2><span class="aq-head__gap"></span>${close}</div>
|
|
210
227
|
<div class="aq-body aq-body--empty"><div class="aq-frame"><p class="aq-frame__note">${esc(words)}</p></div></div>
|
|
211
228
|
${notAppliedHtml()}`;
|
|
212
229
|
return;
|
|
213
230
|
}
|
|
214
|
-
loadRenders(item);
|
|
231
|
+
if (state.peek) loadRenders(item);
|
|
215
232
|
dialog.innerHTML = `
|
|
216
233
|
<div class="aq-head">
|
|
217
234
|
<span class="aq-eyebrow">${esc(L.eyebrow(item))}</span>
|
|
218
235
|
<h2 class="aq-title" id="aq-title">${esc(L.displayTitle(item))} <span class="aq-title__sub">${esc(L.subLine(item))}</span></h2>
|
|
219
236
|
<span class="aq-head__gap"></span>
|
|
220
|
-
${pills('phase', L.PHASES, state.view.phase, 'Before or after')}
|
|
221
237
|
${close}
|
|
222
238
|
</div>
|
|
223
239
|
<div class="aq-body">
|
|
224
|
-
<
|
|
225
|
-
<aside class="aq-lines" aria-label="The words you changed">
|
|
226
|
-
<div class="aq-views">${pills('device', L.DEVICES, state.view.device, 'Desktop or phone')}${pills('mode', L.MODES, state.view.mode, 'Light or dark')}</div>
|
|
240
|
+
<section class="aq-lines" aria-label="The words you changed">
|
|
227
241
|
${linesHtml(item)}
|
|
228
|
-
</
|
|
242
|
+
</section>
|
|
243
|
+
${peekHtml(item)}
|
|
229
244
|
</div>
|
|
230
245
|
${footHtml(item)}
|
|
231
246
|
${notAppliedHtml()}`;
|
|
@@ -276,7 +291,9 @@
|
|
|
276
291
|
|
|
277
292
|
// ---- open / close ----------------------------------------------------------
|
|
278
293
|
|
|
279
|
-
|
|
294
|
+
// `pageId` (optional) lands on that page's card when it is in the queue, so a
|
|
295
|
+
// row elsewhere that says "needs to be reviewed" opens its own card.
|
|
296
|
+
async function open(pageId, { reload = true } = {}) {
|
|
280
297
|
state.opener = document.activeElement;
|
|
281
298
|
state.open = true;
|
|
282
299
|
state.error = null;
|
|
@@ -285,9 +302,14 @@
|
|
|
285
302
|
document.documentElement.classList.add('aq-open');
|
|
286
303
|
paint();
|
|
287
304
|
dialog.focus();
|
|
288
|
-
await loadQueue();
|
|
305
|
+
if (reload || !state.loaded) await loadQueue();
|
|
306
|
+
if (typeof pageId === 'string') {
|
|
307
|
+
const at = state.queue.findIndex((q) => q.page_id === pageId);
|
|
308
|
+
if (at !== -1) state.idx = at;
|
|
309
|
+
else if (state.queue.length) state.error = 'That page is not waiting for your sign-off right now.';
|
|
310
|
+
}
|
|
289
311
|
paint();
|
|
290
|
-
const first = dialog.querySelector('[data-
|
|
312
|
+
const first = dialog.querySelector('[data-approve]:not([disabled])') || dialog.querySelector('[data-close]');
|
|
291
313
|
if (first) first.focus();
|
|
292
314
|
}
|
|
293
315
|
|
|
@@ -322,6 +344,7 @@
|
|
|
322
344
|
if (t.dataset.device) return flip('device', t.dataset.device);
|
|
323
345
|
if (t.dataset.mode) return flip('mode', t.dataset.mode);
|
|
324
346
|
if (('approve' in t.dataset)) return decide('approved');
|
|
347
|
+
if (('peek' in t.dataset)) { state.peek = !state.peek; paint(); return undefined; }
|
|
325
348
|
if (('openNote' in t.dataset)) { state.noteOpen = true; paint(); return focusNote(); }
|
|
326
349
|
if (('send' in t.dataset)) return decide('sent');
|
|
327
350
|
if (t.dataset.next != null) { state.idx = Number(t.dataset.next); state.noteOpen = false; state.error = null; paint(); return undefined; }
|
|
@@ -354,6 +377,7 @@
|
|
|
354
377
|
close,
|
|
355
378
|
async refresh() { await loadQueue(); paint(); return countNow(); },
|
|
356
379
|
count: countNow,
|
|
380
|
+
notAppliedCount: () => (state.notApplied || []).length,
|
|
357
381
|
};
|
|
358
382
|
}
|
|
359
383
|
|
|
@@ -164,9 +164,11 @@
|
|
|
164
164
|
page_id: p.page_id,
|
|
165
165
|
title: titleOf(p),
|
|
166
166
|
surface: surfaceWord(p.surface),
|
|
167
|
-
state: p.state_word || 'Needs
|
|
167
|
+
state: p.state_word || 'Needs to be reviewed',
|
|
168
168
|
age,
|
|
169
169
|
stuck: !!p.stuck,
|
|
170
|
+
// A page waiting on a sign-off opens its approval card.
|
|
171
|
+
review: p.state === 'waiting_for_artist',
|
|
170
172
|
// A round the reads cannot name has no action of its own: the row offers
|
|
171
173
|
// a release (task 1004837). task_id pins the round the viewer looked at.
|
|
172
174
|
release: p.state === 'unknown',
|
|
@@ -191,8 +193,8 @@
|
|
|
191
193
|
const v = num(n);
|
|
192
194
|
if (v <= 0) return '';
|
|
193
195
|
return v === 1
|
|
194
|
-
? '1 page has been asked for. It comes up first in
|
|
195
|
-
: `${v} pages have been asked for. They come up first in
|
|
196
|
+
? '1 page has been asked for. It comes up first in Work through tweaks.'
|
|
197
|
+
: `${v} pages have been asked for. They come up first in Work through tweaks.`;
|
|
196
198
|
}
|
|
197
199
|
|
|
198
200
|
// A "pick another" chip names the page and its surface (the artboard's label).
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
shell's top bar is the page's one <header>. -->
|
|
100
100
|
<div class="st-words" id="st-words">
|
|
101
101
|
<h1 class="st-greet" id="studio-greet" data-words>Good evening.</h1>
|
|
102
|
-
<p class="st-sub" id="studio-sub" data-words>Nothing is on your desk yet.
|
|
102
|
+
<p class="st-sub" id="studio-sub" data-words>Nothing is on your desk yet. Work through tweaks has a page ready for you.</p>
|
|
103
103
|
<button type="button" class="st-hint" id="st-hint" aria-controls="st-offer">click any words here to rewrite them</button>
|
|
104
104
|
<p class="st-editing" id="st-editing" aria-live="polite" hidden></p>
|
|
105
105
|
<div class="st-offer" id="st-offer" hidden>
|
|
@@ -120,16 +120,16 @@
|
|
|
120
120
|
<span class="st-resume__detail" id="st-resume-detail"></span>
|
|
121
121
|
</a>
|
|
122
122
|
<button type="button" class="st-action" id="st-flow" aria-haspopup="dialog">
|
|
123
|
-
<span class="st-action__label">
|
|
123
|
+
<span class="st-action__label">Work through tweaks</span>
|
|
124
124
|
<span class="st-action__detail" id="st-flow-detail">the next page to tweak</span>
|
|
125
125
|
</button>
|
|
126
|
-
<button type="button" class="st-action" id="studio-approvals" data-approvals aria-haspopup="dialog">
|
|
127
|
-
<span class="st-action__label">
|
|
128
|
-
<span class="st-action__detail" id="studio-approvals-detail">
|
|
126
|
+
<button type="button" class="st-action" id="studio-approvals" data-approvals aria-haspopup="dialog" hidden>
|
|
127
|
+
<span class="st-action__label">Approve and confirm tweaks</span>
|
|
128
|
+
<span class="st-action__detail" id="studio-approvals-detail">tweaks waiting for your sign-off</span>
|
|
129
129
|
</button>
|
|
130
130
|
<button type="button" class="st-action" id="st-status" aria-haspopup="dialog">
|
|
131
|
-
<span class="st-action__label">
|
|
132
|
-
<span class="st-action__detail" id="st-status-detail">how far each surface has come</span>
|
|
131
|
+
<span class="st-action__label">Needs to be reviewed</span>
|
|
132
|
+
<span class="st-action__detail" id="st-status-detail">pages waiting on you, and how far each surface has come</span>
|
|
133
133
|
</button>
|
|
134
134
|
<!-- Task 1004499: the reviews builders wrote on the public site with
|
|
135
135
|
its Artist review button. Each opens here, in the palette's panel. -->
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
<div class="st-overlay" id="st-panel" hidden>
|
|
151
151
|
<div class="st-dialog" role="dialog" aria-modal="true" aria-labelledby="st-panel-title">
|
|
152
152
|
<div class="st-dialog__head">
|
|
153
|
-
<h2 class="st-dialog__title" id="st-panel-title" tabindex="-1">
|
|
153
|
+
<h2 class="st-dialog__title" id="st-panel-title" tabindex="-1">Work through tweaks</h2>
|
|
154
154
|
<button type="button" class="st-close" data-close-panel>close</button>
|
|
155
155
|
</div>
|
|
156
156
|
<div class="st-dialog__body" id="st-panel-body"></div>
|
|
@@ -128,6 +128,8 @@
|
|
|
128
128
|
const RANK_ORDER = { archon: 4, metic: 3, thetes: 2, xenos: 1 };
|
|
129
129
|
const MAX_WORDS = 2000; // the abandon/merge `reason` cap the routes apply anyway
|
|
130
130
|
|
|
131
|
+
// Also the floor for the approve door: a studio viewer who cannot pass a tweak
|
|
132
|
+
// is not shown the door (cosmetic; the approve and send-back routes decide).
|
|
131
133
|
function canVerdict() {
|
|
132
134
|
const rank = String((viewer && viewer.rank) || '').toLowerCase();
|
|
133
135
|
return (RANK_ORDER[rank] ?? 0) >= RANK_ORDER.metic;
|
|
@@ -570,15 +572,31 @@
|
|
|
570
572
|
const door = $('#studio-approvals');
|
|
571
573
|
const Q = window.OTBApprovalQueue;
|
|
572
574
|
const lib = window.OTBApprovalQueueLib;
|
|
573
|
-
if (!door || !Q || !lib) return;
|
|
575
|
+
if (!door || !Q || !lib) return false;
|
|
574
576
|
approvals = Q.mount({
|
|
575
577
|
api,
|
|
576
578
|
apiBase: API,
|
|
577
579
|
writes: { approve: WRITE_ROUTES.approve, sendBack: WRITE_ROUTES.sendBack },
|
|
578
580
|
onCount: (n) => { const d = $('#studio-approvals-detail'); if (d) d.textContent = lib.doorDetail(n); },
|
|
579
581
|
});
|
|
580
|
-
door
|
|
582
|
+
// Nothing to approve means no dialog: the door's own detail line already
|
|
583
|
+
// says so, and a click on it just confirms it.
|
|
584
|
+
door.addEventListener('click', async () => {
|
|
585
|
+
const n = await approvals.refresh();
|
|
586
|
+
// Submitted-but-not-applied rounds still show in the dialog, so they count as something to see.
|
|
587
|
+
if (n === 0 && !approvals.notAppliedCount()) { toast('Nothing is waiting for your sign-off right now.'); return; }
|
|
588
|
+
approvals.open(undefined, { reload: false });
|
|
589
|
+
});
|
|
581
590
|
approvals.refresh();
|
|
591
|
+
return true;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
// The approve door is for artists who can pass a tweak (metic and up). Below
|
|
595
|
+
// that rank it never shows; the routes still decide who may (ADR 0016).
|
|
596
|
+
function showApprovals() {
|
|
597
|
+
const door = $('#studio-approvals');
|
|
598
|
+
if (!door || !canVerdict()) return;
|
|
599
|
+
if (mountApprovals()) door.hidden = false;
|
|
582
600
|
}
|
|
583
601
|
|
|
584
602
|
// ===========================================================================
|
|
@@ -682,7 +700,7 @@
|
|
|
682
700
|
|
|
683
701
|
// ---- the small glass panels -----------------------------------------------
|
|
684
702
|
|
|
685
|
-
const TITLES = Object.freeze({ flow: '
|
|
703
|
+
const TITLES = Object.freeze({ flow: 'Work through tweaks', status: 'Needs to be reviewed', site: 'From the live site' });
|
|
686
704
|
|
|
687
705
|
function flowHtml() {
|
|
688
706
|
if (!home.next) {
|
|
@@ -725,7 +743,7 @@
|
|
|
725
743
|
const asked = lib.askedLine(home.next && home.next.asked_pages);
|
|
726
744
|
const flight = lib.inFlightRows(home.pages, new Date()).map((f) => `
|
|
727
745
|
<li class="st-flight${f.stuck ? ' st-flight--stuck' : ''}">
|
|
728
|
-
|
|
746
|
+
${f.review && approvals ? `<a class="st-flight__page" href="#review" data-review-page="${escapeHtml(f.page_id)}">${escapeHtml(f.title)}</a>` : `<a class="st-flight__page" href="${escapeHtml(editorHref(f.page_id))}">${escapeHtml(f.title)}</a>`}
|
|
729
747
|
<span class="st-flight__where">${escapeHtml(f.surface)}</span>
|
|
730
748
|
<span class="st-flight__state">${escapeHtml(f.state)}${f.age ? ` · ${escapeHtml(f.age)}` : ''}${f.stuck ? ' · stuck' : ''}</span>
|
|
731
749
|
${f.release && canVerdict() ? `<button type="button" class="st-release" data-release-page="${escapeHtml(f.page_id)}" data-release-task="${escapeHtml(f.task_id || '')}">release</button>` : ''}
|
|
@@ -1021,6 +1039,8 @@
|
|
|
1021
1039
|
if (overlay) {
|
|
1022
1040
|
overlay.addEventListener('click', (ev) => {
|
|
1023
1041
|
if (ev.target === overlay || ev.target.closest('[data-close-panel]')) { closePanel(); return; }
|
|
1042
|
+
const review = ev.target.closest('[data-review-page]');
|
|
1043
|
+
if (review && approvals) { ev.preventDefault(); const id = review.getAttribute('data-review-page'); closePanel(); approvals.open(id); return; }
|
|
1024
1044
|
const rel = ev.target.closest('[data-release-page]');
|
|
1025
1045
|
if (rel) { releasePage(rel.getAttribute('data-release-page'), rel.getAttribute('data-release-task'), rel); return; }
|
|
1026
1046
|
const take = ev.target.closest('[data-take]');
|
|
@@ -1082,9 +1102,9 @@
|
|
|
1082
1102
|
|
|
1083
1103
|
(async () => {
|
|
1084
1104
|
startSky();
|
|
1085
|
-
mountApprovals();
|
|
1086
1105
|
const me = await api.request('GET', `${API}/me`);
|
|
1087
1106
|
if (me.ok) viewer = me.data.builder || me.data;
|
|
1107
|
+
showApprovals();
|
|
1088
1108
|
bootHome(me.ok);
|
|
1089
1109
|
// Reviews first (the richer craft), then flags — each newest-first within.
|
|
1090
1110
|
const [reviews, flags] = await Promise.all([loadReviews(), loadFlags()]);
|