diff --git a/src/public/app/components/app_context.ts b/src/public/app/components/app_context.ts index b28dda410..ca4f9e1ce 100644 --- a/src/public/app/components/app_context.ts +++ b/src/public/app/components/app_context.ts @@ -19,7 +19,8 @@ import { ResolveOptions } from "../widgets/dialogs/delete_notes.js"; import { PromptDialogOptions } from "../widgets/dialogs/prompt.js"; import { ConfirmWithMessageOptions, ConfirmWithTitleOptions } from "../widgets/dialogs/confirm.js"; import { Node } from "../services/tree.js"; -import FAttribute from "../entities/fattribute.js"; +import LoadResults from "../services/load_results.js"; +import { Attribute } from "../services/attribute_parser.js"; interface Layout { getRootWidget: (appContext: AppContext) => RootWidget; @@ -36,7 +37,7 @@ interface BeforeUploadListener extends Component { /** * Base interface for the data/arguments for a given command (see {@link CommandMappings}). */ -interface CommandData { +export interface CommandData { ntxId?: string; } @@ -144,8 +145,13 @@ export type CommandMappings = { copyImageReferenceToClipboard: CommandData; copyImageToClipboard: CommandData; updateAttributesList: { - attributes: FAttribute[]; + attributes: Attribute[]; }; + + addNewLabel: CommandData; + addNewRelation: CommandData; + addNewLabelDefinition: CommandData; + addNewRelationDefinition: CommandData; } type EventMappings = { @@ -162,8 +168,19 @@ type EventMappings = { noteId: string; messages: string[]; }; + entitiesReloaded: { + loadResults: LoadResults + }; + addNewLabel: CommandData; + addNewRelation: CommandData; } +export type EventListener = { + [key in T as `${key}Event`]: (data: EventData) => void +} + +export type EventData = EventMappings[T]; + type CommandAndEventMappings = (CommandMappings & EventMappings); /** diff --git a/src/public/app/services/attribute_parser.ts b/src/public/app/services/attribute_parser.ts index 07677a1e5..c2a10d471 100644 --- a/src/public/app/services/attribute_parser.ts +++ b/src/public/app/services/attribute_parser.ts @@ -7,13 +7,14 @@ interface Token { endIndex: number; } -interface Attribute { +export interface Attribute { type: AttributeType; name: string; isInheritable: boolean; value?: string; - startIndex: number; - endIndex: number; + startIndex?: number; + endIndex?: number; + noteId?: string; } function lex(str: string) { diff --git a/src/public/app/services/attributes.ts b/src/public/app/services/attributes.ts index e8dbcb89e..bd8c46480 100644 --- a/src/public/app/services/attributes.ts +++ b/src/public/app/services/attributes.ts @@ -1,6 +1,7 @@ import server from './server.js'; import froca from './froca.js'; import FNote from '../entities/fnote.js'; +import { AttributeRow } from './load_results.js'; async function addLabel(noteId: string, name: string, value: string = "") { await server.put(`notes/${noteId}/attribute`, { @@ -23,18 +24,18 @@ async function removeAttributeById(noteId: string, attributeId: string) { } /** - * @returns {boolean} - returns true if this attribute has the potential to influence the note in the argument. + * @returns - returns true if this attribute has the potential to influence the note in the argument. * That can happen in multiple ways: * 1. attribute is owned by the note * 2. attribute is owned by the template of the note * 3. attribute is owned by some note's ancestor and is inheritable */ -function isAffecting(this: { isInheritable: boolean }, attrRow: { noteId: string }, affectedNote: FNote) { +function isAffecting(attrRow: AttributeRow, affectedNote: FNote) { if (!affectedNote || !attrRow) { return false; } - const attrNote = froca.notes[attrRow.noteId]; + const attrNote = attrRow.noteId && froca.notes[attrRow.noteId]; if (!attrNote) { // the note (owner of the attribute) is not even loaded into the cache, so it should not affect anything else @@ -50,6 +51,7 @@ function isAffecting(this: { isInheritable: boolean }, attrRow: { noteId: string } // TODO: This doesn't seem right. + //@ts-ignore if (this.isInheritable) { for (const owningNote of owningNotes) { if (owningNote.hasAncestor(attrNote.noteId, true)) { diff --git a/src/public/app/services/load_results.ts b/src/public/app/services/load_results.ts index 7627fc2c8..b72fa2852 100644 --- a/src/public/app/services/load_results.ts +++ b/src/public/app/services/load_results.ts @@ -5,9 +5,11 @@ interface BranchRow { componentId: string; } -interface AttributeRow { +export interface AttributeRow { + noteId?: string; attributeId: string; componentId: string; + isInheritable?: boolean; } interface RevisionRow { @@ -79,9 +81,9 @@ export default class LoadResults { if (!this.noteIdToComponentId[noteId].includes(componentId)) { this.noteIdToComponentId[noteId].push(componentId); } - + this.componentIdToNoteIds[componentId] = this.componentIdToNoteIds[componentId] || []; - + if (this.componentIdToNoteIds[componentId]) { this.componentIdToNoteIds[componentId].push(noteId); } @@ -110,11 +112,11 @@ export default class LoadResults { this.attributeRows.push({attributeId, componentId}); } - getAttributeRows(componentId = 'none') { + getAttributeRows(componentId = 'none'): AttributeRow[] { return this.attributeRows .filter(row => row.componentId !== componentId) .map(row => this.getEntityRow("attributes", row.attributeId)) - .filter(attr => !!attr); + .filter(attr => !!attr) as AttributeRow[]; } addRevision(revisionId: string, noteId?: string, componentId?: string | null) { diff --git a/src/public/app/services/note_autocomplete.ts b/src/public/app/services/note_autocomplete.ts index d83d83f62..52aeab1bb 100644 --- a/src/public/app/services/note_autocomplete.ts +++ b/src/public/app/services/note_autocomplete.ts @@ -30,14 +30,14 @@ interface Options { } async function autocompleteSourceForCKEditor(queryText: string) { - return await new Promise((res, rej) => { + return await new Promise((res, rej) => { autocompleteSource(queryText, rows => { res(rows.map(row => { return { action: row.action, noteTitle: row.noteTitle, id: `@${row.notePathTitle}`, - name: row.notePathTitle, + name: row.notePathTitle || "", link: `#${row.notePath}`, notePath: row.notePath, highlightedNotePathTitle: row.highlightedNotePathTitle @@ -62,7 +62,7 @@ async function autocompleteSource(term: string, cb: (rows: Suggestion[]) => void }] ); } - + const activeNoteId = appContext.tabManager.getActiveContextNoteId(); let results: Suggestion[] = await server.get(`autocomplete?query=${encodeURIComponent(term)}&activeNoteId=${activeNoteId}&fastSearch=${fastSearch}`); @@ -135,7 +135,7 @@ function fullTextSearch($el: JQuery, options: Options){ const searchString = $el.autocomplete('val') as unknown as string; if (options.fastSearch === false || searchString?.trim().length === 0) { return; - } + } $el.trigger('focus'); options.fastSearch = false; $el.autocomplete('val', ''); @@ -168,7 +168,7 @@ function initNoteAutocomplete($el: JQuery, options?: Options) { const $fullTextSearchButton = $("