mirror of
https://github.com/github/awesome-copilot.git
synced 2026-10-14 07:44:43 +00:00
fix(canvases): sort column cards oldest first
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: cd29e26b-0e56-48bf-a046-ac749aef86ce
This commit is contained in:
co-authored by
Copilot App
parent
a10206b7f6
commit
0f1ca9817a
@@ -10,6 +10,7 @@ Open it by asking Copilot to "open the plugin review board" (canvas id `external
|
||||
- **Kanban board** with buckets: Unreviewed → Reviewing → Straight reject / Probably reject / Needs review /
|
||||
Accept → Actioned. Drag cards between buckets (or use the *Bucket* dropdown in the details panel).
|
||||
Dragging a card back to *Unreviewed* clears its AI review so it's picked up by the next review.
|
||||
Cards in each bucket are sorted oldest to newest by creation date.
|
||||
- **Perform review** asks the agent to review every item without an AI review, using
|
||||
[`review-guidance.md`](./review-guidance.md) and the decisions you've made from the board. Results are
|
||||
recorded with the `record_review` canvas action and move cards into their recommended bucket.
|
||||
@@ -58,6 +59,7 @@ not imported; boards start fresh.
|
||||
|
||||
## Regression tests
|
||||
|
||||
Run `node --test eng/board-column-order.test.mjs` to check oldest-first column ordering.
|
||||
Run `node --experimental-vm-modules --test eng/board-state-storage.test.mjs` from the repository root
|
||||
to check both canvases' session-scoped persistence without accessing GitHub.
|
||||
Run `node --test eng/board-bulk-actions.test.mjs` to check column confirmation, staged feedback,
|
||||
|
||||
@@ -179,7 +179,9 @@ function renderBoard() {
|
||||
);
|
||||
|
||||
const columns = board.columns.map((column) => {
|
||||
const items = board.items.filter((item) => item.column === column.id && matchesFilter(item));
|
||||
const items = board.items
|
||||
.filter((item) => item.column === column.id && matchesFilter(item))
|
||||
.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt) || a.number - b.number);
|
||||
const cards = h(
|
||||
"div",
|
||||
{ class: "column-cards" },
|
||||
|
||||
@@ -10,7 +10,8 @@ authenticated `gh` CLI.
|
||||
|
||||
- **Buckets** — `Unreviewed`, `Reviewing`, `Close`, `Request changes`,
|
||||
`Needs insight`, `Approve`, `Actioned`. The AI recommendation picks the bucket;
|
||||
dragging a card overrides it.
|
||||
dragging a card overrides it. Cards in each bucket are sorted oldest to newest
|
||||
by creation date.
|
||||
- **AI reviews** — "Review pending" asks the agent to review every PR that has never
|
||||
been reviewed or whose review is stale. The agent records structured results
|
||||
(rationale, repo fit, compliance, differentiation, risks, validation, confidence,
|
||||
@@ -90,6 +91,7 @@ Results arriving after a manual move, reset, or replacement review are rejected.
|
||||
|
||||
## Regression tests
|
||||
|
||||
Run `node --test eng/board-column-order.test.mjs` to check oldest-first column ordering.
|
||||
Run `node --test eng/open-pr-board.test.mjs` from the repository root. GitHub writes
|
||||
are tested with injected in-process fakes, never the authenticated CLI.
|
||||
Run `node --test eng/board-bulk-actions.test.mjs` to check column confirmation, staged feedback,
|
||||
|
||||
@@ -280,7 +280,9 @@ function renderBoard() {
|
||||
for (const list of el.board.querySelectorAll(".column-cards")) scroll.set(list.dataset.column, list.scrollTop);
|
||||
|
||||
const columns = board.columns.map((column) => {
|
||||
const items = board.items.filter((item) => item.column === column.id && matchesFilter(item));
|
||||
const items = board.items
|
||||
.filter((item) => item.column === column.id && matchesFilter(item))
|
||||
.sort((a, b) => new Date(a.createdAt) - new Date(b.createdAt) || a.number - b.number);
|
||||
const list = h(
|
||||
"div",
|
||||
{
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { readFile } from "node:fs/promises";
|
||||
import vm from "node:vm";
|
||||
import { test } from "node:test";
|
||||
|
||||
for (const boardName of ["open-pr-board", "external-plugin-review-board"]) {
|
||||
test(`${boardName}: columns render oldest to newest without changing board state`, async () => {
|
||||
const source = await readFile(
|
||||
new URL(`../.github/extensions/${boardName}/public/app.js`, import.meta.url), "utf8",
|
||||
);
|
||||
const items = [
|
||||
{ number: 50, column: "approve", createdAt: "2026-10-14T00:00:00Z", updatedAt: "2026-10-14T00:00:00Z" },
|
||||
{ number: 30, column: "approve", createdAt: "2026-10-01T00:00:00Z", updatedAt: "2026-10-14T01:00:00Z" },
|
||||
{ number: 10, column: "close", createdAt: "2026-09-01T00:00:00Z" },
|
||||
{ number: 20, column: "approve", createdAt: "2026-10-01T00:00:00Z" },
|
||||
{ number: 5, column: "approve", createdAt: "2026-08-01T00:00:00Z", hidden: true },
|
||||
{ number: 40, column: "close", createdAt: "2026-10-10T00:00:00Z" },
|
||||
];
|
||||
const original = structuredClone(items);
|
||||
const rendered = [];
|
||||
const node = { querySelectorAll: () => [], replaceChildren() {} };
|
||||
const ui = {
|
||||
board: node, title: {}, summary: {}, meta: {}, review: {},
|
||||
};
|
||||
const context = vm.createContext({
|
||||
board: { items, columns: [{ id: "approve" }, { id: "close" }, { id: "empty" }] },
|
||||
el: ui, ui, filter: "",
|
||||
matchesFilter: (item) => !item.hidden,
|
||||
renderCard: (item) => { rendered.push(item.number); return {}; },
|
||||
h: () => ({}),
|
||||
relativeTime: () => "now",
|
||||
pendingReviewCount: () => 0,
|
||||
COLUMN_HINTS: {},
|
||||
});
|
||||
vm.runInContext(source.slice(source.indexOf("function renderBoard()"), source.indexOf("function columnItems(")), context);
|
||||
context.renderBoard();
|
||||
assert.deepEqual(rendered, [20, 30, 50, 10, 40]);
|
||||
assert.deepEqual(items, original);
|
||||
|
||||
items[0].column = "close";
|
||||
rendered.length = 0;
|
||||
context.renderBoard();
|
||||
assert.deepEqual(rendered, [20, 30, 10, 40, 50]);
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user