import { useState } from "preact/hooks";
import FNote from "../../entities/fnote";
import "./PromotedAttributesDisplay.css";
import { useTriliumEvent } from "../react/hooks";
import attributes from "../../services/attributes";
import { DefinitionObject } from "../../services/promoted_attribute_definition_parser";
import { formatDateTime } from "../../utils/formatters";
import { ComponentChildren } from "preact";
import Icon from "../react/Icon";
interface PromotedAttributesDisplayProps {
note: FNote;
ignoredAttributes?: string[];
}
interface AttributeWithDefinitions {
friendlyName: string;
name: string;
type: string;
value: string;
def: DefinitionObject;
}
export default function PromotedAttributesDisplay({ note, ignoredAttributes }: PromotedAttributesDisplayProps) {
const promotedDefinitionAttributes = useNoteAttributesWithDefinitions(note, ignoredAttributes);
return promotedDefinitionAttributes?.length > 0 && (
{promotedDefinitionAttributes?.map((attr) => {
return (
{formatLabelValue(attr)}
);
}
)}
)
}
function useNoteAttributesWithDefinitions(note: FNote, attributesToIgnore: string[] = []): AttributeWithDefinitions[] {
const [ promotedDefinitionAttributes, setPromotedDefinitionAttributes ] = useState(getAttributesWithDefinitions(note, attributesToIgnore));
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
if (loadResults.getAttributeRows().some(attr => attributes.isAffecting(attr, note))) {
setPromotedDefinitionAttributes(getAttributesWithDefinitions(note, attributesToIgnore));
}
});
return promotedDefinitionAttributes;
}
function formatLabelValue(attr: AttributeWithDefinitions): ComponentChildren {
let value = attr.value;
switch (attr.def.labelType) {
case "number":
let formattedValue = value;
const numberValue = Number(value);
if (attr.def.numberPrecision) {
formattedValue = numberValue.toFixed(attr.def.numberPrecision);
}
return <>{attr.friendlyName}: {formattedValue}>;
case "date":
case "datetime": {
const date = new Date(value);
const timeFormat = attr.def.labelType !== "date" ? "short" : "none";
return <>{attr.friendlyName}: {formatDateTime(date, "short", timeFormat)}>;
}
case "time": {
const date = new Date(`1970-01-01T${value}Z`);
return <>{attr.friendlyName}: {formatDateTime(date, "none", "short")}>;
}
case "boolean":
return <> {attr.friendlyName}>;
case "text":
default:
return <>{attr.friendlyName}: {value}>;
}
}
function getAttributesWithDefinitions(note: FNote, attributesToIgnore: string[] = []): AttributeWithDefinitions[] {
const promotedDefinitionAttributes = note.getPromotedDefinitionAttributes();
const result: AttributeWithDefinitions[] = [];
for (const attr of promotedDefinitionAttributes) {
const def = attr.getDefinition();
const [ type, name ] = attr.name.split(":", 2);
const value = note.getLabelValue(name);
const friendlyName = def?.promotedAlias || name;
if (!value) continue;
if (attributesToIgnore.includes(name)) continue;
result.push({ def, name, type, value, friendlyName });
}
return result;
}