Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Combine Project Explorer and Editor into a Single Interface (#198) #199

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
351 changes: 341 additions & 10 deletions packages/editor/package-lock.json

Large diffs are not rendered by default.

6 changes: 4 additions & 2 deletions packages/editor/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,15 @@
"lint": "next lint"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.17.1",
"@dnd-kit/core": "^6.1.0",
"@dnd-kit/sortable": "^8.0.0",
"@dnd-kit/utilities": "^3.2.2",
"@google/generative-ai": "^0.2.1",
"@radix-ui/react-accordion": "^1.2.1",
"@radix-ui/react-checkbox": "^1.1.2",
"@radix-ui/react-collapsible": "^1.1.1",
"@radix-ui/react-context-menu": "^2.2.3",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.2",
"@radix-ui/react-label": "^2.1.0",
Expand All @@ -34,11 +37,10 @@
"next": "15.0.3",
"next-themes": "^0.4.3",
"openai": "^4.73.1",
"@anthropic-ai/sdk": "^0.17.1",
"@google/generative-ai": "^0.2.1",
"react": "^18.3.1",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.1.2",
"react-resizable-panels": "^2.1.7",
"react-syntax-highlighter": "^15.6.1",
"sonner": "^1.7.0",
"tailwind-merge": "^2.5.4",
Expand Down
121 changes: 62 additions & 59 deletions packages/editor/src/app/api/files/route.ts
Original file line number Diff line number Diff line change
@@ -1,122 +1,125 @@
import { writeFile, mkdir, rm, unlink, readFile } from 'fs/promises'
import { NextResponse } from 'next/server'
import path from 'path'
import { writeFile, mkdir, rm, unlink, readFile } from "fs/promises";
import { NextResponse } from "next/server";
import path from "path";

function getBasePath() {
return path.join(process.cwd(), '..', 'compiled')
return path.join(process.cwd(), "..", "compiled");
}

export async function POST(request: Request) {
try {
const { path: filePath, content } = await request.json()
const fullPath = path.join(getBasePath(), filePath)
const { path: filePath, content, isDirectory } = await request.json();
const fullPath = path.join(getBasePath(), filePath);

// Ensure the directory exists
await mkdir(path.dirname(fullPath), { recursive: true })

// Write the file
await writeFile(fullPath, JSON.stringify(content, null, 2))
return NextResponse.json({ success: true })
await mkdir(path.dirname(fullPath), { recursive: true });

if (isDirectory) {
// If it's a directory, just create it
await mkdir(fullPath, { recursive: true });
} else {
// If it's a file, write the content
await writeFile(fullPath, JSON.stringify(content, null, 2));
}

return NextResponse.json({ success: true });
} catch (error) {
console.error('Error creating file:', error)
console.error("Error creating file:", error);
return NextResponse.json(
{ error: 'Failed to create file' },
{ error: "Failed to create file" },
{ status: 500 }
)
);
}
}

export async function DELETE(request: Request) {
try {
const { path: itemPath, type } = await request.json()
const fullPath = path.join(getBasePath(), itemPath)
const { path: itemPath, type } = await request.json();
const fullPath = path.join(getBasePath(), itemPath);

if (type === 'folder') {
await rm(fullPath, { recursive: true, force: true })
if (type === "folder") {
await rm(fullPath, { recursive: true, force: true });
} else {
await unlink(fullPath)
await unlink(fullPath);
}

return NextResponse.json({ success: true })
return NextResponse.json({ success: true });
} catch (error) {
console.error('Error deleting item:', error)
console.error("Error deleting item:", error);
return NextResponse.json(
{ error: 'Failed to delete item' },
{ error: "Failed to delete item" },
{ status: 500 }
)
);
}
}

export async function GET(request: Request) {
try {
const { searchParams } = new URL(request.url)
const filePath = searchParams.get('path')
const { searchParams } = new URL(request.url);
const filePath = searchParams.get("path");

if (!filePath) {
return NextResponse.json(
{ error: 'No file path provided' },
{ error: "No file path provided" },
{ status: 400 }
)
);
}

const fullPath = path.join(getBasePath(), filePath)
const fileContent = await readFile(fullPath, 'utf-8')
const parsedContent = JSON.parse(fileContent)
return NextResponse.json(parsedContent)
const fullPath = path.join(getBasePath(), filePath);
const fileContent = await readFile(fullPath, "utf-8");
const parsedContent = JSON.parse(fileContent);

return NextResponse.json(parsedContent);
} catch (error) {
console.error('Error reading file:', error)
return NextResponse.json(
{ error: 'Failed to read file' },
{ status: 500 }
)
console.error("Error reading file:", error);
return NextResponse.json({ error: "Failed to read file" }, { status: 500 });
}
}

export async function PUT(request: Request) {
try {
const { path: filePath, content } = await request.json()
const { path: filePath, content } = await request.json();

if (!filePath) {
return NextResponse.json(
{ error: 'No file path provided' },
{ error: "No file path provided" },
{ status: 400 }
)
);
}

// Validate content
if (!content) {
return NextResponse.json(
{ error: 'No content provided' },
{ error: "No content provided" },
{ status: 400 }
)
);
}

const fullPath = path.join(getBasePath(), filePath)
const fullPath = path.join(getBasePath(), filePath);

// Check if directory exists, if not create it
await mkdir(path.dirname(fullPath), { recursive: true })
await mkdir(path.dirname(fullPath), { recursive: true });

// Add retry logic
const maxRetries = 3;
for (let i = 0; i < maxRetries; i++) {
try {
const jsonContent = JSON.stringify(content, null, 2)
await writeFile(fullPath, jsonContent, 'utf-8')
return NextResponse.json({ success: true })
const jsonContent = JSON.stringify(content, null, 2);
await writeFile(fullPath, jsonContent, "utf-8");
return NextResponse.json({ success: true });
} catch (writeError) {
if (i === maxRetries - 1) throw writeError;
await new Promise(resolve => setTimeout(resolve, 1000)); // Wait 1s before retry
await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait 1s before retry
}
}
} catch (error) {
console.error('Error writing file:', error)
console.error("Error writing file:", error);
return NextResponse.json(
{
error: 'Failed to write file',
details: error instanceof Error ? error.message : 'Unknown error'
{
error: "Failed to write file",
details: error instanceof Error ? error.message : "Unknown error",
},
{ status: 500 }
)
);
}
}
}
Loading
Loading