fix(dashboard): expose column roles to browser bundle (#3151)
## Summary - export the browser-safe `@fusion/core/column-roles` subpath - keep Vite/Vitest aliases ahead of broad `@fusion/core` aliases - restore production dashboard builds after task undo classification adopted shared column-role helpers ## Test plan - `node scripts/check-no-node-only-core-imports-in-dashboard.mjs` - `FUSION_DASHBOARD_DEEP=1 pnpm --filter @fusion/dashboard exec vitest run app/utils/__tests__/taskRevert.test.ts --pool=threads --maxWorkers=1` - `pnpm --filter @fusion/core typecheck` - `pnpm --filter @fusion/dashboard typecheck` - `CI=true pnpm check:changesets` - `pnpm build` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Fixed dashboard build compatibility for browser-based environments. * Improved reliability when importing column role functionality across supported application components. * **Refactor** * Made column role utilities available through a dedicated browser-safe entry point. * **Chores** * Updated development and test configurations to consistently resolve the new entry point. * Documented the browser-safe module classification and recorded the release patch. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
7
.changeset/dashboard-column-role-browser-export.md
Normal file
7
.changeset/dashboard-column-role-browser-export.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
"@runfusion/fusion": patch
|
||||||
|
---
|
||||||
|
|
||||||
|
summary: Fix the dashboard build after task undo classification began using shared column-role helpers.
|
||||||
|
category: fix
|
||||||
|
dev: Export the browser-safe column-roles core leaf and mirror its alias across Vite and Vitest consumers so broad core aliases cannot swallow the subpath.
|
||||||
@@ -29,6 +29,11 @@
|
|||||||
"source": "./src/task-delete-attribution.ts",
|
"source": "./src/task-delete-attribution.ts",
|
||||||
"import": "./dist/task-delete-attribution.js"
|
"import": "./dist/task-delete-attribution.js"
|
||||||
},
|
},
|
||||||
|
"./column-roles": {
|
||||||
|
"types": "./src/column-roles.ts",
|
||||||
|
"source": "./src/column-roles.ts",
|
||||||
|
"import": "./dist/column-roles.js"
|
||||||
|
},
|
||||||
"./detect-content-language": {
|
"./detect-content-language": {
|
||||||
"types": "./src/detect-content-language.ts",
|
"types": "./src/detect-content-language.ts",
|
||||||
"source": "./src/detect-content-language.ts",
|
"source": "./src/detect-content-language.ts",
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { Task } from "@fusion/core";
|
import type { Task } from "@fusion/core";
|
||||||
import { isTerminalColumnRole, type ColumnRoleTraitFlags } from "@fusion/core";
|
import { isTerminalColumnRole, type ColumnRoleTraitFlags } from "@fusion/core/column-roles";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* FNXC:TaskRevert 2026-07-04-00:00:
|
* FNXC:TaskRevert 2026-07-04-00:00:
|
||||||
|
|||||||
@@ -141,6 +141,7 @@ export default defineConfig({
|
|||||||
Ordered before the `@fusion/core` entry because Vite matches aliases in order and the broader key would otherwise swallow this subpath — the exact failure this line was added to fix (`"FUSION_CLIENT_HEADER" is not exported by ../core/src/types.ts`).
|
Ordered before the `@fusion/core` entry because Vite matches aliases in order and the broader key would otherwise swallow this subpath — the exact failure this line was added to fix (`"FUSION_CLIENT_HEADER" is not exported by ../core/src/types.ts`).
|
||||||
*/
|
*/
|
||||||
"@fusion/core/task-delete-attribution": resolve(__dirname, "../core/src/task-delete-attribution.ts"),
|
"@fusion/core/task-delete-attribution": resolve(__dirname, "../core/src/task-delete-attribution.ts"),
|
||||||
|
"@fusion/core/column-roles": resolve(__dirname, "../core/src/column-roles.ts"),
|
||||||
"@fusion/core/detect-content-language": resolve(__dirname, "../core/src/detect-content-language.ts"),
|
"@fusion/core/detect-content-language": resolve(__dirname, "../core/src/detect-content-language.ts"),
|
||||||
"@fusion/core": resolve(__dirname, "../core/src/types.ts"),
|
"@fusion/core": resolve(__dirname, "../core/src/types.ts"),
|
||||||
"@fusion/dashboard/app/components/TaskCard": resolve(__dirname, "app/components/TaskCard.tsx"),
|
"@fusion/dashboard/app/components/TaskCard": resolve(__dirname, "app/components/TaskCard.tsx"),
|
||||||
|
|||||||
@@ -534,6 +534,7 @@ export default defineConfig({
|
|||||||
Keep this exact alias before the broader core alias so Vite does not rewrite the subpath.
|
Keep this exact alias before the broader core alias so Vite does not rewrite the subpath.
|
||||||
*/
|
*/
|
||||||
"@fusion/core/task-delete-attribution": resolve(__dirname, "../core/src/task-delete-attribution.ts"),
|
"@fusion/core/task-delete-attribution": resolve(__dirname, "../core/src/task-delete-attribution.ts"),
|
||||||
|
"@fusion/core/column-roles": resolve(__dirname, "../core/src/column-roles.ts"),
|
||||||
"@fusion/core": resolve(__dirname, "../core/src/index.ts"),
|
"@fusion/core": resolve(__dirname, "../core/src/index.ts"),
|
||||||
"@fusion/engine": resolve(__dirname, "../engine/src/index.ts"),
|
"@fusion/engine": resolve(__dirname, "../engine/src/index.ts"),
|
||||||
"@fusion/plugin-sdk": resolve(__dirname, "../plugin-sdk/src/index.ts"),
|
"@fusion/plugin-sdk": resolve(__dirname, "../plugin-sdk/src/index.ts"),
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ const fusionAliases = {
|
|||||||
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
||||||
browser-safe delete-attribution leaf.
|
browser-safe delete-attribution leaf.
|
||||||
*/
|
*/
|
||||||
|
"@fusion/core/column-roles": resolve(__dirname, "../core/src/column-roles.ts"),
|
||||||
"@fusion/core/task-delete-attribution": resolve(__dirname, "../core/src/task-delete-attribution.ts"),
|
"@fusion/core/task-delete-attribution": resolve(__dirname, "../core/src/task-delete-attribution.ts"),
|
||||||
"@fusion/core": resolve(__dirname, "../core/src/index.ts"),
|
"@fusion/core": resolve(__dirname, "../core/src/index.ts"),
|
||||||
"@fusion/dashboard": resolve(__dirname, "../dashboard/src/index.ts"),
|
"@fusion/dashboard": resolve(__dirname, "../dashboard/src/index.ts"),
|
||||||
|
|||||||
@@ -168,7 +168,7 @@ pgDescribe("scheduler parked-column resolution against a live store", () => {
|
|||||||
|
|
||||||
it("REGRESSION — a dependent in a RENAMED hold column IS unblocked when its blocker is deleted", async () => {
|
it("REGRESSION — a dependent in a RENAMED hold column IS unblocked when its blocker is deleted", async () => {
|
||||||
/*
|
/*
|
||||||
FNXC:WorkflowResolvedColumns 2026-08-01-02:20 (fleet — the flip this test was written to catch):
|
FNXC:WorkflowResolvedColumns 2026-07-31-06:35 (fleet — the flip this test was written to catch):
|
||||||
This was a CHARACTERIZATION of the inert sync read: `resolveTaskParkedColumnsSync` answered
|
This was a CHARACTERIZATION of the inert sync read: `resolveTaskParkedColumnsSync` answered
|
||||||
`{ hold: "todo" }` for a board whose hold column is `backlog`, so the reconciliation queried a
|
`{ hold: "todo" }` for a board whose hold column is `backlog`, so the reconciliation queried a
|
||||||
column that does not exist, found no dependents, and left `blockedBy` pointing at a deleted task.
|
column that does not exist, found no dependents, and left `blockedBy` pointing at a deleted task.
|
||||||
|
|||||||
@@ -450,7 +450,7 @@ function mergeParkedColumns(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
FNXC:WorkflowResolvedColumns 2026-08-01-01:40 (fleet):
|
FNXC:WorkflowResolvedColumns 2026-07-31-06:35 (fleet):
|
||||||
The ASYNC twin. The sync one below cannot answer for a custom workflow in production, so any guard that
|
The ASYNC twin. The sync one below cannot answer for a custom workflow in production, so any guard that
|
||||||
can reach this one must.
|
can reach this one must.
|
||||||
|
|
||||||
@@ -477,7 +477,7 @@ async function resolveTaskParkedColumns(store: TaskStore, taskId: string): Promi
|
|||||||
archived,
|
archived,
|
||||||
terminal: new Set([complete, archived]),
|
terminal: new Set([complete, archived]),
|
||||||
/*
|
/*
|
||||||
FNXC:WorkflowResolvedColumns 2026-08-01-02:05 (fleet):
|
FNXC:WorkflowResolvedColumns 2026-07-31-06:35 (fleet):
|
||||||
The wake set UNIONS the legacy ids rather than replacing them, and that is load-bearing rather
|
The wake set UNIONS the legacy ids rather than replacing them, and that is load-bearing rather
|
||||||
than defensive. Post-U11 the default lineage has no `triage` column, so a RESOLVED answer returns
|
than defensive. Post-U11 the default lineage has no `triage` column, so a RESOLVED answer returns
|
||||||
`intake: "todo"` where the old inert path fell back to `"triage"`. Converting without the union
|
`intake: "todo"` where the old inert path fell back to `"triage"`. Converting without the union
|
||||||
@@ -1268,7 +1268,7 @@ export class Scheduler {
|
|||||||
schedulerLog.warn(`Failed to reset dispatch oscillation state for ${task.id} on unpause: ${error instanceof Error ? error.message : String(error)}`);
|
schedulerLog.warn(`Failed to reset dispatch oscillation state for ${task.id} on unpause: ${error instanceof Error ? error.message : String(error)}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
/* FNXC:WorkflowResolvedColumns 2026-08-01-01:40 (fleet): the answer only gates `schedule()`,
|
/* FNXC:WorkflowResolvedColumns 2026-07-31-06:35 (fleet): the answer only gates `schedule()`,
|
||||||
which is async and fire-and-forget, so resolving it properly costs nothing observable. */
|
which is async and fire-and-forget, so resolving it properly costs nothing observable. */
|
||||||
void (async () => {
|
void (async () => {
|
||||||
const unpausedParked = await resolveTaskParkedColumns(this.store, task.id);
|
const unpausedParked = await resolveTaskParkedColumns(this.store, task.id);
|
||||||
@@ -1299,7 +1299,7 @@ export class Scheduler {
|
|||||||
this.planningTaskIds.add(task.id);
|
this.planningTaskIds.add(task.id);
|
||||||
} else if (this.planningTaskIds.has(task.id)) {
|
} else if (this.planningTaskIds.has(task.id)) {
|
||||||
this.planningTaskIds.delete(task.id);
|
this.planningTaskIds.delete(task.id);
|
||||||
/* FNXC:WorkflowResolvedColumns 2026-08-01-01:40 (fleet): as with the unpause wake above, the
|
/* FNXC:WorkflowResolvedColumns 2026-07-31-06:35 (fleet): as with the unpause wake above, the
|
||||||
answer only gates `schedule()`. The `planningTaskIds.delete` stays SYNCHRONOUS — it is the
|
answer only gates `schedule()`. The `planningTaskIds.delete` stays SYNCHRONOUS — it is the
|
||||||
edge-trigger bookkeeping, and deferring it would let a second update re-enter this branch. */
|
edge-trigger bookkeeping, and deferring it would let a second update re-enter this branch. */
|
||||||
void (async () => {
|
void (async () => {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ export default defineConfig({
|
|||||||
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
||||||
browser-safe delete-attribution leaf.
|
browser-safe delete-attribution leaf.
|
||||||
*/
|
*/
|
||||||
|
"@fusion/core/column-roles": resolve(__dirname, "../core/src/column-roles.ts"),
|
||||||
"@fusion/core/task-delete-attribution": resolve(__dirname, "../core/src/task-delete-attribution.ts"),
|
"@fusion/core/task-delete-attribution": resolve(__dirname, "../core/src/task-delete-attribution.ts"),
|
||||||
"@fusion/core": resolve(__dirname, "../core/src/index.ts"),
|
"@fusion/core": resolve(__dirname, "../core/src/index.ts"),
|
||||||
"@fusion/test-utils": resolve(__dirname, "../core/src/__test-utils__/workspace.ts"),
|
"@fusion/test-utils": resolve(__dirname, "../core/src/__test-utils__/workspace.ts"),
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export default defineConfig({
|
|||||||
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
||||||
browser-safe delete-attribution leaf.
|
browser-safe delete-attribution leaf.
|
||||||
*/
|
*/
|
||||||
|
"@fusion/core/column-roles": fileURLToPath(new URL("../../packages/core/src/column-roles.ts", import.meta.url)),
|
||||||
"@fusion/core/task-delete-attribution": fileURLToPath(new URL("../../packages/core/src/task-delete-attribution.ts", import.meta.url)),
|
"@fusion/core/task-delete-attribution": fileURLToPath(new URL("../../packages/core/src/task-delete-attribution.ts", import.meta.url)),
|
||||||
"@fusion/core": fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)),
|
"@fusion/core": fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)),
|
||||||
"@fusion/plugin-sdk": fileURLToPath(new URL("../../packages/plugin-sdk/src/index.ts", import.meta.url)),
|
"@fusion/plugin-sdk": fileURLToPath(new URL("../../packages/plugin-sdk/src/index.ts", import.meta.url)),
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ export default defineConfig({
|
|||||||
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
||||||
browser-safe delete-attribution leaf.
|
browser-safe delete-attribution leaf.
|
||||||
*/
|
*/
|
||||||
|
{ find: "@fusion/core/column-roles", replacement: fileURLToPath(new URL("../../packages/core/src/column-roles.ts", import.meta.url)) },
|
||||||
{ find: "@fusion/core/task-delete-attribution", replacement: fileURLToPath(new URL("../../packages/core/src/task-delete-attribution.ts", import.meta.url)) },
|
{ find: "@fusion/core/task-delete-attribution", replacement: fileURLToPath(new URL("../../packages/core/src/task-delete-attribution.ts", import.meta.url)) },
|
||||||
{ find: "@fusion/core", replacement: fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)) },
|
{ find: "@fusion/core", replacement: fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)) },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export default defineConfig({
|
|||||||
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
||||||
browser-safe delete-attribution leaf.
|
browser-safe delete-attribution leaf.
|
||||||
*/
|
*/
|
||||||
|
{ find: "@fusion/core/column-roles", replacement: fileURLToPath(new URL("../../packages/core/src/column-roles.ts", import.meta.url)) },
|
||||||
{ find: "@fusion/core/task-delete-attribution", replacement: fileURLToPath(new URL("../../packages/core/src/task-delete-attribution.ts", import.meta.url)) },
|
{ find: "@fusion/core/task-delete-attribution", replacement: fileURLToPath(new URL("../../packages/core/src/task-delete-attribution.ts", import.meta.url)) },
|
||||||
{ find: "@fusion/core", replacement: fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)) },
|
{ find: "@fusion/core", replacement: fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)) },
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ export default defineConfig({
|
|||||||
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
transitively — this project aliases `@fusion/dashboard`, and `app/api/client.ts` imports the
|
||||||
browser-safe delete-attribution leaf.
|
browser-safe delete-attribution leaf.
|
||||||
*/
|
*/
|
||||||
|
"@fusion/core/column-roles": fileURLToPath(new URL("../../packages/core/src/column-roles.ts", import.meta.url)),
|
||||||
"@fusion/core/task-delete-attribution": fileURLToPath(new URL("../../packages/core/src/task-delete-attribution.ts", import.meta.url)),
|
"@fusion/core/task-delete-attribution": fileURLToPath(new URL("../../packages/core/src/task-delete-attribution.ts", import.meta.url)),
|
||||||
"@fusion/core": fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)),
|
"@fusion/core": fileURLToPath(new URL("../../packages/core/src/index.ts", import.meta.url)),
|
||||||
// FNXC:Clipboard 2026-07-12-00:00: The reports plugin imports the dashboard clipboard helper through its package subpath export; keep this exact alias ahead of the package root alias so vitest does not collapse the subpath to src/index.ts.
|
// FNXC:Clipboard 2026-07-12-00:00: The reports plugin imports the dashboard clipboard helper through its package subpath export; keep this exact alias ahead of the package root alias so vitest does not collapse the subpath to src/index.ts.
|
||||||
|
|||||||
@@ -60,6 +60,11 @@
|
|||||||
"reason": "2026-07-26: Delete caller-attribution constants and the pure header resolver are shared by the browser client that stamps `x-fusion-client` and the route that reads it; the module has no imports at all.",
|
"reason": "2026-07-26: Delete caller-attribution constants and the pure header resolver are shared by the browser client that stamps `x-fusion-client` and the route that reads it; the module has no imports at all.",
|
||||||
"verifiedAt": "2026-07-26"
|
"verifiedAt": "2026-07-26"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"module": "column-roles",
|
||||||
|
"reason": "2026-07-31: Column role predicates depend only on erased trait types and provide browser-safe flags-first lifecycle classification.",
|
||||||
|
"verifiedAt": "2026-07-31"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"module": "live-agent-count",
|
"module": "live-agent-count",
|
||||||
"reason": "2026-07-21: FN-8453 shares pure workflow-trait-based Running and Waiting predicates with dashboard capacity indicators; its dependency graph has no Node-only modules.",
|
"reason": "2026-07-21: FN-8453 shares pure workflow-trait-based Running and Waiting predicates with dashboard capacity indicators; its dependency graph has no Node-only modules.",
|
||||||
|
|||||||
Reference in New Issue
Block a user