mirror of
https://github.com/zadam/trilium.git
synced 2025-12-06 07:24:25 +01:00
refactor(note_create): simplify type implementation and documentation
This commit is contained in:
parent
bcb29d22f5
commit
a5ef5eee2f
@ -11,7 +11,7 @@ import froca from "../services/froca.js";
|
|||||||
import linkService from "../services/link.js";
|
import linkService from "../services/link.js";
|
||||||
import { t } from "../services/i18n.js";
|
import { t } from "../services/i18n.js";
|
||||||
import { CreateChildrenResponse, SqlExecuteResponse } from "@triliumnext/commons";
|
import { CreateChildrenResponse, SqlExecuteResponse } from "@triliumnext/commons";
|
||||||
import noteCreateService, { CreateNoteIntoInboxURLOpts, CreateNoteTarget } from "../services/note_create.js";
|
import noteCreateService, { CreateNoteIntoInboxOpts, CreateNoteTarget } from "../services/note_create.js";
|
||||||
|
|
||||||
export default class Entrypoints extends Component {
|
export default class Entrypoints extends Component {
|
||||||
constructor() {
|
constructor() {
|
||||||
@ -26,7 +26,7 @@ export default class Entrypoints extends Component {
|
|||||||
|
|
||||||
async createNoteIntoInboxCommand() {
|
async createNoteIntoInboxCommand() {
|
||||||
await noteCreateService.createNote(
|
await noteCreateService.createNote(
|
||||||
{ target: CreateNoteTarget.IntoInbox } as CreateNoteIntoInboxURLOpts
|
{ target: CreateNoteTarget.IntoInbox } as CreateNoteIntoInboxOpts
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import appContext, { type EventData } from "./app_context.js";
|
import appContext, { type EventData } from "./app_context.js";
|
||||||
import noteCreateService, { CreateNoteTarget, CreateNoteIntoURLOpts, CreateNoteAfterURLOpts } from "../services/note_create.js";
|
import noteCreateService, { CreateNoteTarget, CreateNoteIntoUrlOpts, CreateNoteAfterUrlOpts } from "../services/note_create.js";
|
||||||
import treeService from "../services/tree.js";
|
import treeService from "../services/tree.js";
|
||||||
import hoistedNoteService from "../services/hoisted_note.js";
|
import hoistedNoteService from "../services/hoisted_note.js";
|
||||||
import Component from "./component.js";
|
import Component from "./component.js";
|
||||||
@ -55,7 +55,7 @@ export default class MainTreeExecutors extends Component {
|
|||||||
isProtected: activeNoteContext.note.isProtected,
|
isProtected: activeNoteContext.note.isProtected,
|
||||||
saveSelection: false,
|
saveSelection: false,
|
||||||
promptForType: false,
|
promptForType: false,
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ export default class MainTreeExecutors extends Component {
|
|||||||
targetBranchId: node.data.branchId,
|
targetBranchId: node.data.branchId,
|
||||||
isProtected: isProtected,
|
isProtected: isProtected,
|
||||||
saveSelection: false
|
saveSelection: false
|
||||||
} as CreateNoteAfterURLOpts
|
} as CreateNoteAfterUrlOpts
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import options from "../services/options.js";
|
|||||||
import froca from "../services/froca.js";
|
import froca from "../services/froca.js";
|
||||||
import utils from "../services/utils.js";
|
import utils from "../services/utils.js";
|
||||||
import toastService from "../services/toast.js";
|
import toastService from "../services/toast.js";
|
||||||
import noteCreateService, { CreateNoteIntoURLOpts, CreateNoteTarget } from "../services/note_create.js";
|
import noteCreateService, { CreateNoteIntoUrlOpts, CreateNoteTarget } from "../services/note_create.js";
|
||||||
|
|
||||||
export default class RootCommandExecutor extends Component {
|
export default class RootCommandExecutor extends Component {
|
||||||
editReadOnlyNoteCommand() {
|
editReadOnlyNoteCommand() {
|
||||||
@ -249,7 +249,7 @@ export default class RootCommandExecutor extends Component {
|
|||||||
messages: [],
|
messages: [],
|
||||||
title: "New AI Chat"
|
title: "New AI Chat"
|
||||||
}),
|
}),
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result.note) {
|
if (!result.note) {
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import NoteColorPicker from "./custom-items/NoteColorPicker.jsx";
|
|||||||
import treeService from "../services/tree.js";
|
import treeService from "../services/tree.js";
|
||||||
import froca from "../services/froca.js";
|
import froca from "../services/froca.js";
|
||||||
import clipboard from "../services/clipboard.js";
|
import clipboard from "../services/clipboard.js";
|
||||||
import noteCreateService, { CreateNoteAfterURLOpts, CreateNoteIntoURLOpts, CreateNoteTarget } from "../services/note_create.js";
|
import noteCreateService, { CreateNoteAfterUrlOpts, CreateNoteIntoUrlOpts, CreateNoteTarget } from "../services/note_create.js";
|
||||||
import contextMenu, { type MenuCommandItem, type MenuItem } from "./context_menu.js";
|
import contextMenu, { type MenuCommandItem, type MenuItem } from "./context_menu.js";
|
||||||
import appContext, { type ContextMenuCommandData, type FilteredCommandNames } from "../components/app_context.js";
|
import appContext, { type ContextMenuCommandData, type FilteredCommandNames } from "../components/app_context.js";
|
||||||
import noteTypesService from "../services/note_types.js";
|
import noteTypesService from "../services/note_types.js";
|
||||||
@ -293,7 +293,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
|
|||||||
isProtected: isProtected,
|
isProtected: isProtected,
|
||||||
templateNoteId: templateNoteId,
|
templateNoteId: templateNoteId,
|
||||||
promptForType: false,
|
promptForType: false,
|
||||||
} as CreateNoteAfterURLOpts
|
} as CreateNoteAfterUrlOpts
|
||||||
);
|
);
|
||||||
} else if (command === "insertChildNote") {
|
} else if (command === "insertChildNote") {
|
||||||
const parentNotePath = treeService.getNotePath(this.node);
|
const parentNotePath = treeService.getNotePath(this.node);
|
||||||
@ -306,7 +306,7 @@ export default class TreeContextMenu implements SelectMenuItemEventListener<Tree
|
|||||||
isProtected: this.node.data.isProtected,
|
isProtected: this.node.data.isProtected,
|
||||||
templateNoteId: templateNoteId,
|
templateNoteId: templateNoteId,
|
||||||
promptForType: false,
|
promptForType: false,
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
);
|
);
|
||||||
} else if (command === "openNoteInSplit") {
|
} else if (command === "openNoteInSplit") {
|
||||||
const subContexts = appContext.tabManager.getActiveContext()?.getSubContexts();
|
const subContexts = appContext.tabManager.getActiveContext()?.getSubContexts();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import server from "./server.js";
|
import server from "./server.js";
|
||||||
import appContext from "../components/app_context.js";
|
import appContext from "../components/app_context.js";
|
||||||
import noteCreateService, { CreateNoteIntoURLOpts, CreateNoteTarget, CreateNoteIntoInboxURLOpts } from "./note_create.js";
|
import noteCreateService, { CreateNoteIntoUrlOpts, CreateNoteTarget, CreateNoteIntoInboxOpts } from "./note_create.js";
|
||||||
import froca from "./froca.js";
|
import froca from "./froca.js";
|
||||||
import { t } from "./i18n.js";
|
import { t } from "./i18n.js";
|
||||||
import commandRegistry from "./command_registry.js";
|
import commandRegistry from "./command_registry.js";
|
||||||
@ -487,7 +487,7 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
|
|||||||
title: suggestion.noteTitle,
|
title: suggestion.noteTitle,
|
||||||
activate: true,
|
activate: true,
|
||||||
promptForType: true,
|
promptForType: true,
|
||||||
} as CreateNoteIntoInboxURLOpts
|
} as CreateNoteIntoInboxOpts
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!note) return;
|
if (!note) return;
|
||||||
@ -507,7 +507,7 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
|
|||||||
title: suggestion.noteTitle,
|
title: suggestion.noteTitle,
|
||||||
activate: false,
|
activate: false,
|
||||||
promptForType: true,
|
promptForType: true,
|
||||||
} as CreateNoteIntoInboxURLOpts,
|
} as CreateNoteIntoInboxOpts,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!note) return;
|
if (!note) return;
|
||||||
@ -528,7 +528,7 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
|
|||||||
title: suggestion.noteTitle,
|
title: suggestion.noteTitle,
|
||||||
activate: true,
|
activate: true,
|
||||||
promptForType: true,
|
promptForType: true,
|
||||||
} as CreateNoteIntoURLOpts,
|
} as CreateNoteIntoUrlOpts,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!note) return;
|
if (!note) return;
|
||||||
@ -549,7 +549,7 @@ function initNoteAutocomplete($el: JQuery<HTMLElement>, options?: Options) {
|
|||||||
title: suggestion.noteTitle,
|
title: suggestion.noteTitle,
|
||||||
activate: false,
|
activate: false,
|
||||||
promptForType: true,
|
promptForType: true,
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!note) return;
|
if (!note) return;
|
||||||
|
|||||||
@ -13,44 +13,56 @@ import type { CKTextEditor } from "@triliumnext/ckeditor5";
|
|||||||
import dateNoteService from "../services/date_notes.js";
|
import dateNoteService from "../services/date_notes.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The `note_create` function can be called with multiple valid combinations
|
* Defines the type hierarchy and rules for valid argument combinations
|
||||||
* of arguments. This type hierarchy defines and enforces which combinations
|
* accepted by `note_create`.
|
||||||
* are valid at compile time.
|
|
||||||
*
|
*
|
||||||
* The function overloads later in `note_create` correspond to these types,
|
* ## Overview
|
||||||
* ensuring that each variant of note creation accepts only the correct
|
* Each variant (e.g. `CreateNoteIntoUrlOpts`, `CreateNoteBeforeUrlOpts`, etc.)
|
||||||
* set of arguments.
|
* extends `CreateNoteOpts` and enforces specific constraints to ensure only
|
||||||
|
* valid note creation options are allowed at compile time.
|
||||||
*
|
*
|
||||||
* Theoretically: If type checking produces no errors, then the provided
|
* ## Type Safety
|
||||||
* arguments represent a valid state — assuming the types below are defined
|
* The `PromptingRule` ensures that `promptForType` and `type` stay mutually
|
||||||
* correctly. Through the Curry–Howard correspondence, this type system
|
* exclusive (if prompting, `type` is undefined).
|
||||||
* effectively acts as a proof system: a successful type check serves as a
|
|
||||||
* compile-time proof that the arguments of `create_note` can only produce
|
|
||||||
* a valid state.
|
|
||||||
*
|
*
|
||||||
* To align with its theoretical foundation in type theory (via the
|
* The type system prevents invalid argument mixes by design — successful type
|
||||||
* Curry–Howard correspondence), `type` is used instead of `interface`
|
* checks guarantee a valid state, following Curry–Howard correspondence
|
||||||
|
* principles (types as proofs).
|
||||||
*
|
*
|
||||||
* * Hierarchy of general to specific categories(hypernyms -> hyponyms):
|
* ## Maintenance
|
||||||
|
* If adding or modifying `Opts`, ensure:
|
||||||
|
* - All valid combinations are represented (avoid *false negatives*).
|
||||||
|
* - No invalid ones slip through (avoid *false positives*).
|
||||||
*
|
*
|
||||||
* * CreateNoteEntity
|
* Hierarchy (general → specific):
|
||||||
* |
|
* - CreateNoteOpts
|
||||||
* \-- CreateNoteOpts
|
* - CreateNoteAtUrlOpts
|
||||||
* |
|
* - CreateNoteIntoUrlOpts
|
||||||
* +-- CreateNoteAtUrlOpts
|
* - CreateNoteBeforeUrlOpts
|
||||||
* | +-- CreateNoteIntoURLOpts
|
* - CreateNoteAfterUrlOpts
|
||||||
* | \-- CreateNoteSiblingURLOpts
|
* - CreateNoteIntoInboxOpts
|
||||||
* | +-- CreateNoteBeforeURLOpts
|
|
||||||
* | \-- CreateNoteAfterURLOpts
|
|
||||||
* |
|
|
||||||
* \-- CreateNoteIntoInboxURLOpts
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/** enforces a truth rule:
|
||||||
* this is the shared basis for all types. Every other type is child (hyponym)
|
* - If `promptForType` is true → `type` must be undefined.
|
||||||
* of it (Its the domain hypernym).
|
* - If `promptForType` is false → `type` must be defined.
|
||||||
*/
|
*/
|
||||||
type CreateNoteEntity = {
|
type PromptingRule = {
|
||||||
|
promptForType: true;
|
||||||
|
type?: never;
|
||||||
|
} | {
|
||||||
|
promptForType?: false;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base type for all note creation options (domain hypernym).
|
||||||
|
* All specific note option types extend from this.
|
||||||
|
*
|
||||||
|
* Combine with `&` to ensure valid logical combinations.
|
||||||
|
*/
|
||||||
|
export type CreateNoteOpts = {
|
||||||
target: CreateNoteTarget;
|
target: CreateNoteTarget;
|
||||||
isProtected?: boolean;
|
isProtected?: boolean;
|
||||||
saveSelection?: boolean;
|
saveSelection?: boolean;
|
||||||
@ -62,43 +74,30 @@ type CreateNoteEntity = {
|
|||||||
activate?: boolean;
|
activate?: boolean;
|
||||||
focus?: "title" | "content";
|
focus?: "title" | "content";
|
||||||
textEditor?: CKTextEditor;
|
textEditor?: CKTextEditor;
|
||||||
}
|
} & PromptingRule;
|
||||||
|
|
||||||
export type CreateNoteOpts =
|
|
||||||
| (CreateNoteEntity & {
|
|
||||||
promptForType: true;
|
|
||||||
type?: never;
|
|
||||||
})
|
|
||||||
| (CreateNoteEntity & {
|
|
||||||
promptForType?: false;
|
|
||||||
type?: string;
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For creating a note in a specific path. At is the broader category (hypernym)
|
* Defines options for creating a note at a specific path.
|
||||||
* of "into" and "as siblings". It is not exported because it only exists, to
|
* Serves as a base (not exported) for "into", "before", and "after" variants,
|
||||||
* have its legal values propagated to its children (types inheriting from it).
|
* sharing common URL-related fields.
|
||||||
*/
|
*/
|
||||||
type CreateNoteAtUrlOpts = CreateNoteOpts & {
|
type CreateNoteAtUrlOpts = CreateNoteOpts & {
|
||||||
// `Url` means either parentNotePath or parentNoteId.
|
// `Url` may refer to either parentNotePath or parentNoteId.
|
||||||
// The vocabulary is inspired by its loose semantics of getNoteIdFromUrl.
|
// The vocabulary is inspired by existing function getNoteIdFromUrl.
|
||||||
parentNoteUrl: string;
|
parentNoteUrl: string;
|
||||||
/*
|
|
||||||
* targetBranchId disambiguates the position for cloned notes. This is a
|
// Disambiguates the position for cloned notes.
|
||||||
* concern whenever we are given a note URL.
|
|
||||||
*/
|
|
||||||
targetBranchId: string;
|
targetBranchId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CreateNoteIntoURLOpts = CreateNoteAtUrlOpts;
|
export type CreateNoteIntoUrlOpts = CreateNoteAtUrlOpts;
|
||||||
|
export type CreateNoteBeforeUrlOpts = CreateNoteAtUrlOpts;
|
||||||
|
export type CreateNoteAfterUrlOpts = CreateNoteAtUrlOpts;
|
||||||
|
|
||||||
type CreateNoteSiblingURLOpts = CreateNoteAtUrlOpts;
|
type NeverDefineParentNoteUrlRule = {
|
||||||
export type CreateNoteBeforeURLOpts = CreateNoteSiblingURLOpts;
|
|
||||||
export type CreateNoteAfterURLOpts = CreateNoteSiblingURLOpts;
|
|
||||||
|
|
||||||
export type CreateNoteIntoInboxURLOpts = CreateNoteOpts & {
|
|
||||||
parentNoteUrl?: never;
|
parentNoteUrl?: never;
|
||||||
}
|
};
|
||||||
|
export type CreateNoteIntoInboxOpts = CreateNoteOpts & NeverDefineParentNoteUrlRule;
|
||||||
|
|
||||||
export enum CreateNoteTarget {
|
export enum CreateNoteTarget {
|
||||||
IntoNoteURL,
|
IntoNoteURL,
|
||||||
@ -118,23 +117,6 @@ interface DuplicateResponse {
|
|||||||
note: FNote;
|
note: FNote;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We are overloading createNote for each type */
|
|
||||||
async function createNote(
|
|
||||||
options: CreateNoteIntoURLOpts
|
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }>;
|
|
||||||
|
|
||||||
async function createNote(
|
|
||||||
options: CreateNoteAfterURLOpts
|
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }>;
|
|
||||||
|
|
||||||
async function createNote(
|
|
||||||
options: CreateNoteBeforeURLOpts
|
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }>;
|
|
||||||
|
|
||||||
async function createNote(
|
|
||||||
options: CreateNoteIntoInboxURLOpts
|
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }>;
|
|
||||||
|
|
||||||
async function createNote(
|
async function createNote(
|
||||||
options: CreateNoteOpts
|
options: CreateNoteOpts
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
|
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
|
||||||
@ -143,41 +125,28 @@ async function createNote(
|
|||||||
|
|
||||||
// handle prompts centrally to write once fix for all
|
// handle prompts centrally to write once fix for all
|
||||||
if (options.promptForType) {
|
if (options.promptForType) {
|
||||||
const { success, noteType, templateNoteId, notePath } = await chooseNoteType();
|
let maybeResolvedOptions = await promptForType(options);
|
||||||
|
if (!maybeResolvedOptions) {
|
||||||
if (!success) return {
|
return {
|
||||||
note: null, branch: undefined
|
note: null, branch: undefined
|
||||||
};
|
};
|
||||||
|
|
||||||
resolvedOptions = {
|
|
||||||
...resolvedOptions,
|
|
||||||
promptForType: false,
|
|
||||||
type: noteType,
|
|
||||||
templateNoteId,
|
|
||||||
} as CreateNoteOpts;
|
|
||||||
|
|
||||||
if (notePath) {
|
|
||||||
resolvedOptions = resolvedOptions as CreateNoteIntoURLOpts;
|
|
||||||
resolvedOptions = {
|
|
||||||
...resolvedOptions,
|
|
||||||
target: CreateNoteTarget.IntoNoteURL,
|
|
||||||
parentNoteUrl: notePath,
|
|
||||||
} as CreateNoteIntoURLOpts;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolvedOptions = maybeResolvedOptions;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (resolvedOptions.target) {
|
switch (resolvedOptions.target) {
|
||||||
case CreateNoteTarget.IntoNoteURL:
|
case CreateNoteTarget.IntoNoteURL:
|
||||||
return await createNoteIntoNote(resolvedOptions as CreateNoteIntoURLOpts);
|
return await createNoteAtNote("into", {...options} as CreateNoteAtUrlOpts);
|
||||||
|
|
||||||
case CreateNoteTarget.BeforeNoteURL:
|
case CreateNoteTarget.BeforeNoteURL:
|
||||||
return await createNoteBeforeNote(resolvedOptions as CreateNoteBeforeURLOpts);
|
return await createNoteAtNote("before", resolvedOptions as CreateNoteBeforeUrlOpts);
|
||||||
|
|
||||||
case CreateNoteTarget.AfterNoteURL:
|
case CreateNoteTarget.AfterNoteURL:
|
||||||
return await createNoteAfterNote(resolvedOptions as CreateNoteAfterURLOpts);
|
return await createNoteAtNote("after", resolvedOptions as CreateNoteAfterUrlOpts);
|
||||||
|
|
||||||
case CreateNoteTarget.IntoInbox:
|
case CreateNoteTarget.IntoInbox:
|
||||||
return await createNoteIntoInbox(resolvedOptions as CreateNoteIntoInboxURLOpts);
|
return await createNoteIntoInbox(resolvedOptions as CreateNoteIntoInboxOpts);
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
console.warn("[createNote] Unknown target:", options.target, resolvedOptions);
|
console.warn("[createNote] Unknown target:", options.target, resolvedOptions);
|
||||||
@ -187,14 +156,40 @@ async function createNote(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function promptForType(
|
||||||
|
options: CreateNoteOpts
|
||||||
|
) : Promise<CreateNoteOpts | null> {
|
||||||
|
const { success, noteType, templateNoteId, notePath } = await chooseNoteType();
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let resolvedOptions = {
|
||||||
|
...options,
|
||||||
|
promptForType: false,
|
||||||
|
type: noteType,
|
||||||
|
templateNoteId,
|
||||||
|
} as CreateNoteOpts;
|
||||||
|
|
||||||
|
if (notePath) {
|
||||||
|
resolvedOptions = resolvedOptions as CreateNoteIntoUrlOpts;
|
||||||
|
resolvedOptions = {
|
||||||
|
...resolvedOptions,
|
||||||
|
target: CreateNoteTarget.IntoNoteURL,
|
||||||
|
parentNoteUrl: notePath,
|
||||||
|
} as CreateNoteIntoUrlOpts;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resolvedOptions;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Core function that creates a new note under the specified parent note path.
|
* Creates a new note under a specified parent note path.
|
||||||
*
|
*
|
||||||
* @param target - Duplicates apps/server/src/routes/api/notes.ts createNote
|
* @param target - Mirrors the `createNote` API in apps/server/src/routes/api/notes.ts.
|
||||||
* @param {CreateNoteEntity} [options] - Options controlling note creation (title, content, type, template, focus, etc.).
|
* @param options - Note creation options
|
||||||
* with parentNotePath - The parent note path where the new note will be created.
|
* @returns A promise resolving with the created note and its branch.
|
||||||
* @returns {Promise<{ note: FNote | null; branch: FBranch | undefined }>}
|
|
||||||
* Resolves with the created note and branch entities.
|
|
||||||
*/
|
*/
|
||||||
async function createNoteAtNote(
|
async function createNoteAtNote(
|
||||||
target: "into" | "after" | "before",
|
target: "into" | "after" | "before",
|
||||||
@ -271,35 +266,15 @@ async function createNoteAtNote(
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Small wrapper functions for @see createNoteAtNote, using it a certain way to
|
|
||||||
// remove code duplication
|
|
||||||
async function createNoteIntoNote(
|
|
||||||
options: CreateNoteIntoURLOpts
|
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
|
|
||||||
return createNoteAtNote("into", {...options} as CreateNoteAtUrlOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createNoteBeforeNote(
|
|
||||||
options: CreateNoteBeforeURLOpts
|
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
|
|
||||||
return createNoteAtNote("before", {...options} as CreateNoteAtUrlOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function createNoteAfterNote(
|
|
||||||
options: CreateNoteAfterURLOpts
|
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
|
|
||||||
return createNoteAtNote("after", {...options} as CreateNoteAtUrlOpts);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new note inside the user's Inbox.
|
* Creates a new note inside the user's Inbox.
|
||||||
*
|
*
|
||||||
* @param {CreateNoteEntity} [options] - Optional settings such as title, type, template, or content.
|
* @param {CreateNoteIntoInboxOpts} [options] - Optional settings such as title, type, template, or content.
|
||||||
* @returns {Promise<{ note: FNote | null; branch: FBranch | undefined }>}
|
* @returns {Promise<{ note: FNote | null; branch: FBranch | undefined }>}
|
||||||
* Resolves with the created note and its branch, or `{ note: null, branch: undefined }` if the inbox is missing.
|
* Resolves with the created note and its branch, or `{ note: null, branch: undefined }` if the inbox is missing.
|
||||||
*/
|
*/
|
||||||
async function createNoteIntoInbox(
|
async function createNoteIntoInbox(
|
||||||
options: CreateNoteIntoInboxURLOpts
|
options: CreateNoteIntoInboxOpts
|
||||||
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
|
): Promise<{ note: FNote | null; branch: FBranch | undefined }> {
|
||||||
const inboxNote = await dateNoteService.getInboxNote();
|
const inboxNote = await dateNoteService.getInboxNote();
|
||||||
if (!inboxNote) {
|
if (!inboxNote) {
|
||||||
@ -313,11 +288,11 @@ async function createNoteIntoInbox(
|
|||||||
inboxNote.isProtected && protectedSessionHolder.isProtectedSessionAvailable();
|
inboxNote.isProtected && protectedSessionHolder.isProtectedSessionAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await createNoteIntoNote(
|
const result = await createNoteAtNote("into",
|
||||||
{
|
{
|
||||||
...options,
|
...options,
|
||||||
parentNoteUrl: inboxNote.noteId,
|
parentNoteUrl: inboxNote.noteId,
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
);
|
);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import branches from "../../../services/branches";
|
|||||||
import { executeBulkActions } from "../../../services/bulk_action";
|
import { executeBulkActions } from "../../../services/bulk_action";
|
||||||
import froca from "../../../services/froca";
|
import froca from "../../../services/froca";
|
||||||
import { t } from "../../../services/i18n";
|
import { t } from "../../../services/i18n";
|
||||||
import note_create, { CreateNoteIntoURLOpts, CreateNoteTarget } from "../../../services/note_create.js";
|
import note_create, { CreateNoteIntoUrlOpts, CreateNoteTarget } from "../../../services/note_create.js";
|
||||||
import server from "../../../services/server";
|
import server from "../../../services/server";
|
||||||
import { ColumnMap } from "./data";
|
import { ColumnMap } from "./data";
|
||||||
|
|
||||||
@ -44,7 +44,7 @@ export default class BoardApi {
|
|||||||
parentNoteUrl: parentNotePath,
|
parentNoteUrl: parentNotePath,
|
||||||
activate: false,
|
activate: false,
|
||||||
title,
|
title,
|
||||||
} as CreateNoteIntoURLOpts);
|
} as CreateNoteIntoUrlOpts);
|
||||||
|
|
||||||
if (newNote && newBranch) {
|
if (newNote && newBranch) {
|
||||||
await this.changeColumn(newNote.noteId, column);
|
await this.changeColumn(newNote.noteId, column);
|
||||||
@ -150,7 +150,7 @@ export default class BoardApi {
|
|||||||
activate: false,
|
activate: false,
|
||||||
targetBranchId: relativeToBranchId,
|
targetBranchId: relativeToBranchId,
|
||||||
title: t("board_view.new-item"),
|
title: t("board_view.new-item"),
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!note || !branch) {
|
if (!note || !branch) {
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import branches from "../../../services/branches.js";
|
|||||||
import Component from "../../../components/component.js";
|
import Component from "../../../components/component.js";
|
||||||
import NoteColorPicker from "../../../menus/custom-items/NoteColorPicker.jsx";
|
import NoteColorPicker from "../../../menus/custom-items/NoteColorPicker.jsx";
|
||||||
import { RefObject } from "preact";
|
import { RefObject } from "preact";
|
||||||
import { CreateNoteAfterURLOpts, CreateNoteBeforeURLOpts, CreateNoteTarget } from "../../../services/note_create.js";
|
import { CreateNoteAfterUrlOpts, CreateNoteBeforeUrlOpts, CreateNoteTarget } from "../../../services/note_create.js";
|
||||||
|
|
||||||
export function useContextMenu(parentNote: FNote, parentComponent: Component | null | undefined, tabulator: RefObject<Tabulator>): Partial<EventCallBackMethods> {
|
export function useContextMenu(parentNote: FNote, parentComponent: Component | null | undefined, tabulator: RefObject<Tabulator>): Partial<EventCallBackMethods> {
|
||||||
const events: Partial<EventCallBackMethods> = {};
|
const events: Partial<EventCallBackMethods> = {};
|
||||||
@ -186,7 +186,7 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
|
|||||||
customOpts: {
|
customOpts: {
|
||||||
target: CreateNoteTarget.BeforeNoteURL,
|
target: CreateNoteTarget.BeforeNoteURL,
|
||||||
targetBranchId: rowData.branchId,
|
targetBranchId: rowData.branchId,
|
||||||
} as CreateNoteBeforeURLOpts
|
} as CreateNoteBeforeUrlOpts
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -200,7 +200,7 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
|
|||||||
customOpts: {
|
customOpts: {
|
||||||
target: CreateNoteTarget.AfterNoteURL,
|
target: CreateNoteTarget.AfterNoteURL,
|
||||||
targetBranchId: branchId,
|
targetBranchId: branchId,
|
||||||
} as CreateNoteAfterURLOpts
|
} as CreateNoteAfterUrlOpts
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -213,7 +213,7 @@ export function showRowContextMenu(parentComponent: Component, e: MouseEvent, ro
|
|||||||
customOpts: {
|
customOpts: {
|
||||||
target: CreateNoteTarget.AfterNoteURL,
|
target: CreateNoteTarget.AfterNoteURL,
|
||||||
targetBranchId: rowData.branchId,
|
targetBranchId: rowData.branchId,
|
||||||
} as CreateNoteAfterURLOpts
|
} as CreateNoteAfterUrlOpts
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
{ kind: "separator" },
|
{ kind: "separator" },
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { EventCallBackMethods, RowComponent, Tabulator } from "tabulator-tables";
|
import { EventCallBackMethods, RowComponent, Tabulator } from "tabulator-tables";
|
||||||
import { CommandListenerData } from "../../../components/app_context";
|
import { CommandListenerData } from "../../../components/app_context";
|
||||||
import note_create, { CreateNoteOpts, CreateNoteIntoURLOpts as CreateNoteIntoURLOpts, CreateNoteTarget } from "../../../services/note_create";
|
import note_create, { CreateNoteOpts, CreateNoteIntoUrlOpts as CreateNoteIntoUrlOpts, CreateNoteTarget } from "../../../services/note_create";
|
||||||
import { useLegacyImperativeHandlers } from "../../react/hooks";
|
import { useLegacyImperativeHandlers } from "../../react/hooks";
|
||||||
import { RefObject } from "preact";
|
import { RefObject } from "preact";
|
||||||
import { setAttribute, setLabel } from "../../../services/attributes";
|
import { setAttribute, setLabel } from "../../../services/attributes";
|
||||||
@ -23,7 +23,7 @@ export default function useRowTableEditing(api: RefObject<Tabulator>, attributeD
|
|||||||
{
|
{
|
||||||
parentNoteUrl: notePath,
|
parentNoteUrl: notePath,
|
||||||
...opts
|
...opts
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
).then(({ branch }) => {
|
).then(({ branch }) => {
|
||||||
if (branch) {
|
if (branch) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import appContext from "../../components/app_context";
|
|||||||
import contextMenu from "../../menus/context_menu";
|
import contextMenu from "../../menus/context_menu";
|
||||||
import branches from "../../services/branches";
|
import branches from "../../services/branches";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import note_create, { CreateNoteIntoURLOpts, CreateNoteTarget } from "../../services/note_create";
|
import note_create, { CreateNoteIntoUrlOpts, CreateNoteTarget } from "../../services/note_create";
|
||||||
import tree from "../../services/tree";
|
import tree from "../../services/tree";
|
||||||
import ActionButton from "../react/ActionButton";
|
import ActionButton from "../react/ActionButton";
|
||||||
import { ParentComponent } from "../react/react_utils";
|
import { ParentComponent } from "../react/react_utils";
|
||||||
@ -33,7 +33,7 @@ export default function MobileDetailMenu() {
|
|||||||
{
|
{
|
||||||
target: CreateNoteTarget.IntoNoteURL,
|
target: CreateNoteTarget.IntoNoteURL,
|
||||||
parentNoteUrl: appContext.tabManager.getActiveContextNotePath() ?? undefined
|
parentNoteUrl: appContext.tabManager.getActiveContextNotePath() ?? undefined
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
);
|
);
|
||||||
} else if (command === "delete") {
|
} else if (command === "delete") {
|
||||||
const notePath = appContext.tabManager.getActiveContextNotePath();
|
const notePath = appContext.tabManager.getActiveContextNotePath();
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import branchService from "../services/branches.js";
|
|||||||
import ws from "../services/ws.js";
|
import ws from "../services/ws.js";
|
||||||
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
import NoteContextAwareWidget from "./note_context_aware_widget.js";
|
||||||
import server from "../services/server.js";
|
import server from "../services/server.js";
|
||||||
import noteCreateService, { CreateNoteIntoURLOpts, CreateNoteTarget } from "../services/note_create.js";
|
import noteCreateService, { CreateNoteIntoUrlOpts, CreateNoteTarget } from "../services/note_create.js";
|
||||||
import toastService from "../services/toast.js";
|
import toastService from "../services/toast.js";
|
||||||
import appContext, { type CommandListenerData, type EventData } from "../components/app_context.js";
|
import appContext, { type CommandListenerData, type EventData } from "../components/app_context.js";
|
||||||
import keyboardActionsService from "../services/keyboard_actions.js";
|
import keyboardActionsService from "../services/keyboard_actions.js";
|
||||||
@ -229,7 +229,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
target: CreateNoteTarget.IntoNoteURL,
|
target: CreateNoteTarget.IntoNoteURL,
|
||||||
parentNoteUrl: parentNotePath,
|
parentNoteUrl: parentNotePath,
|
||||||
isProtected: node.data.isProtected
|
isProtected: node.data.isProtected
|
||||||
} as CreateNoteIntoURLOpts,
|
} as CreateNoteIntoUrlOpts,
|
||||||
);
|
);
|
||||||
} else if (target.classList.contains("enter-workspace-button")) {
|
} else if (target.classList.contains("enter-workspace-button")) {
|
||||||
const node = $.ui.fancytree.getNode(e as unknown as Event);
|
const node = $.ui.fancytree.getNode(e as unknown as Event);
|
||||||
@ -1847,7 +1847,7 @@ export default class NoteTreeWidget extends NoteContextAwareWidget {
|
|||||||
target: CreateNoteTarget.IntoNoteURL,
|
target: CreateNoteTarget.IntoNoteURL,
|
||||||
parentNoteUrl: notePath,
|
parentNoteUrl: notePath,
|
||||||
isProtected: node.data.isProtected
|
isProtected: node.data.isProtected
|
||||||
} as CreateNoteIntoURLOpts
|
} as CreateNoteIntoUrlOpts
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import contextMenu from "../../../menus/context_menu";
|
|||||||
import type { CommandData, FilteredCommandNames } from "../../../components/app_context";
|
import type { CommandData, FilteredCommandNames } from "../../../components/app_context";
|
||||||
import { AttributeType } from "@triliumnext/commons";
|
import { AttributeType } from "@triliumnext/commons";
|
||||||
import attributes from "../../../services/attributes";
|
import attributes from "../../../services/attributes";
|
||||||
import note_create, { CreateNoteAfterURLOpts, CreateNoteIntoURLOpts, CreateNoteTarget, CreateNoteIntoInboxURLOpts } from "../../../services/note_create";
|
import note_create, { CreateNoteAfterUrlOpts, CreateNoteIntoUrlOpts, CreateNoteTarget, CreateNoteIntoInboxOpts } from "../../../services/note_create";
|
||||||
import { CreateNoteAction } from "@triliumnext/commons";
|
import { CreateNoteAction } from "@triliumnext/commons";
|
||||||
|
|
||||||
type AttributeCommandNames = FilteredCommandNames<CommandData>;
|
type AttributeCommandNames = FilteredCommandNames<CommandData>;
|
||||||
@ -266,7 +266,7 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
|
|||||||
target: CreateNoteTarget.IntoInbox,
|
target: CreateNoteTarget.IntoInbox,
|
||||||
title,
|
title,
|
||||||
activate: false
|
activate: false
|
||||||
} as CreateNoteIntoInboxURLOpts
|
} as CreateNoteIntoInboxOpts
|
||||||
);
|
);
|
||||||
return note?.getBestNotePathString() ?? "";
|
return note?.getBestNotePathString() ?? "";
|
||||||
}
|
}
|
||||||
@ -280,7 +280,7 @@ export default function AttributeEditor({ api, note, componentId, notePath, ntxI
|
|||||||
title,
|
title,
|
||||||
activate: false,
|
activate: false,
|
||||||
promptForType: true,
|
promptForType: true,
|
||||||
} as CreateNoteIntoURLOpts,
|
} as CreateNoteIntoUrlOpts,
|
||||||
)
|
)
|
||||||
return resp?.note?.getBestNotePathString() ?? "";
|
return resp?.note?.getBestNotePathString() ?? "";
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user