Skip to content

Commit ada9adb

Browse files
committed
Merge PR_26177_ALFA_058-flat-project-tags
2 parents 7dc5a06 + 6c51668 commit ada9adb

34 files changed

Lines changed: 2419 additions & 2905 deletions

assets/toolbox/game-configuration/js/index.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getSessionCurrent } from "../../../../src/api/session-api-client.js";
12
import {
23
createServerRepositoryClient,
34
readServerToolConstants,
@@ -65,6 +66,23 @@ function setText(element, value) {
6566
}
6667
}
6768

69+
function currentSession() {
70+
try {
71+
return getSessionCurrent();
72+
} catch {
73+
return { authenticated: false };
74+
}
75+
}
76+
77+
function redirectGuestWriteAction() {
78+
if (currentSession()?.authenticated === true) {
79+
return false;
80+
}
81+
setText(elements.statusLog, "Sign in before saving Game Configuration.");
82+
window.location.href = new URL("/account/sign-in.html", window.location.href).href;
83+
return true;
84+
}
85+
6886
function createListItem(text) {
6987
const item = document.createElement("li");
7088
item.textContent = text;
@@ -190,6 +208,9 @@ elements.form?.addEventListener("change", renderFormValidation);
190208

191209
elements.form?.addEventListener("submit", (event) => {
192210
event.preventDefault();
211+
if (redirectGuestWriteAction()) {
212+
return;
213+
}
193214
const snapshot = repository.getSnapshot();
194215
const projectId = snapshot.handoff.activeProject?.id || "";
195216

assets/toolbox/game-design/js/index.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getSessionCurrent } from "../../../../src/api/session-api-client.js";
12
import {
23
createServerRepositoryClient,
34
readServerToolConstants,
@@ -62,6 +63,23 @@ function setText(element, value) {
6263
}
6364
}
6465

66+
function currentSession() {
67+
try {
68+
return getSessionCurrent();
69+
} catch {
70+
return { authenticated: false };
71+
}
72+
}
73+
74+
function redirectGuestWriteAction() {
75+
if (currentSession()?.authenticated === true) {
76+
return false;
77+
}
78+
setText(elements.statusLog, "Sign in before saving Game Design.");
79+
window.location.href = new URL("/account/sign-in.html", window.location.href).href;
80+
return true;
81+
}
82+
6583
function populateSelect(select, values, placeholder) {
6684
if (!select) {
6785
return;
@@ -291,6 +309,9 @@ elements.form?.addEventListener("input", renderFormValidation);
291309

292310
elements.form?.addEventListener("submit", (event) => {
293311
event.preventDefault();
312+
if (redirectGuestWriteAction()) {
313+
return;
314+
}
294315
const result = repository.saveDesign(readForm());
295316
setText(elements.statusLog, result.message);
296317
render();

assets/toolbox/tags/js/index.js

Lines changed: 83 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { getSessionCurrent } from "../../../../src/api/session-api-client.js";
12
import {
23
createServerRepositoryClient,
34
readServerToolConstants,
@@ -16,14 +17,17 @@ const repository = createTagsToolApiRepository();
1617

1718
const elements = {
1819
add: document.querySelector("[data-tags-add]"),
20+
activeProject: document.querySelector("[data-tags-active-project]"),
21+
assignedCount: document.querySelector("[data-tags-assigned-count]"),
22+
assignedLabels: document.querySelector("[data-tags-assigned-labels]"),
1923
count: document.querySelector("[data-tags-count]"),
2024
log: document.querySelector("[data-tags-log]"),
2125
outputStatus: document.querySelector("[data-tags-output-status]"),
26+
refresh: document.querySelector("[data-tags-refresh]"),
2227
selected: document.querySelector("[data-tags-selected]"),
2328
status: document.querySelector("[data-tags-status]"),
2429
table: document.querySelector("[data-tags-table]"),
2530
tableCounts: document.querySelector("[data-tags-table-counts]"),
26-
usageCount: document.querySelector("[data-tags-usage-count]"),
2731
};
2832

2933
let editingTagId = "";
@@ -63,20 +67,42 @@ function createInput(value, label, datasetName) {
6367
function editingValues(row) {
6468
return {
6569
description: row.querySelector("[data-tags-description-input]")?.value || "",
66-
name: row.querySelector("[data-tags-name-input]")?.value || "",
70+
label: row.querySelector("[data-tags-name-input]")?.value || "",
6771
};
6872
}
6973

74+
function currentSession() {
75+
try {
76+
return getSessionCurrent();
77+
} catch {
78+
return { authenticated: false };
79+
}
80+
}
81+
82+
function redirectGuestWriteAction() {
83+
if (currentSession()?.authenticated === true) {
84+
return false;
85+
}
86+
setText(elements.log, "Sign in before saving project tags.");
87+
window.location.href = new URL("/account/sign-in.html", window.location.href).href;
88+
return true;
89+
}
90+
91+
function tagLabel(tag) {
92+
return tag?.label || tag?.name || "";
93+
}
94+
7095
function createEditRow(tag = null) {
7196
const row = document.createElement("tr");
7297
row.dataset.tagsEditingRow = tag?.id || "__new__";
7398

7499
const nameCell = document.createElement("td");
75-
nameCell.append(createInput(tag?.name || "", "Tag Name", "tagsNameInput"));
100+
nameCell.append(createInput(tagLabel(tag), "Tag Label", "tagsNameInput"));
76101

77102
const descriptionCell = document.createElement("td");
78103
descriptionCell.append(createInput(tag?.description || "", "Description", "tagsDescriptionInput"));
79104

105+
const assignedCell = createCell(tag?.assigned ? "Yes" : "No");
80106
const usageCell = createCell(tag ? String(tag.usageCount || 0) : "0");
81107

82108
const actionsCell = document.createElement("td");
@@ -88,15 +114,15 @@ function createEditRow(tag = null) {
88114
);
89115
actionsCell.append(actions);
90116

91-
row.append(nameCell, descriptionCell, usageCell, actionsCell);
117+
row.append(nameCell, descriptionCell, assignedCell, usageCell, actionsCell);
92118
return row;
93119
}
94120

95121
function createUsageCountButton(tag) {
96122
const cell = document.createElement("td");
97123
const button = createButton(String(tag.usageCount || 0), "tagsToggleUsage", tag.id);
98124
button.setAttribute("aria-expanded", String(expandedTagId === tag.id));
99-
button.setAttribute("aria-label", `Show usage for ${tag.name}`);
125+
button.setAttribute("aria-label", `Show usage for ${tagLabel(tag)}`);
100126
cell.append(button);
101127
return cell;
102128
}
@@ -113,14 +139,18 @@ function createTagRow(tag) {
113139
const actions = document.createElement("div");
114140
actions.className = "action-group action-group--tight";
115141
actions.append(
142+
tag.assigned
143+
? createButton("Remove", "tagsRemove", tag.id)
144+
: createButton("Assign", "tagsAssign", tag.id),
116145
createButton("Edit", "tagsEdit", tag.id),
117146
createButton("Trash", "tagsDelete", tag.id)
118147
);
119148
actionsCell.append(actions);
120149

121150
row.append(
122-
createCell(tag.name),
151+
createCell(tagLabel(tag)),
123152
createCell(tag.description || "No description"),
153+
createCell(tag.assigned ? "Yes" : "No"),
124154
createUsageCountButton(tag),
125155
actionsCell
126156
);
@@ -132,14 +162,14 @@ function createUsageRow(tag) {
132162
row.dataset.tagsUsageRow = tag.id;
133163

134164
const cell = document.createElement("td");
135-
cell.colSpan = 4;
165+
cell.colSpan = 5;
136166

137167
const wrapper = document.createElement("div");
138168
wrapper.className = "table-wrapper";
139169

140170
const table = document.createElement("table");
141171
table.className = "data-table";
142-
table.setAttribute("aria-label", `${tag.name} usage`);
172+
table.setAttribute("aria-label", `${tagLabel(tag)} usage`);
143173

144174
const head = document.createElement("thead");
145175
const headRow = document.createElement("tr");
@@ -151,7 +181,9 @@ function createUsageRow(tag) {
151181
const emptyRow = document.createElement("tr");
152182
const emptyCell = document.createElement("td");
153183
emptyCell.colSpan = 2;
154-
emptyCell.textContent = "No usage yet.";
184+
emptyCell.textContent = tag.assigned
185+
? "Assigned to the active project."
186+
: "No usage yet.";
155187
emptyRow.append(emptyCell);
156188
body.append(emptyRow);
157189
} else {
@@ -182,7 +214,7 @@ function renderTable(snapshot) {
182214
if (!snapshot.tags.length && editingTagId !== "__new__") {
183215
const row = document.createElement("tr");
184216
const cell = document.createElement("td");
185-
cell.colSpan = 4;
217+
cell.colSpan = 5;
186218
cell.textContent = "No tags added yet.";
187219
row.append(cell);
188220
elements.table.append(row);
@@ -212,11 +244,13 @@ function renderTableCounts(snapshot) {
212244

213245
function render() {
214246
const snapshot = repository.getSnapshot();
215-
const usageCount = snapshot.tags.reduce((total, tag) => total + tag.usageCount, 0);
247+
const assignedLabels = snapshot.assignedTags.map(tagLabel).join(", ") || "None";
216248
setText(elements.status, snapshot.status);
217249
setText(elements.outputStatus, snapshot.status);
250+
setText(elements.activeProject, snapshot.activeProject?.name || "No active project");
251+
setText(elements.assignedCount, String(snapshot.assignedTags.length));
252+
setText(elements.assignedLabels, assignedLabels);
218253
setText(elements.count, String(snapshot.tags.length));
219-
setText(elements.usageCount, String(usageCount));
220254
setText(elements.selected, selectedTagName);
221255
if (elements.add) {
222256
elements.add.disabled = editingTagId === "__new__";
@@ -229,15 +263,22 @@ elements.add?.addEventListener("click", () => {
229263
editingTagId = "__new__";
230264
expandedTagId = "";
231265
selectedTagName = "New tag";
232-
setText(elements.log, "Adding a workspace tag.");
266+
setText(elements.log, "Adding a project tag.");
267+
render();
268+
});
269+
270+
elements.refresh?.addEventListener("click", () => {
271+
setText(elements.log, "Project tags refreshed from the API.");
233272
render();
234273
});
235274

236275
elements.table?.addEventListener("click", (event) => {
276+
const assign = event.target.closest("[data-tags-assign]");
237277
const edit = event.target.closest("[data-tags-edit]");
238278
const save = event.target.closest("[data-tags-save]");
239279
const cancel = event.target.closest("[data-tags-cancel]");
240280
const deleteButton = event.target.closest("[data-tags-delete]");
281+
const remove = event.target.closest("[data-tags-remove]");
241282
const toggleUsage = event.target.closest("[data-tags-toggle-usage]");
242283

243284
if (toggleUsage) {
@@ -248,6 +289,28 @@ elements.table?.addEventListener("click", (event) => {
248289
return;
249290
}
250291

292+
if (assign) {
293+
if (redirectGuestWriteAction()) {
294+
return;
295+
}
296+
const result = repository.assignTagToProject(assign.dataset.tagsAssign);
297+
selectedTagName = tagLabel(result.tag) || selectedTagName;
298+
setText(elements.log, result.message);
299+
render();
300+
return;
301+
}
302+
303+
if (remove) {
304+
if (redirectGuestWriteAction()) {
305+
return;
306+
}
307+
const result = repository.removeTagFromProject(remove.dataset.tagsRemove);
308+
selectedTagName = tagLabel(result.tag) || selectedTagName;
309+
setText(elements.log, result.message);
310+
render();
311+
return;
312+
}
313+
251314
if (edit) {
252315
editingTagId = edit.dataset.tagsEdit;
253316
expandedTagId = "";
@@ -266,21 +329,27 @@ elements.table?.addEventListener("click", (event) => {
266329
}
267330

268331
if (save) {
332+
if (redirectGuestWriteAction()) {
333+
return;
334+
}
269335
const row = save.closest("[data-tags-editing-row]");
270336
const values = editingValues(row);
271337
const result = save.dataset.tagsSave === "__new__"
272338
? repository.addTag(values)
273339
: repository.updateTag(save.dataset.tagsSave, values);
274340
if (result.added || result.updated) {
275341
editingTagId = "";
276-
selectedTagName = result.tag?.name || "None";
342+
selectedTagName = tagLabel(result.tag) || "None";
277343
}
278344
setText(elements.log, result.message);
279345
render();
280346
return;
281347
}
282348

283349
if (deleteButton) {
350+
if (redirectGuestWriteAction()) {
351+
return;
352+
}
284353
const result = repository.deleteTag(deleteButton.dataset.tagsDelete);
285354
if (result.deleted) {
286355
editingTagId = "";

docs_build/database/ddl/game-configuration.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,18 @@ CREATE TABLE IF NOT EXISTS game_configuration_records (
2020
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_gamekey ON game_configuration_records ("gameKey");
2121
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_createdby ON game_configuration_records ("createdBy");
2222
CREATE INDEX IF NOT EXISTS idx_game_configuration_records_updatedby ON game_configuration_records ("updatedBy");
23+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameName" text;
24+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gamePurpose" text;
25+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameType" text;
26+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "genre" text;
27+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "playStyle" text;
28+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameBasics" text;
29+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "gameRules" text;
30+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "playerSetup" text;
31+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "worldSetup" text;
32+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "objectSetup" text;
33+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "audioSetup" text;
34+
ALTER TABLE game_configuration_records ADD COLUMN IF NOT EXISTS "testReadiness" text;
2335

2436
CREATE TABLE IF NOT EXISTS game_configuration_validation_items (
2537
key text PRIMARY KEY,
@@ -36,3 +48,4 @@ CREATE TABLE IF NOT EXISTS game_configuration_validation_items (
3648
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_gamekey ON game_configuration_validation_items ("gameKey");
3749
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_createdby ON game_configuration_validation_items ("createdBy");
3850
CREATE INDEX IF NOT EXISTS idx_game_configuration_validation_items_updatedby ON game_configuration_validation_items ("updatedBy");
51+
ALTER TABLE game_configuration_validation_items ADD COLUMN IF NOT EXISTS "section" text;

docs_build/database/ddl/game-design.sql

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,15 @@ CREATE INDEX IF NOT EXISTS idx_game_design_documents_gamekey ON game_design_docu
2020
CREATE INDEX IF NOT EXISTS idx_game_design_documents_createdby ON game_design_documents ("createdBy");
2121
CREATE INDEX IF NOT EXISTS idx_game_design_documents_updatedby ON game_design_documents ("updatedBy");
2222

23+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "gamePurpose" text;
24+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "gameType" text;
25+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "genre" text;
26+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "playStyle" text;
27+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "playerMode" text;
28+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "designSummary" text;
29+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "capabilityDemoAuthoring" boolean NOT NULL DEFAULT false;
30+
ALTER TABLE game_design_documents ADD COLUMN IF NOT EXISTS "capabilityDemoNotes" text;
31+
2332
CREATE TABLE IF NOT EXISTS game_design_validation_items (
2433
key text PRIMARY KEY,
2534
"gameKey" text REFERENCES game_workspace_games(key),
@@ -35,3 +44,21 @@ CREATE TABLE IF NOT EXISTS game_design_validation_items (
3544
CREATE INDEX IF NOT EXISTS idx_game_design_validation_items_gamekey ON game_design_validation_items ("gameKey");
3645
CREATE INDEX IF NOT EXISTS idx_game_design_validation_items_createdby ON game_design_validation_items ("createdBy");
3746
CREATE INDEX IF NOT EXISTS idx_game_design_validation_items_updatedby ON game_design_validation_items ("updatedBy");
47+
ALTER TABLE game_design_validation_items ADD COLUMN IF NOT EXISTS "field" text;
48+
49+
CREATE TABLE IF NOT EXISTS game_design_capability_demos (
50+
key text PRIMARY KEY,
51+
"gameKey" text REFERENCES game_workspace_games(key),
52+
"gameName" text,
53+
"gamePurpose" text,
54+
"authoringMode" text,
55+
"status" text,
56+
"createdAt" timestamptz NOT NULL DEFAULT now(),
57+
"updatedAt" timestamptz NOT NULL DEFAULT now(),
58+
"createdBy" text NOT NULL REFERENCES users(key),
59+
"updatedBy" text NOT NULL REFERENCES users(key)
60+
);
61+
62+
CREATE INDEX IF NOT EXISTS idx_game_design_capability_demos_gamekey ON game_design_capability_demos ("gameKey");
63+
CREATE INDEX IF NOT EXISTS idx_game_design_capability_demos_createdby ON game_design_capability_demos ("createdBy");
64+
CREATE INDEX IF NOT EXISTS idx_game_design_capability_demos_updatedby ON game_design_capability_demos ("updatedBy");

0 commit comments

Comments
 (0)