File size: 4,049 Bytes
1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 893b0be 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 893b0be 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 7450ebd 1778c9e 7450ebd |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
import { idb } from "$lib/remult.js";
import { snapshot } from "$lib/utils/object.svelte";
import { dequal } from "dequal";
import { Entity, Fields, repo } from "remult";
import { conversations, type ConversationEntityMembers } from "./conversations.svelte";
import { ProjectEntity, projects } from "./projects.svelte";
@Entity("checkpoint")
export class Checkpoint {
@Fields.cuid()
id!: string;
@Fields.boolean()
favorite: boolean = false;
@Fields.createdAt()
timestamp!: Date;
@Fields.json()
conversations: ConversationEntityMembers[] = [];
@Fields.string()
projectId!: string;
}
const checkpointsRepo = repo(Checkpoint, idb);
class Checkpoints {
#checkpoints: Record<ProjectEntity["id"], Checkpoint[]> = $state({});
for(projectId: ProjectEntity["id"]) {
// Async load from db
checkpointsRepo
.find({
where: {
projectId,
},
})
.then(c => {
// Dequal to avoid infinite loops
if (dequal(c, this.#checkpoints[projectId])) return;
this.#checkpoints[projectId] = c;
});
return (
this.#checkpoints[projectId]?.toSorted((a, b) => {
const aTime = a.timestamp?.getTime() ?? new Date().getTime();
const bTime = b.timestamp?.getTime() ?? new Date().getTime();
return bTime - aTime;
}) ?? []
);
}
async commit(projectId: ProjectEntity["id"]) {
const project = projects.all.find(p => p.id == projectId);
if (!project) return;
const newCheckpoint = await checkpointsRepo.save(
snapshot({
conversations: conversations.for(project.id).map(c => c.data),
timestamp: new Date(),
projectId: project.id,
})
);
// Hack because dates are formatted to string by save
newCheckpoint.conversations.forEach((c, i) => {
newCheckpoint.conversations[i] = { ...c, createdAt: new Date(c.createdAt) };
});
const prev: Checkpoint[] = this.#checkpoints[projectId] ?? [];
this.#checkpoints[projectId] = [...prev, newCheckpoint];
}
restore(checkpoint: Checkpoint) {
const cloned = snapshot(checkpoint);
const modified = {
...cloned,
conversations: cloned.conversations.map(c => ({
...c,
projectId: cloned.projectId,
})),
};
const project = projects.all.find(p => p.id == modified.projectId);
if (!project) return;
projects.activeId = modified.projectId;
// conversations.deleteAllFrom(cloned.projectId);
const prev = conversations.for(modified.projectId);
modified.conversations.forEach((c, i) => {
const prevC = prev[i];
if (prevC) return prevC.update({ ...c });
conversations.create({
...c,
projectId: modified.projectId,
});
});
if (modified.conversations.length < prev.length) {
prev.forEach((p, i) => {
if (i < modified.conversations.length) return;
conversations.delete(p.data);
});
}
}
async toggleFavorite({ id, projectId }: Checkpoint) {
if (!id) return;
const p = await checkpointsRepo.findFirst({ id });
if (!p) return;
await checkpointsRepo.update(id, { favorite: !p.favorite });
const prev: Checkpoint[] = snapshot(this.#checkpoints[projectId] ?? []);
this.#checkpoints[projectId] = prev.map(c => {
if (c.id !== id) return c;
return { ...c, favorite: !c.favorite };
});
}
async delete({ id, projectId }: Checkpoint) {
if (!id) return;
await checkpointsRepo.delete(id);
const prev: Checkpoint[] = this.#checkpoints[projectId] ?? [];
this.#checkpoints[projectId] = prev.filter(c => c.id != id);
}
async clear(projectId: ProjectEntity["id"]) {
await checkpointsRepo.deleteMany({ where: { projectId } });
this.#checkpoints[projectId] = [];
}
async migrate(from: ProjectEntity["id"], to: ProjectEntity["id"]) {
await checkpointsRepo.updateMany({ where: { projectId: from }, set: { projectId: to } });
const fromArr = snapshot(this.#checkpoints[from] ?? []);
this.#checkpoints[to] = [
...fromArr.map(c => ({
...c,
projectId: to,
conversations: c.conversations.map(cn => ({ ...cn, projectId: to })),
})),
];
this.#checkpoints[from] = [];
}
}
export const checkpoints = new Checkpoints();
|