mirror of
https://github.com/zadam/trilium.git
synced 2026-05-06 09:17:35 +02:00
feat(revisions): add a source field
This commit is contained in:
@@ -310,7 +310,12 @@
|
||||
"description_placeholder": "Add a description (optional)",
|
||||
"revision_saved": "Note revision has been saved.",
|
||||
"edit_description": "Edit description",
|
||||
"description_updated": "Revision description has been updated."
|
||||
"description_updated": "Revision description has been updated.",
|
||||
"source_auto": "Auto",
|
||||
"source_manual": "Manual",
|
||||
"source_etapi": "ETAPI",
|
||||
"source_llm": "LLM",
|
||||
"source_restore": "Restore"
|
||||
},
|
||||
"sort_child_notes": {
|
||||
"sort_children_by": "Sort children by...",
|
||||
|
||||
@@ -200,7 +200,23 @@ function RevisionsList({ revisions, onSelect, currentRevision }: { revisions: Re
|
||||
active={currentRevision && item.revisionId === currentRevision.revisionId}
|
||||
>
|
||||
<div>
|
||||
{item.dateCreated && item.dateCreated.substr(0, 16)} ({item.contentLength && utils.formatSize(item.contentLength)})
|
||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: "4px" }}>
|
||||
<span>{item.dateCreated && item.dateCreated.substr(0, 16)}</span>
|
||||
{item.source && item.source !== "auto" && (
|
||||
<span className="revision-source-badge" style={{
|
||||
fontSize: "0.75em",
|
||||
padding: "0 4px",
|
||||
borderRadius: "3px",
|
||||
backgroundColor: "var(--accented-background-color)",
|
||||
whiteSpace: "nowrap"
|
||||
}}>
|
||||
{t(`revisions.source_${item.source}`)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div style={{ fontSize: "0.85em", opacity: 0.7 }}>
|
||||
{item.contentLength && utils.formatSize(item.contentLength)}
|
||||
</div>
|
||||
{item.description && (
|
||||
<div className="revision-description" style={{ fontSize: "0.85em", opacity: 0.7, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
|
||||
{item.description}
|
||||
|
||||
@@ -49,6 +49,7 @@ CREATE TABLE IF NOT EXISTS "revisions" (`revisionId` TEXT NOT NULL PRIMARY KEY,
|
||||
mime TEXT DEFAULT '' NOT NULL,
|
||||
`title` TEXT NOT NULL,
|
||||
`description` TEXT DEFAULT '' NOT NULL,
|
||||
`source` TEXT DEFAULT 'auto' NOT NULL,
|
||||
`isProtected` INT NOT NULL DEFAULT 0,
|
||||
blobId TEXT DEFAULT NULL,
|
||||
`utcDateLastEdited` TEXT NOT NULL,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { AttachmentRow, AttributeType, CloneResponse, NoteRow, NoteType, RevisionRow } from "@triliumnext/commons";
|
||||
import type { AttachmentRow, AttributeType, CloneResponse, NoteRow, NoteType, RevisionRow, RevisionSource } from "@triliumnext/commons";
|
||||
import { dayjs, getNoteIcon } from "@triliumnext/commons";
|
||||
|
||||
import cloningService from "../../services/cloning.js";
|
||||
@@ -1543,7 +1543,7 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
||||
return !(this.noteId in this.becca.notes) || this.isBeingDeleted;
|
||||
}
|
||||
|
||||
saveRevision(description?: string): BRevision {
|
||||
saveRevision(opts: { description?: string; source?: RevisionSource } = {}): BRevision {
|
||||
return sql.transactional(() => {
|
||||
let noteContent = this.getContent();
|
||||
|
||||
@@ -1552,7 +1552,8 @@ class BNote extends AbstractBeccaEntity<BNote> {
|
||||
noteId: this.noteId,
|
||||
// title and text should be decrypted now
|
||||
title: this.title,
|
||||
description: description || "",
|
||||
description: opts.description || "",
|
||||
source: opts.source || "auto",
|
||||
type: this.type,
|
||||
mime: this.mime,
|
||||
isProtected: this.isProtected,
|
||||
|
||||
@@ -7,7 +7,7 @@ import becca from "../becca.js";
|
||||
import AbstractBeccaEntity from "./abstract_becca_entity.js";
|
||||
import sql from "../../services/sql.js";
|
||||
import BAttachment from "./battachment.js";
|
||||
import type { AttachmentRow, NoteType, RevisionPojo, RevisionRow } from "@triliumnext/commons";
|
||||
import type { AttachmentRow, NoteType, RevisionPojo, RevisionRow, RevisionSource } from "@triliumnext/commons";
|
||||
import eraseService from "../../services/erase.js";
|
||||
|
||||
interface ContentOpts {
|
||||
@@ -31,7 +31,7 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
|
||||
return "revisionId";
|
||||
}
|
||||
static get hashedProperties() {
|
||||
return ["revisionId", "noteId", "title", "description", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified", "blobId"];
|
||||
return ["revisionId", "noteId", "title", "description", "source", "isProtected", "dateLastEdited", "dateCreated", "utcDateLastEdited", "utcDateCreated", "utcDateModified", "blobId"];
|
||||
}
|
||||
|
||||
revisionId?: string;
|
||||
@@ -40,6 +40,7 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
|
||||
mime!: string;
|
||||
title!: string;
|
||||
description!: string;
|
||||
source!: RevisionSource;
|
||||
dateLastEdited?: string;
|
||||
utcDateLastEdited?: string;
|
||||
contentLength?: number;
|
||||
@@ -63,6 +64,7 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
|
||||
this.isProtected = !!row.isProtected;
|
||||
this.title = row.title;
|
||||
this.description = row.description || "";
|
||||
this.source = row.source || "auto";
|
||||
this.blobId = row.blobId;
|
||||
this.dateLastEdited = row.dateLastEdited;
|
||||
this.dateCreated = row.dateCreated;
|
||||
@@ -196,6 +198,7 @@ class BRevision extends AbstractBeccaEntity<BRevision> {
|
||||
isProtected: this.isProtected,
|
||||
title: this.title,
|
||||
description: this.description,
|
||||
source: this.source,
|
||||
blobId: this.blobId,
|
||||
dateLastEdited: this.dateLastEdited,
|
||||
dateCreated: this.dateCreated,
|
||||
|
||||
@@ -74,6 +74,7 @@ function mapRevisionToPojo(revision: BRevision) {
|
||||
isProtected: revision.isProtected,
|
||||
title: revision.title,
|
||||
description: revision.description,
|
||||
source: revision.source,
|
||||
blobId: revision.blobId,
|
||||
dateLastEdited: revision.dateLastEdited,
|
||||
dateCreated: revision.dateCreated,
|
||||
|
||||
@@ -193,7 +193,7 @@ function register(router: Router) {
|
||||
const note = eu.getAndCheckNote(req.params.noteId);
|
||||
|
||||
const description = req.body?.description || "";
|
||||
const revision = note.saveRevision(description);
|
||||
const revision = note.saveRevision({ description, source: "etapi" });
|
||||
|
||||
res.status(201).json(mappers.mapRevisionToPojo(revision));
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ const MIGRATIONS: (SqlMigration | JsMigration)[] = [
|
||||
version: 238,
|
||||
sql: /*sql*/`
|
||||
ALTER TABLE revisions ADD COLUMN description TEXT DEFAULT '' NOT NULL;
|
||||
ALTER TABLE revisions ADD COLUMN source TEXT DEFAULT 'auto' NOT NULL;
|
||||
`,
|
||||
ignoreErrors: true
|
||||
},
|
||||
|
||||
@@ -352,7 +352,7 @@ function forceSaveRevision(req: Request<{ noteId: string }>) {
|
||||
}
|
||||
|
||||
const description = req.body?.description || "";
|
||||
const revision = note.saveRevision(description);
|
||||
const revision = note.saveRevision({ description, source: "manual" });
|
||||
|
||||
return {
|
||||
revisionId: revision.revisionId
|
||||
|
||||
@@ -137,7 +137,7 @@ function restoreRevision(req: Request<{ revisionId: string }>) {
|
||||
const note = revision.getNote();
|
||||
|
||||
sql.transactional(() => {
|
||||
note.saveRevision();
|
||||
note.saveRevision({ source: "restore" });
|
||||
|
||||
for (const oldNoteAttachment of note.getAttachments()) {
|
||||
oldNoteAttachment.markAsDeleted();
|
||||
|
||||
@@ -116,7 +116,7 @@ export const noteTools = defineTools({
|
||||
return { error: `Cannot update content for note type: ${note.type}` };
|
||||
}
|
||||
|
||||
note.saveRevision();
|
||||
note.saveRevision({ source: "llm" });
|
||||
setNoteContentFromLlm(note, content);
|
||||
return {
|
||||
success: true,
|
||||
@@ -158,7 +158,7 @@ export const noteTools = defineTools({
|
||||
newContent = existingContent + (existingContent.endsWith("\n") ? "" : "\n") + content;
|
||||
}
|
||||
|
||||
note.saveRevision();
|
||||
note.saveRevision({ source: "llm" });
|
||||
note.setContent(newContent);
|
||||
return {
|
||||
success: true,
|
||||
|
||||
@@ -21,6 +21,9 @@ export interface AttachmentRow {
|
||||
encoding?: "base64";
|
||||
}
|
||||
|
||||
export const REVISION_SOURCES = ["auto", "manual", "etapi", "llm", "restore"] as const;
|
||||
export type RevisionSource = (typeof REVISION_SOURCES)[number];
|
||||
|
||||
export interface RevisionRow {
|
||||
revisionId?: string;
|
||||
noteId: string;
|
||||
@@ -29,6 +32,7 @@ export interface RevisionRow {
|
||||
isProtected?: boolean;
|
||||
title: string;
|
||||
description?: string;
|
||||
source?: RevisionSource;
|
||||
blobId?: string;
|
||||
dateLastEdited?: string;
|
||||
dateCreated?: string;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { AttachmentRow, AttributeRow, BranchRow, NoteRow, NoteType } from "./rows.js";
|
||||
import { AttachmentRow, AttributeRow, BranchRow, NoteRow, NoteType, RevisionSource } from "./rows.js";
|
||||
|
||||
type Response = {
|
||||
success: true,
|
||||
@@ -34,6 +34,7 @@ export interface RevisionItem {
|
||||
type: NoteType;
|
||||
title: string;
|
||||
description?: string;
|
||||
source?: RevisionSource;
|
||||
isProtected?: boolean;
|
||||
mime: string;
|
||||
}
|
||||
@@ -46,6 +47,7 @@ export interface RevisionPojo {
|
||||
isProtected?: boolean;
|
||||
title: string;
|
||||
description?: string;
|
||||
source?: RevisionSource;
|
||||
blobId?: string;
|
||||
dateLastEdited?: string;
|
||||
dateCreated?: string;
|
||||
|
||||
Reference in New Issue
Block a user