mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00
chore(code): fix editorconfig for src/public
This commit is contained in:
parent
ae90ff2df4
commit
b321d99076
@ -1,18 +1,18 @@
|
||||
// TODO: Deduplicate with src/services/entity_changes_interface.ts
|
||||
export interface EntityChange {
|
||||
id?: number | null;
|
||||
noteId?: string;
|
||||
entityName: string;
|
||||
entityId: string;
|
||||
entity?: any;
|
||||
positions?: Record<string, number>;
|
||||
hash: string;
|
||||
utcDateChanged?: string;
|
||||
utcDateModified?: string;
|
||||
utcDateCreated?: string;
|
||||
isSynced: boolean | 1 | 0;
|
||||
isErased: boolean | 1 | 0;
|
||||
componentId?: string | null;
|
||||
changeId?: string | null;
|
||||
instanceId?: string | null;
|
||||
id?: number | null;
|
||||
noteId?: string;
|
||||
entityName: string;
|
||||
entityId: string;
|
||||
entity?: any;
|
||||
positions?: Record<string, number>;
|
||||
hash: string;
|
||||
utcDateChanged?: string;
|
||||
utcDateModified?: string;
|
||||
utcDateCreated?: string;
|
||||
isSynced: boolean | 1 | 0;
|
||||
isErased: boolean | 1 | 0;
|
||||
componentId?: string | null;
|
||||
changeId?: string | null;
|
||||
instanceId?: string | null;
|
||||
}
|
@ -111,4 +111,3 @@
|
||||
.calendar-dropdown-widget .calendar-date:not(.calendar-date-active) {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
|
@ -30,7 +30,7 @@ html {
|
||||
|
||||
body {
|
||||
/* Fix for CKEditor block gutter icon "stretching" body and causing scrollbar to appear after pressing enter
|
||||
on the last line of the editor. */
|
||||
on the last line of the editor. */
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Light theme is special since it's also baseline/default so when a theme does not define some variable then
|
||||
value from this theme will be used. For this reason this theme uses "html" instead of ":root"
|
||||
since it's less "specific" and thus serves as default */
|
||||
value from this theme will be used. For this reason this theme uses "html" instead of ":root"
|
||||
since it's less "specific" and thus serves as default */
|
||||
html {
|
||||
/* either light or dark, colored theme with darker tones are also dark, used e.g. for note map node colors */
|
||||
--theme-style: light;
|
||||
|
@ -49,18 +49,18 @@ function getRecentNotes(activeNoteId: string) {
|
||||
}
|
||||
|
||||
const recentNotes = becca.getRecentNotesFromQuery(`
|
||||
SELECT
|
||||
SELECT
|
||||
recent_notes.*
|
||||
FROM
|
||||
FROM
|
||||
recent_notes
|
||||
JOIN notes USING(noteId)
|
||||
WHERE
|
||||
WHERE
|
||||
notes.isDeleted = 0
|
||||
AND notes.noteId != ?
|
||||
${extraCondition}
|
||||
ORDER BY
|
||||
ORDER BY
|
||||
utcDateCreated DESC
|
||||
LIMIT 200`, params);
|
||||
LIMIT 200`, params);
|
||||
|
||||
return recentNotes.map(rn => {
|
||||
const notePathArray = rn.notePath.split('/');
|
||||
|
@ -219,9 +219,9 @@ function getDeleteNotesPreview(req: Request) {
|
||||
brokenRelations = sql.getRows<AttributeRow>(`
|
||||
SELECT attr.noteId, attr.name, attr.value
|
||||
FROM attributes attr
|
||||
JOIN param_list ON param_list.paramId = attr.value
|
||||
JOIN param_list ON param_list.paramId = attr.value
|
||||
WHERE attr.isDeleted = 0
|
||||
AND attr.type = 'relation'`).filter(attr => attr.noteId && !noteIdsToBeDeleted.has(attr.noteId));
|
||||
AND attr.type = 'relation'`).filter(attr => attr.noteId && !noteIdsToBeDeleted.has(attr.noteId));
|
||||
}
|
||||
|
||||
return {
|
||||
|
@ -35,7 +35,7 @@ function getRevisionBlob(req: Request) {
|
||||
function getRevisions(req: Request) {
|
||||
return becca.getRevisionsFromQuery(`
|
||||
SELECT revisions.*,
|
||||
LENGTH(blobs.content) AS contentLength
|
||||
LENGTH(blobs.content) AS contentLength
|
||||
FROM revisions
|
||||
JOIN blobs ON revisions.blobId = blobs.blobId
|
||||
WHERE revisions.noteId = ?
|
||||
@ -160,7 +160,7 @@ function getEditedNotesOnDate(req: Request) {
|
||||
WHERE noteId IN (
|
||||
SELECT noteId FROM notes
|
||||
WHERE notes.dateCreated LIKE :date
|
||||
OR notes.dateModified LIKE :date
|
||||
OR notes.dateModified LIKE :date
|
||||
UNION ALL
|
||||
SELECT noteId FROM revisions
|
||||
WHERE revisions.dateLastEdited LIKE :date
|
||||
|
@ -12,8 +12,8 @@ function getNoteSize(req: Request) {
|
||||
LEFT JOIN attachments ON attachments.blobId = blobs.blobId AND attachments.ownerId = ? AND attachments.isDeleted = 0
|
||||
LEFT JOIN revisions ON revisions.blobId = blobs.blobId AND revisions.noteId = ?
|
||||
WHERE notes.noteId IS NOT NULL
|
||||
OR attachments.attachmentId IS NOT NULL
|
||||
OR revisions.revisionId IS NOT NULL`, [noteId, noteId, noteId]);
|
||||
OR attachments.attachmentId IS NOT NULL
|
||||
OR revisions.revisionId IS NOT NULL`, [noteId, noteId, noteId]);
|
||||
|
||||
const noteSize = Object.values(blobSizes).reduce((acc, blobSize) => acc + blobSize, 0);
|
||||
|
||||
|
@ -103,7 +103,7 @@ function getChanged(req: Request) {
|
||||
SELECT *
|
||||
FROM entity_changes
|
||||
WHERE isSynced = 1
|
||||
AND id > ?
|
||||
AND id > ?
|
||||
ORDER BY id
|
||||
LIMIT 1000`, [lastEntityChangeId]);
|
||||
|
||||
@ -133,8 +133,8 @@ function getChanged(req: Request) {
|
||||
SELECT COUNT(id)
|
||||
FROM entity_changes
|
||||
WHERE isSynced = 1
|
||||
AND instanceId != ?
|
||||
AND id > ?`, [clientInstanceId, lastEntityChangeId])
|
||||
AND instanceId != ?
|
||||
AND id > ?`, [clientInstanceId, lastEntityChangeId])
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -18,22 +18,22 @@ const persistentCacheStatic = (root: string, options?: serveStatic.ServeStaticOp
|
||||
async function register(app: express.Application) {
|
||||
const srcRoot = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
if (env.isDev()) {
|
||||
const webpack = (await import("webpack")).default;
|
||||
const webpackMiddleware = (await import("webpack-dev-middleware")).default;
|
||||
const productionConfig = (await import("../../webpack.config.js")).default;
|
||||
const webpack = (await import("webpack")).default;
|
||||
const webpackMiddleware = (await import("webpack-dev-middleware")).default;
|
||||
const productionConfig = (await import("../../webpack.config.js")).default;
|
||||
|
||||
const frontendCompiler = webpack({
|
||||
const frontendCompiler = webpack({
|
||||
mode: "development",
|
||||
entry: productionConfig.entry,
|
||||
module: productionConfig.module,
|
||||
resolve: productionConfig.resolve,
|
||||
devtool: productionConfig.devtool,
|
||||
target: productionConfig.target
|
||||
});
|
||||
});
|
||||
|
||||
app.use(`/${assetPath}/app`, webpackMiddleware(frontendCompiler));
|
||||
app.use(`/${assetPath}/app`, webpackMiddleware(frontendCompiler));
|
||||
} else {
|
||||
app.use(`/${assetPath}/app`, persistentCacheStatic(path.join(srcRoot, 'public/app')));
|
||||
app.use(`/${assetPath}/app`, persistentCacheStatic(path.join(srcRoot, 'public/app')));
|
||||
}
|
||||
app.use(`/${assetPath}/app-dist`, persistentCacheStatic(path.join(srcRoot, 'public/app-dist')));
|
||||
app.use(`/${assetPath}/fonts`, persistentCacheStatic(path.join(srcRoot, 'public/fonts')));
|
||||
@ -56,19 +56,19 @@ async function register(app: express.Application) {
|
||||
|
||||
// KaTeX
|
||||
app.use(
|
||||
`/${assetPath}/node_modules/katex/dist/katex.min.js`,
|
||||
persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/katex.min.js')));
|
||||
`/${assetPath}/node_modules/katex/dist/katex.min.js`,
|
||||
persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/katex.min.js')));
|
||||
app.use(
|
||||
`/${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js`,
|
||||
persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/contrib/mhchem.min.js')));
|
||||
`/${assetPath}/node_modules/katex/dist/contrib/mhchem.min.js`,
|
||||
persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/contrib/mhchem.min.js')));
|
||||
app.use(
|
||||
`/${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js`,
|
||||
persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/contrib/auto-render.min.js')));
|
||||
`/${assetPath}/node_modules/katex/dist/contrib/auto-render.min.js`,
|
||||
persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/contrib/auto-render.min.js')));
|
||||
// expose the whole dist folder
|
||||
app.use(`/node_modules/katex/dist/`,
|
||||
express.static(path.join(srcRoot, '..', 'node_modules/katex/dist/')));
|
||||
express.static(path.join(srcRoot, '..', 'node_modules/katex/dist/')));
|
||||
app.use(`/${assetPath}/node_modules/katex/dist/`,
|
||||
persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/')));
|
||||
persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/katex/dist/')));
|
||||
|
||||
app.use(`/${assetPath}/node_modules/dayjs/`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/dayjs/')));
|
||||
app.use(`/${assetPath}/node_modules/force-graph/dist/`, persistentCacheStatic(path.join(srcRoot, '..', 'node_modules/force-graph/dist/')));
|
||||
|
@ -24,9 +24,9 @@ UPDATE attributes SET name = 'name' WHERE type = 'relation' AND name NOT IN (${b
|
||||
UPDATE branches SET prefix = 'prefix' WHERE prefix IS NOT NULL AND prefix != 'recovered';
|
||||
UPDATE options SET value = 'anonymized' WHERE name IN
|
||||
('documentId', 'documentSecret', 'encryptedDataKey',
|
||||
'passwordVerificationHash', 'passwordVerificationSalt',
|
||||
'passwordDerivedKeySalt', 'username', 'syncServerHost', 'syncProxy')
|
||||
AND value != '';
|
||||
'passwordVerificationHash', 'passwordVerificationSalt',
|
||||
'passwordDerivedKeySalt', 'username', 'syncServerHost', 'syncProxy')
|
||||
AND value != '';
|
||||
|
||||
VACUUM;
|
||||
`;
|
||||
@ -37,15 +37,15 @@ VACUUM;
|
||||
function getLightAnonymizationScript() {
|
||||
return `UPDATE blobs SET content = 'text' WHERE content IS NOT NULL AND blobId NOT IN (
|
||||
SELECT blobId FROM notes WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend')
|
||||
UNION ALL
|
||||
UNION ALL
|
||||
SELECT blobId FROM revisions WHERE mime IN ('application/javascript;env=backend', 'application/javascript;env=frontend')
|
||||
);
|
||||
|
||||
UPDATE options SET value = 'anonymized' WHERE name IN
|
||||
('documentId', 'documentSecret', 'encryptedDataKey',
|
||||
'passwordVerificationHash', 'passwordVerificationSalt',
|
||||
'passwordDerivedKeySalt', 'username', 'syncServerHost', 'syncProxy')
|
||||
AND value != '';`;
|
||||
('documentId', 'documentSecret', 'encryptedDataKey',
|
||||
'passwordVerificationHash', 'passwordVerificationSalt',
|
||||
'passwordDerivedKeySalt', 'username', 'syncServerHost', 'syncProxy')
|
||||
AND value != '';`;
|
||||
}
|
||||
|
||||
async function createAnonymizedCopy(type: "full" | "light") {
|
||||
|
@ -48,7 +48,7 @@ function installLocalAppIcon() {
|
||||
|
||||
fs.writeFile(desktopFilePath, getDesktopFileContent(), function (err) {
|
||||
if (err) {
|
||||
log.error("Desktop icon installation to ~/.local/share/applications failed.");
|
||||
log.error("Desktop icon installation to ~/.local/share/applications failed.");
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -66,7 +66,7 @@ function escapePath(path: string) {
|
||||
}
|
||||
|
||||
function getExePath() {
|
||||
return path.resolve(resourceDir.ELECTRON_APP_ROOT_DIR, 'trilium');
|
||||
return path.resolve(resourceDir.ELECTRON_APP_ROOT_DIR, 'trilium');
|
||||
}
|
||||
|
||||
export default {
|
||||
|
@ -66,10 +66,10 @@ function getAttributeNames(type: string, nameLike: string) {
|
||||
|
||||
let names = sql.getColumn<string>(
|
||||
`SELECT DISTINCT name
|
||||
FROM attributes
|
||||
WHERE isDeleted = 0
|
||||
AND type = ?
|
||||
AND name LIKE ?`, [type, `%${nameLike}%`]);
|
||||
FROM attributes
|
||||
WHERE isDeleted = 0
|
||||
AND type = ?
|
||||
AND name LIKE ?`, [type, `%${nameLike}%`]);
|
||||
|
||||
for (const attr of BUILTIN_ATTRIBUTES) {
|
||||
if (attr.type === type && attr.name.toLowerCase().includes(nameLike) && !names.includes(attr.name)) {
|
||||
|
@ -61,51 +61,51 @@ interface NoteAndBranch {
|
||||
|
||||
interface Api {
|
||||
/**
|
||||
* Note where the script started executing (entrypoint).
|
||||
* As an analogy, in C this would be the file which contains the main() function of the current process.
|
||||
*/
|
||||
* Note where the script started executing (entrypoint).
|
||||
* As an analogy, in C this would be the file which contains the main() function of the current process.
|
||||
*/
|
||||
startNote?: BNote | null;
|
||||
|
||||
/**
|
||||
* Note where the script is currently executing. This comes into play when your script is spread in multiple code
|
||||
* notes, the script starts in "startNote", but then through function calls may jump into another note (currentNote).
|
||||
* A similar concept in C would be __FILE__
|
||||
* Don't mix this up with the concept of active note.
|
||||
*/
|
||||
* Note where the script is currently executing. This comes into play when your script is spread in multiple code
|
||||
* notes, the script starts in "startNote", but then through function calls may jump into another note (currentNote).
|
||||
* A similar concept in C would be __FILE__
|
||||
* Don't mix this up with the concept of active note.
|
||||
*/
|
||||
currentNote: BNote;
|
||||
|
||||
/**
|
||||
* Entity whose event triggered this execution
|
||||
*/
|
||||
* Entity whose event triggered this execution
|
||||
*/
|
||||
originEntity?: AbstractBeccaEntity<any> | null;
|
||||
|
||||
/**
|
||||
* Axios library for HTTP requests. See {@link https://axios-http.com} for documentation
|
||||
* @deprecated use native (browser compatible) fetch() instead
|
||||
*/
|
||||
* Axios library for HTTP requests. See {@link https://axios-http.com} for documentation
|
||||
* @deprecated use native (browser compatible) fetch() instead
|
||||
*/
|
||||
axios: typeof axios;
|
||||
|
||||
/**
|
||||
* day.js library for date manipulation. See {@link https://day.js.org} for documentation
|
||||
*/
|
||||
* day.js library for date manipulation. See {@link https://day.js.org} for documentation
|
||||
*/
|
||||
dayjs: typeof dayjs;
|
||||
|
||||
/**
|
||||
* xml2js library for XML parsing. See {@link https://github.com/Leonidas-from-XIV/node-xml2js} for documentation
|
||||
*/
|
||||
* xml2js library for XML parsing. See {@link https://github.com/Leonidas-from-XIV/node-xml2js} for documentation
|
||||
*/
|
||||
|
||||
xml2js: typeof xml2js;
|
||||
|
||||
/**
|
||||
* cheerio library for HTML parsing and manipulation. See {@link https://cheerio.js.org} for documentation
|
||||
*/
|
||||
* cheerio library for HTML parsing and manipulation. See {@link https://cheerio.js.org} for documentation
|
||||
*/
|
||||
|
||||
cheerio: typeof cheerio;
|
||||
|
||||
/**
|
||||
* Instance name identifies particular Trilium instance. It can be useful for scripts
|
||||
* if some action needs to happen on only one specific instance.
|
||||
*/
|
||||
* Instance name identifies particular Trilium instance. It can be useful for scripts
|
||||
* if some action needs to happen on only one specific instance.
|
||||
*/
|
||||
getInstanceName(): string | null;
|
||||
|
||||
getNote(noteId: string): BNote | null;
|
||||
@ -120,76 +120,76 @@ interface Api {
|
||||
getAttribute(attributeId: string): BAttribute | null;
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "#dateModified =* MONTH AND #log". See {@link https://triliumnext.github.io/Docs/Wiki/search.html} for full documentation for all options
|
||||
*/
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "#dateModified =* MONTH AND #log". See {@link https://triliumnext.github.io/Docs/Wiki/search.html} for full documentation for all options
|
||||
*/
|
||||
searchForNotes(query: string, searchParams: SearchParams): BNote[];
|
||||
|
||||
/**
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "#dateModified =* MONTH AND #log". See {@link https://triliumnext.github.io/Docs/Wiki/search.html} for full documentation for all options
|
||||
*/
|
||||
* This is a powerful search method - you can search by attributes and their values, e.g.:
|
||||
* "#dateModified =* MONTH AND #log". See {@link https://triliumnext.github.io/Docs/Wiki/search.html} for full documentation for all options
|
||||
*/
|
||||
searchForNote(query: string, searchParams: SearchParams): BNote | null;
|
||||
|
||||
/**
|
||||
* Retrieves notes with given label name & value
|
||||
*
|
||||
* @param name - attribute name
|
||||
* @param value - attribute value
|
||||
*/
|
||||
* Retrieves notes with given label name & value
|
||||
*
|
||||
* @param name - attribute name
|
||||
* @param value - attribute value
|
||||
*/
|
||||
getNotesWithLabel(name: string, value?: string): BNote[];
|
||||
|
||||
/**
|
||||
* Retrieves first note with given label name & value
|
||||
*
|
||||
* @param name - attribute name
|
||||
* @param value - attribute value
|
||||
*/
|
||||
* Retrieves first note with given label name & value
|
||||
*
|
||||
* @param name - attribute name
|
||||
* @param value - attribute value
|
||||
*/
|
||||
getNoteWithLabel(name: string, value?: string): BNote | null;
|
||||
|
||||
/**
|
||||
* If there's no branch between note and parent note, create one. Otherwise, do nothing. Returns the new or existing branch.
|
||||
*
|
||||
* @param prefix - if branch is created between note and parent note, set this prefix
|
||||
*/
|
||||
* If there's no branch between note and parent note, create one. Otherwise, do nothing. Returns the new or existing branch.
|
||||
*
|
||||
* @param prefix - if branch is created between note and parent note, set this prefix
|
||||
*/
|
||||
ensureNoteIsPresentInParent(noteId: string, parentNoteId: string, prefix: string): {
|
||||
branch: BBranch | null
|
||||
};
|
||||
|
||||
/**
|
||||
* If there's a branch between note and parent note, remove it. Otherwise, do nothing.
|
||||
*/
|
||||
* If there's a branch between note and parent note, remove it. Otherwise, do nothing.
|
||||
*/
|
||||
ensureNoteIsAbsentFromParent(noteId: string, parentNoteId: string): void;
|
||||
|
||||
/**
|
||||
* Based on the value, either create or remove branch between note and parent note.
|
||||
*
|
||||
* @param present - true if we want the branch to exist, false if we want it gone
|
||||
* @param prefix - if branch is created between note and parent note, set this prefix
|
||||
*/
|
||||
* Based on the value, either create or remove branch between note and parent note.
|
||||
*
|
||||
* @param present - true if we want the branch to exist, false if we want it gone
|
||||
* @param prefix - if branch is created between note and parent note, set this prefix
|
||||
*/
|
||||
toggleNoteInParent(present: true, noteId: string, parentNoteId: string, prefix: string): void;
|
||||
|
||||
/**
|
||||
* Create text note. See also createNewNote() for more options.
|
||||
*/
|
||||
* Create text note. See also createNewNote() for more options.
|
||||
*/
|
||||
createTextNote(parentNoteId: string, title: string, content: string): NoteAndBranch;
|
||||
|
||||
/**
|
||||
* Create data note - data in this context means object serializable to JSON. Created note will be of type 'code' and
|
||||
* JSON MIME type. See also createNewNote() for more options.
|
||||
*/
|
||||
* Create data note - data in this context means object serializable to JSON. Created note will be of type 'code' and
|
||||
* JSON MIME type. See also createNewNote() for more options.
|
||||
*/
|
||||
createDataNote(parentNoteId: string, title: string, content: {}): NoteAndBranch;
|
||||
|
||||
/**
|
||||
* @returns object contains newly created entities note and branch
|
||||
*/
|
||||
* @returns object contains newly created entities note and branch
|
||||
*/
|
||||
createNewNote(params: NoteParams): NoteAndBranch;
|
||||
|
||||
/**
|
||||
* @deprecated please use createTextNote() with similar API for simpler use cases or createNewNote() for more complex needs
|
||||
* @param parentNoteId - create new note under this parent
|
||||
* @returns object contains newly created entities note and branch
|
||||
*/
|
||||
* @deprecated please use createTextNote() with similar API for simpler use cases or createNewNote() for more complex needs
|
||||
* @param parentNoteId - create new note under this parent
|
||||
* @returns object contains newly created entities note and branch
|
||||
*/
|
||||
createNote(parentNoteId: string, title: string, content: string, extraOptions: Omit<NoteParams, "title" | "content" | "type" | "parentNoteId"> & {
|
||||
/** should the note be JSON */
|
||||
json?: boolean;
|
||||
@ -200,37 +200,37 @@ interface Api {
|
||||
logSpacedUpdates: Record<string, SpacedUpdate>;
|
||||
|
||||
/**
|
||||
* Log given message to trilium logs and log pane in UI
|
||||
*/
|
||||
* Log given message to trilium logs and log pane in UI
|
||||
*/
|
||||
log(message: string): void;
|
||||
|
||||
/**
|
||||
* Returns root note of the calendar.
|
||||
*/
|
||||
* Returns root note of the calendar.
|
||||
*/
|
||||
getRootCalendarNote(): BNote | null;
|
||||
|
||||
/**
|
||||
* Returns day note for given date. If such note doesn't exist, it is created.
|
||||
*
|
||||
* @method
|
||||
* @param date in YYYY-MM-DD format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
* Returns day note for given date. If such note doesn't exist, it is created.
|
||||
*
|
||||
* @method
|
||||
* @param date in YYYY-MM-DD format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
getDayNote(date: string, rootNote?: BNote): BNote | null;
|
||||
|
||||
/**
|
||||
* Returns today's day note. If such note doesn't exist, it is created.
|
||||
*
|
||||
* @param rootNote specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
* Returns today's day note. If such note doesn't exist, it is created.
|
||||
*
|
||||
* @param rootNote specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
getTodayNote(rootNote?: BNote): BNote | null;
|
||||
|
||||
/**
|
||||
* Returns note for the first date of the week of the given date.
|
||||
*
|
||||
* @param date in YYYY-MM-DD format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
* Returns note for the first date of the week of the given date.
|
||||
*
|
||||
* @param date in YYYY-MM-DD format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
getWeekNote(date: string, options: {
|
||||
// TODO: Deduplicate type with date_notes.ts once ES modules are added.
|
||||
/** either "monday" (default) or "sunday" */
|
||||
@ -238,90 +238,90 @@ interface Api {
|
||||
}, rootNote: BNote): BNote | null;
|
||||
|
||||
/**
|
||||
* Returns month note for given date. If such a note doesn't exist, it is created.
|
||||
*
|
||||
* @param date in YYYY-MM format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
* Returns month note for given date. If such a note doesn't exist, it is created.
|
||||
*
|
||||
* @param date in YYYY-MM format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
getMonthNote(date: string, rootNote: BNote): BNote | null;
|
||||
|
||||
/**
|
||||
* Returns year note for given year. If such a note doesn't exist, it is created.
|
||||
*
|
||||
* @param year in YYYY format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
* Returns year note for given year. If such a note doesn't exist, it is created.
|
||||
*
|
||||
* @param year in YYYY format
|
||||
* @param rootNote - specify calendar root note, normally leave empty to use the default calendar
|
||||
*/
|
||||
getYearNote(year: string, rootNote?: BNote): BNote | null;
|
||||
|
||||
/**
|
||||
* Sort child notes of a given note.
|
||||
*/
|
||||
* Sort child notes of a given note.
|
||||
*/
|
||||
sortNotes(parentNoteId: string, sortConfig: {
|
||||
/** 'title', 'dateCreated', 'dateModified' or a label name
|
||||
* See {@link https://triliumnext.github.io/Docs/Wiki/sorting.html} for details. */
|
||||
* See {@link https://triliumnext.github.io/Docs/Wiki/sorting.html} for details. */
|
||||
sortBy?: string;
|
||||
reverse?: boolean;
|
||||
foldersFirst?: boolean;
|
||||
}): void;
|
||||
|
||||
/**
|
||||
* This method finds note by its noteId and prefix and either sets it to the given parentNoteId
|
||||
* or removes the branch (if parentNoteId is not given).
|
||||
*
|
||||
* This method looks similar to toggleNoteInParent() but differs because we're looking up branch by prefix.
|
||||
*
|
||||
* @deprecated this method is pretty confusing and serves specialized purpose only
|
||||
*/
|
||||
* This method finds note by its noteId and prefix and either sets it to the given parentNoteId
|
||||
* or removes the branch (if parentNoteId is not given).
|
||||
*
|
||||
* This method looks similar to toggleNoteInParent() but differs because we're looking up branch by prefix.
|
||||
*
|
||||
* @deprecated this method is pretty confusing and serves specialized purpose only
|
||||
*/
|
||||
setNoteToParent(noteId: string, prefix: string, parentNoteId: string | null): void;
|
||||
|
||||
/**
|
||||
* This functions wraps code which is supposed to be running in transaction. If transaction already
|
||||
* exists, then we'll use that transaction.
|
||||
*
|
||||
* @param func
|
||||
* @returns result of func callback
|
||||
*/
|
||||
* This functions wraps code which is supposed to be running in transaction. If transaction already
|
||||
* exists, then we'll use that transaction.
|
||||
*
|
||||
* @param func
|
||||
* @returns result of func callback
|
||||
*/
|
||||
transactional(func: () => void): any;
|
||||
|
||||
/**
|
||||
* Return randomly generated string of given length. This random string generation is NOT cryptographically secure.
|
||||
*
|
||||
* @param length of the string
|
||||
* @returns random string
|
||||
*/
|
||||
* Return randomly generated string of given length. This random string generation is NOT cryptographically secure.
|
||||
*
|
||||
* @param length of the string
|
||||
* @returns random string
|
||||
*/
|
||||
randomString(length: number): string;
|
||||
|
||||
/**
|
||||
* @param to escape
|
||||
* @returns escaped string
|
||||
*/
|
||||
* @param to escape
|
||||
* @returns escaped string
|
||||
*/
|
||||
escapeHtml(string: string): string;
|
||||
|
||||
/**
|
||||
* @param string to unescape
|
||||
* @returns unescaped string
|
||||
*/
|
||||
* @param string to unescape
|
||||
* @returns unescaped string
|
||||
*/
|
||||
unescapeHtml(string: string): string;
|
||||
|
||||
/**
|
||||
* sql
|
||||
* @type {module:sql}
|
||||
*/
|
||||
* sql
|
||||
* @type {module:sql}
|
||||
*/
|
||||
sql: any;
|
||||
|
||||
getAppInfo(): typeof appInfo;
|
||||
|
||||
/**
|
||||
* Creates a new launcher to the launchbar. If the launcher (id) already exists, it will be updated.
|
||||
*/
|
||||
* Creates a new launcher to the launchbar. If the launcher (id) already exists, it will be updated.
|
||||
*/
|
||||
createOrUpdateLauncher(opts: {
|
||||
/** id of the launcher, only alphanumeric at least 6 characters long */
|
||||
id: string;
|
||||
/** one of
|
||||
* - "note" - activating the launcher will navigate to the target note (specified in targetNoteId param)
|
||||
* - "script" - activating the launcher will execute the script (specified in scriptNoteId param)
|
||||
* - "customWidget" - the launcher will be rendered with a custom widget (specified in widgetNoteId param)
|
||||
*/
|
||||
* - "note" - activating the launcher will navigate to the target note (specified in targetNoteId param)
|
||||
* - "script" - activating the launcher will execute the script (specified in scriptNoteId param)
|
||||
* - "customWidget" - the launcher will be rendered with a custom widget (specified in widgetNoteId param)
|
||||
*/
|
||||
type: "note" | "script" | "customWidget";
|
||||
title: string;
|
||||
/** if true, will be created in the "Visible launchers", otherwise in "Available launchers" */
|
||||
@ -339,44 +339,44 @@ interface Api {
|
||||
}): { note: BNote };
|
||||
|
||||
/**
|
||||
* @param format - either 'html' or 'markdown'
|
||||
*/
|
||||
* @param format - either 'html' or 'markdown'
|
||||
*/
|
||||
exportSubtreeToZipFile(noteId: string, format: "markdown" | "html", zipFilePath: string): Promise<void>;
|
||||
|
||||
/**
|
||||
* Executes given anonymous function on the frontend(s).
|
||||
* Internally, this serializes the anonymous function into string and sends it to frontend(s) via WebSocket.
|
||||
* Note that there can be multiple connected frontend instances (e.g. in different tabs). In such case, all
|
||||
* instances execute the given function.
|
||||
*
|
||||
* @param script - script to be executed on the frontend
|
||||
* @param params - list of parameters to the anonymous function to be sent to frontend
|
||||
* @returns no return value is provided.
|
||||
*/
|
||||
* Executes given anonymous function on the frontend(s).
|
||||
* Internally, this serializes the anonymous function into string and sends it to frontend(s) via WebSocket.
|
||||
* Note that there can be multiple connected frontend instances (e.g. in different tabs). In such case, all
|
||||
* instances execute the given function.
|
||||
*
|
||||
* @param script - script to be executed on the frontend
|
||||
* @param params - list of parameters to the anonymous function to be sent to frontend
|
||||
* @returns no return value is provided.
|
||||
*/
|
||||
runOnFrontend(script: () => void | string, params: []): void;
|
||||
|
||||
/**
|
||||
* Sync process can make data intermittently inconsistent. Scripts which require strong data consistency
|
||||
* can use this function to wait for a possible sync process to finish and prevent new sync process from starting
|
||||
* while it is running.
|
||||
*
|
||||
* Because this is an async process, the inner callback doesn't have automatic transaction handling, so in case
|
||||
* you need to make some DB changes, you need to surround your call with api.transactional(...)
|
||||
*
|
||||
* @param callback - function to be executed while sync process is not running
|
||||
* @returns resolves once the callback is finished (callback is awaited)
|
||||
*/
|
||||
* Sync process can make data intermittently inconsistent. Scripts which require strong data consistency
|
||||
* can use this function to wait for a possible sync process to finish and prevent new sync process from starting
|
||||
* while it is running.
|
||||
*
|
||||
* Because this is an async process, the inner callback doesn't have automatic transaction handling, so in case
|
||||
* you need to make some DB changes, you need to surround your call with api.transactional(...)
|
||||
*
|
||||
* @param callback - function to be executed while sync process is not running
|
||||
* @returns resolves once the callback is finished (callback is awaited)
|
||||
*/
|
||||
runOutsideOfSync(callback: () => void): Promise<void>;
|
||||
|
||||
/**
|
||||
* @param backupName - If the backupName is e.g. "now", then the backup will be written to "backup-now.db" file
|
||||
* @returns resolves once the backup is finished
|
||||
*/
|
||||
* @param backupName - If the backupName is e.g. "now", then the backup will be written to "backup-now.db" file
|
||||
* @returns resolves once the backup is finished
|
||||
*/
|
||||
backupNow(backupName: string): Promise<string>;
|
||||
|
||||
/**
|
||||
* This object contains "at your risk" and "no BC guarantees" objects for advanced use cases.
|
||||
*/
|
||||
/**
|
||||
* This object contains "at your risk" and "no BC guarantees" objects for advanced use cases.
|
||||
*/
|
||||
__private: {
|
||||
/** provides access to the backend in-memory object graph, see {@link Becca} */
|
||||
becca: Becca;
|
||||
|
@ -27,8 +27,8 @@ class ConsistencyChecks {
|
||||
private reloadNeeded: boolean;
|
||||
|
||||
/**
|
||||
* @param autoFix - automatically fix all encountered problems. False is only for debugging during development (fail fast)
|
||||
*/
|
||||
* @param autoFix - automatically fix all encountered problems. False is only for debugging during development (fail fast)
|
||||
*/
|
||||
constructor(autoFix: boolean) {
|
||||
this.autoFix = autoFix;
|
||||
this.unrecoveredConsistencyErrors = false;
|
||||
@ -138,9 +138,9 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT branchId, branches.noteId
|
||||
FROM branches
|
||||
LEFT JOIN notes USING (noteId)
|
||||
LEFT JOIN notes USING (noteId)
|
||||
WHERE branches.isDeleted = 0
|
||||
AND notes.noteId IS NULL`,
|
||||
AND notes.noteId IS NULL`,
|
||||
({branchId, noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const branch = becca.getBranch(branchId);
|
||||
@ -160,10 +160,10 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT branchId, branches.parentNoteId AS parentNoteId
|
||||
FROM branches
|
||||
LEFT JOIN notes ON notes.noteId = branches.parentNoteId
|
||||
LEFT JOIN notes ON notes.noteId = branches.parentNoteId
|
||||
WHERE branches.isDeleted = 0
|
||||
AND branches.noteId != 'root'
|
||||
AND notes.noteId IS NULL`,
|
||||
AND branches.noteId != 'root'
|
||||
AND notes.noteId IS NULL`,
|
||||
({branchId, parentNoteId}) => {
|
||||
if (this.autoFix) {
|
||||
// Delete the old branch and recreate it with root as parent.
|
||||
@ -205,9 +205,9 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT attributeId, attributes.noteId
|
||||
FROM attributes
|
||||
LEFT JOIN notes USING (noteId)
|
||||
LEFT JOIN notes USING (noteId)
|
||||
WHERE attributes.isDeleted = 0
|
||||
AND notes.noteId IS NULL`,
|
||||
AND notes.noteId IS NULL`,
|
||||
({attributeId, noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const attribute = becca.getAttribute(attributeId);
|
||||
@ -227,10 +227,10 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT attributeId, attributes.value AS noteId
|
||||
FROM attributes
|
||||
LEFT JOIN notes ON notes.noteId = attributes.value
|
||||
LEFT JOIN notes ON notes.noteId = attributes.value
|
||||
WHERE attributes.isDeleted = 0
|
||||
AND attributes.type = 'relation'
|
||||
AND notes.noteId IS NULL`,
|
||||
AND attributes.type = 'relation'
|
||||
AND notes.noteId IS NULL`,
|
||||
({attributeId, noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const attribute = becca.getAttribute(attributeId);
|
||||
@ -255,7 +255,7 @@ class ConsistencyChecks {
|
||||
UNION ALL
|
||||
SELECT revisionId FROM revisions
|
||||
)
|
||||
AND attachments.isDeleted = 0`,
|
||||
AND attachments.isDeleted = 0`,
|
||||
({attachmentId, ownerId}) => {
|
||||
if (this.autoFix) {
|
||||
const attachment = becca.getAttachment(attachmentId);
|
||||
@ -282,11 +282,11 @@ class ConsistencyChecks {
|
||||
// another check might create missing branch
|
||||
this.findAndFixIssues(`
|
||||
SELECT branchId,
|
||||
noteId
|
||||
noteId
|
||||
FROM branches
|
||||
JOIN notes USING (noteId)
|
||||
JOIN notes USING (noteId)
|
||||
WHERE notes.isDeleted = 1
|
||||
AND branches.isDeleted = 0`,
|
||||
AND branches.isDeleted = 0`,
|
||||
({branchId, noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const branch = becca.getBranch(branchId);
|
||||
@ -303,11 +303,11 @@ class ConsistencyChecks {
|
||||
|
||||
this.findAndFixIssues(`
|
||||
SELECT branchId,
|
||||
parentNoteId
|
||||
parentNoteId
|
||||
FROM branches
|
||||
JOIN notes AS parentNote ON parentNote.noteId = branches.parentNoteId
|
||||
JOIN notes AS parentNote ON parentNote.noteId = branches.parentNoteId
|
||||
WHERE parentNote.isDeleted = 1
|
||||
AND branches.isDeleted = 0
|
||||
AND branches.isDeleted = 0
|
||||
`, ({branchId, parentNoteId}) => {
|
||||
if (this.autoFix) {
|
||||
const branch = becca.getBranch(branchId);
|
||||
@ -327,9 +327,9 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT DISTINCT notes.noteId
|
||||
FROM notes
|
||||
LEFT JOIN branches ON notes.noteId = branches.noteId AND branches.isDeleted = 0
|
||||
LEFT JOIN branches ON notes.noteId = branches.noteId AND branches.isDeleted = 0
|
||||
WHERE notes.isDeleted = 0
|
||||
AND branches.branchId IS NULL
|
||||
AND branches.branchId IS NULL
|
||||
`, ({noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const branch = new BBranch({
|
||||
@ -349,21 +349,21 @@ class ConsistencyChecks {
|
||||
// there should be a unique relationship between note and its parent
|
||||
this.findAndFixIssues(`
|
||||
SELECT noteId,
|
||||
parentNoteId
|
||||
parentNoteId
|
||||
FROM branches
|
||||
WHERE branches.isDeleted = 0
|
||||
GROUP BY branches.parentNoteId,
|
||||
branches.noteId
|
||||
branches.noteId
|
||||
HAVING COUNT(1) > 1`,
|
||||
({noteId, parentNoteId}) => {
|
||||
if (this.autoFix) {
|
||||
const branchIds = sql.getColumn<string>(
|
||||
`SELECT branchId
|
||||
FROM branches
|
||||
WHERE noteId = ?
|
||||
and parentNoteId = ?
|
||||
and isDeleted = 0
|
||||
ORDER BY utcDateModified`, [noteId, parentNoteId]);
|
||||
FROM branches
|
||||
WHERE noteId = ?
|
||||
and parentNoteId = ?
|
||||
and isDeleted = 0
|
||||
ORDER BY utcDateModified`, [noteId, parentNoteId]);
|
||||
|
||||
const branches = branchIds.map(branchId => becca.getBranch(branchId));
|
||||
|
||||
@ -393,11 +393,11 @@ class ConsistencyChecks {
|
||||
|
||||
this.findAndFixIssues(`
|
||||
SELECT attachmentId,
|
||||
attachments.ownerId AS noteId
|
||||
attachments.ownerId AS noteId
|
||||
FROM attachments
|
||||
JOIN notes ON notes.noteId = attachments.ownerId
|
||||
JOIN notes ON notes.noteId = attachments.ownerId
|
||||
WHERE notes.isDeleted = 1
|
||||
AND attachments.isDeleted = 0`,
|
||||
AND attachments.isDeleted = 0`,
|
||||
({attachmentId, noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const attachment = becca.getAttachment(attachmentId);
|
||||
@ -420,7 +420,7 @@ class ConsistencyChecks {
|
||||
SELECT noteId, type
|
||||
FROM notes
|
||||
WHERE isDeleted = 0
|
||||
AND type NOT IN (${noteTypesStr})`,
|
||||
AND type NOT IN (${noteTypesStr})`,
|
||||
({noteId, type}) => {
|
||||
if (this.autoFix) {
|
||||
const note = becca.getNote(noteId);
|
||||
@ -439,7 +439,7 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT notes.noteId, notes.isProtected, notes.type, notes.mime
|
||||
FROM notes
|
||||
LEFT JOIN blobs USING (blobId)
|
||||
LEFT JOIN blobs USING (blobId)
|
||||
WHERE blobs.blobId IS NULL
|
||||
AND notes.isDeleted = 0`,
|
||||
({noteId, isProtected, type, mime}) => {
|
||||
@ -494,10 +494,10 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT notes.noteId, notes.type, notes.mime
|
||||
FROM notes
|
||||
JOIN blobs USING (blobId)
|
||||
JOIN blobs USING (blobId)
|
||||
WHERE isDeleted = 0
|
||||
AND isProtected = 0
|
||||
AND content IS NULL`,
|
||||
AND isProtected = 0
|
||||
AND content IS NULL`,
|
||||
({noteId, type, mime}) => {
|
||||
if (this.autoFix) {
|
||||
const note = becca.getNote(noteId);
|
||||
@ -520,7 +520,7 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT revisions.revisionId, blobs.blobId
|
||||
FROM revisions
|
||||
LEFT JOIN blobs USING (blobId)
|
||||
LEFT JOIN blobs USING (blobId)
|
||||
WHERE blobs.blobId IS NULL`,
|
||||
({revisionId, blobId}) => {
|
||||
if (this.autoFix) {
|
||||
@ -537,7 +537,7 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT attachments.attachmentId, blobs.blobId
|
||||
FROM attachments
|
||||
LEFT JOIN blobs USING (blobId)
|
||||
LEFT JOIN blobs USING (blobId)
|
||||
WHERE blobs.blobId IS NULL`,
|
||||
({attachmentId, blobId}) => {
|
||||
if (this.autoFix) {
|
||||
@ -554,17 +554,17 @@ class ConsistencyChecks {
|
||||
this.findAndFixIssues(`
|
||||
SELECT parentNoteId
|
||||
FROM branches
|
||||
JOIN notes ON notes.noteId = branches.parentNoteId
|
||||
JOIN notes ON notes.noteId = branches.parentNoteId
|
||||
WHERE notes.isDeleted = 0
|
||||
AND notes.type == 'search'
|
||||
AND branches.isDeleted = 0`,
|
||||
AND notes.type == 'search'
|
||||
AND branches.isDeleted = 0`,
|
||||
({parentNoteId}) => {
|
||||
if (this.autoFix) {
|
||||
const branchIds = sql.getColumn<string>(`
|
||||
SELECT branchId
|
||||
FROM branches
|
||||
WHERE isDeleted = 0
|
||||
AND parentNoteId = ?`, [parentNoteId]);
|
||||
AND parentNoteId = ?`, [parentNoteId]);
|
||||
|
||||
const branches = branchIds.map(branchId => becca.getBranch(branchId));
|
||||
|
||||
@ -594,8 +594,8 @@ class ConsistencyChecks {
|
||||
SELECT attributeId
|
||||
FROM attributes
|
||||
WHERE isDeleted = 0
|
||||
AND type = 'relation'
|
||||
AND value = ''`,
|
||||
AND type = 'relation'
|
||||
AND value = ''`,
|
||||
({attributeId}) => {
|
||||
if (this.autoFix) {
|
||||
const relation = becca.getAttribute(attributeId);
|
||||
@ -612,11 +612,11 @@ class ConsistencyChecks {
|
||||
|
||||
this.findAndFixIssues(`
|
||||
SELECT attributeId,
|
||||
type
|
||||
type
|
||||
FROM attributes
|
||||
WHERE isDeleted = 0
|
||||
AND type != 'label'
|
||||
AND type != 'relation'`,
|
||||
AND type != 'label'
|
||||
AND type != 'relation'`,
|
||||
({attributeId, type}) => {
|
||||
if (this.autoFix) {
|
||||
const attribute = becca.getAttribute(attributeId);
|
||||
@ -634,11 +634,11 @@ class ConsistencyChecks {
|
||||
|
||||
this.findAndFixIssues(`
|
||||
SELECT attributeId,
|
||||
attributes.noteId
|
||||
attributes.noteId
|
||||
FROM attributes
|
||||
JOIN notes ON attributes.noteId = notes.noteId
|
||||
WHERE attributes.isDeleted = 0
|
||||
AND notes.isDeleted = 1`,
|
||||
AND notes.isDeleted = 1`,
|
||||
({attributeId, noteId}) => {
|
||||
if (this.autoFix) {
|
||||
const attribute = becca.getAttribute(attributeId);
|
||||
@ -655,12 +655,12 @@ class ConsistencyChecks {
|
||||
|
||||
this.findAndFixIssues(`
|
||||
SELECT attributeId,
|
||||
attributes.value AS targetNoteId
|
||||
attributes.value AS targetNoteId
|
||||
FROM attributes
|
||||
JOIN notes ON attributes.value = notes.noteId
|
||||
WHERE attributes.type = 'relation'
|
||||
AND attributes.isDeleted = 0
|
||||
AND notes.isDeleted = 1`,
|
||||
AND attributes.isDeleted = 0
|
||||
AND notes.isDeleted = 1`,
|
||||
({attributeId, targetNoteId}) => {
|
||||
if (this.autoFix) {
|
||||
const attribute = becca.getAttribute(attributeId);
|
||||
@ -706,9 +706,9 @@ class ConsistencyChecks {
|
||||
FROM entity_changes
|
||||
LEFT JOIN ${entityName} ON entityId = ${entityName}.${key}
|
||||
WHERE
|
||||
entity_changes.isErased = 0
|
||||
AND entity_changes.entityName = '${entityName}'
|
||||
AND ${entityName}.${key} IS NULL`,
|
||||
entity_changes.isErased = 0
|
||||
AND entity_changes.entityName = '${entityName}'
|
||||
AND ${entityName}.${key} IS NULL`,
|
||||
({id, entityId}) => {
|
||||
if (this.autoFix) {
|
||||
sql.execute("DELETE FROM entity_changes WHERE entityName = ? AND entityId = ?", [entityName, entityId]);
|
||||
@ -724,8 +724,8 @@ class ConsistencyChecks {
|
||||
FROM entity_changes
|
||||
JOIN ${entityName} ON entityId = ${entityName}.${key}
|
||||
WHERE
|
||||
entity_changes.isErased = 1
|
||||
AND entity_changes.entityName = '${entityName}'`,
|
||||
entity_changes.isErased = 1
|
||||
AND entity_changes.entityName = '${entityName}'`,
|
||||
({id, entityId}) => {
|
||||
if (this.autoFix) {
|
||||
sql.execute(`DELETE FROM ${entityName} WHERE ${key} = ?`, [entityId]);
|
||||
|
@ -18,12 +18,12 @@ function getEntityHashes() {
|
||||
const hashRows = sql.disableSlowQueryLogging(
|
||||
() => sql.getRawRows<HashRow>(`
|
||||
SELECT entityName,
|
||||
entityId,
|
||||
hash,
|
||||
isErased
|
||||
entityId,
|
||||
hash,
|
||||
isErased
|
||||
FROM entity_changes
|
||||
WHERE isSynced = 1
|
||||
AND entityName != 'note_reordering'`)
|
||||
AND entityName != 'note_reordering'`)
|
||||
);
|
||||
|
||||
// sorting is faster in memory
|
||||
|
@ -39,9 +39,9 @@ function putEntityChange(origEntityChange: EntityChange) {
|
||||
ec.isErased = ec.isErased ? 1 : 0;
|
||||
ec.id = sql.replace("entity_changes", ec);
|
||||
|
||||
if (ec.id) {
|
||||
maxEntityChangeId = Math.max(maxEntityChangeId, ec.id);
|
||||
}
|
||||
if (ec.id) {
|
||||
maxEntityChangeId = Math.max(maxEntityChangeId, ec.id);
|
||||
}
|
||||
|
||||
cls.putEntityChange(ec);
|
||||
}
|
||||
@ -110,9 +110,9 @@ function addEntityChangesForDependingEntity(sector: string, tableName: string, p
|
||||
|
||||
function cleanupEntityChangesForMissingEntities(entityName: string, entityPrimaryKey: string) {
|
||||
sql.execute(`
|
||||
DELETE
|
||||
FROM entity_changes
|
||||
WHERE
|
||||
DELETE
|
||||
FROM entity_changes
|
||||
WHERE
|
||||
isErased = 0
|
||||
AND entityName = '${entityName}'
|
||||
AND entityId NOT IN (SELECT ${entityPrimaryKey} FROM ${entityName})`);
|
||||
|
@ -1,27 +1,27 @@
|
||||
export interface EntityChange {
|
||||
id?: number | null;
|
||||
noteId?: string;
|
||||
entityName: string;
|
||||
entityId: string;
|
||||
entity?: any;
|
||||
positions?: Record<string, number>;
|
||||
hash: string;
|
||||
utcDateChanged?: string;
|
||||
utcDateModified?: string;
|
||||
utcDateCreated?: string;
|
||||
isSynced: boolean | 1 | 0;
|
||||
isErased: boolean | 1 | 0;
|
||||
componentId?: string | null;
|
||||
changeId?: string | null;
|
||||
instanceId?: string | null;
|
||||
id?: number | null;
|
||||
noteId?: string;
|
||||
entityName: string;
|
||||
entityId: string;
|
||||
entity?: any;
|
||||
positions?: Record<string, number>;
|
||||
hash: string;
|
||||
utcDateChanged?: string;
|
||||
utcDateModified?: string;
|
||||
utcDateCreated?: string;
|
||||
isSynced: boolean | 1 | 0;
|
||||
isErased: boolean | 1 | 0;
|
||||
componentId?: string | null;
|
||||
changeId?: string | null;
|
||||
instanceId?: string | null;
|
||||
}
|
||||
|
||||
export interface EntityRow {
|
||||
isDeleted?: boolean;
|
||||
content?: Buffer | string;
|
||||
isDeleted?: boolean;
|
||||
content?: Buffer | string;
|
||||
}
|
||||
|
||||
export interface EntityChangeRecord {
|
||||
entityChange: EntityChange;
|
||||
entity?: EntityRow;
|
||||
entityChange: EntityChange;
|
||||
entity?: EntityRow;
|
||||
}
|
||||
|
@ -101,8 +101,8 @@ function eraseUnusedBlobs() {
|
||||
LEFT JOIN attachments ON attachments.blobId = blobs.blobId
|
||||
LEFT JOIN revisions ON revisions.blobId = blobs.blobId
|
||||
WHERE notes.noteId IS NULL
|
||||
AND attachments.attachmentId IS NULL
|
||||
AND revisions.revisionId IS NULL`);
|
||||
AND attachments.attachmentId IS NULL
|
||||
AND revisions.revisionId IS NULL`);
|
||||
|
||||
if (unusedBlobIds.length === 0) {
|
||||
return;
|
||||
|
@ -8,25 +8,25 @@ let instance: TurndownService | null = null;
|
||||
const fencedCodeBlockFilter: TurndownService.Rule = {
|
||||
filter: function (node, options) {
|
||||
return (
|
||||
options.codeBlockStyle === 'fenced' &&
|
||||
node.nodeName === 'PRE' &&
|
||||
node.firstChild !== null &&
|
||||
node.firstChild.nodeName === 'CODE'
|
||||
options.codeBlockStyle === 'fenced' &&
|
||||
node.nodeName === 'PRE' &&
|
||||
node.firstChild !== null &&
|
||||
node.firstChild.nodeName === 'CODE'
|
||||
)
|
||||
},
|
||||
|
||||
replacement: function (content, node, options) {
|
||||
if (!node.firstChild || !("getAttribute" in node.firstChild) || typeof node.firstChild.getAttribute !== "function") {
|
||||
return content;
|
||||
return content;
|
||||
}
|
||||
|
||||
const className = node.firstChild.getAttribute('class') || ''
|
||||
const language = rewriteLanguageTag((className.match(/language-(\S+)/) || [null, ''])[1]);
|
||||
|
||||
return (
|
||||
'\n\n' + options.fence + language + '\n' +
|
||||
node.firstChild.textContent +
|
||||
'\n' + options.fence + '\n\n'
|
||||
'\n\n' + options.fence + language + '\n' +
|
||||
node.firstChild.textContent +
|
||||
'\n' + options.fence + '\n\n'
|
||||
)
|
||||
}
|
||||
};
|
||||
@ -44,7 +44,7 @@ function toMarkdown(content: string) {
|
||||
|
||||
function rewriteLanguageTag(source: string) {
|
||||
if (!source) {
|
||||
return source;
|
||||
return source;
|
||||
}
|
||||
|
||||
if (source === "text-x-trilium-auto") {
|
||||
|
@ -324,9 +324,9 @@ async function exportToZip(taskContext: TaskContext, branch: BBranch, format: "h
|
||||
</head>
|
||||
<body>
|
||||
<div class="content">
|
||||
<h1 data-trilium-h1>${htmlTitle}</h1>
|
||||
<h1 data-trilium-h1>${htmlTitle}</h1>
|
||||
|
||||
<div class="ck-content">${content}</div>
|
||||
<div class="ck-content">${content}</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>`;
|
||||
|
@ -11,12 +11,12 @@ export async function initializeTranslations() {
|
||||
|
||||
// Initialize translations
|
||||
await i18next.use(Backend).init({
|
||||
lng: getCurrentLanguage(),
|
||||
fallbackLng: "en",
|
||||
ns: "server",
|
||||
backend: {
|
||||
loadPath: join(resourceDir, "translations/{{lng}}/{{ns}}.json")
|
||||
}
|
||||
lng: getCurrentLanguage(),
|
||||
fallbackLng: "en",
|
||||
ns: "server",
|
||||
backend: {
|
||||
loadPath: join(resourceDir, "translations/{{lng}}/{{ns}}.json")
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -601,8 +601,8 @@ function getDefaultKeyboardActions() {
|
||||
];
|
||||
|
||||
/*
|
||||
* Apply macOS-specific tweaks.
|
||||
*/
|
||||
* Apply macOS-specific tweaks.
|
||||
*/
|
||||
const platformModifier = isMac ? 'Meta' : 'Ctrl';
|
||||
|
||||
for (const action of DEFAULT_KEYBOARD_ACTIONS) {
|
||||
|
@ -5,13 +5,13 @@ export interface KeyboardShortcut {
|
||||
defaultShortcuts?: string[];
|
||||
effectiveShortcuts?: string[];
|
||||
/**
|
||||
* Scope here means on which element the keyboard shortcuts are attached - this means that for the shortcut to work,
|
||||
* the focus has to be inside the element.
|
||||
*
|
||||
* So e.g. shortcuts with "note-tree" scope work only when the focus is in note tree.
|
||||
* This allows to have the same shortcut have different actions attached based on the context
|
||||
* e.g. CTRL-C in note tree does something a bit different from CTRL-C in the text editor.
|
||||
*/
|
||||
* Scope here means on which element the keyboard shortcuts are attached - this means that for the shortcut to work,
|
||||
* the focus has to be inside the element.
|
||||
*
|
||||
* So e.g. shortcuts with "note-tree" scope work only when the focus is in note tree.
|
||||
* This allows to have the same shortcut have different actions attached based on the context
|
||||
* e.g. CTRL-C in note tree does something a bit different from CTRL-C in the text editor.
|
||||
*/
|
||||
scope?: "window" | "note-tree" | "text-detail" | "code-detail";
|
||||
}
|
||||
|
||||
|
@ -75,8 +75,8 @@ async function migrate() {
|
||||
await executeMigration(mig);
|
||||
|
||||
sql.execute(`UPDATE options
|
||||
SET value = ?
|
||||
WHERE name = ?`, [mig.dbVersion.toString(), "dbVersion"]);
|
||||
SET value = ?
|
||||
WHERE name = ?`, [mig.dbVersion.toString(), "dbVersion"]);
|
||||
|
||||
log.info(`Migration to version ${mig.dbVersion} has been successful.`);
|
||||
} catch (e: any) {
|
||||
|
@ -812,9 +812,9 @@ function undeleteBranch(branchId: string, deleteId: string, taskContext: TaskCon
|
||||
const attributeRows = sql.getRows<AttributeRow>(`
|
||||
SELECT * FROM attributes
|
||||
WHERE isDeleted = 1
|
||||
AND deleteId = ?
|
||||
AND (noteId = ?
|
||||
OR (type = 'relation' AND value = ?))`, [deleteId, noteRow.noteId, noteRow.noteId]);
|
||||
AND deleteId = ?
|
||||
AND (noteId = ?
|
||||
OR (type = 'relation' AND value = ?))`, [deleteId, noteRow.noteId, noteRow.noteId]);
|
||||
|
||||
for (const attributeRow of attributeRows) {
|
||||
// relation might point to a note which hasn't been undeleted yet and would thus throw up
|
||||
@ -824,8 +824,8 @@ function undeleteBranch(branchId: string, deleteId: string, taskContext: TaskCon
|
||||
const attachmentRows = sql.getRows<AttachmentRow>(`
|
||||
SELECT * FROM attachments
|
||||
WHERE isDeleted = 1
|
||||
AND deleteId = ?
|
||||
AND ownerId = ?`, [deleteId, noteRow.noteId]);
|
||||
AND deleteId = ?
|
||||
AND ownerId = ?`, [deleteId, noteRow.noteId]);
|
||||
|
||||
for (const attachmentRow of attachmentRows) {
|
||||
new BAttachment(attachmentRow).save();
|
||||
@ -835,8 +835,8 @@ function undeleteBranch(branchId: string, deleteId: string, taskContext: TaskCon
|
||||
SELECT branches.branchId
|
||||
FROM branches
|
||||
WHERE branches.isDeleted = 1
|
||||
AND branches.deleteId = ?
|
||||
AND branches.parentNoteId = ?`, [deleteId, noteRow.noteId]);
|
||||
AND branches.deleteId = ?
|
||||
AND branches.parentNoteId = ?`, [deleteId, noteRow.noteId]);
|
||||
|
||||
for (const childBranchId of childBranchIds) {
|
||||
undeleteBranch(childBranchId, deleteId, taskContext);
|
||||
@ -853,9 +853,9 @@ function getUndeletedParentBranchIds(noteId: string, deleteId: string) {
|
||||
FROM branches
|
||||
JOIN notes AS parentNote ON parentNote.noteId = branches.parentNoteId
|
||||
WHERE branches.noteId = ?
|
||||
AND branches.isDeleted = 1
|
||||
AND branches.deleteId = ?
|
||||
AND parentNote.isDeleted = 0`, [noteId, deleteId]);
|
||||
AND branches.isDeleted = 1
|
||||
AND branches.deleteId = ?
|
||||
AND parentNote.isDeleted = 0`, [noteId, deleteId]);
|
||||
}
|
||||
|
||||
function scanForLinks(note: BNote, content: string | Buffer) {
|
||||
|
@ -26,10 +26,10 @@ interface NotSyncedOpts {
|
||||
interface DefaultOption {
|
||||
name: string;
|
||||
/**
|
||||
* The value to initialize the option with, if the option is not already present in the database.
|
||||
*
|
||||
* If a function is passed in instead, the function is called if the option does not exist (with access to the current options) and the return value is used instead. Useful to migrate a new option with a value depending on some other option that might be initialized.
|
||||
*/
|
||||
* The value to initialize the option with, if the option is not already present in the database.
|
||||
*
|
||||
* If a function is passed in instead, the function is called if the option does not exist (with access to the current options) and the return value is used instead. Useful to migrate a new option with a value depending on some other option that might be initialized.
|
||||
*/
|
||||
value: string | ((options: OptionMap) => string);
|
||||
isSynced: boolean;
|
||||
}
|
||||
|
@ -96,7 +96,7 @@ function upsert<T extends {}>(tableName: string, primaryKey: string, rec: T) {
|
||||
const updateMarks = keys.map(colName => `${colName} = @${colName}`).join(", ");
|
||||
|
||||
const query = `INSERT INTO ${tableName} (${columns}) VALUES (${questionMarks})
|
||||
ON CONFLICT (${primaryKey}) DO UPDATE SET ${updateMarks}`;
|
||||
ON CONFLICT (${primaryKey}) DO UPDATE SET ${updateMarks}`;
|
||||
|
||||
for (const idx in rec) {
|
||||
if (rec[idx] === true || rec[idx] === false) {
|
||||
@ -345,60 +345,60 @@ export default {
|
||||
replace,
|
||||
|
||||
/**
|
||||
* Get single value from the given query - first column from first returned row.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns single value
|
||||
*/
|
||||
* Get single value from the given query - first column from first returned row.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns single value
|
||||
*/
|
||||
getValue,
|
||||
|
||||
/**
|
||||
* Get first returned row.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns - map of column name to column value
|
||||
*/
|
||||
* Get first returned row.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns - map of column name to column value
|
||||
*/
|
||||
getRow,
|
||||
getRowOrNull,
|
||||
|
||||
/**
|
||||
* Get all returned rows.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns - array of all rows, each row is a map of column name to column value
|
||||
*/
|
||||
* Get all returned rows.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns - array of all rows, each row is a map of column name to column value
|
||||
*/
|
||||
getRows,
|
||||
getRawRows,
|
||||
iterateRows,
|
||||
getManyRows,
|
||||
|
||||
/**
|
||||
* Get a map of first column mapping to second column.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns - map of first column to second column
|
||||
*/
|
||||
* Get a map of first column mapping to second column.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns - map of first column to second column
|
||||
*/
|
||||
getMap,
|
||||
|
||||
/**
|
||||
* Get a first column in an array.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns array of first column of all returned rows
|
||||
*/
|
||||
* Get a first column in an array.
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
* @returns array of first column of all returned rows
|
||||
*/
|
||||
getColumn,
|
||||
|
||||
/**
|
||||
* Execute SQL
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
*/
|
||||
* Execute SQL
|
||||
*
|
||||
* @param query - SQL query with ? used as parameter placeholder
|
||||
* @param params - array of params if needed
|
||||
*/
|
||||
execute,
|
||||
executeMany,
|
||||
executeScript,
|
||||
|
@ -22,7 +22,7 @@ const dbReady = utils.deferred<void>();
|
||||
|
||||
function schemaExists() {
|
||||
return !!sql.getValue(`SELECT name FROM sqlite_master
|
||||
WHERE type = 'table' AND name = 'options'`);
|
||||
WHERE type = 'table' AND name = 'options'`);
|
||||
}
|
||||
|
||||
function isDbInitialized() {
|
||||
|
@ -272,14 +272,14 @@ function timeLimit<T>(promise: Promise<T>, limitMs: number, errorMessage?: strin
|
||||
}
|
||||
|
||||
interface DeferredPromise<T> extends Promise<T> {
|
||||
resolve: (value: T | PromiseLike<T>) => void,
|
||||
reject: (reason?: any) => void
|
||||
resolve: (value: T | PromiseLike<T>) => void,
|
||||
reject: (reason?: any) => void
|
||||
}
|
||||
|
||||
function deferred<T>(): DeferredPromise<T> {
|
||||
return (() => {
|
||||
let resolve!: (value: T | PromiseLike<T>) => void;
|
||||
let reject!: (reason?: any) => void;
|
||||
let reject!: (reason?: any) => void;
|
||||
|
||||
let promise = new Promise<T>((res, rej) => {
|
||||
resolve = res;
|
||||
|
Loading…
x
Reference in New Issue
Block a user