mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 10:02:59 +08:00
Revert "Merge pull request #1234 from TriliumNext/feature/task_list"
This reverts commit 58a8821c229898c45551da16476d44c010c345ef, reversing changes made to 50d491b432ce811c4d5e597e952eb18a89ae6c19.
This commit is contained in:
parent
ee7b97ae56
commit
00e576b052
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@ -5,8 +5,8 @@
|
|||||||
{
|
{
|
||||||
"console": "integratedTerminal",
|
"console": "integratedTerminal",
|
||||||
"internalConsoleOptions": "neverOpen",
|
"internalConsoleOptions": "neverOpen",
|
||||||
"name": "nodemon server:start",
|
"name": "nodemon start-server",
|
||||||
"program": "${workspaceFolder}/src/main",
|
"program": "${workspaceFolder}/src/www",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"restart": true,
|
"restart": true,
|
||||||
"runtimeExecutable": "nodemon",
|
"runtimeExecutable": "nodemon",
|
||||||
|
@ -132,14 +132,3 @@ CREATE INDEX IDX_attachments_ownerId_role
|
|||||||
CREATE INDEX IDX_notes_blobId on notes (blobId);
|
CREATE INDEX IDX_notes_blobId on notes (blobId);
|
||||||
CREATE INDEX IDX_revisions_blobId on revisions (blobId);
|
CREATE INDEX IDX_revisions_blobId on revisions (blobId);
|
||||||
CREATE INDEX IDX_attachments_blobId on attachments (blobId);
|
CREATE INDEX IDX_attachments_blobId on attachments (blobId);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS "tasks"
|
|
||||||
(
|
|
||||||
"taskId" TEXT NOT NULL PRIMARY KEY,
|
|
||||||
"parentNoteId" TEXT NOT NULL,
|
|
||||||
"title" TEXT NOT NULL DEFAULT "",
|
|
||||||
"dueDate" INTEGER,
|
|
||||||
"isDone" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"isDeleted" INTEGER NOT NULL DEFAULT 0,
|
|
||||||
"utcDateModified" TEXT NOT NULL
|
|
||||||
);
|
|
@ -12,7 +12,6 @@ import type { AttachmentRow, BlobRow, RevisionRow } from "./entities/rows.js";
|
|||||||
import BBlob from "./entities/bblob.js";
|
import BBlob from "./entities/bblob.js";
|
||||||
import BRecentNote from "./entities/brecent_note.js";
|
import BRecentNote from "./entities/brecent_note.js";
|
||||||
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
||||||
import type BTask from "./entities/btask.js";
|
|
||||||
|
|
||||||
interface AttachmentOpts {
|
interface AttachmentOpts {
|
||||||
includeContentLength?: boolean;
|
includeContentLength?: boolean;
|
||||||
@ -33,7 +32,6 @@ export default class Becca {
|
|||||||
attributeIndex!: Record<string, BAttribute[]>;
|
attributeIndex!: Record<string, BAttribute[]>;
|
||||||
options!: Record<string, BOption>;
|
options!: Record<string, BOption>;
|
||||||
etapiTokens!: Record<string, BEtapiToken>;
|
etapiTokens!: Record<string, BEtapiToken>;
|
||||||
tasks!: Record<string, BTask>;
|
|
||||||
|
|
||||||
allNoteSetCache: NoteSet | null;
|
allNoteSetCache: NoteSet | null;
|
||||||
|
|
||||||
@ -50,7 +48,6 @@ export default class Becca {
|
|||||||
this.attributeIndex = {};
|
this.attributeIndex = {};
|
||||||
this.options = {};
|
this.options = {};
|
||||||
this.etapiTokens = {};
|
this.etapiTokens = {};
|
||||||
this.tasks = {};
|
|
||||||
|
|
||||||
this.dirtyNoteSetCache();
|
this.dirtyNoteSetCache();
|
||||||
|
|
||||||
@ -216,14 +213,6 @@ export default class Becca {
|
|||||||
return this.etapiTokens[etapiTokenId];
|
return this.etapiTokens[etapiTokenId];
|
||||||
}
|
}
|
||||||
|
|
||||||
getTasks(): BTask[] {
|
|
||||||
return Object.values(this.tasks);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTask(taskId: string): BTask | null {
|
|
||||||
return this.tasks[taskId];
|
|
||||||
}
|
|
||||||
|
|
||||||
getEntity<T extends AbstractBeccaEntity<T>>(entityName: string, entityId: string): AbstractBeccaEntity<T> | null {
|
getEntity<T extends AbstractBeccaEntity<T>>(entityName: string, entityId: string): AbstractBeccaEntity<T> | null {
|
||||||
if (!entityName || !entityId) {
|
if (!entityName || !entityId) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -11,10 +11,9 @@ import BOption from "./entities/boption.js";
|
|||||||
import BEtapiToken from "./entities/betapi_token.js";
|
import BEtapiToken from "./entities/betapi_token.js";
|
||||||
import cls from "../services/cls.js";
|
import cls from "../services/cls.js";
|
||||||
import entityConstructor from "../becca/entity_constructor.js";
|
import entityConstructor from "../becca/entity_constructor.js";
|
||||||
import type { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow, TaskRow } from "./entities/rows.js";
|
import type { AttributeRow, BranchRow, EtapiTokenRow, NoteRow, OptionRow } from "./entities/rows.js";
|
||||||
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
import type AbstractBeccaEntity from "./entities/abstract_becca_entity.js";
|
||||||
import ws from "../services/ws.js";
|
import ws from "../services/ws.js";
|
||||||
import BTask from "./entities/btask.js";
|
|
||||||
|
|
||||||
const beccaLoaded = new Promise<void>(async (res, rej) => {
|
const beccaLoaded = new Promise<void>(async (res, rej) => {
|
||||||
const sqlInit = (await import("../services/sql_init.js")).default;
|
const sqlInit = (await import("../services/sql_init.js")).default;
|
||||||
@ -64,17 +63,6 @@ function load() {
|
|||||||
for (const row of sql.getRows<EtapiTokenRow>(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) {
|
for (const row of sql.getRows<EtapiTokenRow>(`SELECT etapiTokenId, name, tokenHash, utcDateCreated, utcDateModified FROM etapi_tokens WHERE isDeleted = 0`)) {
|
||||||
new BEtapiToken(row);
|
new BEtapiToken(row);
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
for (const row of sql.getRows<TaskRow>(`SELECT taskId, parentNoteId, title, dueDate, isDone, isDeleted FROM tasks WHERE isDeleted = 0`)) {
|
|
||||||
new BTask(row);
|
|
||||||
}
|
|
||||||
} catch (e: any) {
|
|
||||||
// Some older migrations trigger becca which would fail since the "tasks" table is not yet defined (didn't reach the right migration).
|
|
||||||
if (!(e.message.includes("no such table"))) {
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const noteId in becca.notes) {
|
for (const noteId in becca.notes) {
|
||||||
|
@ -1,84 +0,0 @@
|
|||||||
import date_utils from "../../services/date_utils.js";
|
|
||||||
import AbstractBeccaEntity from "./abstract_becca_entity.js";
|
|
||||||
import type BOption from "./boption.js";
|
|
||||||
import type { TaskRow } from "./rows.js";
|
|
||||||
|
|
||||||
export default class BTask extends AbstractBeccaEntity<BOption> {
|
|
||||||
|
|
||||||
static get entityName() {
|
|
||||||
return "tasks";
|
|
||||||
}
|
|
||||||
|
|
||||||
static get primaryKeyName() {
|
|
||||||
return "taskId";
|
|
||||||
}
|
|
||||||
|
|
||||||
static get hashedProperties() {
|
|
||||||
return ["taskId", "parentNoteId", "title", "dueDate", "isDone", "isDeleted"];
|
|
||||||
}
|
|
||||||
|
|
||||||
taskId?: string;
|
|
||||||
parentNoteId!: string;
|
|
||||||
title!: string;
|
|
||||||
dueDate?: string;
|
|
||||||
isDone!: boolean;
|
|
||||||
private _isDeleted?: boolean;
|
|
||||||
|
|
||||||
constructor(row?: TaskRow) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (!row) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.updateFromRow(row);
|
|
||||||
this.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
get isDeleted() {
|
|
||||||
return !!this._isDeleted;
|
|
||||||
}
|
|
||||||
|
|
||||||
updateFromRow(row: TaskRow) {
|
|
||||||
this.taskId = row.taskId;
|
|
||||||
this.parentNoteId = row.parentNoteId;
|
|
||||||
this.title = row.title;
|
|
||||||
this.dueDate = row.dueDate;
|
|
||||||
this.isDone = !!row.isDone;
|
|
||||||
this._isDeleted = !!row.isDeleted;
|
|
||||||
this.utcDateModified = row.utcDateModified;
|
|
||||||
|
|
||||||
if (this.taskId) {
|
|
||||||
this.becca.tasks[this.taskId] = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
init() {
|
|
||||||
if (this.taskId) {
|
|
||||||
this.becca.tasks[this.taskId] = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected beforeSaving(opts?: {}): void {
|
|
||||||
super.beforeSaving();
|
|
||||||
|
|
||||||
this.utcDateModified = date_utils.utcNowDateTime();
|
|
||||||
|
|
||||||
if (this.taskId) {
|
|
||||||
this.becca.tasks[this.taskId] = this;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getPojo() {
|
|
||||||
return {
|
|
||||||
taskId: this.taskId,
|
|
||||||
parentNoteId: this.parentNoteId,
|
|
||||||
title: this.title,
|
|
||||||
dueDate: this.dueDate,
|
|
||||||
isDone: this.isDone,
|
|
||||||
isDeleted: this.isDeleted,
|
|
||||||
utcDateModified: this.utcDateModified
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -139,13 +139,3 @@ export interface NoteRow {
|
|||||||
utcDateModified: string;
|
utcDateModified: string;
|
||||||
content?: string | Buffer;
|
content?: string | Buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TaskRow {
|
|
||||||
taskId?: string;
|
|
||||||
parentNoteId: string;
|
|
||||||
title: string;
|
|
||||||
dueDate?: string;
|
|
||||||
isDone?: boolean;
|
|
||||||
isDeleted?: boolean;
|
|
||||||
utcDateModified?: string;
|
|
||||||
}
|
|
||||||
|
@ -9,7 +9,6 @@ import BNote from "./entities/bnote.js";
|
|||||||
import BOption from "./entities/boption.js";
|
import BOption from "./entities/boption.js";
|
||||||
import BRecentNote from "./entities/brecent_note.js";
|
import BRecentNote from "./entities/brecent_note.js";
|
||||||
import BRevision from "./entities/brevision.js";
|
import BRevision from "./entities/brevision.js";
|
||||||
import BTask from "./entities/btask.js";
|
|
||||||
|
|
||||||
type EntityClass = new (row?: any) => AbstractBeccaEntity<any>;
|
type EntityClass = new (row?: any) => AbstractBeccaEntity<any>;
|
||||||
|
|
||||||
@ -22,8 +21,7 @@ const ENTITY_NAME_TO_ENTITY: Record<string, ConstructorData<any> & EntityClass>
|
|||||||
notes: BNote,
|
notes: BNote,
|
||||||
options: BOption,
|
options: BOption,
|
||||||
recent_notes: BRecentNote,
|
recent_notes: BRecentNote,
|
||||||
revisions: BRevision,
|
revisions: BRevision
|
||||||
tasks: BTask
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) {
|
function getEntityFromEntityName(entityName: keyof typeof ENTITY_NAME_TO_ENTITY) {
|
||||||
|
@ -28,8 +28,7 @@ const NOTE_TYPE_ICONS = {
|
|||||||
doc: "bx bxs-file-doc",
|
doc: "bx bxs-file-doc",
|
||||||
contentWidget: "bx bxs-widget",
|
contentWidget: "bx bxs-widget",
|
||||||
mindMap: "bx bx-sitemap",
|
mindMap: "bx bx-sitemap",
|
||||||
geoMap: "bx bx-map-alt",
|
geoMap: "bx bx-map-alt"
|
||||||
taskList: "bx bx-list-check"
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -37,25 +36,7 @@ const NOTE_TYPE_ICONS = {
|
|||||||
* end user. Those types should be used only for checking against, they are
|
* end user. Those types should be used only for checking against, they are
|
||||||
* not for direct use.
|
* not for direct use.
|
||||||
*/
|
*/
|
||||||
export type NoteType =
|
export type NoteType = "file" | "image" | "search" | "noteMap" | "launcher" | "doc" | "contentWidget" | "text" | "relationMap" | "render" | "canvas" | "mermaid" | "book" | "webView" | "code" | "mindMap" | "geoMap";
|
||||||
| "file"
|
|
||||||
| "image"
|
|
||||||
| "search"
|
|
||||||
| "noteMap"
|
|
||||||
| "launcher"
|
|
||||||
| "doc"
|
|
||||||
| "contentWidget"
|
|
||||||
| "text"
|
|
||||||
| "relationMap"
|
|
||||||
| "render"
|
|
||||||
| "canvas"
|
|
||||||
| "mermaid"
|
|
||||||
| "book"
|
|
||||||
| "webView"
|
|
||||||
| "code"
|
|
||||||
| "mindMap"
|
|
||||||
| "geoMap"
|
|
||||||
| "taskList";
|
|
||||||
|
|
||||||
export interface NotePathRecord {
|
export interface NotePathRecord {
|
||||||
isArchived: boolean;
|
isArchived: boolean;
|
||||||
|
@ -1,34 +0,0 @@
|
|||||||
import type { Froca } from "../services/froca-interface.js";
|
|
||||||
|
|
||||||
export interface FTaskRow {
|
|
||||||
taskId: string;
|
|
||||||
parentNoteId: string;
|
|
||||||
title: string;
|
|
||||||
dueDate?: string;
|
|
||||||
isDone?: boolean;
|
|
||||||
utcDateModified: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class FTask {
|
|
||||||
private froca: Froca;
|
|
||||||
taskId!: string;
|
|
||||||
parentNoteId!: string;
|
|
||||||
title!: string;
|
|
||||||
dueDate?: string;
|
|
||||||
isDone!: boolean;
|
|
||||||
utcDateModified!: string;
|
|
||||||
|
|
||||||
constructor(froca: Froca, row: FTaskRow) {
|
|
||||||
this.froca = froca;
|
|
||||||
this.update(row);
|
|
||||||
}
|
|
||||||
|
|
||||||
update(row: FTaskRow) {
|
|
||||||
this.taskId = row.taskId;
|
|
||||||
this.parentNoteId = row.parentNoteId;
|
|
||||||
this.title = row.title;
|
|
||||||
this.dueDate = row.dueDate;
|
|
||||||
this.isDone = !!row.isDone;
|
|
||||||
this.utcDateModified = row.utcDateModified;
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,8 +6,6 @@ import appContext from "../components/app_context.js";
|
|||||||
import FBlob, { type FBlobRow } from "../entities/fblob.js";
|
import FBlob, { type FBlobRow } from "../entities/fblob.js";
|
||||||
import FAttachment, { type FAttachmentRow } from "../entities/fattachment.js";
|
import FAttachment, { type FAttachmentRow } from "../entities/fattachment.js";
|
||||||
import type { Froca } from "./froca-interface.js";
|
import type { Froca } from "./froca-interface.js";
|
||||||
import FTask from "../entities/ftask.js";
|
|
||||||
import type { FTaskRow } from "../entities/ftask.js";
|
|
||||||
|
|
||||||
interface SubtreeResponse {
|
interface SubtreeResponse {
|
||||||
notes: FNoteRow[];
|
notes: FNoteRow[];
|
||||||
@ -39,7 +37,6 @@ class FrocaImpl implements Froca {
|
|||||||
attributes!: Record<string, FAttribute>;
|
attributes!: Record<string, FAttribute>;
|
||||||
attachments!: Record<string, FAttachment>;
|
attachments!: Record<string, FAttachment>;
|
||||||
blobPromises!: Record<string, Promise<void | FBlob> | null>;
|
blobPromises!: Record<string, Promise<void | FBlob> | null>;
|
||||||
tasks!: Record<string, FTask>;
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.initializedPromise = this.loadInitialTree();
|
this.initializedPromise = this.loadInitialTree();
|
||||||
@ -55,7 +52,6 @@ class FrocaImpl implements Froca {
|
|||||||
this.attributes = {};
|
this.attributes = {};
|
||||||
this.attachments = {};
|
this.attachments = {};
|
||||||
this.blobPromises = {};
|
this.blobPromises = {};
|
||||||
this.tasks = {};
|
|
||||||
|
|
||||||
this.addResp(resp);
|
this.addResp(resp);
|
||||||
}
|
}
|
||||||
@ -372,24 +368,6 @@ class FrocaImpl implements Froca {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getTask(taskId: string) {
|
|
||||||
return this.tasks[taskId];
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTasks(parentNoteId: string) {
|
|
||||||
const taskRows = await server.get<FTaskRow[]>(`tasks/${parentNoteId}`);
|
|
||||||
return this.processTaskRow(taskRows);
|
|
||||||
}
|
|
||||||
|
|
||||||
processTaskRow(taskRows: FTaskRow[]): FTask[] {
|
|
||||||
return taskRows.map((taskRow) => {
|
|
||||||
const task = new FTask(this, taskRow);
|
|
||||||
this.tasks[task.taskId] = task;
|
|
||||||
|
|
||||||
return task;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async getBlob(entityType: string, entityId: string) {
|
async getBlob(entityType: string, entityId: string) {
|
||||||
// I'm not sure why we're not using blobIds directly, it would save us this composite key ...
|
// I'm not sure why we're not using blobIds directly, it would save us this composite key ...
|
||||||
// perhaps one benefit is that we're always requesting the latest blob, not relying on perhaps faulty/slow
|
// perhaps one benefit is that we're always requesting the latest blob, not relying on perhaps faulty/slow
|
||||||
|
@ -8,8 +8,6 @@ import FAttribute, { type FAttributeRow } from "../entities/fattribute.js";
|
|||||||
import FAttachment, { type FAttachmentRow } from "../entities/fattachment.js";
|
import FAttachment, { type FAttachmentRow } from "../entities/fattachment.js";
|
||||||
import type { default as FNote, FNoteRow } from "../entities/fnote.js";
|
import type { default as FNote, FNoteRow } from "../entities/fnote.js";
|
||||||
import type { EntityChange } from "../server_types.js";
|
import type { EntityChange } from "../server_types.js";
|
||||||
import type { FTaskRow } from "../entities/ftask.js";
|
|
||||||
import FTask from "../entities/ftask.js";
|
|
||||||
|
|
||||||
async function processEntityChanges(entityChanges: EntityChange[]) {
|
async function processEntityChanges(entityChanges: EntityChange[]) {
|
||||||
const loadResults = new LoadResults(entityChanges);
|
const loadResults = new LoadResults(entityChanges);
|
||||||
@ -39,8 +37,6 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
|
|||||||
processAttachment(loadResults, ec);
|
processAttachment(loadResults, ec);
|
||||||
} else if (ec.entityName === "blobs" || ec.entityName === "etapi_tokens") {
|
} else if (ec.entityName === "blobs" || ec.entityName === "etapi_tokens") {
|
||||||
// NOOP
|
// NOOP
|
||||||
} else if (ec.entityName === "tasks") {
|
|
||||||
processTaskChange(loadResults, ec);
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Unknown entityName '${ec.entityName}'`);
|
throw new Error(`Unknown entityName '${ec.entityName}'`);
|
||||||
}
|
}
|
||||||
@ -310,35 +306,6 @@ function processAttachment(loadResults: LoadResults, ec: EntityChange) {
|
|||||||
loadResults.addAttachmentRow(attachmentEntity);
|
loadResults.addAttachmentRow(attachmentEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
function processTaskChange(loadResults: LoadResults, ec: EntityChange) {
|
|
||||||
if (ec.isErased && ec.entityId in froca.tasks) {
|
|
||||||
utils.reloadFrontendApp(`${ec.entityName} '${ec.entityId}' is erased, need to do complete reload.`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let task = froca.tasks[ec.entityId];
|
|
||||||
const taskEntity = ec.entity as FTaskRow;
|
|
||||||
|
|
||||||
if (ec.isErased || (ec.entity as any)?.isDeleted) {
|
|
||||||
if (task) {
|
|
||||||
delete froca.tasks[ec.entityId];
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ec.entity) {
|
|
||||||
if (task) {
|
|
||||||
task.update(ec.entity as FTaskRow);
|
|
||||||
} else {
|
|
||||||
task = new FTask(froca, ec.entity as FTaskRow);
|
|
||||||
froca.tasks[task.taskId] = task;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadResults.addTaskRow(taskEntity);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
processEntityChanges
|
processEntityChanges
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import type { TaskRow, AttachmentRow } from "../../../becca/entities/rows.js";
|
import type { AttachmentRow } from "../../../becca/entities/rows.js";
|
||||||
import type { AttributeType } from "../entities/fattribute.js";
|
import type { AttributeType } from "../entities/fattribute.js";
|
||||||
import type { EntityChange } from "../server_types.js";
|
import type { EntityChange } from "../server_types.js";
|
||||||
|
|
||||||
@ -71,7 +71,6 @@ export default class LoadResults {
|
|||||||
private contentNoteIdToComponentId: ContentNoteIdToComponentIdRow[];
|
private contentNoteIdToComponentId: ContentNoteIdToComponentIdRow[];
|
||||||
private optionNames: string[];
|
private optionNames: string[];
|
||||||
private attachmentRows: AttachmentRow[];
|
private attachmentRows: AttachmentRow[];
|
||||||
private taskRows: TaskRow[];
|
|
||||||
|
|
||||||
constructor(entityChanges: EntityChange[]) {
|
constructor(entityChanges: EntityChange[]) {
|
||||||
const entities: Record<string, Record<string, any>> = {};
|
const entities: Record<string, Record<string, any>> = {};
|
||||||
@ -100,8 +99,6 @@ export default class LoadResults {
|
|||||||
this.optionNames = [];
|
this.optionNames = [];
|
||||||
|
|
||||||
this.attachmentRows = [];
|
this.attachmentRows = [];
|
||||||
|
|
||||||
this.taskRows = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getEntityRow<T extends EntityRowNames>(entityName: T, entityId: string): EntityRowMappings[T] {
|
getEntityRow<T extends EntityRowNames>(entityName: T, entityId: string): EntityRowMappings[T] {
|
||||||
@ -184,14 +181,6 @@ export default class LoadResults {
|
|||||||
return this.contentNoteIdToComponentId.find((l) => l.noteId === noteId && l.componentId !== componentId);
|
return this.contentNoteIdToComponentId.find((l) => l.noteId === noteId && l.componentId !== componentId);
|
||||||
}
|
}
|
||||||
|
|
||||||
isTaskListReloaded(parentNoteId: string) {
|
|
||||||
if (!parentNoteId) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return !!this.taskRows.find((tr) => tr.parentNoteId === parentNoteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
addOption(name: string) {
|
addOption(name: string) {
|
||||||
this.optionNames.push(name);
|
this.optionNames.push(name);
|
||||||
}
|
}
|
||||||
@ -212,14 +201,6 @@ export default class LoadResults {
|
|||||||
return this.attachmentRows;
|
return this.attachmentRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
addTaskRow(task: TaskRow) {
|
|
||||||
this.taskRows.push(task);
|
|
||||||
}
|
|
||||||
|
|
||||||
getTaskRows() {
|
|
||||||
return this.taskRows;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @returns {boolean} true if there are changes which could affect the attributes (including inherited ones)
|
* @returns {boolean} true if there are changes which could affect the attributes (including inherited ones)
|
||||||
* notably changes in note itself should not have any effect on attributes
|
* notably changes in note itself should not have any effect on attributes
|
||||||
@ -237,8 +218,7 @@ export default class LoadResults {
|
|||||||
this.revisionRows.length === 0 &&
|
this.revisionRows.length === 0 &&
|
||||||
this.contentNoteIdToComponentId.length === 0 &&
|
this.contentNoteIdToComponentId.length === 0 &&
|
||||||
this.optionNames.length === 0 &&
|
this.optionNames.length === 0 &&
|
||||||
this.attachmentRows.length === 0 &&
|
this.attachmentRows.length === 0
|
||||||
this.taskRows.length === 0
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,7 +18,6 @@ async function getNoteTypeItems(command?: TreeCommandNames) {
|
|||||||
{ title: t("note_types.web-view"), command, type: "webView", uiIcon: "bx bx-globe-alt" },
|
{ title: t("note_types.web-view"), command, type: "webView", uiIcon: "bx bx-globe-alt" },
|
||||||
{ title: t("note_types.mind-map"), command, type: "mindMap", uiIcon: "bx bx-sitemap" },
|
{ title: t("note_types.mind-map"), command, type: "mindMap", uiIcon: "bx bx-sitemap" },
|
||||||
{ title: t("note_types.geo-map"), command, type: "geoMap", uiIcon: "bx bx-map-alt" },
|
{ title: t("note_types.geo-map"), command, type: "geoMap", uiIcon: "bx bx-map-alt" },
|
||||||
{ title: t("note_types.task-list"), command, type: "taskList", uiIcon: "bx bx-list-check" }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const templateNoteIds = await server.get<string[]>("search-templates");
|
const templateNoteIds = await server.get<string[]>("search-templates");
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
import type FTask from "../entities/ftask.js";
|
|
||||||
import server from "./server.js";
|
|
||||||
|
|
||||||
interface CreateNewTasksOpts {
|
|
||||||
parentNoteId: string;
|
|
||||||
title: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function createNewTask({ parentNoteId, title }: CreateNewTasksOpts) {
|
|
||||||
await server.post(`tasks`, {
|
|
||||||
parentNoteId,
|
|
||||||
title: title.trim()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function toggleTaskDone(taskId: string) {
|
|
||||||
await server.post(`tasks/${taskId}/toggle`);
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function updateTask(task: FTask) {
|
|
||||||
if (!task.taskId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await server.patch(`tasks/${task.taskId}/`, {
|
|
||||||
taskId: task.taskId,
|
|
||||||
dueDate: task.dueDate,
|
|
||||||
isDone: task.isDone
|
|
||||||
});
|
|
||||||
}
|
|
@ -28,8 +28,7 @@ const byNoteType: Record<Exclude<NoteType, "book">, string | null> = {
|
|||||||
render: null,
|
render: null,
|
||||||
search: null,
|
search: null,
|
||||||
text: null,
|
text: null,
|
||||||
webView: null,
|
webView: null
|
||||||
taskList: null
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const byBookType: Record<ViewTypeOptions, string | null> = {
|
const byBookType: Record<ViewTypeOptions, string | null> = {
|
||||||
|
@ -35,7 +35,6 @@ import GeoMapTypeWidget from "./type_widgets/geo_map.js";
|
|||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
import type { NoteType } from "../entities/fnote.js";
|
import type { NoteType } from "../entities/fnote.js";
|
||||||
import type TypeWidget from "./type_widgets/type_widget.js";
|
import type TypeWidget from "./type_widgets/type_widget.js";
|
||||||
import TaskListWidget from "./type_widgets/task_list.js";
|
|
||||||
|
|
||||||
const TPL = `
|
const TPL = `
|
||||||
<div class="note-detail">
|
<div class="note-detail">
|
||||||
@ -73,8 +72,7 @@ const typeWidgetClasses = {
|
|||||||
attachmentDetail: AttachmentDetailTypeWidget,
|
attachmentDetail: AttachmentDetailTypeWidget,
|
||||||
attachmentList: AttachmentListTypeWidget,
|
attachmentList: AttachmentListTypeWidget,
|
||||||
mindMap: MindMapWidget,
|
mindMap: MindMapWidget,
|
||||||
geoMap: GeoMapTypeWidget,
|
geoMap: GeoMapTypeWidget
|
||||||
taskList: TaskListWidget
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,8 +49,7 @@ const NOTE_TYPES: NoteTypeMapping[] = [
|
|||||||
{ type: "image", title: t("note_types.image"), selectable: false },
|
{ type: "image", title: t("note_types.image"), selectable: false },
|
||||||
{ type: "launcher", mime: "", title: t("note_types.launcher"), selectable: false },
|
{ type: "launcher", mime: "", title: t("note_types.launcher"), selectable: false },
|
||||||
{ type: "noteMap", mime: "", title: t("note_types.note-map"), selectable: false },
|
{ type: "noteMap", mime: "", title: t("note_types.note-map"), selectable: false },
|
||||||
{ type: "search", title: t("note_types.saved-search"), selectable: false },
|
{ type: "search", title: t("note_types.saved-search"), selectable: false }
|
||||||
{ type: "taskList", title: t("note_types.task-list"), selectable: false }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter((nt) => !nt.selectable).map((nt) => nt.type);
|
const NOT_SELECTABLE_NOTE_TYPES = NOTE_TYPES.filter((nt) => !nt.selectable).map((nt) => nt.type);
|
||||||
|
@ -1,268 +0,0 @@
|
|||||||
import type FNote from "../../entities/fnote.js";
|
|
||||||
import type FTask from "../../entities/ftask.js";
|
|
||||||
import froca from "../../services/froca.js";
|
|
||||||
import TypeWidget from "./type_widget.js";
|
|
||||||
import * as taskService from "../../services/tasks.js";
|
|
||||||
import type { EventData } from "../../components/app_context.js";
|
|
||||||
import dayjs from "dayjs";
|
|
||||||
import calendarTime from "dayjs/plugin/calendar.js";
|
|
||||||
import { t } from "../../services/i18n.js";
|
|
||||||
dayjs.extend(calendarTime);
|
|
||||||
|
|
||||||
const TPL = `
|
|
||||||
<div class="note-detail-task-list note-detail-printable">
|
|
||||||
|
|
||||||
<header>
|
|
||||||
<input type="text" placeholder="Add a new task" class="add-new-task" />
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<ol class="task-container">
|
|
||||||
</ol>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
.note-detail-task-list {
|
|
||||||
height: 100%;
|
|
||||||
contain: none;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list > header {
|
|
||||||
position: sticky;
|
|
||||||
top: 0;
|
|
||||||
z-index: 100;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.5em 0;
|
|
||||||
background-color: var(--main-background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .add-new-task {
|
|
||||||
width: 100%;
|
|
||||||
padding: 0.25em 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .task-container {
|
|
||||||
list-style-type: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
border-radius: var(--bs-border-radius);
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .task-container li {
|
|
||||||
background: var(--input-background-color);
|
|
||||||
border-bottom: 1px solid var(--main-background-color);
|
|
||||||
padding: 0.5em 1em;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .task-container li:hover {
|
|
||||||
background: var(--input-hover-background);
|
|
||||||
transition: background 250ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .task-container li > header {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
justify-content: flex-end;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .task-container li .check {
|
|
||||||
margin-right: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .task-container li .title {
|
|
||||||
flex-grow: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .task-container li .due-date {
|
|
||||||
font-size: 0.9rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.note-detail-task-list .task-container li.overdue .due-date {
|
|
||||||
color: #fd8282;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</div>
|
|
||||||
`;
|
|
||||||
|
|
||||||
function buildTasks(tasks: FTask[]) {
|
|
||||||
let html = "";
|
|
||||||
|
|
||||||
const now = dayjs();
|
|
||||||
const dateFormat = "DD-MM-YYYY";
|
|
||||||
for (const task of tasks) {
|
|
||||||
const classes = ["task"];
|
|
||||||
|
|
||||||
if (task.dueDate && dayjs(task.dueDate).isBefore(now, "days")) {
|
|
||||||
classes.push("overdue");
|
|
||||||
}
|
|
||||||
|
|
||||||
html += `<li class="${classes.join(" ")}" data-task-id="${task.taskId}">`;
|
|
||||||
html += "<header>";
|
|
||||||
html += '<span class="title">';
|
|
||||||
html += `<input type="checkbox" class="check" ${task.isDone ? "checked" : ""} />`;
|
|
||||||
html += `${task.title}</span>`;
|
|
||||||
html += '</span>';
|
|
||||||
if (task.dueDate) {
|
|
||||||
html += `<span class="due-date">`;
|
|
||||||
html += `<span class="bx bx-calendar"></span> `;
|
|
||||||
html += dayjs(task.dueDate).calendar(null, {
|
|
||||||
sameDay: `[${t("tasks.due.today")}]`,
|
|
||||||
nextDay: `[${t("tasks.due.tomorrow")}]`,
|
|
||||||
nextWeek: "dddd",
|
|
||||||
lastDay: `[${t("tasks.due.yesterday")}]`,
|
|
||||||
lastWeek: dateFormat,
|
|
||||||
sameElse: dateFormat
|
|
||||||
});
|
|
||||||
html += "</span>";
|
|
||||||
}
|
|
||||||
html += "</header>";
|
|
||||||
html += `<div class="edit-container"></div>`;
|
|
||||||
html += `</li>`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html;
|
|
||||||
}
|
|
||||||
|
|
||||||
function buildEditContainer(task: FTask) {
|
|
||||||
return `\
|
|
||||||
<label>Due date:</label>
|
|
||||||
<input type="date" data-tasks-role="due-date" value="${task.dueDate ?? ""}" />
|
|
||||||
`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class TaskListWidget extends TypeWidget {
|
|
||||||
|
|
||||||
private $taskContainer!: JQuery<HTMLElement>;
|
|
||||||
private $addNewTask!: JQuery<HTMLElement>;
|
|
||||||
|
|
||||||
static getType() {
|
|
||||||
return "taskList";
|
|
||||||
}
|
|
||||||
|
|
||||||
doRender() {
|
|
||||||
this.$widget = $(TPL);
|
|
||||||
this.$addNewTask = this.$widget.find(".add-new-task");
|
|
||||||
this.$taskContainer = this.$widget.find(".task-container");
|
|
||||||
|
|
||||||
this.$addNewTask.on("keydown", (e) => {
|
|
||||||
if (e.key === "Enter") {
|
|
||||||
this.#createNewTask(String(this.$addNewTask.val()));
|
|
||||||
this.$addNewTask.val("");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$taskContainer.on("change", "input.check", (e) => {
|
|
||||||
const $target = $(e.target);
|
|
||||||
const taskId = $target.closest("li")[0].dataset.taskId;
|
|
||||||
|
|
||||||
if (!taskId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
taskService.toggleTaskDone(taskId);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$taskContainer.on("click", "li", (e) => {
|
|
||||||
if ((e.target as HTMLElement).tagName === "INPUT") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const $target = $(e.target);
|
|
||||||
|
|
||||||
// Clear existing edit containers.
|
|
||||||
const $existingContainers = this.$taskContainer.find(".edit-container");
|
|
||||||
|
|
||||||
$existingContainers.html("");
|
|
||||||
|
|
||||||
// Add the new edit container.
|
|
||||||
const $editContainer = $target.closest("li").find(".edit-container");
|
|
||||||
const task = this.#getCorrespondingTask($target);
|
|
||||||
if (task) {
|
|
||||||
$editContainer.html(buildEditContainer(task));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$taskContainer.on("change", "input:not(.check)", async (e) => {
|
|
||||||
const $target = $(e.target);
|
|
||||||
const task = this.#getCorrespondingTask($target);
|
|
||||||
if (!task) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const role = $target.data("tasks-role");
|
|
||||||
const value = String($target.val());
|
|
||||||
|
|
||||||
switch (role) {
|
|
||||||
case "due-date":
|
|
||||||
task.dueDate = value;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
await taskService.updateTask(task);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
#getCorrespondingTask($target: JQuery<HTMLElement>) {
|
|
||||||
const $parentEl = $target.closest("li");
|
|
||||||
if (!$parentEl.length) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const taskId = $parentEl[0].dataset.taskId;
|
|
||||||
if (!taskId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return froca.getTask(taskId);
|
|
||||||
}
|
|
||||||
|
|
||||||
async #createNewTask(title: string) {
|
|
||||||
if (!title || !this.noteId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await taskService.createNewTask({
|
|
||||||
title,
|
|
||||||
parentNoteId: this.noteId
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async #getTasks() {
|
|
||||||
if (!this.noteId) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
return (await froca.getTasks(this.noteId)).toSorted((a, b) => {
|
|
||||||
// Sort by due date, closest date first.
|
|
||||||
if (!a.dueDate) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!b.dueDate) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return a.dueDate.localeCompare(b.dueDate, "en");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async doRefresh(note: FNote) {
|
|
||||||
this.$widget.show();
|
|
||||||
|
|
||||||
if (!this.note || !this.noteId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tasks = await this.#getTasks();
|
|
||||||
const tasksHtml = buildTasks(tasks);
|
|
||||||
this.$taskContainer.html(tasksHtml);
|
|
||||||
}
|
|
||||||
|
|
||||||
entitiesReloadedEvent({ loadResults }: EventData<"entitiesReloaded">) {
|
|
||||||
if (this.noteId && loadResults.isTaskListReloaded(this.noteId)) {
|
|
||||||
this.refresh();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1422,8 +1422,7 @@
|
|||||||
"widget": "Widget",
|
"widget": "Widget",
|
||||||
"confirm-change": "It is not recommended to change note type when note content is not empty. Do you want to continue anyway?",
|
"confirm-change": "It is not recommended to change note type when note content is not empty. Do you want to continue anyway?",
|
||||||
"geo-map": "Geo Map",
|
"geo-map": "Geo Map",
|
||||||
"beta-feature": "Beta",
|
"beta-feature": "Beta"
|
||||||
"task-list": "To-Do List"
|
|
||||||
},
|
},
|
||||||
"protect_note": {
|
"protect_note": {
|
||||||
"toggle-on": "Protect the note",
|
"toggle-on": "Protect the note",
|
||||||
|
@ -1,24 +0,0 @@
|
|||||||
import type { Request } from "express";
|
|
||||||
import * as tasksService from "../../services/tasks.js";
|
|
||||||
|
|
||||||
export function getTasks(req: Request) {
|
|
||||||
const { parentNoteId } = req.params;
|
|
||||||
return tasksService.getTasks(parentNoteId);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createNewTask(req: Request) {
|
|
||||||
return tasksService.createNewTask(req.body);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateTask(req: Request) {
|
|
||||||
return tasksService.updateTask(req.params.taskId, req.body);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleTaskDone(req: Request) {
|
|
||||||
const { taskId } = req.params;
|
|
||||||
if (!taskId) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return tasksService.toggleTaskDone(taskId);
|
|
||||||
}
|
|
@ -72,7 +72,6 @@ import etapiSpecRoute from "../etapi/spec.js";
|
|||||||
import etapiBackupRoute from "../etapi/backup.js";
|
import etapiBackupRoute from "../etapi/backup.js";
|
||||||
|
|
||||||
import apiDocsRoute from "./api_docs.js";
|
import apiDocsRoute from "./api_docs.js";
|
||||||
import * as tasksRoute from "./api/tasks.js";
|
|
||||||
|
|
||||||
const MAX_ALLOWED_FILE_SIZE_MB = 250;
|
const MAX_ALLOWED_FILE_SIZE_MB = 250;
|
||||||
const GET = "get",
|
const GET = "get",
|
||||||
@ -280,11 +279,6 @@ function register(app: express.Application) {
|
|||||||
apiRoute(PATCH, "/api/etapi-tokens/:etapiTokenId", etapiTokensApiRoutes.patchToken);
|
apiRoute(PATCH, "/api/etapi-tokens/:etapiTokenId", etapiTokensApiRoutes.patchToken);
|
||||||
apiRoute(DEL, "/api/etapi-tokens/:etapiTokenId", etapiTokensApiRoutes.deleteToken);
|
apiRoute(DEL, "/api/etapi-tokens/:etapiTokenId", etapiTokensApiRoutes.deleteToken);
|
||||||
|
|
||||||
apiRoute(GET, "/api/tasks/:parentNoteId", tasksRoute.getTasks);
|
|
||||||
apiRoute(PST, "/api/tasks", tasksRoute.createNewTask);
|
|
||||||
apiRoute(PST, "/api/tasks/:taskId/toggle", tasksRoute.toggleTaskDone);
|
|
||||||
apiRoute(PATCH, "/api/tasks/:taskId", tasksRoute.updateTask);
|
|
||||||
|
|
||||||
// in case of local electron, local calls are allowed unauthenticated, for server they need auth
|
// in case of local electron, local calls are allowed unauthenticated, for server they need auth
|
||||||
const clipperMiddleware = isElectron ? [] : [auth.checkEtapiToken];
|
const clipperMiddleware = isElectron ? [] : [auth.checkEtapiToken];
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ import packageJson from "../../package.json" with { type: "json" };
|
|||||||
import dataDir from "./data_dir.js";
|
import dataDir from "./data_dir.js";
|
||||||
|
|
||||||
const APP_DB_VERSION = 228;
|
const APP_DB_VERSION = 228;
|
||||||
const SYNC_VERSION = 35;
|
const SYNC_VERSION = 34;
|
||||||
const CLIPPER_PROTOCOL_VERSION = "1.0";
|
const CLIPPER_PROTOCOL_VERSION = "1.0";
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -888,7 +888,7 @@ class ConsistencyChecks {
|
|||||||
return `${tableName}: ${count}`;
|
return `${tableName}: ${count}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tables = ["notes", "revisions", "attachments", "branches", "attributes", "etapi_tokens", "blobs", "tasks"];
|
const tables = ["notes", "revisions", "attachments", "branches", "attributes", "etapi_tokens", "blobs"];
|
||||||
|
|
||||||
log.info(`Table counts: ${tables.map((tableName) => getTableRowCount(tableName)).join(", ")}`);
|
log.info(`Table counts: ${tables.map((tableName) => getTableRowCount(tableName)).join(", ")}`);
|
||||||
}
|
}
|
||||||
|
@ -15,8 +15,7 @@ const noteTypes = [
|
|||||||
{ type: "doc", defaultMime: "" },
|
{ type: "doc", defaultMime: "" },
|
||||||
{ type: "contentWidget", defaultMime: "" },
|
{ type: "contentWidget", defaultMime: "" },
|
||||||
{ type: "mindMap", defaultMime: "application/json" },
|
{ type: "mindMap", defaultMime: "application/json" },
|
||||||
{ type: "geoMap", defaultMime: "application/json" },
|
{ type: "geoMap", defaultMime: "application/json" }
|
||||||
{ type: "taskList", defaultMime: "" }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
function getDefaultMimeForNoteType(typeName: string) {
|
function getDefaultMimeForNoteType(typeName: string) {
|
||||||
|
@ -1,35 +0,0 @@
|
|||||||
import becca from "../becca/becca.js";
|
|
||||||
import BTask from "../becca/entities/btask.js";
|
|
||||||
import type { TaskRow } from "../becca/entities/rows.js";
|
|
||||||
|
|
||||||
export function getTasks(parentNoteId: string) {
|
|
||||||
return becca.getTasks().filter((task) => task.parentNoteId === parentNoteId && !task.isDone);
|
|
||||||
}
|
|
||||||
|
|
||||||
interface CreateTaskParams {
|
|
||||||
parentNoteId: string;
|
|
||||||
title: string;
|
|
||||||
dueDate?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createNewTask(params: CreateTaskParams) {
|
|
||||||
const task = new BTask(params);
|
|
||||||
task.save();
|
|
||||||
|
|
||||||
return {
|
|
||||||
task
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function toggleTaskDone(taskId: string) {
|
|
||||||
const task = becca.tasks[taskId];
|
|
||||||
task.isDone = !task.isDone;
|
|
||||||
task.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
export function updateTask(taskId: string, content: TaskRow) {
|
|
||||||
const task = becca.tasks[taskId];
|
|
||||||
task.isDone = !!content.isDone;
|
|
||||||
task.dueDate = content.dueDate;
|
|
||||||
task.save();
|
|
||||||
}
|
|
@ -188,12 +188,6 @@ function fillInAdditionalProperties(entityChange: EntityChange) {
|
|||||||
WHERE attachmentId = ?`,
|
WHERE attachmentId = ?`,
|
||||||
[entityChange.entityId]
|
[entityChange.entityId]
|
||||||
);
|
);
|
||||||
} else if (entityChange.entityName === "tasks") {
|
|
||||||
entityChange.entity = becca.getTask(entityChange.entity);
|
|
||||||
|
|
||||||
if (!entityChange.entity) {
|
|
||||||
entityChange.entity = sql.getRow(`SELECT * FROM tasks WHERE taskId = ?`, [entityChange.entityId]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entityChange.entity instanceof AbstractBeccaEntity) {
|
if (entityChange.entity instanceof AbstractBeccaEntity) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user