mirror of
https://github.com/zadam/trilium.git
synced 2025-10-20 15:19:01 +02:00
refactor(react): add type safety for note labels
This commit is contained in:
parent
8a66ee7565
commit
b8e4947adb
@ -2,7 +2,7 @@ import { ComponentChildren } from "preact";
|
||||
import { Dispatch, StateUpdater, useEffect, useState } from "preact/hooks";
|
||||
import FNote from "../../entities/fnote";
|
||||
import froca from "../../services/froca";
|
||||
import { useNoteLabel } from "../react/hooks";
|
||||
import { useNoteLabelInt } from "../react/hooks";
|
||||
import { t } from "../../services/i18n";
|
||||
|
||||
interface PaginationContext {
|
||||
@ -62,9 +62,8 @@ export function usePagination(note: FNote, noteIds: string[]): PaginationContext
|
||||
const [ pageNotes, setPageNotes ] = useState<FNote[]>();
|
||||
|
||||
// Parse page size.
|
||||
const [ pageSize ] = useNoteLabel(note, "pageSize");
|
||||
const pageSizeNum = parseInt(pageSize ?? "", 10);
|
||||
const normalizedPageSize = (pageSizeNum && pageSizeNum > 0 ? pageSizeNum : 20);
|
||||
const [ pageSize ] = useNoteLabelInt(note, "pageSize");
|
||||
const normalizedPageSize = (pageSize && pageSize > 0 ? pageSize : 20);
|
||||
|
||||
// Calculate start/end index.
|
||||
const startIdx = (page - 1) * normalizedPageSize;
|
||||
|
@ -2,7 +2,7 @@ import { Inputs, MutableRef, useCallback, useContext, useDebugValue, useEffect,
|
||||
import { CommandListenerData, EventData, EventNames } from "../../components/app_context";
|
||||
import { ParentComponent } from "./react_utils";
|
||||
import SpacedUpdate from "../../services/spaced_update";
|
||||
import { KeyboardActionNames, OptionNames } from "@triliumnext/commons";
|
||||
import { FilterLabelsByType, KeyboardActionNames, OptionNames } from "@triliumnext/commons";
|
||||
import options, { type OptionValue } from "../../services/options";
|
||||
import utils, { escapeRegExp, reloadFrontendApp } from "../../services/utils";
|
||||
import NoteContext from "../../components/note_context";
|
||||
@ -13,7 +13,7 @@ import FBlob from "../../entities/fblob";
|
||||
import NoteContextAwareWidget from "../note_context_aware_widget";
|
||||
import { RefObject, VNode } from "preact";
|
||||
import { Tooltip } from "bootstrap";
|
||||
import { CSSProperties, DragEventHandler } from "preact/compat";
|
||||
import { CSSProperties } from "preact/compat";
|
||||
import keyboard_actions from "../../services/keyboard_actions";
|
||||
import Mark from "mark.js";
|
||||
import { DragData } from "../note_tree";
|
||||
@ -291,7 +291,7 @@ export function useNoteRelation(note: FNote | undefined | null, relationName: st
|
||||
* @param labelName the name of the label to read/write.
|
||||
* @returns an array where the first element is the getter and the second element is the setter. The setter has a special behaviour for convenience: if the value is undefined, the label is created without a value (e.g. a tag), if the value is null then the label is removed.
|
||||
*/
|
||||
export function useNoteLabel(note: FNote | undefined | null, labelName: string): [string | null | undefined, (newValue: string | null | undefined) => void] {
|
||||
export function useNoteLabel(note: FNote | undefined | null, labelName: FilterLabelsByType<string>): [string | null | undefined, (newValue: string | null | undefined) => void] {
|
||||
const [ , setLabelValue ] = useState<string | null | undefined>();
|
||||
|
||||
useEffect(() => setLabelValue(note?.getLabelValue(labelName) ?? null), [ note ]);
|
||||
@ -325,12 +325,12 @@ export function useNoteLabel(note: FNote | undefined | null, labelName: string):
|
||||
] as const;
|
||||
}
|
||||
|
||||
export function useNoteLabelWithDefault(note: FNote | undefined | null, labelName: string, defaultValue: string): [string, (newValue: string | null | undefined) => void] {
|
||||
export function useNoteLabelWithDefault(note: FNote | undefined | null, labelName: FilterLabelsByType<string>, defaultValue: string): [string, (newValue: string | null | undefined) => void] {
|
||||
const [ labelValue, setLabelValue ] = useNoteLabel(note, labelName);
|
||||
return [ labelValue ?? defaultValue, setLabelValue];
|
||||
}
|
||||
|
||||
export function useNoteLabelBoolean(note: FNote | undefined | null, labelName: string): [ boolean, (newValue: boolean) => void] {
|
||||
export function useNoteLabelBoolean(note: FNote | undefined | null, labelName: FilterLabelsByType<boolean>): [ boolean, (newValue: boolean) => void] {
|
||||
const [ labelValue, setLabelValue ] = useState<boolean>(!!note?.hasLabel(labelName));
|
||||
|
||||
useEffect(() => setLabelValue(!!note?.hasLabel(labelName)), [ note ]);
|
||||
@ -358,7 +358,8 @@ export function useNoteLabelBoolean(note: FNote | undefined | null, labelName: s
|
||||
return [ labelValue, setter ] as const;
|
||||
}
|
||||
|
||||
export function useNoteLabelInt(note: FNote | undefined | null, labelName: string): [ number | undefined, (newValue: number) => void] {
|
||||
export function useNoteLabelInt(note: FNote | undefined | null, labelName: FilterLabelsByType<number>): [ number | undefined, (newValue: number) => void] {
|
||||
//@ts-expect-error `useNoteLabel` only accepts string properties but we need to be able to read number ones.
|
||||
const [ value, setValue ] = useNoteLabel(note, labelName);
|
||||
useDebugValue(labelName);
|
||||
return [
|
||||
|
@ -118,6 +118,7 @@ function CheckboxPropertyView({ note, property }: { note: FNote, property: Check
|
||||
}
|
||||
|
||||
function NumberPropertyView({ note, property }: { note: FNote, property: NumberProperty }) {
|
||||
//@ts-expect-error Interop with text box which takes in string values even for numbers.
|
||||
const [ value, setValue ] = useNoteLabel(note, property.bindToLabel);
|
||||
|
||||
return (
|
||||
|
@ -4,6 +4,7 @@ import attributes from "../../services/attributes";
|
||||
import NoteContextAwareWidget from "../note_context_aware_widget";
|
||||
import { DEFAULT_MAP_LAYER_NAME, MAP_LAYERS, type MapLayer } from "../collections/geomap/map_layer";
|
||||
import { ViewTypeOptions } from "../collections/interface";
|
||||
import { FilterLabelsByType } from "@triliumnext/commons";
|
||||
|
||||
interface BookConfig {
|
||||
properties: BookProperty[];
|
||||
@ -12,7 +13,7 @@ interface BookConfig {
|
||||
export interface CheckBoxProperty {
|
||||
type: "checkbox",
|
||||
label: string;
|
||||
bindToLabel: string
|
||||
bindToLabel: FilterLabelsByType<boolean>
|
||||
}
|
||||
|
||||
export interface ButtonProperty {
|
||||
@ -26,7 +27,7 @@ export interface ButtonProperty {
|
||||
export interface NumberProperty {
|
||||
type: "number",
|
||||
label: string;
|
||||
bindToLabel: string;
|
||||
bindToLabel: FilterLabelsByType<number>;
|
||||
width?: number;
|
||||
min?: number;
|
||||
}
|
||||
@ -44,7 +45,7 @@ interface ComboBoxGroup {
|
||||
export interface ComboBoxProperty {
|
||||
type: "combobox",
|
||||
label: string;
|
||||
bindToLabel: string;
|
||||
bindToLabel: FilterLabelsByType<string>;
|
||||
/**
|
||||
* The default value is used when the label is not set.
|
||||
*/
|
||||
|
@ -9,3 +9,4 @@ export * from "./lib/bulk_actions.js";
|
||||
export * from "./lib/server_api.js";
|
||||
export * from "./lib/shared_constants.js";
|
||||
export * from "./lib/ws_api.js";
|
||||
export * from "./lib/attribute_names.js";
|
||||
|
45
packages/commons/src/lib/attribute_names.ts
Normal file
45
packages/commons/src/lib/attribute_names.ts
Normal file
@ -0,0 +1,45 @@
|
||||
type Labels = {
|
||||
color: string;
|
||||
iconClass: string;
|
||||
workspaceIconClass: string;
|
||||
executeDescription: string;
|
||||
executeTitle: string;
|
||||
limit: string; // should be probably be number
|
||||
calendarRoot: boolean;
|
||||
workspaceCalendarRoot: boolean;
|
||||
archived: boolean;
|
||||
sorted: boolean;
|
||||
template: boolean;
|
||||
autoReadOnlyDisabled: boolean;
|
||||
language: string;
|
||||
originalFileName: string;
|
||||
pageUrl: string;
|
||||
|
||||
// Search
|
||||
searchString: string;
|
||||
ancestorDepth: string;
|
||||
orderBy: string;
|
||||
orderDirection: string;
|
||||
|
||||
// Collection-specific
|
||||
viewType: string;
|
||||
status: string;
|
||||
pageSize: number;
|
||||
geolocation: string;
|
||||
readOnly: boolean;
|
||||
expanded: boolean;
|
||||
"calendar:hideWeekends": boolean;
|
||||
"calendar:weekNumbers": boolean;
|
||||
"calendar:view": string;
|
||||
"map:style": string;
|
||||
"map:scale": boolean;
|
||||
"board:groupBy": string;
|
||||
maxNestingDepth: number;
|
||||
includeArchived: boolean;
|
||||
}
|
||||
|
||||
export type LabelNames = keyof Labels;
|
||||
|
||||
export type FilterLabelsByType<U> = {
|
||||
[K in keyof Labels]: Labels[K] extends U ? K : never;
|
||||
}[keyof Labels];
|
Loading…
x
Reference in New Issue
Block a user