Browse Source

fix: remove Save As button, hide Array node, add Kie error logging

- Remove Save As button and handler from Header (feature not ready)
- Remove Array node button from FloatingActionBar (not ready for release)
- Add error logging for failed Kie.ai tasks to aid debugging
- Add .superset/ to .gitignore

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
handoff-20260429-1057
shrimbly 5 months ago
parent
commit
97500e494d
  1. 4
      .gitignore
  2. 1
      src/app/api/generate/providers/kie.ts
  3. 1
      src/components/FloatingActionBar.tsx
  4. 44
      src/components/Header.tsx
  5. 39
      src/components/__tests__/Header.test.tsx

4
.gitignore

@ -47,4 +47,6 @@ logs/*.json
.planning/ .planning/
# agents # agents
.agents/ .agents/
.superset/

1
src/app/api/generate/providers/kie.ts

@ -324,6 +324,7 @@ export async function pollKieTaskCompletion(
} }
if (state === "FAIL" || state === "FAILED" || state === "ERROR") { if (state === "FAIL" || state === "FAILED" || state === "ERROR") {
console.error(`[API:${requestId}] Kie task failed. Full response:`, JSON.stringify(result).substring(0, 1000));
const errorMessage = result.data?.failMsg || result.data?.errorMessage || result.error || result.message || "Generation failed"; const errorMessage = result.data?.failMsg || result.data?.errorMessage || result.error || result.message || "Generation failed";
return { success: false, error: errorMessage }; return { success: false, error: errorMessage };
} }

1
src/components/FloatingActionBar.tsx

@ -263,7 +263,6 @@ export function FloatingActionBar() {
<NodeButton type="imageInput" label="Image" /> <NodeButton type="imageInput" label="Image" />
<NodeButton type="annotation" label="Annotate" /> <NodeButton type="annotation" label="Annotate" />
<NodeButton type="prompt" label="Prompt" /> <NodeButton type="prompt" label="Prompt" />
<NodeButton type="array" label="Array" />
<GenerateComboButton /> <GenerateComboButton />
<NodeButton type="output" label="Output" /> <NodeButton type="output" label="Output" />

44
src/components/Header.tsx

@ -67,7 +67,6 @@ export function Header() {
isSaving, isSaving,
setWorkflowMetadata, setWorkflowMetadata,
saveToFile, saveToFile,
saveAsFile,
loadWorkflow, loadWorkflow,
previousWorkflowSnapshot, previousWorkflowSnapshot,
revertToSnapshot, revertToSnapshot,
@ -163,31 +162,6 @@ export function Header() {
} }
}; };
const handleSaveAs = async () => {
if (!workflowName || !saveDirectoryPath) {
handleOpenSettings();
return;
}
const value = window.prompt("Save project as", workflowName);
if (value === null) return;
const newName = value.trim();
if (!newName) {
alert("Project name cannot be empty.");
return;
}
try {
const success = await saveAsFile(newName);
if (!success) {
alert("Save As failed. Please try again.");
}
} catch (error) {
console.error("Failed to save project as:", error);
alert("Save As failed. Please try again.");
}
};
const handleRevertAIChanges = useCallback(() => { const handleRevertAIChanges = useCallback(() => {
const confirmed = window.confirm( const confirmed = window.confirm(
@ -281,24 +255,6 @@ export function Header() {
<span className="absolute top-0.5 right-0.5 w-2 h-2 rounded-full bg-red-500 ring-2 ring-neutral-900" /> <span className="absolute top-0.5 right-0.5 w-2 h-2 rounded-full bg-red-500 ring-2 ring-neutral-900" />
)} )}
</button> </button>
{canSave && (
<button
onClick={handleSaveAs}
disabled={isSaving}
className="p-1.5 text-neutral-400 hover:text-neutral-200 hover:bg-neutral-800 rounded transition-colors disabled:opacity-50"
title="Save as new workflow"
>
<svg
className="w-4 h-4"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={1.5}
>
<path strokeLinecap="round" strokeLinejoin="round" d="M7.5 3.75h6a3.75 3.75 0 013.75 3.75v6M16.5 3.75L20.25 7.5M16.5 12.75h-9a3.75 3.75 0 00-3.75 3.75v3.75h12v-3.75a3.75 3.75 0 00-3.75-3.75z" />
</svg>
</button>
)}
{saveDirectoryPath && ( {saveDirectoryPath && (
<button <button
onClick={handleOpenDirectory} onClick={handleOpenDirectory}

39
src/components/__tests__/Header.test.tsx

@ -5,7 +5,6 @@ import { Header } from "@/components/Header";
// Mock the workflow store // Mock the workflow store
const mockSetWorkflowMetadata = vi.fn(); const mockSetWorkflowMetadata = vi.fn();
const mockSaveToFile = vi.fn(); const mockSaveToFile = vi.fn();
const mockSaveAsFile = vi.fn();
const mockLoadWorkflow = vi.fn(); const mockLoadWorkflow = vi.fn();
const mockUseWorkflowStore = vi.fn(); const mockUseWorkflowStore = vi.fn();
@ -46,7 +45,6 @@ const createDefaultState = (overrides = {}) => ({
isSaving: false, isSaving: false,
setWorkflowMetadata: mockSetWorkflowMetadata, setWorkflowMetadata: mockSetWorkflowMetadata,
saveToFile: mockSaveToFile, saveToFile: mockSaveToFile,
saveAsFile: mockSaveAsFile,
loadWorkflow: mockLoadWorkflow, loadWorkflow: mockLoadWorkflow,
getNodesWithComments: mockGetNodesWithComments, getNodesWithComments: mockGetNodesWithComments,
getUnviewedCommentCount: mockGetUnviewedCommentCount, getUnviewedCommentCount: mockGetUnviewedCommentCount,
@ -59,7 +57,6 @@ const createDefaultState = (overrides = {}) => ({
describe("Header", () => { describe("Header", () => {
beforeEach(() => { beforeEach(() => {
vi.clearAllMocks(); vi.clearAllMocks();
mockSaveAsFile.mockResolvedValue(true);
// Default mock implementation - unconfigured project // Default mock implementation - unconfigured project
mockGetNodesWithComments.mockReturnValue([]); mockGetNodesWithComments.mockReturnValue([]);
mockGetUnviewedCommentCount.mockReturnValue(0); mockGetUnviewedCommentCount.mockReturnValue(0);
@ -327,42 +324,6 @@ describe("Header", () => {
}); });
}); });
describe("Save As Button", () => {
beforeEach(() => {
mockUseWorkflowStore.mockImplementation((selector) => {
return selector(createDefaultState({
workflowName: "My Project",
workflowId: "project-123",
saveDirectoryPath: "/path/to/project",
}));
});
});
it("should render Save As button for configured project", () => {
render(<Header />);
expect(screen.getByTitle("Save as new workflow")).toBeInTheDocument();
});
it("should call saveAsFile with the prompted name", () => {
const promptSpy = vi.spyOn(window, "prompt").mockReturnValue("Version 2");
render(<Header />);
fireEvent.click(screen.getByTitle("Save as new workflow"));
expect(mockSaveAsFile).toHaveBeenCalledWith("Version 2");
promptSpy.mockRestore();
});
it("should not call saveAsFile when prompt is cancelled", () => {
const promptSpy = vi.spyOn(window, "prompt").mockReturnValue(null);
render(<Header />);
fireEvent.click(screen.getByTitle("Save as new workflow"));
expect(mockSaveAsFile).not.toHaveBeenCalled();
promptSpy.mockRestore();
});
});
describe("Settings Button", () => { describe("Settings Button", () => {
it("should open ProjectSetupModal in 'settings' mode when settings button clicked", () => { it("should open ProjectSetupModal in 'settings' mode when settings button clicked", () => {

Loading…
Cancel
Save