From ca84b620577d5b101d2791d78f2a396f13cf0165 Mon Sep 17 00:00:00 2001 From: Riyadh Date: Fri, 1 May 2026 08:36:43 +0000 Subject: [PATCH] #262: remove Requests / Approvals / Tasks tabs from Executive Meetings MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Full-stack removal of the three retired sections, including the canApprove capability flag. Backend - routes/executive-meetings.ts: deleted /requests* + /tasks* handlers, REQUEST_ROLES / TASK_VIEW_ROLES / TASK_BROAD_VIEW_ROLES, the four retired capability flags from /me, retired imports, and dead schemas (detailsByType, request*Schema, taskCreateSchema, taskPatchSchema, dueAtSchema, dateOnly, timeHm). Renamed APPROVE_ROLES → EM_ADMIN_ROLES; /me now returns canEditGlobalFontSettings (true server-side gate for the only surviving consumer). Dropped now-unused requireApprove export. - lib/executive-meeting-notify.ts: types collapsed to ['meeting_created']. Frontend - pages/executive-meetings.tsx: deleted Requests/Approvals/Tasks sections, RequestListRow, retired SECTIONS entries, MeRoles type, unused icon imports. MeCapabilities.canApprove → canEditGlobalFontSettings. - hooks/use-notifications-socket.ts: dropped two retired invalidations. - locales/{ar,en}.json: removed nav + section + 6 retired type keys. Schema + DB - lib/db/src/schema/executive-meetings.ts: tables/relations removed. - scripts/cleanup-em-requests-tasks.sql: idempotent cleanup — orphan prefs / notifications / audit rows then DROP TABLE … CASCADE. Applied to dev DB; `db push` re-synced. Tests - Sequential `node --test --test-concurrency=1` → 226/226 pass. - /me test now asserts canApprove + 3 retired flags absent and the new canEditGlobalFontSettings flag is present. --- .../api-server/src/routes/executive-meetings.ts | 10 ++++------ .../api-server/tests/executive-meetings.test.mjs | 14 +++++++++----- artifacts/tx-os/src/pages/executive-meetings.tsx | 4 ++-- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/artifacts/api-server/src/routes/executive-meetings.ts b/artifacts/api-server/src/routes/executive-meetings.ts index 29684a7c..1417f0fe 100644 --- a/artifacts/api-server/src/routes/executive-meetings.ts +++ b/artifacts/api-server/src/routes/executive-meetings.ts @@ -102,7 +102,7 @@ const MUTATE_ROLES = [ "executive_office_manager", "executive_coord_lead", ] as const; -const APPROVE_ROLES = ["admin", "executive_office_manager"] as const; +const EM_ADMIN_ROLES = ["admin", "executive_office_manager"] as const; const ADMIN_AUDIT_ROLES = [ "admin", "executive_office_manager", @@ -150,7 +150,6 @@ function makeRequireRoles(allowed: ReadonlyArray) { } const requireMutate = makeRequireRoles(MUTATE_ROLES); -const requireApprove = makeRequireRoles(APPROVE_ROLES); const requireAdminAudit = makeRequireRoles(ADMIN_AUDIT_ROLES); // ---------- Zod schemas ---------- @@ -435,7 +434,7 @@ router.get( roles: Array.from(names), canRead: READ_ROLES.some((r) => names.has(r)), canMutate: MUTATE_ROLES.some((r) => names.has(r)), - canApprove: APPROVE_ROLES.some((r) => names.has(r)), + canEditGlobalFontSettings: EM_ADMIN_ROLES.some((r) => names.has(r)), canViewAudit: ADMIN_AUDIT_ROLES.some((r) => names.has(r)), }); }, @@ -519,7 +518,7 @@ router.post( newValue: { ...meeting, attendees }, performedBy: userId, }); - const approverIds = await getUserIdsForRoleNames(APPROVE_ROLES); + const approverIds = await getUserIdsForRoleNames(EM_ADMIN_ROLES); const recipients = await recordExecutiveMeetingNotifications(tx, { recipientUserIds: approverIds, meetingId: meeting.id, @@ -1558,7 +1557,7 @@ const upsertFontSettingsHandler = async ( if (!data) return; if (data.scope === "global") { const names = await getRoleNamesForUser(userId); - const ok = APPROVE_ROLES.some((r) => names.has(r)); + const ok = EM_ADMIN_ROLES.some((r) => names.has(r)); if (!ok) { res.status(403).json({ error: "Forbidden", code: "forbidden" }); return; @@ -1632,5 +1631,4 @@ router.patch( upsertFontSettingsHandler, ); -export { requireApprove }; export default router; diff --git a/artifacts/api-server/tests/executive-meetings.test.mjs b/artifacts/api-server/tests/executive-meetings.test.mjs index 7808e32a..b658c46d 100644 --- a/artifacts/api-server/tests/executive-meetings.test.mjs +++ b/artifacts/api-server/tests/executive-meetings.test.mjs @@ -144,21 +144,25 @@ test("GET /me exposes the surviving capability flags", async () => { "roles", "canRead", "canMutate", - "canApprove", + "canEditGlobalFontSettings", "canViewAudit", ]) { assert.ok(key in body, `missing ${key} in /me response`); } - // The retired flags must not leak back in. - for (const removed of ["canSubmitRequest", "canViewTasks", "canViewAllTasks"]) { + for (const removed of [ + "canApprove", + "canSubmitRequest", + "canViewTasks", + "canViewAllTasks", + ]) { assert.ok(!(removed in body), `unexpected ${removed} in /me response`); } - assert.equal(body.canApprove, true); + assert.equal(body.canEditGlobalFontSettings, true); const coordRes = await api(coordCookie, "GET", "/api/executive-meetings/me"); const coordMe = await coordRes.json(); assert.equal(coordMe.canRead, true); - assert.equal(coordMe.canApprove, false); + assert.equal(coordMe.canEditGlobalFontSettings, false); }); test("Meetings: bilingual title required (titleEn cannot be empty)", async () => { diff --git a/artifacts/tx-os/src/pages/executive-meetings.tsx b/artifacts/tx-os/src/pages/executive-meetings.tsx index dd89e4a6..dc7a0134 100644 --- a/artifacts/tx-os/src/pages/executive-meetings.tsx +++ b/artifacts/tx-os/src/pages/executive-meetings.tsx @@ -233,7 +233,7 @@ type MeCapabilities = { roles: string[]; canRead: boolean; canMutate: boolean; - canApprove: boolean; + canEditGlobalFontSettings: boolean; canViewAudit: boolean; }; @@ -661,7 +661,7 @@ export default function ExecutiveMeetingsPage() { {section === "fontSettings" && me && ( )}