merge with upstream/main
This commit is contained in:
@@ -80,10 +80,6 @@ export class FilesStore {
|
||||
this.#modifiedFiles.clear();
|
||||
}
|
||||
|
||||
markFileAsNew(filePath: string) {
|
||||
this.#modifiedFiles.set(filePath, '');
|
||||
}
|
||||
|
||||
async saveFile(filePath: string, content: string) {
|
||||
const webcontainer = await this.#webcontainer;
|
||||
|
||||
@@ -216,9 +212,5 @@ function isBinaryFile(buffer: Uint8Array | undefined) {
|
||||
* array buffer.
|
||||
*/
|
||||
function convertToBuffer(view: Uint8Array): Buffer {
|
||||
const buffer = new Uint8Array(view.buffer, view.byteOffset, view.byteLength);
|
||||
|
||||
Object.setPrototypeOf(buffer, Buffer.prototype);
|
||||
|
||||
return buffer as Buffer;
|
||||
return Buffer.from(view.buffer, view.byteOffset, view.byteLength);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { coloredText } from '~/utils/terminal';
|
||||
export class TerminalStore {
|
||||
#webcontainer: Promise<WebContainer>;
|
||||
#terminals: Array<{ terminal: ITerminal; process: WebContainerProcess }> = [];
|
||||
#boltTerminal = newBoltShellProcess()
|
||||
#boltTerminal = newBoltShellProcess();
|
||||
|
||||
showTerminal: WritableAtom<boolean> = import.meta.hot?.data.showTerminal ?? atom(true);
|
||||
|
||||
@@ -27,8 +27,8 @@ export class TerminalStore {
|
||||
}
|
||||
async attachBoltTerminal(terminal: ITerminal) {
|
||||
try {
|
||||
let wc = await this.#webcontainer
|
||||
await this.#boltTerminal.init(wc, terminal)
|
||||
const wc = await this.#webcontainer;
|
||||
await this.#boltTerminal.init(wc, terminal);
|
||||
} catch (error: any) {
|
||||
terminal.write(coloredText.red('Failed to spawn bolt shell\n\n') + error.message);
|
||||
return;
|
||||
|
||||
@@ -11,9 +11,8 @@ import { PreviewsStore } from './previews';
|
||||
import { TerminalStore } from './terminal';
|
||||
import JSZip from 'jszip';
|
||||
import { saveAs } from 'file-saver';
|
||||
import { Octokit, type RestEndpointMethodTypes } from "@octokit/rest";
|
||||
import { Octokit, type RestEndpointMethodTypes } from '@octokit/rest';
|
||||
import * as nodePath from 'node:path';
|
||||
import type { WebContainerProcess } from '@webcontainer/api';
|
||||
import { extractRelativePath } from '~/utils/diff';
|
||||
|
||||
export interface ArtifactState {
|
||||
@@ -32,7 +31,6 @@ export type WorkbenchViewType = 'code' | 'preview';
|
||||
export class WorkbenchStore {
|
||||
#previewsStore = new PreviewsStore(webcontainer);
|
||||
#filesStore = new FilesStore(webcontainer);
|
||||
|
||||
#editorStore = new EditorStore(this.#filesStore);
|
||||
#terminalStore = new TerminalStore(webcontainer);
|
||||
|
||||
@@ -43,7 +41,6 @@ export class WorkbenchStore {
|
||||
unsavedFiles: WritableAtom<Set<string>> = import.meta.hot?.data.unsavedFiles ?? atom(new Set<string>());
|
||||
modifiedFiles = new Set<string>();
|
||||
artifactIdList: string[] = [];
|
||||
#boltTerminal: { terminal: ITerminal; process: WebContainerProcess } | undefined;
|
||||
#globalExecutionQueue = Promise.resolve();
|
||||
constructor() {
|
||||
if (import.meta.hot) {
|
||||
@@ -55,7 +52,7 @@ export class WorkbenchStore {
|
||||
}
|
||||
|
||||
addToExecutionQueue(callback: () => Promise<void>) {
|
||||
this.#globalExecutionQueue = this.#globalExecutionQueue.then(() => callback())
|
||||
this.#globalExecutionQueue = this.#globalExecutionQueue.then(() => callback());
|
||||
}
|
||||
|
||||
get previews() {
|
||||
@@ -97,7 +94,6 @@ export class WorkbenchStore {
|
||||
this.#terminalStore.attachTerminal(terminal);
|
||||
}
|
||||
attachBoltTerminal(terminal: ITerminal) {
|
||||
|
||||
this.#terminalStore.attachBoltTerminal(terminal);
|
||||
}
|
||||
|
||||
@@ -262,7 +258,8 @@ export class WorkbenchStore {
|
||||
this.artifacts.setKey(messageId, { ...artifact, ...state });
|
||||
}
|
||||
addAction(data: ActionCallbackData) {
|
||||
this._addAction(data)
|
||||
this._addAction(data);
|
||||
|
||||
// this.addToExecutionQueue(()=>this._addAction(data))
|
||||
}
|
||||
async _addAction(data: ActionCallbackData) {
|
||||
@@ -279,10 +276,9 @@ export class WorkbenchStore {
|
||||
|
||||
runAction(data: ActionCallbackData, isStreaming: boolean = false) {
|
||||
if (isStreaming) {
|
||||
this._runAction(data, isStreaming)
|
||||
}
|
||||
else {
|
||||
this.addToExecutionQueue(() => this._runAction(data, isStreaming))
|
||||
this._runAction(data, isStreaming);
|
||||
} else {
|
||||
this.addToExecutionQueue(() => this._runAction(data, isStreaming));
|
||||
}
|
||||
}
|
||||
async _runAction(data: ActionCallbackData, isStreaming: boolean = false) {
|
||||
@@ -293,16 +289,21 @@ export class WorkbenchStore {
|
||||
if (!artifact) {
|
||||
unreachable('Artifact not found');
|
||||
}
|
||||
|
||||
if (data.action.type === 'file') {
|
||||
let wc = await webcontainer
|
||||
const wc = await webcontainer;
|
||||
const fullPath = nodePath.join(wc.workdir, data.action.filePath);
|
||||
|
||||
if (this.selectedFile.value !== fullPath) {
|
||||
this.setSelectedFile(fullPath);
|
||||
}
|
||||
|
||||
if (this.currentView.value !== 'code') {
|
||||
this.currentView.set('code');
|
||||
}
|
||||
|
||||
const doc = this.#editorStore.documents.get()[fullPath];
|
||||
|
||||
if (!doc) {
|
||||
await artifact.runner.runAction(data, isStreaming);
|
||||
}
|
||||
@@ -382,63 +383,7 @@ export class WorkbenchStore {
|
||||
return syncedFiles;
|
||||
}
|
||||
|
||||
async uploadFilesFromDisk(sourceHandle: FileSystemDirectoryHandle) {
|
||||
const loadedFiles = [];
|
||||
const wc = await webcontainer;
|
||||
const newFiles = {};
|
||||
|
||||
const processDirectory = async (handle: FileSystemDirectoryHandle, currentPath: string = '') => {
|
||||
const entries = await Array.fromAsync(handle.values());
|
||||
|
||||
for (const entry of entries) {
|
||||
const entryPath = currentPath ? `${currentPath}/${entry.name}` : entry.name;
|
||||
const fullPath = `/${entryPath}`;
|
||||
|
||||
if (entry.kind === 'directory') {
|
||||
await wc.fs.mkdir(fullPath, { recursive: true });
|
||||
const subDirHandle = await handle.getDirectoryHandle(entry.name);
|
||||
await processDirectory(subDirHandle, entryPath);
|
||||
} else {
|
||||
const file = await entry.getFile();
|
||||
const content = await file.text();
|
||||
|
||||
// Write to WebContainer
|
||||
await wc.fs.writeFile(fullPath, content);
|
||||
|
||||
// Mark file as new
|
||||
this.#filesStore.markFileAsNew(fullPath);
|
||||
|
||||
// Update the files store with the current content
|
||||
this.files.setKey(fullPath, { type: 'file', content, isBinary: false });
|
||||
|
||||
// Collect for editor store with actual content
|
||||
newFiles[fullPath] = { type: 'file', content, isBinary: false };
|
||||
loadedFiles.push(entryPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await processDirectory(sourceHandle);
|
||||
|
||||
return loadedFiles;
|
||||
}
|
||||
|
||||
async refreshFiles() {
|
||||
// Clear old state
|
||||
this.modifiedFiles = new Set<string>();
|
||||
this.artifactIdList = [];
|
||||
|
||||
// Reset stores
|
||||
this.#filesStore = new FilesStore(webcontainer);
|
||||
this.#editorStore = new EditorStore(this.#filesStore);
|
||||
|
||||
// Update UI state
|
||||
this.currentView.set('code');
|
||||
this.unsavedFiles.set(new Set<string>());
|
||||
}
|
||||
|
||||
async pushToGitHub(repoName: string, githubUsername: string, ghToken: string) {
|
||||
|
||||
try {
|
||||
// Get the GitHub auth token from environment variables
|
||||
const githubToken = ghToken;
|
||||
@@ -453,10 +398,11 @@ export class WorkbenchStore {
|
||||
const octokit = new Octokit({ auth: githubToken });
|
||||
|
||||
// Check if the repository already exists before creating it
|
||||
let repo: RestEndpointMethodTypes["repos"]["get"]["response"]['data']
|
||||
let repo: RestEndpointMethodTypes['repos']['get']['response']['data'];
|
||||
|
||||
try {
|
||||
let resp = await octokit.repos.get({ owner: owner, repo: repoName });
|
||||
repo = resp.data
|
||||
const resp = await octokit.repos.get({ owner, repo: repoName });
|
||||
repo = resp.data;
|
||||
} catch (error) {
|
||||
if (error instanceof Error && 'status' in error && error.status === 404) {
|
||||
// Repository doesn't exist, so create a new one
|
||||
@@ -474,6 +420,7 @@ export class WorkbenchStore {
|
||||
|
||||
// Get all files
|
||||
const files = this.files.get();
|
||||
|
||||
if (!files || Object.keys(files).length === 0) {
|
||||
throw new Error('No files found to push');
|
||||
}
|
||||
@@ -490,7 +437,9 @@ export class WorkbenchStore {
|
||||
});
|
||||
return { path: extractRelativePath(filePath), sha: blob.sha };
|
||||
}
|
||||
})
|
||||
|
||||
return null;
|
||||
}),
|
||||
);
|
||||
|
||||
const validBlobs = blobs.filter(Boolean); // Filter out any undefined blobs
|
||||
@@ -542,21 +491,6 @@ export class WorkbenchStore {
|
||||
console.error('Error pushing to GitHub:', error instanceof Error ? error.message : String(error));
|
||||
}
|
||||
}
|
||||
|
||||
async markFileAsModified(filePath: string) {
|
||||
const file = this.#filesStore.getFile(filePath);
|
||||
if (file?.type === 'file') {
|
||||
// First collect all original content
|
||||
const originalContent = file.content;
|
||||
console.log(`Processing ${filePath}:`, originalContent);
|
||||
|
||||
// Then save modifications
|
||||
await this.saveFile(filePath, originalContent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
export const workbenchStore = new WorkbenchStore();
|
||||
|
||||
Reference in New Issue
Block a user