mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-03 20:06:08 +01:00 
			
		
		
		
	fix(react/settings): etapi list not always reacting to changes
This commit is contained in:
		@@ -35,8 +35,10 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
 | 
				
			|||||||
                loadResults.addOption(attributeEntity.name);
 | 
					                loadResults.addOption(attributeEntity.name);
 | 
				
			||||||
            } else if (ec.entityName === "attachments") {
 | 
					            } else if (ec.entityName === "attachments") {
 | 
				
			||||||
                processAttachment(loadResults, ec);
 | 
					                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
 | 
					                // 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 {
 | 
					            } else {
 | 
				
			||||||
                throw new Error(`Unknown entityName '${ec.entityName}'`);
 | 
					                throw new Error(`Unknown entityName '${ec.entityName}'`);
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
@@ -77,9 +79,7 @@ async function processEntityChanges(entityChanges: EntityChange[]) {
 | 
				
			|||||||
            noteAttributeCache.invalidate();
 | 
					            noteAttributeCache.invalidate();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // TODO: Remove after porting the file
 | 
					        const appContext = (await import("../components/app_context.js")).default;
 | 
				
			||||||
        // @ts-ignore
 | 
					 | 
				
			||||||
        const appContext = (await import("../components/app_context.js")).default as any;
 | 
					 | 
				
			||||||
        await appContext.triggerEvent("entitiesReloaded", { loadResults });
 | 
					        await appContext.triggerEvent("entitiesReloaded", { loadResults });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -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 { AttributeType } from "../entities/fattribute.js";
 | 
				
			||||||
import type { EntityChange } from "../server_types.js";
 | 
					import type { EntityChange } from "../server_types.js";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -53,6 +53,7 @@ type EntityRowMappings = {
 | 
				
			|||||||
    options: OptionRow;
 | 
					    options: OptionRow;
 | 
				
			||||||
    revisions: RevisionRow;
 | 
					    revisions: RevisionRow;
 | 
				
			||||||
    note_reordering: NoteReorderingRow;
 | 
					    note_reordering: NoteReorderingRow;
 | 
				
			||||||
 | 
					    etapi_tokens: EtapiTokenRow;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export type EntityRowNames = keyof EntityRowMappings;
 | 
					export type EntityRowNames = keyof EntityRowMappings;
 | 
				
			||||||
@@ -68,6 +69,7 @@ export default class LoadResults {
 | 
				
			|||||||
    private contentNoteIdToComponentId: ContentNoteIdToComponentIdRow[];
 | 
					    private contentNoteIdToComponentId: ContentNoteIdToComponentIdRow[];
 | 
				
			||||||
    private optionNames: string[];
 | 
					    private optionNames: string[];
 | 
				
			||||||
    private attachmentRows: AttachmentRow[];
 | 
					    private attachmentRows: AttachmentRow[];
 | 
				
			||||||
 | 
					    public hasEtapiTokenChanges: boolean = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    constructor(entityChanges: EntityChange[]) {
 | 
					    constructor(entityChanges: EntityChange[]) {
 | 
				
			||||||
        const entities: Record<string, Record<string, any>> = {};
 | 
					        const entities: Record<string, Record<string, any>> = {};
 | 
				
			||||||
@@ -215,7 +217,8 @@ export default class LoadResults {
 | 
				
			|||||||
            this.revisionRows.length === 0 &&
 | 
					            this.revisionRows.length === 0 &&
 | 
				
			||||||
            this.contentNoteIdToComponentId.length === 0 &&
 | 
					            this.contentNoteIdToComponentId.length === 0 &&
 | 
				
			||||||
            this.optionNames.length === 0 &&
 | 
					            this.optionNames.length === 0 &&
 | 
				
			||||||
            this.attachmentRows.length === 0
 | 
					            this.attachmentRows.length === 0 &&
 | 
				
			||||||
 | 
					            !this.hasEtapiTokenChanges
 | 
				
			||||||
        );
 | 
					        );
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,6 +10,7 @@ import toast from "../../../services/toast";
 | 
				
			|||||||
import dialog from "../../../services/dialog";
 | 
					import dialog from "../../../services/dialog";
 | 
				
			||||||
import { formatDateTime } from "../../../utils/formatters";
 | 
					import { formatDateTime } from "../../../utils/formatters";
 | 
				
			||||||
import ActionButton from "../../react/ActionButton";
 | 
					import ActionButton from "../../react/ActionButton";
 | 
				
			||||||
 | 
					import useTriliumEvent from "../../react/hooks";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
type RenameTokenCallback = (tokenId: string, oldName: string) => Promise<void>;
 | 
					type RenameTokenCallback = (tokenId: string, oldName: string) => Promise<void>;
 | 
				
			||||||
type DeleteTokenCallback = (tokenId: string, name: string ) => Promise<void>;
 | 
					type DeleteTokenCallback = (tokenId: string, name: string ) => Promise<void>;
 | 
				
			||||||
@@ -22,6 +23,11 @@ export default function EtapiSettings() {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    useEffect(refreshTokens, []);
 | 
					    useEffect(refreshTokens, []);
 | 
				
			||||||
 | 
					    useTriliumEvent("entitiesReloaded", ({loadResults}) => {
 | 
				
			||||||
 | 
					        if (loadResults.hasEtapiTokenChanges) {
 | 
				
			||||||
 | 
					            refreshTokens();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const createTokenCallback = useCallback(async () => {
 | 
					    const createTokenCallback = useCallback(async () => {
 | 
				
			||||||
        const tokenName = await dialog.prompt({
 | 
					        const tokenName = await dialog.prompt({
 | 
				
			||||||
@@ -42,33 +48,6 @@ export default function EtapiSettings() {
 | 
				
			|||||||
            message: t("etapi.token_created_message"),
 | 
					            message: t("etapi.token_created_message"),
 | 
				
			||||||
            defaultValue: authToken
 | 
					            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 (
 | 
					    return (
 | 
				
			||||||
@@ -92,16 +71,38 @@ export default function EtapiSettings() {
 | 
				
			|||||||
            <hr />
 | 
					            <hr />
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            <h5>{t("etapi.existing_tokens")}</h5>
 | 
					            <h5>{t("etapi.existing_tokens")}</h5>
 | 
				
			||||||
            <TokenList tokens={tokens} renameCallback={renameTokenCallback} deleteCallback={deleteTokenCallback} />
 | 
					            <TokenList tokens={tokens} />
 | 
				
			||||||
        </OptionsSection>
 | 
					        </OptionsSection>
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
function TokenList({ tokens, renameCallback, deleteCallback }: { tokens: EtapiToken[], renameCallback: RenameTokenCallback, deleteCallback: DeleteTokenCallback }) {
 | 
					function TokenList({ tokens }: { tokens: EtapiToken[] }) {
 | 
				
			||||||
    if (!tokens.length) {
 | 
					    if (!tokens.length) {
 | 
				
			||||||
        return <div>{t("etapi.no_tokens_yet")}</div>;
 | 
					        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 (
 | 
					    return (
 | 
				
			||||||
        <div style={{ overflow: "auto", height: "500px"}}>
 | 
					        <div style={{ overflow: "auto", height: "500px"}}>
 | 
				
			||||||
            <table className="table table-stripped">
 | 
					            <table className="table table-stripped">
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user