mirror of
				https://github.com/zadam/trilium.git
				synced 2025-11-04 13:39:01 +01:00 
			
		
		
		
	feat(react/dialogs): port import
This commit is contained in:
		
							parent
							
								
									90f9416524
								
							
						
					
					
						commit
						8d27a5aa39
					
				@ -1,180 +0,0 @@
 | 
			
		||||
import { escapeQuotes } from "../../services/utils.js";
 | 
			
		||||
import treeService from "../../services/tree.js";
 | 
			
		||||
import importService, { type UploadFilesOptions } from "../../services/import.js";
 | 
			
		||||
import options from "../../services/options.js";
 | 
			
		||||
import BasicWidget from "../basic_widget.js";
 | 
			
		||||
import { t } from "../../services/i18n.js";
 | 
			
		||||
import { Modal, Tooltip } from "bootstrap";
 | 
			
		||||
import type { EventData } from "../../components/app_context.js";
 | 
			
		||||
import { openDialog } from "../../services/dialog.js";
 | 
			
		||||
 | 
			
		||||
const TPL = /*html*/`
 | 
			
		||||
<div class="import-dialog modal fade mx-auto" tabindex="-1" role="dialog">
 | 
			
		||||
    <div class="modal-dialog modal-lg" role="document">
 | 
			
		||||
        <div class="modal-content">
 | 
			
		||||
            <div class="modal-header">
 | 
			
		||||
                <h5 class="modal-title">${t("import.importIntoNote")}</h5>
 | 
			
		||||
                <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="${t("import.close")}"></button>
 | 
			
		||||
            </div>
 | 
			
		||||
            <form class="import-form">
 | 
			
		||||
                <div class="modal-body">
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <label for="import-file-upload-input"><strong>${t("import.chooseImportFile")}</strong></label>
 | 
			
		||||
 | 
			
		||||
                        <label class="tn-file-input tn-input-field">
 | 
			
		||||
                            <input type="file" class="import-file-upload-input form-control-file" multiple />
 | 
			
		||||
                        </label>
 | 
			
		||||
 | 
			
		||||
                        <p>${t("import.importDescription")} <strong class="import-note-title"></strong>.
 | 
			
		||||
                    </div>
 | 
			
		||||
 | 
			
		||||
                    <div class="form-group">
 | 
			
		||||
                        <strong>${t("import.options")}:</strong>
 | 
			
		||||
 | 
			
		||||
                        <div class="checkbox">
 | 
			
		||||
                            <label class="tn-checkbox" data-bs-toggle="tooltip" title="${escapeQuotes(t("import.safeImportTooltip"))}">
 | 
			
		||||
                                <input class="safe-import-checkbox" value="1" type="checkbox" checked>
 | 
			
		||||
                                <span>${t("import.safeImport")}</span>
 | 
			
		||||
                            </label>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="checkbox">
 | 
			
		||||
                            <label class="tn-checkbox" data-bs-toggle="tooltip" title="${escapeQuotes(t("import.explodeArchivesTooltip"))}">
 | 
			
		||||
                                <input class="explode-archives-checkbox" value="1" type="checkbox" checked>
 | 
			
		||||
                                <span>${t("import.explodeArchives")}</span>
 | 
			
		||||
                            </label>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="checkbox">
 | 
			
		||||
                            <label class="tn-checkbox" data-bs-toggle="tooltip" title="${escapeQuotes(t("import.shrinkImagesTooltip"))}">
 | 
			
		||||
                                <input class="shrink-images-checkbox" value="1" type="checkbox" checked> <span>${t("import.shrinkImages")}</span>
 | 
			
		||||
                            </label>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="checkbox">
 | 
			
		||||
                            <label class="tn-checkbox">
 | 
			
		||||
                                <input class="text-imported-as-text-checkbox" value="1" type="checkbox" checked>
 | 
			
		||||
                                ${t("import.textImportedAsText")}
 | 
			
		||||
                            </label>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="checkbox">
 | 
			
		||||
                            <label class="tn-checkbox">
 | 
			
		||||
                                <input class="code-imported-as-code-checkbox" value="1" type="checkbox" checked> ${t("import.codeImportedAsCode")}
 | 
			
		||||
                            </label>
 | 
			
		||||
                        </div>
 | 
			
		||||
 | 
			
		||||
                        <div class="checkbox">
 | 
			
		||||
                            <label class="tn-checkbox">
 | 
			
		||||
                                <input class="replace-underscores-with-spaces-checkbox" value="1" type="checkbox" checked>
 | 
			
		||||
                                ${t("import.replaceUnderscoresWithSpaces")}
 | 
			
		||||
                            </label>
 | 
			
		||||
                        </div>
 | 
			
		||||
                    </div>
 | 
			
		||||
                </div>
 | 
			
		||||
                <div class="modal-footer">
 | 
			
		||||
                    <button class="import-button btn btn-primary">${t("import.import")}</button>
 | 
			
		||||
                </div>
 | 
			
		||||
            </form>
 | 
			
		||||
        </div>
 | 
			
		||||
    </div>
 | 
			
		||||
</div>`;
 | 
			
		||||
 | 
			
		||||
export default class ImportDialog extends BasicWidget {
 | 
			
		||||
 | 
			
		||||
    private parentNoteId: string | null;
 | 
			
		||||
 | 
			
		||||
    private $form!: JQuery<HTMLElement>;
 | 
			
		||||
    private $noteTitle!: JQuery<HTMLElement>;
 | 
			
		||||
    private $fileUploadInput!: JQuery<HTMLInputElement>;
 | 
			
		||||
    private $importButton!: JQuery<HTMLElement>;
 | 
			
		||||
    private $safeImportCheckbox!: JQuery<HTMLElement>;
 | 
			
		||||
    private $shrinkImagesCheckbox!: JQuery<HTMLElement>;
 | 
			
		||||
    private $textImportedAsTextCheckbox!: JQuery<HTMLElement>;
 | 
			
		||||
    private $codeImportedAsCodeCheckbox!: JQuery<HTMLElement>;
 | 
			
		||||
    private $explodeArchivesCheckbox!: JQuery<HTMLElement>;
 | 
			
		||||
    private $replaceUnderscoresWithSpacesCheckbox!: JQuery<HTMLElement>;
 | 
			
		||||
 | 
			
		||||
    constructor() {
 | 
			
		||||
        super();
 | 
			
		||||
 | 
			
		||||
        this.parentNoteId = null;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    doRender() {
 | 
			
		||||
        this.$widget = $(TPL);
 | 
			
		||||
        Modal.getOrCreateInstance(this.$widget[0]);
 | 
			
		||||
 | 
			
		||||
        this.$form = this.$widget.find(".import-form");
 | 
			
		||||
        this.$noteTitle = this.$widget.find(".import-note-title");
 | 
			
		||||
        this.$fileUploadInput = this.$widget.find(".import-file-upload-input");
 | 
			
		||||
        this.$importButton = this.$widget.find(".import-button");
 | 
			
		||||
        this.$safeImportCheckbox = this.$widget.find(".safe-import-checkbox");
 | 
			
		||||
        this.$shrinkImagesCheckbox = this.$widget.find(".shrink-images-checkbox");
 | 
			
		||||
        this.$textImportedAsTextCheckbox = this.$widget.find(".text-imported-as-text-checkbox");
 | 
			
		||||
        this.$codeImportedAsCodeCheckbox = this.$widget.find(".code-imported-as-code-checkbox");
 | 
			
		||||
        this.$explodeArchivesCheckbox = this.$widget.find(".explode-archives-checkbox");
 | 
			
		||||
        this.$replaceUnderscoresWithSpacesCheckbox = this.$widget.find(".replace-underscores-with-spaces-checkbox");
 | 
			
		||||
 | 
			
		||||
        this.$form.on("submit", () => {
 | 
			
		||||
            // disabling so that import is not triggered again.
 | 
			
		||||
            this.$importButton.attr("disabled", "disabled");
 | 
			
		||||
 | 
			
		||||
            if (this.parentNoteId) {
 | 
			
		||||
                this.importIntoNote(this.parentNoteId);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        this.$fileUploadInput.on("change", () => {
 | 
			
		||||
            if (this.$fileUploadInput.val()) {
 | 
			
		||||
                this.$importButton.removeAttr("disabled");
 | 
			
		||||
            } else {
 | 
			
		||||
                this.$importButton.attr("disabled", "disabled");
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        let _ = [...this.$widget.find('[data-bs-toggle="tooltip"]')].forEach((element) => {
 | 
			
		||||
            Tooltip.getOrCreateInstance(element, {
 | 
			
		||||
                html: true
 | 
			
		||||
            });
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async showImportDialogEvent({ noteId }: EventData<"showImportDialog">) {
 | 
			
		||||
        this.parentNoteId = noteId;
 | 
			
		||||
 | 
			
		||||
        this.$fileUploadInput.val("").trigger("change"); // to trigger Import button disabling listener below
 | 
			
		||||
 | 
			
		||||
        this.$safeImportCheckbox.prop("checked", true);
 | 
			
		||||
        this.$shrinkImagesCheckbox.prop("checked", options.is("compressImages"));
 | 
			
		||||
        this.$textImportedAsTextCheckbox.prop("checked", true);
 | 
			
		||||
        this.$codeImportedAsCodeCheckbox.prop("checked", true);
 | 
			
		||||
        this.$explodeArchivesCheckbox.prop("checked", true);
 | 
			
		||||
        this.$replaceUnderscoresWithSpacesCheckbox.prop("checked", true);
 | 
			
		||||
 | 
			
		||||
        this.$noteTitle.text(await treeService.getNoteTitle(this.parentNoteId));
 | 
			
		||||
 | 
			
		||||
        openDialog(this.$widget);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async importIntoNote(parentNoteId: string) {
 | 
			
		||||
        const files = Array.from(this.$fileUploadInput[0].files ?? []); // shallow copy since we're resetting the upload button below
 | 
			
		||||
 | 
			
		||||
        const boolToString = ($el: JQuery<HTMLElement>) => ($el.is(":checked") ? "true" : "false");
 | 
			
		||||
 | 
			
		||||
        const options: UploadFilesOptions = {
 | 
			
		||||
            safeImport: boolToString(this.$safeImportCheckbox),
 | 
			
		||||
            shrinkImages: boolToString(this.$shrinkImagesCheckbox),
 | 
			
		||||
            textImportedAsText: boolToString(this.$textImportedAsTextCheckbox),
 | 
			
		||||
            codeImportedAsCode: boolToString(this.$codeImportedAsCodeCheckbox),
 | 
			
		||||
            explodeArchives: boolToString(this.$explodeArchivesCheckbox),
 | 
			
		||||
            replaceUnderscoresWithSpaces: boolToString(this.$replaceUnderscoresWithSpacesCheckbox)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        this.$widget.modal("hide");
 | 
			
		||||
 | 
			
		||||
        await importService.uploadFiles("notes", parentNoteId, files, options);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								apps/client/src/widgets/dialogs/import.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								apps/client/src/widgets/dialogs/import.tsx
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
import { useState } from "preact/hooks";
 | 
			
		||||
import { EventData } from "../../components/app_context";
 | 
			
		||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
 | 
			
		||||
import { t } from "../../services/i18n";
 | 
			
		||||
import tree from "../../services/tree";
 | 
			
		||||
import Button from "../react/Button";
 | 
			
		||||
import FormCheckbox from "../react/FormCheckbox";
 | 
			
		||||
import FormFileUpload from "../react/FormFileUpload";
 | 
			
		||||
import FormGroup from "../react/FormGroup";
 | 
			
		||||
import Modal from "../react/Modal";
 | 
			
		||||
import RawHtml from "../react/RawHtml";
 | 
			
		||||
import ReactBasicWidget from "../react/ReactBasicWidget";
 | 
			
		||||
import importService, { UploadFilesOptions } from "../../services/import";
 | 
			
		||||
 | 
			
		||||
interface ImportDialogComponentProps {
 | 
			
		||||
    parentNoteId?: string;
 | 
			
		||||
    noteTitle?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function ImportDialogComponent({  parentNoteId, noteTitle }: ImportDialogComponentProps) {
 | 
			
		||||
    const [ files, setFiles ] = useState<FileList | null>(null);
 | 
			
		||||
    const [ safeImport, setSafeImport ] = useState(true);
 | 
			
		||||
    const [ explodeArchives, setExplodeArchives ] = useState(true);
 | 
			
		||||
    const [ shrinkImages, setShrinkImages ] = useState(true);
 | 
			
		||||
    const [ textImportedAsText, setTextImportedAsText ] = useState(true);
 | 
			
		||||
    const [ codeImportedAsCode, setCodeImportedAsCode ] = useState(true);
 | 
			
		||||
    const [ replaceUnderscoresWithSpaces, setReplaceUnderscoresWithSpaces ] = useState(true);
 | 
			
		||||
 | 
			
		||||
    return (parentNoteId &&
 | 
			
		||||
        <Modal
 | 
			
		||||
            className="import-dialog"
 | 
			
		||||
            size="lg"
 | 
			
		||||
            title={t("import.importIntoNote")}
 | 
			
		||||
            onSubmit={async () => {
 | 
			
		||||
                if (!files) {
 | 
			
		||||
                    return;
 | 
			
		||||
                }                
 | 
			
		||||
 | 
			
		||||
                const options: UploadFilesOptions = {
 | 
			
		||||
                    safeImport: boolToString(safeImport),
 | 
			
		||||
                    shrinkImages: boolToString(shrinkImages),
 | 
			
		||||
                    textImportedAsText: boolToString(textImportedAsText),
 | 
			
		||||
                    codeImportedAsCode: boolToString(codeImportedAsCode),
 | 
			
		||||
                    explodeArchives: boolToString(explodeArchives),
 | 
			
		||||
                    replaceUnderscoresWithSpaces: boolToString(replaceUnderscoresWithSpaces)
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                closeActiveDialog();
 | 
			
		||||
                await importService.uploadFiles("notes", parentNoteId, Array.from(files), options);
 | 
			
		||||
            }}
 | 
			
		||||
            footer={<Button text={t("import.import")} primary disabled={!files} />}
 | 
			
		||||
        >
 | 
			
		||||
            <FormGroup label={t("import.chooseImportFile")} description={<>{t("import.importDescription")} <strong>{ noteTitle }</strong></>}>
 | 
			
		||||
                <FormFileUpload multiple onChange={setFiles} />
 | 
			
		||||
            </FormGroup>
 | 
			
		||||
 | 
			
		||||
            <FormGroup label={t("import.options")}>
 | 
			
		||||
                <FormCheckbox
 | 
			
		||||
                    name="safe-import" hint={t("import.safeImportTooltip")} label={t("import.safeImport")}
 | 
			
		||||
                    currentValue={safeImport} onChange={setSafeImport}
 | 
			
		||||
                />
 | 
			
		||||
                <FormCheckbox
 | 
			
		||||
                    name="explode-archives" hint={t("import.explodeArchivesTooltip")} label={<RawHtml html={t("import.explodeArchives")} />}
 | 
			
		||||
                    currentValue={explodeArchives} onChange={setExplodeArchives}
 | 
			
		||||
                />
 | 
			
		||||
                <FormCheckbox
 | 
			
		||||
                    name="shrink-images" hint={t("import.shrinkImagesTooltip")} label={t("import.shrinkImages")}
 | 
			
		||||
                    currentValue={shrinkImages} onChange={setShrinkImages}
 | 
			
		||||
                />
 | 
			
		||||
                <FormCheckbox
 | 
			
		||||
                    name="text-imported-as-text" label={t("import.textImportedAsText")}
 | 
			
		||||
                    currentValue={textImportedAsText} onChange={setTextImportedAsText}
 | 
			
		||||
                />
 | 
			
		||||
                <FormCheckbox
 | 
			
		||||
                    name="code-imported-as-code" label={<RawHtml html={t("import.codeImportedAsCode")} />}
 | 
			
		||||
                    currentValue={codeImportedAsCode} onChange={setCodeImportedAsCode}
 | 
			
		||||
                />
 | 
			
		||||
                <FormCheckbox
 | 
			
		||||
                    name="replace-underscores-with-spaces" label={t("import.replaceUnderscoresWithSpaces")} 
 | 
			
		||||
                    currentValue={replaceUnderscoresWithSpaces} onChange={setReplaceUnderscoresWithSpaces}
 | 
			
		||||
                />
 | 
			
		||||
            </FormGroup>
 | 
			
		||||
        </Modal>
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default class ImportDialog extends ReactBasicWidget {
 | 
			
		||||
 | 
			
		||||
    private props?: ImportDialogComponentProps = {};
 | 
			
		||||
 | 
			
		||||
    get component() {
 | 
			
		||||
        return <ImportDialogComponent {...this.props} />
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async showImportDialogEvent({ noteId }: EventData<"showImportDialog">) {
 | 
			
		||||
        this.props = {
 | 
			
		||||
            parentNoteId: noteId,
 | 
			
		||||
            noteTitle: await tree.getNoteTitle(noteId)
 | 
			
		||||
        }
 | 
			
		||||
        this.doRender();
 | 
			
		||||
 | 
			
		||||
        openDialog(this.$widget);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function boolToString(value: boolean) {
 | 
			
		||||
    return value ? "true" : "false";
 | 
			
		||||
}
 | 
			
		||||
@ -1,10 +1,11 @@
 | 
			
		||||
import { Tooltip } from "bootstrap";
 | 
			
		||||
import { useEffect, useRef } from "preact/compat";
 | 
			
		||||
import { escapeQuotes } from "../../services/utils";
 | 
			
		||||
import { ComponentChildren } from "preact";
 | 
			
		||||
 | 
			
		||||
interface FormCheckboxProps {
 | 
			
		||||
    name: string;
 | 
			
		||||
    label: string;
 | 
			
		||||
    label: string | ComponentChildren;
 | 
			
		||||
    /**
 | 
			
		||||
     * If set, the checkbox label will be underlined and dotted, indicating a hint. When hovered, it will show the hint text.
 | 
			
		||||
     */
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ interface FormGroupProps {
 | 
			
		||||
    title?: string;
 | 
			
		||||
    className?: string;
 | 
			
		||||
    children: ComponentChildren;
 | 
			
		||||
    description?: string;
 | 
			
		||||
    description?: string | ComponentChildren;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function FormGroup({ label, title, className, children, description, labelRef }: FormGroupProps) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user