This commit is contained in:
Nikita Galaiko 2023-03-27 15:47:32 +02:00
parent 8cadaed8a0
commit e955f4a786
4 changed files with 111 additions and 111 deletions

View File

@ -9,49 +9,49 @@ export type OperationInsert = { insert: [number, string] };
export type Operation = OperationDelete | OperationInsert;
export namespace Operation {
export const isDelete = (operation: Operation): operation is OperationDelete =>
'delete' in operation;
export const isDelete = (operation: Operation): operation is OperationDelete =>
'delete' in operation;
export const isInsert = (operation: Operation): operation is OperationInsert =>
'insert' in operation;
export const isInsert = (operation: Operation): operation is OperationInsert =>
'insert' in operation;
}
export type Delta = { timestampMs: number; operations: Operation[] };
export type DeltasEvent = {
deltas: Delta[];
filePath: string;
deltas: Delta[];
filePath: string;
};
export const list = (params: { projectId: string; sessionId: string; paths?: string[] }) =>
invoke<Record<string, Delta[]>>('list_deltas', params);
invoke<Record<string, Delta[]>>('list_deltas', params);
export const subscribe = (
params: { projectId: string; sessionId: string },
callback: (filepath: string, deltas: Delta[]) => void
params: { projectId: string; sessionId: string },
callback: (filepath: string, deltas: Delta[]) => void
) => {
log.info(`Subscribing to deltas for ${params.projectId}, ${params.sessionId}`);
return appWindow.listen<DeltasEvent>(
`project://${params.projectId}/sessions/${params.sessionId}/deltas`,
(event) => {
log.info(
`Received deltas for ${params.projectId}, ${params.sessionId}, ${event.payload.filePath}`
);
callback(event.payload.filePath, event.payload.deltas);
}
);
log.info(`Subscribing to deltas for ${params.projectId}, ${params.sessionId}`);
return appWindow.listen<DeltasEvent>(
`project://${params.projectId}/sessions/${params.sessionId}/deltas`,
(event) => {
log.info(
`Received deltas for ${params.projectId}, ${params.sessionId}, ${event.payload.filePath}`
);
callback(event.payload.filePath, event.payload.deltas);
}
);
};
export default async (params: { projectId: string; sessionId: string }) => {
const init = await list(params);
const init = await list(params);
const store = writable<Record<string, Delta[]>>(init);
subscribe(params, (filepath, newDeltas) =>
store.update((deltas) => ({
...deltas,
[filepath]: newDeltas
}))
);
const store = writable<Record<string, Delta[]>>(init);
subscribe(params, (filepath, newDeltas) =>
store.update((deltas) => ({
...deltas,
[filepath]: newDeltas
}))
);
return store as Readable<Record<string, Delta[]>>;
return store as Readable<Record<string, Delta[]>>;
};

View File

@ -4,54 +4,54 @@ import { writable, type Readable } from 'svelte/store';
import { log } from '$lib';
export type Activity = {
type: string;
timestampMs: number;
message: string;
type: string;
timestampMs: number;
message: string;
};
export namespace Session {
export const within = (session: Session | undefined, timestampMs: number) => {
if (!session) return false;
const { startTimestampMs, lastTimestampMs } = session.meta;
return startTimestampMs <= timestampMs && timestampMs <= lastTimestampMs;
};
export const within = (session: Session | undefined, timestampMs: number) => {
if (!session) return false;
const { startTimestampMs, lastTimestampMs } = session.meta;
return startTimestampMs <= timestampMs && timestampMs <= lastTimestampMs;
};
}
export type Session = {
id: string;
hash?: string;
meta: {
startTimestampMs: number;
lastTimestampMs: number;
branch?: string;
commit?: string;
};
activity: Activity[];
id: string;
hash?: string;
meta: {
startTimestampMs: number;
lastTimestampMs: number;
branch?: string;
commit?: string;
};
activity: Activity[];
};
export const listFiles = (params: { projectId: string; sessionId: string; paths?: string[] }) =>
invoke<Record<string, string>>('list_session_files', params);
invoke<Record<string, string>>('list_session_files', params);
const list = (params: { projectId: string }) => invoke<Session[]>('list_sessions', params);
export default async (params: { projectId: string; earliestTimestampMs?: number }) => {
const store = writable([] as Session[]);
list(params).then((sessions) => {
store.set(sessions);
});
const store = writable([] as Session[]);
list(params).then((sessions) => {
store.set(sessions);
});
appWindow.listen<Session>(`project://${params.projectId}/sessions`, async (event) => {
log.info(`Received sessions event, projectId: ${params.projectId}`);
const session = event.payload;
store.update((sessions) => {
const index = sessions.findIndex((session) => session.id === event.payload.id);
if (index === -1) {
return [...sessions, session];
} else {
return [...sessions.slice(0, index), session, ...sessions.slice(index + 1)];
}
});
});
appWindow.listen<Session>(`project://${params.projectId}/sessions`, async (event) => {
log.info(`Received sessions event, projectId: ${params.projectId}`);
const session = event.payload;
store.update((sessions) => {
const index = sessions.findIndex((session) => session.id === event.payload.id);
if (index === -1) {
return [...sessions, session];
} else {
return [...sessions.slice(0, index), session, ...sessions.slice(index + 1)];
}
});
});
return store as Readable<Session[]>;
return store as Readable<Session[]>;
};

View File

@ -4,11 +4,11 @@ import { readable, type Readable } from 'svelte/store';
import type { LayoutLoad } from './$types';
export const load: LayoutLoad = async ({ params }) => {
const sessions: Readable<Session[]> = building
? readable<Session[]>([])
: await import('$lib/sessions').then((m) => m.default({ projectId: params.projectId }));
return {
sessions,
projectId: params.projectId
};
const sessions: Readable<Session[]> = building
? readable<Session[]>([])
: await import('$lib/sessions').then((m) => m.default({ projectId: params.projectId }));
return {
sessions,
projectId: params.projectId
};
};

View File

@ -5,48 +5,48 @@ import { format } from 'date-fns';
import type { PageLoad } from './$types';
const enrichSession = async (projectId: string, session: Session) => {
const sessionsModule = await import('$lib/sessions');
const deltasModule = await import('$lib/deltas');
const files = await sessionsModule.listFiles({ projectId, sessionId: session.id });
const deltas = await deltasModule.list({ projectId, sessionId: session.id }).then((deltas) =>
Object.entries(deltas)
.flatMap(([path, deltas]) => deltas.map((delta) => [path, delta] as [string, Delta]))
.sort((a, b) => a[1].timestampMs - b[1].timestampMs)
);
const deltasFiles = new Set(deltas.map(([path]) => path));
return {
...session,
files: Object.fromEntries(
Object.entries(files).filter(([filepath]) => deltasFiles.has(filepath))
),
deltas
};
const sessionsModule = await import('$lib/sessions');
const deltasModule = await import('$lib/deltas');
const files = await sessionsModule.listFiles({ projectId, sessionId: session.id });
const deltas = await deltasModule.list({ projectId, sessionId: session.id }).then((deltas) =>
Object.entries(deltas)
.flatMap(([path, deltas]) => deltas.map((delta) => [path, delta] as [string, Delta]))
.sort((a, b) => a[1].timestampMs - b[1].timestampMs)
);
const deltasFiles = new Set(deltas.map(([path]) => path));
return {
...session,
files: Object.fromEntries(
Object.entries(files).filter(([filepath]) => deltasFiles.has(filepath))
),
deltas
};
};
export const load: PageLoad = async ({ params, parent, url }) => {
const { sessions } = await parent();
return {
sessions: asyncDerived(sessions, async (sessions) =>
Promise.all(
sessions
.filter((session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === params.date)
.map((session) => enrichSession(params.projectId, session))
).then((sessions) => {
sessions = sessions.sort((a, b) => a.meta.startTimestampMs - b.meta.startTimestampMs);
const fileFilter = url.searchParams.get('file');
if (fileFilter) {
sessions = sessions
.filter((session) => session.files[fileFilter])
.map((session) => ({
...session,
deltas: session.deltas.filter(([path]) => path === fileFilter),
files: {
[fileFilter]: session.files[fileFilter]
}
}));
}
return sessions;
})
)
};
const { sessions } = await parent();
return {
sessions: asyncDerived(sessions, async (sessions) =>
Promise.all(
sessions
.filter((session) => format(session.meta.startTimestampMs, 'yyyy-MM-dd') === params.date)
.map((session) => enrichSession(params.projectId, session))
).then((sessions) => {
sessions = sessions.sort((a, b) => a.meta.startTimestampMs - b.meta.startTimestampMs);
const fileFilter = url.searchParams.get('file');
if (fileFilter) {
sessions = sessions
.filter((session) => session.files[fileFilter])
.map((session) => ({
...session,
deltas: session.deltas.filter(([path]) => path === fileFilter),
files: {
[fileFilter]: session.files[fileFilter]
}
}));
}
return sessions;
})
)
};
};