mirror of
https://github.com/zadam/trilium.git
synced 2025-11-26 02:24:23 +01:00
chore(react/promoted_attributes): handle relations
This commit is contained in:
parent
9c6cd80867
commit
709a47bc6b
@ -8,8 +8,10 @@ import { t } from "../services/i18n";
|
|||||||
import { DefinitionObject, LabelType } from "../services/promoted_attribute_definition_parser";
|
import { DefinitionObject, LabelType } from "../services/promoted_attribute_definition_parser";
|
||||||
import server from "../services/server";
|
import server from "../services/server";
|
||||||
import FNote from "../entities/fnote";
|
import FNote from "../entities/fnote";
|
||||||
import { HTMLInputTypeAttribute, InputHTMLAttributes, MouseEventHandler, TargetedEvent, TargetedInputEvent } from "preact";
|
import { ComponentChild, HTMLInputTypeAttribute, InputHTMLAttributes, MouseEventHandler, TargetedEvent, TargetedInputEvent } from "preact";
|
||||||
import tree from "../services/tree";
|
import tree from "../services/tree";
|
||||||
|
import NoteAutocomplete from "./react/NoteAutocomplete";
|
||||||
|
import ws from "../services/ws";
|
||||||
|
|
||||||
interface Cell {
|
interface Cell {
|
||||||
definitionAttr: FAttribute;
|
definitionAttr: FAttribute;
|
||||||
@ -112,11 +114,24 @@ function PromotedAttributeCell(props: CellProps) {
|
|||||||
}
|
}
|
||||||
}, [ props.shouldFocus ]);
|
}, [ props.shouldFocus ]);
|
||||||
|
|
||||||
|
let correspondingInput: ComponentChild;
|
||||||
|
switch (valueAttr.type) {
|
||||||
|
case "label":
|
||||||
|
correspondingInput = <LabelInput inputId={inputId} {...props} />;
|
||||||
|
break;
|
||||||
|
case "relation":
|
||||||
|
correspondingInput = <RelationInput inputId={inputId} {...props} />;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ws.logError(t(`promoted_attributes.unknown_attribute_type`, { type: valueAttr.type }));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx("promoted-attribute-cell",
|
<div className={clsx("promoted-attribute-cell",
|
||||||
valueAttr.type === "label" ? `promoted-attribute-label-${definition.labelType}` : "promoted-attribute-relation")}>
|
valueAttr.type === "label" ? `promoted-attribute-label-${definition.labelType}` : "promoted-attribute-relation")}>
|
||||||
{definition.labelType !== "boolean" && <label for={inputId}>{definition.promotedAlias ?? valueName}</label>}
|
{definition.labelType !== "boolean" && <label for={inputId}>{definition.promotedAlias ?? valueName}</label>}
|
||||||
<LabelInput inputId={inputId} {...props} />
|
{correspondingInput}
|
||||||
<ActionCell />
|
<ActionCell />
|
||||||
<MultiplicityCell {...props} />
|
<MultiplicityCell {...props} />
|
||||||
</div>
|
</div>
|
||||||
@ -136,7 +151,7 @@ const LABEL_MAPPINGS: Record<LabelType, HTMLInputTypeAttribute> = {
|
|||||||
|
|
||||||
function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
|
function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
|
||||||
const { valueName, valueAttr, definition, definitionAttr } = props.cell;
|
const { valueName, valueAttr, definition, definitionAttr } = props.cell;
|
||||||
const onChangeListener = buildPromotedAttributeChangedListener({...props});
|
const onChangeListener = buildPromotedAttributeLabelChangedListener({...props});
|
||||||
const extraInputProps: InputHTMLAttributes = {};
|
const extraInputProps: InputHTMLAttributes = {};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -249,8 +264,17 @@ function ColorPicker({ cell, onChange, inputId }: CellProps & {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function RelationInput() {
|
function RelationInput({ inputId, ...props }: CellProps & { inputId: string }) {
|
||||||
|
return (
|
||||||
|
<NoteAutocomplete
|
||||||
|
id={inputId}
|
||||||
|
noteId={props.cell.valueAttr.value}
|
||||||
|
noteIdChanged={async (value) => {
|
||||||
|
const { note, cell, componentId } = props;
|
||||||
|
cell.valueAttr.attributeId = (await updateAttribute(note, cell, componentId, value)).attributeId;
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function ActionCell() {
|
function ActionCell() {
|
||||||
@ -384,32 +408,30 @@ function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildPromotedAttributeChangedListener({ note, cell, componentId }: CellProps) {
|
function buildPromotedAttributeLabelChangedListener({ note, cell, componentId, ...props }: CellProps) {
|
||||||
return async (e: TargetedEvent<HTMLInputElement, Event>) => {
|
return async (e: TargetedEvent<HTMLInputElement, Event> | InputEvent) => {
|
||||||
const inputEl = e.target as HTMLInputElement;
|
const inputEl = e.target as HTMLInputElement;
|
||||||
let value: string;
|
let value: string;
|
||||||
|
|
||||||
if (inputEl.type === "checkbox") {
|
if (inputEl.type === "checkbox") {
|
||||||
value = inputEl.checked ? "true" : "false";
|
value = inputEl.checked ? "true" : "false";
|
||||||
} else if (inputEl.dataset.attributeType === "relation") {
|
|
||||||
const selectedPath = $(inputEl).getSelectedNotePath();
|
|
||||||
value = selectedPath ? tree.getNoteIdFromUrl(selectedPath) ?? "" : "";
|
|
||||||
console.log("Got relation ", value);
|
|
||||||
} else {
|
} else {
|
||||||
value = inputEl.value;
|
value = inputEl.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
const result = await server.put<AttributeResult>(
|
cell.valueAttr.attributeId = (await updateAttribute(note, cell, componentId, value)).attributeId;
|
||||||
`notes/${note.noteId}/attribute`,
|
|
||||||
{
|
|
||||||
attributeId: cell.valueAttr.attributeId,
|
|
||||||
type: cell.valueAttr.type,
|
|
||||||
name: cell.valueName,
|
|
||||||
value: value
|
|
||||||
},
|
|
||||||
componentId
|
|
||||||
);
|
|
||||||
|
|
||||||
cell.valueAttr.attributeId = result.attributeId;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateAttribute(note: FNote, cell: Cell, componentId: string, value: string) {
|
||||||
|
return server.put<AttributeResult>(
|
||||||
|
`notes/${note.noteId}/attribute`,
|
||||||
|
{
|
||||||
|
attributeId: cell.valueAttr.attributeId,
|
||||||
|
type: cell.valueAttr.type,
|
||||||
|
name: cell.valueName,
|
||||||
|
value: value
|
||||||
|
},
|
||||||
|
componentId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -1,49 +1,5 @@
|
|||||||
export default class PromotedAttributesWidget extends NoteContextAwareWidget {
|
export default class PromotedAttributesWidget extends NoteContextAwareWidget {
|
||||||
|
|
||||||
async createPromotedAttributeCell(definitionAttr: FAttribute, valueAttr: Attribute, valueName: string) {
|
|
||||||
const definition = definitionAttr.getDefinition();
|
|
||||||
|
|
||||||
const $input = $("<input>")
|
|
||||||
.on("change", (event) => this.promotedAttributeChanged(event));
|
|
||||||
|
|
||||||
if (valueAttr.type === "label") {
|
|
||||||
$wrapper.addClass(`promoted-attribute-label-${definition.labelType}`);
|
|
||||||
} else if (definition.labelType === "boolean") {
|
|
||||||
$input.wrap($(`<label class="tn-checkbox"></label>`));
|
|
||||||
$wrapper.find(".input-group").removeClass("input-group");
|
|
||||||
|
|
||||||
if (valueAttr.value === "true") {
|
|
||||||
$input.prop("checked", "checked");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ws.logError(t("promoted_attributes.unknown_label_type", { type: definition.labelType }));
|
|
||||||
}
|
|
||||||
} else if (valueAttr.type === "relation") {
|
|
||||||
if (valueAttr.value) {
|
|
||||||
$input.val(await treeService.getNoteTitle(valueAttr.value));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (utils.isDesktop()) {
|
|
||||||
// no need to wait for this
|
|
||||||
noteAutocompleteService.initNoteAutocomplete($input, { allowCreatingNotes: true });
|
|
||||||
|
|
||||||
$input.on("autocomplete:noteselected", (event, suggestion, dataset) => {
|
|
||||||
this.promotedAttributeChanged(event);
|
|
||||||
});
|
|
||||||
|
|
||||||
$input.setSelectedNotePath(valueAttr.value);
|
|
||||||
} else {
|
|
||||||
// we can't provide user a way to edit the relation so make it read only
|
|
||||||
$input.attr("readonly", "readonly");
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
ws.logError(t(`promoted_attributes.unknown_attribute_type`, { type: valueAttr.type }));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $wrapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
focus() {
|
focus() {
|
||||||
this.$widget.find(".promoted-attribute-input:first").focus();
|
this.$widget.find(".promoted-attribute-input:first").focus();
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user