chore(react/promoted_attributes): integrate value change listener

This commit is contained in:
Elian Doran 2025-11-23 11:57:31 +02:00
parent 49189bc63e
commit 7f0fe1681b
No known key found for this signature in database
2 changed files with 42 additions and 42 deletions

View File

@ -8,7 +8,8 @@ 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 } from "preact"; import { HTMLInputTypeAttribute, TargetedEvent } from "preact";
import tree from "../services/tree";
interface Cell { interface Cell {
definitionAttr: FAttribute; definitionAttr: FAttribute;
@ -27,6 +28,12 @@ interface CellProps {
setCellToFocus(cell: Cell): void; setCellToFocus(cell: Cell): void;
} }
// TODO: Deduplicate
interface AttributeResult {
attributeId: string;
}
export default function PromotedAttributes() { export default function PromotedAttributes() {
const { note, componentId } = useNoteContext(); const { note, componentId } = useNoteContext();
const [ cells, setCells ] = useState<Cell[]>(); const [ cells, setCells ] = useState<Cell[]>();
@ -130,15 +137,13 @@ const LABEL_MAPPINGS: Record<LabelType, HTMLInputTypeAttribute> = {
function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) { function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
const { valueAttr, definition, definitionAttr } = props.cell; const { valueAttr, definition, definitionAttr } = props.cell;
const onChangeListener = buildPromotedAttributeChangedListener({...props});
useEffect(() => { useEffect(() => {
if (definition.labelType === "text") { if (definition.labelType === "text") {
const el = document.getElementById(inputId); const el = document.getElementById(inputId);
if (el) { if (el) {
setupTextLabelAutocomplete(el as HTMLInputElement, valueAttr, () => { setupTextLabelAutocomplete(el as HTMLInputElement, valueAttr, onChangeListener);
// TODO: Implement me.
console.log("Got change");
});
} }
} }
}, []); }, []);
@ -154,6 +159,7 @@ function LabelInput({ inputId, ...props }: CellProps & { inputId: string }) {
data-attribute-id={valueAttr.attributeId} data-attribute-id={valueAttr.attributeId}
data-attribute-type={valueAttr.type} data-attribute-type={valueAttr.type}
data-attribute-name={valueAttr.name} 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<HTMLInputElement, Event>) {
// no need to await for this, can be done asynchronously // no need to await for this, can be done asynchronously
const $input = $(el); const $input = $(el);
server.get<string[]>(`attribute-values/${encodeURIComponent(valueAttr.name)}`).then((_attributeValues) => { server.get<string[]>(`attribute-values/${encodeURIComponent(valueAttr.name)}`).then((_attributeValues) => {
@ -278,3 +284,33 @@ function setupTextLabelAutocomplete(el: HTMLInputElement, valueAttr: Attribute,
$input.on("autocomplete:selected", onChangeListener); $input.on("autocomplete:selected", onChangeListener);
}); });
} }
function buildPromotedAttributeChangedListener({ note, cell, componentId }: CellProps) {
return async (e: TargetedEvent<HTMLInputElement, Event>) => {
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<AttributeResult>(
`notes/${note.noteId}/attribute`,
{
attributeId: cell.valueAttr.attributeId,
type: cell.valueAttr.type,
name: cell.valueName,
value: value
},
componentId
);
cell.valueAttr.attributeId = result.attributeId;
}
}

View File

@ -12,10 +12,6 @@ import type { Attribute } from "../services/attribute_parser.js";
import type FAttribute from "../entities/fattribute.js"; import type FAttribute from "../entities/fattribute.js";
import type { EventData } from "../components/app_context.js"; import type { EventData } from "../components/app_context.js";
// TODO: Deduplicate
interface AttributeResult {
attributeId: string;
}
export default class PromotedAttributesWidget extends NoteContextAwareWidget { export default class PromotedAttributesWidget extends NoteContextAwareWidget {
@ -44,9 +40,6 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget {
if (valueAttr.value === "true") { if (valueAttr.value === "true") {
$input.prop("checked", "checked"); $input.prop("checked", "checked");
} }
} else if (definition.labelType === "date") {
} else if (definition.labelType === "datetime") {
} else if (definition.labelType === "time") {
} else if (definition.labelType === "url") { } else if (definition.labelType === "url") {
$input.prop("placeholder", t("promoted_attributes.url_placeholder")); $input.prop("placeholder", t("promoted_attributes.url_placeholder"));
@ -114,35 +107,6 @@ export default class PromotedAttributesWidget extends NoteContextAwareWidget {
return $wrapper; return $wrapper;
} }
async promotedAttributeChanged(event: JQuery.TriggeredEvent<HTMLElement, undefined, HTMLElement, HTMLElement>) {
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<AttributeResult>(
`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() { focus() {
this.$widget.find(".promoted-attribute-input:first").focus(); this.$widget.find(".promoted-attribute-input:first").focus();
} }