Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions assets/theme-v2/css/tables.css
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,16 @@ td {
mask-image: url("../images/gfs-chevron-up.svg")
}

.idea-board-notes-child-surface {
margin-left: calc(var(--space-14) * 2);
max-width: calc(100% - (var(--space-14) * 2))
}

.idea-board-notes-child-actions {
padding-left: var(--space-14);
padding-top: var(--space-10)
}

.tool-form-table {
table-layout: fixed;
width: 100%
Expand Down
41 changes: 40 additions & 1 deletion tests/playwright/tools/IdeaBoardTableNotes.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,43 @@ async function expectButtonLeftAligned(page, buttonSelector, containerSelector)
expect(metrics.buttonLeft).toBeLessThan(metrics.containerLeft + metrics.containerWidth / 2);
}

async function expectExpandedNotesChildIndentation(page, ideaId, expectedInputRows = 0) {
const metrics = await page.locator(`[data-idea-board-expanded-row='${ideaId}']`).evaluate((row, targetIdeaId) => {
const expandedCell = row.querySelector(":scope > td");
const childSurface = row.querySelector(".idea-board-notes-child-surface");
const noteCell = row.querySelector(`[data-idea-board-notes-table='${targetIdeaId}'] tbody tr td:first-child`);
const noteInput = row.querySelector("[data-idea-board-note-input]");
const addNote = row.querySelector(`[data-idea-board-add-note='${targetIdeaId}']`);
const addNoteActions = row.querySelector(".idea-board-notes-child-actions");
const expandedStyles = getComputedStyle(expandedCell);
const noteCellStyles = getComputedStyle(noteCell);
const addNoteActionStyles = getComputedStyle(addNoteActions);
const expandedRect = expandedCell.getBoundingClientRect();
const childRect = childSurface.getBoundingClientRect();
const noteCellRect = noteCell.getBoundingClientRect();
const expandedPadding = Number.parseFloat(expandedStyles.paddingLeft || "0");
const noteCellPadding = Number.parseFloat(noteCellStyles.paddingLeft || "0");
return {
addNoteLeft: addNote.getBoundingClientRect().left,
childSurfaceLeft: childRect.left,
expandedContentLeft: expandedRect.left + expandedPadding,
expectedContentLeft: expandedRect.left + 2 * (expandedPadding + noteCellPadding),
inputLeft: noteInput ? noteInput.getBoundingClientRect().left : null,
inputRows: row.querySelectorAll("[data-idea-board-note-input-row]").length,
noteContentLeft: noteCellRect.left + noteCellPadding,
actionContentLeft: addNoteActions.getBoundingClientRect().left + Number.parseFloat(addNoteActionStyles.paddingLeft || "0"),
};
}, ideaId);
expect(metrics.childSurfaceLeft).toBeGreaterThan(metrics.expandedContentLeft);
expect(Math.abs(metrics.noteContentLeft - metrics.expectedContentLeft)).toBeLessThanOrEqual(2);
expect(Math.abs(metrics.addNoteLeft - metrics.expectedContentLeft)).toBeLessThanOrEqual(2);
expect(Math.abs(metrics.actionContentLeft - metrics.expectedContentLeft)).toBeLessThanOrEqual(2);
expect(metrics.inputRows).toBe(expectedInputRows);
if (expectedInputRows > 0) {
expect(Math.abs(metrics.inputLeft - metrics.expectedContentLeft)).toBeLessThanOrEqual(2);
}
}

test("Idea Board uses DB-shaped accordion table ideas and notes", async ({ page }) => {
const server = await startRepoServer();
const previousApiUrl = process.env.GAMEFOUNDRY_API_URL;
Expand Down Expand Up @@ -130,7 +167,7 @@ test("Idea Board uses DB-shaped accordion table ideas and notes", async ({ page
await expect(page.locator("[data-idea-board-expanded-row='top-thoughts'] > td > .content-stack")).toHaveCount(0);
await expect(page.locator("[data-idea-board-notes-table='top-thoughts'] th[scope='col']")).toHaveText(["Note", "Actions"]);
await expect(page.locator("[data-idea-board-add-note='top-thoughts']")).toHaveText("Add Note");
await expectButtonLeftAligned(page, "[data-idea-board-add-note='top-thoughts']", "[data-idea-board-expanded-row='top-thoughts'] > td");
await expectExpandedNotesChildIndentation(page, "top-thoughts");
await expect(page.locator("[data-idea-board-notes-table] th[scope='col']", { hasText: "Type" })).toHaveCount(0);
await expect(page.locator("[data-idea-board-notes-table] th[scope='col']", { hasText: "Created By" })).toHaveCount(0);
await expect(page.locator("[data-idea-board-notes-table] th[scope='col']", { hasText: "Created" })).toHaveCount(0);
Expand All @@ -141,13 +178,15 @@ test("Idea Board uses DB-shaped accordion table ideas and notes", async ({ page
await expect(systemNote.locator("[data-idea-board-note-action='delete']")).toHaveCount(0);
await systemNote.locator("[data-idea-board-note-action='edit']").click();
await expect(page.locator("[data-idea-board-note-input-row] [data-idea-board-note-action]")).toHaveText(["Save", "Cancel"]);
await expectExpandedNotesChildIndentation(page, "top-thoughts", 1);
await page.locator("[data-idea-board-note-input]").fill("System note can be edited in-place.");
await page.locator("[data-idea-board-note-action='save']").click();
await expect(page.locator("[data-idea-board-notes-table='top-thoughts']")).toContainText("System note can be edited in-place.");
await expect(page.locator("[data-idea-board-system-note] [data-idea-board-note-action='delete']")).toHaveCount(0);

await page.locator("[data-idea-board-add-note='top-thoughts']").click();
await expect(page.locator("[data-idea-board-note-input-row] [data-idea-board-note-action]")).toHaveText(["Save", "Cancel"]);
await expectExpandedNotesChildIndentation(page, "top-thoughts", 1);
await page.locator("[data-idea-board-note-input]").fill("Add a fourth table-shaped note.");
await page.locator("[data-idea-board-note-action='save']").click();
await expect(page.locator("[data-idea-board-notes-table='top-thoughts']")).toContainText("Add a fourth table-shaped note.");
Expand Down
39 changes: 38 additions & 1 deletion tests/playwright/tools/ToolboxRoutePages.spec.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,43 @@ async function expectButtonLeftAligned(page, buttonSelector, containerSelector)
expect(metrics.buttonLeft).toBeLessThan(metrics.containerLeft + metrics.containerWidth / 2);
}

async function expectExpandedNotesChildIndentation(page, ideaId, expectedInputRows = 0) {
const metrics = await page.locator(`[data-idea-board-expanded-row='${ideaId}']`).evaluate((row, targetIdeaId) => {
const expandedCell = row.querySelector(":scope > td");
const childSurface = row.querySelector(".idea-board-notes-child-surface");
const noteCell = row.querySelector(`[data-idea-board-notes-table='${targetIdeaId}'] tbody tr td:first-child`);
const noteInput = row.querySelector("[data-idea-board-note-input]");
const addNote = row.querySelector(`[data-idea-board-add-note='${targetIdeaId}']`);
const addNoteActions = row.querySelector(".idea-board-notes-child-actions");
const expandedStyles = getComputedStyle(expandedCell);
const noteCellStyles = getComputedStyle(noteCell);
const addNoteActionStyles = getComputedStyle(addNoteActions);
const expandedRect = expandedCell.getBoundingClientRect();
const childRect = childSurface.getBoundingClientRect();
const noteCellRect = noteCell.getBoundingClientRect();
const expandedPadding = Number.parseFloat(expandedStyles.paddingLeft || "0");
const noteCellPadding = Number.parseFloat(noteCellStyles.paddingLeft || "0");
return {
addNoteLeft: addNote.getBoundingClientRect().left,
childSurfaceLeft: childRect.left,
expandedContentLeft: expandedRect.left + expandedPadding,
expectedContentLeft: expandedRect.left + 2 * (expandedPadding + noteCellPadding),
inputLeft: noteInput ? noteInput.getBoundingClientRect().left : null,
inputRows: row.querySelectorAll("[data-idea-board-note-input-row]").length,
noteContentLeft: noteCellRect.left + noteCellPadding,
actionContentLeft: addNoteActions.getBoundingClientRect().left + Number.parseFloat(addNoteActionStyles.paddingLeft || "0"),
};
}, ideaId);
expect(metrics.childSurfaceLeft).toBeGreaterThan(metrics.expandedContentLeft);
expect(Math.abs(metrics.noteContentLeft - metrics.expectedContentLeft)).toBeLessThanOrEqual(2);
expect(Math.abs(metrics.addNoteLeft - metrics.expectedContentLeft)).toBeLessThanOrEqual(2);
expect(Math.abs(metrics.actionContentLeft - metrics.expectedContentLeft)).toBeLessThanOrEqual(2);
expect(metrics.inputRows).toBe(expectedInputRows);
if (expectedInputRows > 0) {
expect(Math.abs(metrics.inputLeft - metrics.expectedContentLeft)).toBeLessThanOrEqual(2);
}
}

test("tools route aliases render toolbox tool pages", async ({ page }) => {
const server = await startRepoServer();
const failedRequests = [];
Expand Down Expand Up @@ -289,7 +326,7 @@ test("Idea Board launches from Toolbox with accordion table notes model", async
await expect(page.getByText("Selected")).toHaveCount(0);
await expect(page.locator("[data-idea-board-add-note='top-thoughts']")).toBeVisible();
await expect(page.locator("[data-idea-board-add-note='top-thoughts']")).toHaveText("Add Note");
await expectButtonLeftAligned(page, "[data-idea-board-add-note='top-thoughts']", "[data-idea-board-expanded-row='top-thoughts'] > td");
await expectExpandedNotesChildIndentation(page, "top-thoughts");
await expect(page.locator("[data-idea-board-create-project]")).toBeVisible();
await expect(page.locator("[data-idea-board-create-project]")).toBeDisabled();
await expect(page.locator("style, [style], script:not([src])")).toHaveCount(0);
Expand Down
10 changes: 7 additions & 3 deletions toolbox/idea-board/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ function renderExpandedNotesRow(tbody, record) {
const content = document.createElement("td");
content.colSpan = 6;

const childSurface = document.createElement("div");
childSurface.className = "idea-board-notes-child-surface";

const tableWrapper = document.createElement("div");
tableWrapper.className = "table-wrapper";
const notesTable = document.createElement("table");
Expand All @@ -281,7 +284,7 @@ function renderExpandedNotesRow(tbody, record) {
notesBody.dataset.ideaBoardNotesBody = record.ideaId;
notesTable.append(notesBody);
tableWrapper.append(notesTable);
content.append(tableWrapper);
childSurface.append(tableWrapper);

for (const note of notesForIdea(record.ideaId)) {
if (state.editingNoteId === note.noteId) {
Expand All @@ -293,11 +296,12 @@ function renderExpandedNotesRow(tbody, record) {
if (state.addingNoteIdeaId === record.ideaId) renderNoteInputRow(notesBody, record.ideaId);

const controls = document.createElement("div");
controls.className = "action-group";
controls.className = "action-group idea-board-notes-child-actions";
const addNote = actionButton("Add Note", "add", "ideaBoardNoteAction", "primary");
addNote.dataset.ideaBoardAddNote = record.ideaId;
controls.append(addNote);
content.append(controls);
childSurface.append(controls);
content.append(childSurface);

row.append(content);
tbody.append(row);
Expand Down
Loading