fix(react/settings): etapi list not always reacting to changes

This commit is contained in:
Elian Doran 2025-08-15 12:11:40 +03:00
parent c9dcbef014
commit 1f8aa90482
No known key found for this signature in database
3 changed files with 40 additions and 36 deletions

View File

@ -35,8 +35,10 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
loadResults.addOption(attributeEntity.name);
} else if (ec.entityName === "attachments") {
processAttachment(loadResults, ec);
} else if (ec.entityName === "blobs" || ec.entityName === "etapi_tokens") {
} else if (ec.entityName === "blobs") {
// NOOP - these entities are handled at the backend level and don't require frontend processing
} else if (ec.entityName === "etapi_tokens") {
loadResults.hasEtapiTokenChanges = true;
} else {
throw new Error(`Unknown entityName '${ec.entityName}'`);
}
@ -77,9 +79,7 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
noteAttributeCache.invalidate();
}
// TODO: Remove after porting the file
// @ts-ignore
const appContext = (await import("../components/app_context.js")).default as any;
const appContext = (await import("../components/app_context.js")).default;
await appContext.triggerEvent("entitiesReloaded", { loadResults });
}
}

View File

@ -1,4 +1,4 @@
import type { AttachmentRow } from "@triliumnext/commons";
import type { AttachmentRow, EtapiTokenRow } from "@triliumnext/commons";
import type { AttributeType } from "../entities/fattribute.js";
import type { EntityChange } from "../server_types.js";
@ -53,6 +53,7 @@ type EntityRowMappings = {
options: OptionRow;
revisions: RevisionRow;
note_reordering: NoteReorderingRow;
etapi_tokens: EtapiTokenRow;
};
export type EntityRowNames = keyof EntityRowMappings;
@ -68,6 +69,7 @@ export default class LoadResults {
private contentNoteIdToComponentId: ContentNoteIdToComponentIdRow[];
private optionNames: string[];
private attachmentRows: AttachmentRow[];
public hasEtapiTokenChanges: boolean = false;
constructor(entityChanges: EntityChange[]) {
const entities: Record<string, Record<string, any>> = {};
@ -215,7 +217,8 @@ export default class LoadResults {
this.revisionRows.length === 0 &&
this.contentNoteIdToComponentId.length === 0 &&
this.optionNames.length === 0 &&
this.attachmentRows.length === 0
this.attachmentRows.length === 0 &&
!this.hasEtapiTokenChanges
);
}

View File

@ -10,6 +10,7 @@ import toast from "../../../services/toast";
import dialog from "../../../services/dialog";
import { formatDateTime } from "../../../utils/formatters";
import ActionButton from "../../react/ActionButton";
import useTriliumEvent from "../../react/hooks";
type RenameTokenCallback = (tokenId: string, oldName: string) => Promise<void>;
type DeleteTokenCallback = (tokenId: string, name: string ) => Promise<void>;
@ -22,6 +23,11 @@ export default function EtapiSettings() {
}
useEffect(refreshTokens, []);
useTriliumEvent("entitiesReloaded", ({loadResults}) => {
if (loadResults.hasEtapiTokenChanges) {
refreshTokens();
}
});
const createTokenCallback = useCallback(async () => {
const tokenName = await dialog.prompt({
@ -42,34 +48,7 @@ export default function EtapiSettings() {
message: t("etapi.token_created_message"),
defaultValue: authToken
});
refreshTokens();
}, []);
const renameTokenCallback = useCallback<RenameTokenCallback>(async (tokenId: string, oldName: string) => {
const tokenName = await dialog.prompt({
title: t("etapi.rename_token_title"),
message: t("etapi.rename_token_message"),
defaultValue: oldName
});
if (!tokenName?.trim()) {
return;
}
await server.patch(`etapi-tokens/${tokenId}`, { name: tokenName });
refreshTokens();
}, []);
const deleteTokenCallback = useCallback<DeleteTokenCallback>(async (tokenId: string, name: string) => {
if (!(await dialog.confirm(t("etapi.delete_token_confirmation", { name })))) {
return;
}
await server.remove(`etapi-tokens/${tokenId}`);
refreshTokens();
}, []);
}, []);
return (
<OptionsSection title={t("etapi.title")}>
@ -92,15 +71,37 @@ export default function EtapiSettings() {
<hr />
<h5>{t("etapi.existing_tokens")}</h5>
<TokenList tokens={tokens} renameCallback={renameTokenCallback} deleteCallback={deleteTokenCallback} />
<TokenList tokens={tokens} />
</OptionsSection>
)
}
function TokenList({ tokens, renameCallback, deleteCallback }: { tokens: EtapiToken[], renameCallback: RenameTokenCallback, deleteCallback: DeleteTokenCallback }) {
function TokenList({ tokens }: { tokens: EtapiToken[] }) {
if (!tokens.length) {
return <div>{t("etapi.no_tokens_yet")}</div>;
}
const renameCallback = useCallback<RenameTokenCallback>(async (tokenId: string, oldName: string) => {
const tokenName = await dialog.prompt({
title: t("etapi.rename_token_title"),
message: t("etapi.rename_token_message"),
defaultValue: oldName
});
if (!tokenName?.trim()) {
return;
}
await server.patch(`etapi-tokens/${tokenId}`, { name: tokenName });
}, []);
const deleteCallback = useCallback<DeleteTokenCallback>(async (tokenId: string, name: string) => {
if (!(await dialog.confirm(t("etapi.delete_token_confirmation", { name })))) {
return;
}
await server.remove(`etapi-tokens/${tokenId}`);
}, []);
return (
<div style={{ overflow: "auto", height: "500px"}}>