From 7f0fe1681b473f3816f90ce4488536e36656aa08 Mon Sep 17 00:00:00 2001 From: Elian Doran Date: Sun, 23 Nov 2025 11:57:31 +0200 Subject: [PATCH] chore(react/promoted_attributes): integrate value change listener --- .../client/src/widgets/PromotedAttributes.tsx | 48 ++++++++++++++++--- .../client/src/widgets/promoted_attributes.ts | 36 -------------- 2 files changed, 42 insertions(+), 42 deletions(-) diff --git a/apps/client/src/widgets/PromotedAttributes.tsx b/apps/client/src/widgets/PromotedAttributes.tsx index bfed6f6a2..45258577b 100644 --- a/apps/client/src/widgets/PromotedAttributes.tsx +++ b/apps/client/src/widgets/PromotedAttributes.tsx @@ -8,7 +8,8 @@ import { t } from "../services/i18n"; import { DefinitionObject, LabelType } from "../services/promoted_attribute_definition_parser"; import server from "../services/server"; import FNote from "../entities/fnote"; -import { HTMLInputTypeAttribute } from "preact"; +import { HTMLInputTypeAttribute, TargetedEvent } from "preact"; +import tree from "../services/tree"; interface Cell { definitionAttr: FAttribute; @@ -27,6 +28,12 @@ interface CellProps { setCellToFocus(cell: Cell): void; } +// TODO: Deduplicate +interface AttributeResult { + attributeId: string; +} + + export default function PromotedAttributes() { const { note, componentId } = useNoteContext(); const [ cells, setCells ] = useState(); @@ -130,15 +137,13 @@ const LABEL_MAPPINGS: Record = { function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) { const { valueAttr, definition, definitionAttr } = props.cell; + const onChangeListener = buildPromotedAttributeChangedListener({...props}); useEffect(() => { if (definition.labelType === "text") { const el = document.getElementById(inputId); if (el) { - setupTextLabelAutocomplete(el as HTMLInputElement, valueAttr, () => { - // TODO: Implement me. - console.log("Got change"); - }); + setupTextLabelAutocomplete(el as HTMLInputElement, valueAttr, onChangeListener); } } }, []); @@ -154,6 +159,7 @@ function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) { data-attribute-id={valueAttr.attributeId} data-attribute-type={valueAttr.type} data-attribute-name={valueAttr.name} + onChange={onChangeListener} /> ) } @@ -242,7 +248,7 @@ function PromotedActionButton({ icon, title, onClick }: { ) } -function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute, onChangeListener: () => void) { +function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute, onChangeListener: TargetedEvent) { // no need to await for this, can be done asynchronously const $input = $(el); server.get(`attribute-values/${encodeURIComponent(valueAttr.name)}`).then((_attributeValues) => { @@ -278,3 +284,33 @@ function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute, $input.on("autocomplete:selected", onChangeListener); }); } + +function buildPromotedAttributeChangedListener({ note, cell, componentId }: CellProps) { + return async (e: TargetedEvent) => { + const inputEl = e.target as HTMLInputElement; + let value: string; + + if (inputEl.type === "checkbox") { + 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 { + value = inputEl.value; + } + + const result = await server.put( + `notes/${note.noteId}/attribute`, + { + attributeId: cell.valueAttr.attributeId, + type: cell.valueAttr.type, + name: cell.valueName, + value: value + }, + componentId + ); + + cell.valueAttr.attributeId = result.attributeId; + } +} diff --git a/apps/client/src/widgets/promoted_attributes.ts b/apps/client/src/widgets/promoted_attributes.ts index 4f9d9bcc5..1a9666e2a 100644 --- a/apps/client/src/widgets/promoted_attributes.ts +++ b/apps/client/src/widgets/promoted_attributes.ts @@ -12,10 +12,6 @@ import type { Attribute } from "../services/attribute_parser.js"; import type FAttribute from "../entities/fattribute.js"; import type { EventData } from "../components/app_context.js"; -// TODO: Deduplicate -interface AttributeResult { - attributeId: string; -} export default class PromotedAttributesWidget extends NoteContextAwareWidget { @@ -44,9 +40,6 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { if (valueAttr.value === "true") { $input.prop("checked", "checked"); } - } else if (definition.labelType === "date") { - } else if (definition.labelType === "datetime") { - } else if (definition.labelType === "time") { } else if (definition.labelType === "url") { $input.prop("placeholder", t("promoted_attributes.url_placeholder")); @@ -114,35 +107,6 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget { return $wrapper; } - async promotedAttributeChanged(event: JQuery.TriggeredEvent) { - const $attr = $(event.target); - - let value; - - if ($attr.prop("type") === "checkbox") { - value = $attr.is(":checked") ? "true" : "false"; - } else if ($attr.attr("data-attribute-type") === "relation") { - const selectedPath = $attr.getSelectedNotePath(); - - value = selectedPath ? treeService.getNoteIdFromUrl(selectedPath) : ""; - } else { - value = $attr.val(); - } - - const result = await server.put( - `notes/${this.noteId}/attribute`, - { - attributeId: $attr.attr("data-attribute-id"), - type: $attr.attr("data-attribute-type"), - name: $attr.attr("data-attribute-name"), - value: value - }, - this.componentId - ); - - $attr.attr("data-attribute-id", result.attributeId); - } - focus() { this.$widget.find(".promoted-attribute-input:first").focus(); }