Skip to content

Commit

Permalink
Implement cell deletion
Browse files Browse the repository at this point in the history
  • Loading branch information
benjreinhart committed Jul 10, 2024
1 parent 565c815 commit 3d87342
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 65 deletions.
23 changes: 0 additions & 23 deletions packages/api/server/http.mts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@ import {
findSession,
deleteSessionByDirname,
exportSrcmdFile,
findCell,
removeCell,
updateSession,
sessionToResponse,
listSessions,
Expand Down Expand Up @@ -220,27 +218,6 @@ router.post('/sessions/:id/cells', cors(), async (req, res) => {
return res.json({ error: false, result: cell });
});

router.options('/sessions/:id/cells/:cellId', cors());

router.delete('/sessions/:id/cells/:cellId', cors(), async (req, res) => {
const { id, cellId } = req.params;
const session = await findSession(id);
const cell = findCell(session, cellId);

if (!cell) {
return res.status(404).json({ error: true, message: 'Cell not found' });
}

if (cell.type === 'title') {
res.status(400).json({ error: true, message: 'Cannot delete title cell' });
}

const updatedCells = removeCell(session, cellId);
updateSession(session, { cells: updatedCells });

return res.json({ result: updatedCells });
});

router.options('/settings', cors());

router.get('/settings', cors(), async (_req, res) => {
Expand Down
40 changes: 40 additions & 0 deletions packages/api/server/ws.mts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
updateSession,
readPackageJsonContentsFromDisk,
updateCell,
removeCell,
} from '../session.mjs';
import { getSecrets } from '../config.mjs';
import type { SessionType } from '../types.mjs';
Expand All @@ -22,6 +23,7 @@ import type {
CellUpdatePayloadType,
TsServerStartPayloadType,
TsServerStopPayloadType,
CellDeletePayloadType,
} from '@srcbook/shared';
import {
CellErrorPayloadSchema,
Expand All @@ -35,12 +37,14 @@ import {
DepsValidateResponsePayloadSchema,
TsServerStartPayloadSchema,
TsServerStopPayloadSchema,
CellDeletePayloadSchema,
} from '@srcbook/shared';
import tsservers from '../tsservers.mjs';
import { TsServer } from '../tsserver/tsserver.mjs';
import WebSocketServer from './ws-client.mjs';
import { pathToCodeFile } from '../srcbook/path.mjs';
import { formatDiagnostic } from '../tsserver/utils.mjs';
import { removeCodeCellFromDisk } from '../srcbook/index.mjs';

const wss = new WebSocketServer();

Expand Down Expand Up @@ -311,6 +315,41 @@ async function cellUpdate(payload: CellUpdatePayloadType) {
}
}

async function cellDelete(payload: CellDeletePayloadType) {
const session = await findSession(payload.sessionId);

if (!session) {
throw new Error(`No session exists for session '${payload.sessionId}'`);
}

const cell = findCell(session, payload.cellId);

if (!cell) {
throw new Error(
`No cell exists for session '${payload.sessionId}' and cell '${payload.cellId}'`,
);
}

if (cell.type !== 'markdown' && cell.type !== 'code') {
throw new Error(`Cannot delete cell of type '${cell.type}'`);
}

const updatedCells = removeCell(session, cell.id);

const updatedSession = await updateSession(session, { cells: updatedCells });

if (cell.type === 'code') {
removeCodeCellFromDisk(updatedSession.dir, cell.filename);

if (updatedSession.metadata.language === 'typescript' && tsservers.has(updatedSession.id)) {
const file = pathToCodeFile(updatedSession.dir, cell.filename);
const tsserver = tsservers.get(updatedSession.id);
tsserver.close({ file });
sendAllTypeScriptDiagnostics(tsserver, updatedSession);
}
}
}

/**
* Send semantic diagnostics for a TypeScript cell to the client.
*/
Expand Down Expand Up @@ -381,6 +420,7 @@ wss
.incoming('cell:exec', CellExecPayloadSchema, cellExec)
.incoming('cell:stop', CellStopPayloadSchema, cellStop)
.incoming('cell:update', CellUpdatePayloadSchema, cellUpdate)
.incoming('cell:delete', CellDeletePayloadSchema, cellDelete)
.incoming('deps:install', DepsInstallPayloadSchema, depsInstall)
.incoming('deps:validate', DepsValidatePayloadSchema, depsValidate)
.incoming('tsserver:start', TsServerStartPayloadSchema, tsserverStart)
Expand Down
8 changes: 6 additions & 2 deletions packages/api/srcbook/index.mts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,10 @@ function buildTsconfigJson() {
};
}

export async function removeSrcbook(srcbookDir: string) {
await fs.rm(srcbookDir, { recursive: true });
export function removeSrcbook(srcbookDir: string) {
fs.rm(srcbookDir, { recursive: true });
}

export function removeCodeCellFromDisk(srcbookDir: string, filename: string) {
return fs.rm(pathToCodeFile(srcbookDir, filename));
}
5 changes: 5 additions & 0 deletions packages/shared/src/schemas/websockets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ export const CellUpdatePayloadSchema = z.object({
updates: CellUpdateAttrsSchema,
});

export const CellDeletePayloadSchema = z.object({
sessionId: z.string(),
cellId: z.string(),
});

export const CellErrorPayloadSchema = z.object({
sessionId: z.string(),
cellId: z.string(),
Expand Down
2 changes: 2 additions & 0 deletions packages/shared/src/types/websockets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
CellStopPayloadSchema,
CellUpdatePayloadSchema,
CellUpdatedPayloadSchema,
CellDeletePayloadSchema,
CellOutputPayloadSchema,
DepsInstallPayloadSchema,
DepsValidateResponsePayloadSchema,
Expand All @@ -18,6 +19,7 @@ export type CellExecPayloadType = z.infer<typeof CellExecPayloadSchema>;
export type CellStopPayloadType = z.infer<typeof CellStopPayloadSchema>;
export type CellUpdatePayloadType = z.infer<typeof CellUpdatePayloadSchema>;
export type CellUpdatedPayloadType = z.infer<typeof CellUpdatedPayloadSchema>;
export type CellDeletePayloadType = z.infer<typeof CellDeletePayloadSchema>;
export type CellOutputPayloadType = z.infer<typeof CellOutputPayloadSchema>;

export type DepsInstallPayloadType = z.infer<typeof DepsInstallPayloadSchema>;
Expand Down
2 changes: 2 additions & 0 deletions packages/web/src/clients/websocket/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
CellErrorPayloadSchema,
TsServerStartPayloadSchema,
TsServerStopPayloadSchema,
CellDeletePayloadSchema,
} from '@srcbook/shared';

import Channel from '@/clients/websocket/channel';
Expand All @@ -30,6 +31,7 @@ const OutgoingSessionEvents = {
'cell:exec': CellExecPayloadSchema,
'cell:stop': CellStopPayloadSchema,
'cell:update': CellUpdatePayloadSchema,
'cell:delete': CellDeletePayloadSchema,
'deps:install': DepsInstallPayloadSchema,
'deps:validate': DepsValidatePayloadSchema,
'tsserver:start': TsServerStartPayloadSchema,
Expand Down
33 changes: 0 additions & 33 deletions packages/web/src/lib/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -227,39 +227,6 @@ export async function createCell(request: CreateCellRequestType): Promise<Create
return response.json();
}

interface DeleteCellRequestType {
sessionId: string;
cellId: string;
}

type DeleteResponseType = {
error: boolean;
message: string;
};

type SuccessDeleteResponseType = {
result: CellType[];
};

type DeleteCellResponseType = DeleteResponseType | SuccessDeleteResponseType;

export async function deleteCell(request: DeleteCellRequestType): Promise<DeleteCellResponseType> {
const response = await fetch(
API_BASE_URL + '/sessions/' + request.sessionId + '/cells/' + request.cellId,
{
method: 'DELETE',
headers: { 'content-type': 'application/json' },
},
);

if (!response.ok) {
console.error(response);
throw new Error('Request failed');
}

return response.json();
}

// Config settings
interface EditConfigRequestType {
baseDir?: string;
Expand Down
12 changes: 5 additions & 7 deletions packages/web/src/routes/session.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import {
MarkdownCellUpdateAttrsType,
CellErrorPayloadType,
} from '@srcbook/shared';
import { loadSession, createCell, deleteCell } from '@/lib/server';
import { loadSession, createCell } from '@/lib/server';
import { cn } from '@/lib/utils';
import { SessionType } from '@/types';
import SessionMenu from '@/components/session-menu';
Expand Down Expand Up @@ -102,12 +102,10 @@ function Session(props: { session: SessionType; channel: SessionChannel }) {
// Optimistically delete cell
removeCell(cell);

const response = await deleteCell({ sessionId: session.id, cellId: cell.id });
if ('error' in response) {
// Undo optimistic cell deletion
setCells(cells);
console.error('Failed to delete cell', response);
}
channel.push('cell:delete', {
sessionId: session.id,
cellId: cell.id,
});
}

useEffect(() => {
Expand Down

0 comments on commit 3d87342

Please sign in to comment.