FN-6135: remove workflow toolbar collapse toggle
Simplify the workflow board toolbar by removing its collapse state and persistence. - remove the workflow toolbar collapse toggle, handlers, and scoped localStorage persistence from Board - drop collapse-specific workflow toolbar styling and mobile collapsed-layout rules - replace collapse-focused board tests with assertions that the toolbar renders without a collapse affordance - remove the unused workflow toolbar storage key and update project storage expectations Files changed: packages/dashboard/app/components/Board.tsx | 129 +++++--------- packages/dashboard/app/components/Lane.css | 36 ---- .../app/components/__tests__/Board.test.tsx | 187 +++------------------ .../app/utils/__tests__/projectStorage.test.ts | 3 +- packages/dashboard/app/utils/projectStorage.ts | 1 - 5 files changed, 60 insertions(+), 296 deletions(-) Fusion-Task-Id: FN-6135 Fusion-Task-Lineage: 11c17edf-bbed-4ec5-a06e-00a2537ffac1
This commit is contained in:
@@ -4,13 +4,12 @@ import { sortTasksForDisplayColumn } from "./taskSorting";
|
||||
import { Column } from "./Column";
|
||||
import "./Lane.css";
|
||||
import type { ToastType } from "../hooks/useToast";
|
||||
import { useState, useMemo, useEffect, useCallback, useRef, type KeyboardEvent, type MouseEvent } from "react";
|
||||
import { useState, useMemo, useEffect, useCallback, useRef } from "react";
|
||||
import { Pencil, Plus } from "lucide-react";
|
||||
import { fetchWorkflowSteps, fetchBoardWorkflows, promoteTask, type ModelInfo, type BoardWorkflowDefinition, type BoardWorkflowsPayload } from "../api";
|
||||
import { useBlockerFanout } from "../hooks/useBlockerFanout";
|
||||
import { MOBILE_MEDIA_QUERY } from "../hooks/useViewportMode";
|
||||
import { recordResumeEvent } from "../utils/resumeInstrumentation";
|
||||
import { getScopedItem, setScopedItem } from "../utils/projectStorage";
|
||||
import { subscribeSse } from "../sse-bus";
|
||||
import { getBoardCanDropTaskRejection } from "./boardCanDropTask";
|
||||
|
||||
@@ -93,7 +92,6 @@ function areWorkflowNameLookupsEqual(previous: ReadonlyMap<string, string>, next
|
||||
|
||||
export function Board({ tasks, projectId, maxConcurrent, onMoveTask, onPauseTask, onOpenDetail, onOpenGroupModal, addToast, onQuickCreate, onNewTask, autoMerge, onToggleAutoMerge, globalPaused, onUpdateTask, onRetryTask, onArchiveTask, onUnarchiveTask, onDeleteTask, onArchiveAllDone, onLoadArchivedTasks, searchQuery = "", availableModels, onPlanningMode, onSubtaskBreakdown, onOpenDetailWithTab, favoriteProviders, favoriteModels, onToggleFavorite, onToggleModelFavorite, taskStuckTimeoutMs, onOpenMission, staleHighFanoutBlockerAgeThresholdMs, lastFetchTimeMs, prAuthAvailable, onOpenWorkflowEditor, onCreateWorkflow }: BoardProps) {
|
||||
const [archivedCollapsed, setArchivedCollapsed] = useState(true);
|
||||
const [workflowToolbarCollapsed, setWorkflowToolbarCollapsed] = useState<boolean>(() => getScopedItem("kb-dashboard-board-workflow-collapsed", projectId) === "1");
|
||||
const archivedLoadedRef = useRef(false);
|
||||
const [workflowStepNameLookup, setWorkflowStepNameLookup] = useState<ReadonlyMap<string, string>>(EMPTY_WORKFLOW_STEP_NAME_LOOKUP);
|
||||
const boardRef = useRef<HTMLElement | null>(null);
|
||||
@@ -111,29 +109,6 @@ export function Board({ tasks, projectId, maxConcurrent, onMoveTask, onPauseTask
|
||||
archived: [],
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (typeof window !== "undefined") {
|
||||
setScopedItem("kb-dashboard-board-workflow-collapsed", workflowToolbarCollapsed ? "1" : "0", projectId);
|
||||
}
|
||||
}, [workflowToolbarCollapsed, projectId]);
|
||||
|
||||
const toggleWorkflowToolbarCollapsed = useCallback(() => {
|
||||
setWorkflowToolbarCollapsed((collapsed) => !collapsed);
|
||||
}, []);
|
||||
|
||||
const handleWorkflowToolbarKeyDown = useCallback((event: KeyboardEvent<HTMLElement>) => {
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
toggleWorkflowToolbarCollapsed();
|
||||
}
|
||||
}, [toggleWorkflowToolbarCollapsed]);
|
||||
|
||||
const handleExpandedWorkflowToolbarClick = useCallback((event: MouseEvent<HTMLDivElement>) => {
|
||||
if (event.target === event.currentTarget) {
|
||||
toggleWorkflowToolbarCollapsed();
|
||||
}
|
||||
}, [toggleWorkflowToolbarCollapsed]);
|
||||
|
||||
useEffect(() => {
|
||||
recordResumeEvent({
|
||||
view: "Board",
|
||||
@@ -490,71 +465,45 @@ export function Board({ tasks, projectId, maxConcurrent, onMoveTask, onPauseTask
|
||||
return (
|
||||
<div className="board-workflow-view">
|
||||
{(workflowOptions.length > 1 || onCreateWorkflow || onOpenWorkflowEditor) && (
|
||||
<div
|
||||
className="board-workflow-toolbar"
|
||||
data-collapsed={workflowToolbarCollapsed || undefined}
|
||||
onClick={workflowToolbarCollapsed ? undefined : handleExpandedWorkflowToolbarClick}
|
||||
onKeyDown={workflowToolbarCollapsed ? undefined : handleWorkflowToolbarKeyDown}
|
||||
tabIndex={workflowToolbarCollapsed ? undefined : 0}
|
||||
aria-expanded={workflowToolbarCollapsed ? undefined : true}
|
||||
aria-label={workflowToolbarCollapsed ? undefined : "Collapse workflow toolbar"}
|
||||
data-testid={workflowToolbarCollapsed ? undefined : "board-workflow-collapse-toggle"}
|
||||
>
|
||||
{workflowToolbarCollapsed ? (
|
||||
<span
|
||||
className="board-workflow-collapsed-label"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={toggleWorkflowToolbarCollapsed}
|
||||
onKeyDown={handleWorkflowToolbarKeyDown}
|
||||
aria-expanded={false}
|
||||
aria-label="Expand workflow toolbar"
|
||||
data-testid="board-workflow-collapse-toggle"
|
||||
<div className="board-workflow-toolbar">
|
||||
{workflowOptions.length > 1 && (
|
||||
<label className="list-workflow-selector board-workflow-selector">
|
||||
<span>Workflow</span>
|
||||
<select
|
||||
className="select list-workflow-select"
|
||||
value={selectedWorkflow.id}
|
||||
onChange={(event) => setSelectedWorkflowId(event.target.value)}
|
||||
aria-label="Select workflow"
|
||||
>
|
||||
{workflowOptions.map((workflow) => (
|
||||
<option key={workflow.id} value={workflow.id}>
|
||||
{workflow.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
)}
|
||||
{onOpenWorkflowEditor && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-sm board-workflow-edit-btn"
|
||||
onClick={() => onOpenWorkflowEditor(selectedWorkflow.id)}
|
||||
title="Edit workflows"
|
||||
aria-label="Edit workflows"
|
||||
>
|
||||
Workflow
|
||||
</span>
|
||||
) : (
|
||||
<>
|
||||
{workflowOptions.length > 1 && (
|
||||
<label className="list-workflow-selector board-workflow-selector">
|
||||
<span>Workflow</span>
|
||||
<select
|
||||
className="select list-workflow-select"
|
||||
value={selectedWorkflow.id}
|
||||
onChange={(event) => setSelectedWorkflowId(event.target.value)}
|
||||
aria-label="Select workflow"
|
||||
>
|
||||
{workflowOptions.map((workflow) => (
|
||||
<option key={workflow.id} value={workflow.id}>
|
||||
{workflow.name}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</label>
|
||||
)}
|
||||
{onOpenWorkflowEditor && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-sm board-workflow-edit-btn"
|
||||
onClick={() => onOpenWorkflowEditor(selectedWorkflow.id)}
|
||||
title="Edit workflows"
|
||||
aria-label="Edit workflows"
|
||||
>
|
||||
<Pencil size={15} />
|
||||
</button>
|
||||
)}
|
||||
{onCreateWorkflow && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-sm board-workflow-create-btn"
|
||||
onClick={onCreateWorkflow}
|
||||
title="New workflow"
|
||||
aria-label="New workflow"
|
||||
>
|
||||
<Plus size={15} />
|
||||
</button>
|
||||
)}
|
||||
</>
|
||||
<Pencil size={15} />
|
||||
</button>
|
||||
)}
|
||||
{onCreateWorkflow && (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-icon btn-sm board-workflow-create-btn"
|
||||
onClick={onCreateWorkflow}
|
||||
title="New workflow"
|
||||
aria-label="New workflow"
|
||||
>
|
||||
<Plus size={15} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -36,34 +36,6 @@
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.board-workflow-toolbar[data-collapsed] {
|
||||
justify-content: flex-start;
|
||||
gap: var(--space-sm);
|
||||
padding: var(--space-xs) var(--space-md);
|
||||
}
|
||||
|
||||
.board-workflow-toolbar:not([data-collapsed]),
|
||||
.board-workflow-collapsed-label {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.board-workflow-toolbar:focus-visible,
|
||||
.board-workflow-collapsed-label:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: var(--focus-ring-strong);
|
||||
}
|
||||
|
||||
.board-workflow-collapsed-label {
|
||||
border-radius: var(--radius-sm);
|
||||
color: var(--text-muted);
|
||||
font-size: 0.8rem;
|
||||
}
|
||||
|
||||
.board-workflow-collapsed-label:hover,
|
||||
.board-workflow-collapsed-label:focus-visible {
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.board-workflow-selector {
|
||||
margin-left: auto;
|
||||
}
|
||||
@@ -199,11 +171,3 @@
|
||||
scroll-snap-type: x proximity;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.board-workflow-toolbar[data-collapsed] {
|
||||
flex-direction: row;
|
||||
flex-wrap: nowrap;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,8 +72,6 @@ vi.mock("../Lane", () => ({
|
||||
),
|
||||
}));
|
||||
|
||||
const BOARD_WORKFLOW_COLLAPSED_KEY = "kb-dashboard-board-workflow-collapsed";
|
||||
|
||||
const DEFAULT_WORKFLOW = {
|
||||
id: "builtin:coding",
|
||||
name: "Coding (built-in)",
|
||||
@@ -1047,173 +1045,28 @@ describe("Board", () => {
|
||||
expect(onOpenWorkflowEditor).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
describe("workflow toolbar collapsible", () => {
|
||||
function renderWorkflowToolbarBoard() {
|
||||
const onCreateWorkflow = vi.fn();
|
||||
const onOpenWorkflowEditor = vi.fn();
|
||||
enableFlag(
|
||||
{ "FN-1": "builtin:coding", "FN-2": "wf-custom" },
|
||||
[DEFAULT_WORKFLOW, CUSTOM_WORKFLOW],
|
||||
);
|
||||
renderBoard({
|
||||
tasks: [mkTask({ id: "FN-1" }), mkTask({ id: "FN-2", column: "intake" })],
|
||||
onCreateWorkflow,
|
||||
onOpenWorkflowEditor,
|
||||
});
|
||||
return { onCreateWorkflow, onOpenWorkflowEditor };
|
||||
}
|
||||
|
||||
function expectNoEmptyWorkflowToolbarIconButtons() {
|
||||
const toolbar = document.querySelector(".board-workflow-toolbar");
|
||||
expect(toolbar).not.toBeNull();
|
||||
const emptyIconButtons = Array.from(toolbar?.querySelectorAll("button.btn-icon") ?? [])
|
||||
.filter((button) => !button.querySelector("svg") && button.textContent?.trim() === "");
|
||||
expect(emptyIconButtons).toHaveLength(0);
|
||||
expect(toolbar?.querySelector("button.board-workflow-collapse-toggle")).toBeNull();
|
||||
}
|
||||
|
||||
it("defaults to expanded (not collapsed)", async () => {
|
||||
renderWorkflowToolbarBoard();
|
||||
|
||||
expect(await screen.findByLabelText("Select workflow")).toBeDefined();
|
||||
expect(screen.getByRole("button", { name: "New workflow" })).toBeDefined();
|
||||
expect(screen.getByRole("button", { name: "Edit workflows" })).toBeDefined();
|
||||
expect(screen.getByTestId("board-workflow-collapse-toggle").getAttribute("aria-expanded")).toBe("true");
|
||||
it("renders workflow toolbar actions without a collapse affordance", async () => {
|
||||
const onCreateWorkflow = vi.fn();
|
||||
const onOpenWorkflowEditor = vi.fn();
|
||||
enableFlag(
|
||||
{ "FN-1": "builtin:coding", "FN-2": "wf-custom" },
|
||||
[DEFAULT_WORKFLOW, CUSTOM_WORKFLOW],
|
||||
);
|
||||
renderBoard({
|
||||
tasks: [mkTask({ id: "FN-1" }), mkTask({ id: "FN-2", column: "intake" })],
|
||||
onCreateWorkflow,
|
||||
onOpenWorkflowEditor,
|
||||
});
|
||||
|
||||
it("does not render a chevron icon in the workflow toolbar collapse toggle", async () => {
|
||||
renderWorkflowToolbarBoard();
|
||||
|
||||
await screen.findByLabelText("Select workflow");
|
||||
const toolbar = document.querySelector(".board-workflow-toolbar");
|
||||
expect(toolbar?.querySelector(".lucide-chevron-left, .lucide-chevron-right")).toBeNull();
|
||||
});
|
||||
|
||||
it("does not render an empty btn-icon button in the workflow toolbar", async () => {
|
||||
renderWorkflowToolbarBoard();
|
||||
|
||||
await screen.findByLabelText("Select workflow");
|
||||
expectNoEmptyWorkflowToolbarIconButtons();
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
expect(screen.getByText("Workflow")).toBeDefined();
|
||||
expectNoEmptyWorkflowToolbarIconButtons();
|
||||
});
|
||||
|
||||
it("clicking the toggle collapses the toolbar", async () => {
|
||||
renderWorkflowToolbarBoard();
|
||||
await screen.findByLabelText("Select workflow");
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
|
||||
expect(screen.queryByLabelText("Select workflow")).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "New workflow" })).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "Edit workflows" })).toBeNull();
|
||||
expect(screen.getByTestId("board-workflow-collapse-toggle").getAttribute("aria-expanded")).toBe("false");
|
||||
expect(screen.getByText("Workflow")).toBeDefined();
|
||||
});
|
||||
|
||||
it("clicking the toggle again expands the toolbar", async () => {
|
||||
renderWorkflowToolbarBoard();
|
||||
await screen.findByLabelText("Select workflow");
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
expect(screen.queryByLabelText("Select workflow")).toBeNull();
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
|
||||
expect(screen.getByLabelText("Select workflow")).toBeDefined();
|
||||
expect(screen.getByRole("button", { name: "New workflow" })).toBeDefined();
|
||||
expect(screen.getByRole("button", { name: "Edit workflows" })).toBeDefined();
|
||||
expect(screen.getByTestId("board-workflow-collapse-toggle").getAttribute("aria-expanded")).toBe("true");
|
||||
});
|
||||
|
||||
it("toggles the workflow toolbar from the keyboard", async () => {
|
||||
renderWorkflowToolbarBoard();
|
||||
await screen.findByLabelText("Select workflow");
|
||||
|
||||
fireEvent.keyDown(screen.getByTestId("board-workflow-collapse-toggle"), { key: "Enter" });
|
||||
expect(screen.queryByLabelText("Select workflow")).toBeNull();
|
||||
expect(screen.getByTestId("board-workflow-collapse-toggle").getAttribute("aria-expanded")).toBe("false");
|
||||
|
||||
fireEvent.keyDown(screen.getByTestId("board-workflow-collapse-toggle"), { key: " " });
|
||||
expect(screen.getByLabelText("Select workflow")).toBeDefined();
|
||||
expect(screen.getByTestId("board-workflow-collapse-toggle").getAttribute("aria-expanded")).toBe("true");
|
||||
});
|
||||
|
||||
it("persists collapsed state to localStorage", async () => {
|
||||
renderWorkflowToolbarBoard();
|
||||
await screen.findByLabelText("Select workflow");
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
expect(window.localStorage.getItem(BOARD_WORKFLOW_COLLAPSED_KEY)).toBe("1");
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
expect(window.localStorage.getItem(BOARD_WORKFLOW_COLLAPSED_KEY)).toBe("0");
|
||||
});
|
||||
|
||||
it("reads collapsed state from localStorage on mount", async () => {
|
||||
window.localStorage.setItem(BOARD_WORKFLOW_COLLAPSED_KEY, "1");
|
||||
|
||||
renderWorkflowToolbarBoard();
|
||||
await waitFor(() => expect(screen.getByTestId("board-workflow-collapse-toggle")).toBeDefined());
|
||||
|
||||
expect(screen.queryByLabelText("Select workflow")).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "New workflow" })).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "Edit workflows" })).toBeNull();
|
||||
expect(screen.getByTestId("board-workflow-collapse-toggle").getAttribute("aria-expanded")).toBe("false");
|
||||
expect(screen.getByText("Workflow")).toBeDefined();
|
||||
});
|
||||
|
||||
it("collapses and expands a single-workflow toolbar with action callbacks", async () => {
|
||||
const onCreateWorkflow = vi.fn();
|
||||
const onOpenWorkflowEditor = vi.fn();
|
||||
enableFlag({ "FN-1": "builtin:coding" }, [DEFAULT_WORKFLOW]);
|
||||
renderBoard({
|
||||
tasks: [mkTask({ id: "FN-1", column: "triage" })],
|
||||
onCreateWorkflow,
|
||||
onOpenWorkflowEditor,
|
||||
});
|
||||
|
||||
await waitFor(() => expect(screen.getByTestId("column-triage")).toBeDefined());
|
||||
expect(screen.queryByLabelText("Select workflow")).toBeNull();
|
||||
expect(screen.getByRole("button", { name: "New workflow" })).toBeDefined();
|
||||
expect(screen.getByRole("button", { name: "Edit workflows" })).toBeDefined();
|
||||
expectNoEmptyWorkflowToolbarIconButtons();
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
expect(screen.queryByRole("button", { name: "New workflow" })).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "Edit workflows" })).toBeNull();
|
||||
expect(screen.getByTestId("board-workflow-collapse-toggle").getAttribute("aria-expanded")).toBe("false");
|
||||
expectNoEmptyWorkflowToolbarIconButtons();
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
expect(screen.getByRole("button", { name: "New workflow" })).toBeDefined();
|
||||
expect(screen.getByRole("button", { name: "Edit workflows" })).toBeDefined();
|
||||
});
|
||||
|
||||
it("collapses and expands a multi-workflow toolbar without action callbacks", async () => {
|
||||
enableFlag(
|
||||
{ "FN-1": "builtin:coding", "FN-2": "wf-custom" },
|
||||
[DEFAULT_WORKFLOW, CUSTOM_WORKFLOW],
|
||||
);
|
||||
renderBoard({
|
||||
tasks: [mkTask({ id: "FN-1" }), mkTask({ id: "FN-2", column: "intake" })],
|
||||
onCreateWorkflow: undefined,
|
||||
onOpenWorkflowEditor: undefined,
|
||||
});
|
||||
|
||||
expect(await screen.findByLabelText("Select workflow")).toBeDefined();
|
||||
expect(screen.queryByRole("button", { name: "New workflow" })).toBeNull();
|
||||
expect(screen.queryByRole("button", { name: "Edit workflows" })).toBeNull();
|
||||
expectNoEmptyWorkflowToolbarIconButtons();
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
expect(screen.queryByLabelText("Select workflow")).toBeNull();
|
||||
expect(screen.getByTestId("board-workflow-collapse-toggle").getAttribute("aria-expanded")).toBe("false");
|
||||
|
||||
fireEvent.click(screen.getByTestId("board-workflow-collapse-toggle"));
|
||||
expect(screen.getByLabelText("Select workflow")).toBeDefined();
|
||||
});
|
||||
expect(await screen.findByLabelText("Select workflow")).toBeDefined();
|
||||
expect(screen.getByRole("button", { name: "New workflow" })).toBeDefined();
|
||||
expect(screen.getByRole("button", { name: "Edit workflows" })).toBeDefined();
|
||||
const toolbar = document.querySelector(".board-workflow-toolbar");
|
||||
expect(toolbar).not.toBeNull();
|
||||
expect(toolbar?.hasAttribute("data-collapsed")).toBe(false);
|
||||
expect(toolbar?.querySelector(".board-workflow-collapse-toggle")).toBeNull();
|
||||
expect(toolbar?.querySelector(".board-workflow-collapsed-label")).toBeNull();
|
||||
expect(screen.queryByTestId("board-workflow-collapse-toggle")).toBeNull();
|
||||
});
|
||||
|
||||
it("renders one selected workflow at a time and switches workflows from the dropdown", async () => {
|
||||
|
||||
@@ -84,7 +84,6 @@ describe("projectStorage", () => {
|
||||
"kb-dashboard-list-selected-task",
|
||||
"kb-dashboard-list-sidebar-width",
|
||||
"kb-dashboard-mailbox-sidebar-width",
|
||||
"kb-dashboard-board-workflow-collapsed",
|
||||
"kb-quick-entry-text",
|
||||
"kb-inline-create-text",
|
||||
"fn-agent-view",
|
||||
@@ -104,7 +103,7 @@ describe("projectStorage", () => {
|
||||
"fusion-plugin-dependency-graph:positions",
|
||||
]),
|
||||
);
|
||||
expect(PROJECT_STORAGE_KEYS).toHaveLength(26);
|
||||
expect(PROJECT_STORAGE_KEYS).toHaveLength(25);
|
||||
});
|
||||
|
||||
it("stores branch filter values as scoped strings per project", () => {
|
||||
|
||||
@@ -17,7 +17,6 @@ export const PROJECT_STORAGE_KEYS: string[] = [
|
||||
"kb-dashboard-list-selected-task",
|
||||
"kb-dashboard-list-sidebar-width",
|
||||
"kb-dashboard-mailbox-sidebar-width",
|
||||
"kb-dashboard-board-workflow-collapsed",
|
||||
"kb-quick-entry-text",
|
||||
"kb-inline-create-text",
|
||||
"fn-agent-view",
|
||||
|
||||
Reference in New Issue
Block a user