mirror of
https://github.com/zadam/trilium.git
synced 2025-10-21 15:49:00 +02:00
refactor(react/dialogs): integrate self-triggering modal in more dialogs
This commit is contained in:
parent
cd5467bf5c
commit
fa97ec6c72
@ -1,4 +1,3 @@
|
|||||||
import { openDialog } from "../../services/dialog.js";
|
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
||||||
import Modal from "../react/Modal.js";
|
import Modal from "../react/Modal.js";
|
||||||
import { t } from "../../services/i18n.js";
|
import { t } from "../../services/i18n.js";
|
||||||
@ -9,19 +8,26 @@ import openService from "../../services/open.js";
|
|||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import type { CSSProperties } from "preact/compat";
|
import type { CSSProperties } from "preact/compat";
|
||||||
import type { AppInfo } from "@triliumnext/commons";
|
import type { AppInfo } from "@triliumnext/commons";
|
||||||
|
import useTriliumEvent from "../react/hooks.jsx";
|
||||||
|
|
||||||
function AboutDialogComponent() {
|
function AboutDialogComponent() {
|
||||||
let [appInfo, setAppInfo] = useState<AppInfo | null>(null);
|
let [appInfo, setAppInfo] = useState<AppInfo | null>(null);
|
||||||
|
let [shown, setShown] = useState(false);
|
||||||
async function onShown() {
|
|
||||||
const appInfo = await server.get<AppInfo>("app-info");
|
|
||||||
setAppInfo(appInfo);
|
|
||||||
}
|
|
||||||
|
|
||||||
const forceWordBreak: CSSProperties = { wordBreak: "break-all" };
|
const forceWordBreak: CSSProperties = { wordBreak: "break-all" };
|
||||||
|
|
||||||
|
useTriliumEvent("openAboutDialog", () => setShown(true));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal className="about-dialog" size="lg" title={t("about.title")} onShown={onShown}>
|
<Modal className="about-dialog"
|
||||||
|
size="lg"
|
||||||
|
title={t("about.title")}
|
||||||
|
show={shown}
|
||||||
|
onShown={async () => {
|
||||||
|
const appInfo = await server.get<AppInfo>("app-info");
|
||||||
|
setAppInfo(appInfo);
|
||||||
|
}}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
>
|
||||||
<table className="table table-borderless">
|
<table className="table table-borderless">
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
@ -83,7 +89,4 @@ export default class AboutDialog extends ReactBasicWidget {
|
|||||||
return <AboutDialogComponent />;
|
return <AboutDialogComponent />;
|
||||||
}
|
}
|
||||||
|
|
||||||
async openAboutDialogEvent() {
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,5 +1,4 @@
|
|||||||
import { EventData } from "../../components/app_context";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import Modal from "../react/Modal";
|
import Modal from "../react/Modal";
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
@ -10,24 +9,28 @@ import { useRef, useState } from "preact/hooks";
|
|||||||
import tree from "../../services/tree";
|
import tree from "../../services/tree";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import note_autocomplete, { Suggestion } from "../../services/note_autocomplete";
|
import note_autocomplete, { Suggestion } from "../../services/note_autocomplete";
|
||||||
import type { default as TextTypeWidget } from "../type_widgets/editable_text.js";
|
import { default as TextTypeWidget } from "../type_widgets/editable_text.js";
|
||||||
import { logError } from "../../services/ws";
|
import { logError } from "../../services/ws";
|
||||||
import FormGroup from "../react/FormGroup.js";
|
import FormGroup from "../react/FormGroup.js";
|
||||||
import { refToJQuerySelector } from "../react/react_utils";
|
import { refToJQuerySelector } from "../react/react_utils";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
type LinkType = "reference-link" | "external-link" | "hyper-link";
|
type LinkType = "reference-link" | "external-link" | "hyper-link";
|
||||||
|
|
||||||
interface AddLinkDialogProps {
|
function AddLinkDialogComponent() {
|
||||||
text?: string;
|
const [ textTypeWidget, setTextTypeWidget ] = useState<TextTypeWidget>();
|
||||||
textTypeWidget?: TextTypeWidget;
|
const [ text, setText ] = useState<string>();
|
||||||
}
|
|
||||||
|
|
||||||
function AddLinkDialogComponent({ text: _text, textTypeWidget }: AddLinkDialogProps) {
|
|
||||||
const [ text, setText ] = useState(_text ?? "");
|
|
||||||
const [ linkTitle, setLinkTitle ] = useState("");
|
const [ linkTitle, setLinkTitle ] = useState("");
|
||||||
const hasSelection = textTypeWidget?.hasSelection();
|
const hasSelection = textTypeWidget?.hasSelection();
|
||||||
const [ linkType, setLinkType ] = useState<LinkType>(hasSelection ? "hyper-link" : "reference-link");
|
const [ linkType, setLinkType ] = useState<LinkType>(hasSelection ? "hyper-link" : "reference-link");
|
||||||
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
|
|
||||||
|
useTriliumEvent("showAddLinkDialog", ( { textTypeWidget, text }) => {
|
||||||
|
setTextTypeWidget(textTypeWidget);
|
||||||
|
setText(text);
|
||||||
|
setShown(true);
|
||||||
|
});
|
||||||
|
|
||||||
async function setDefaultLinkTitle(noteId: string) {
|
async function setDefaultLinkTitle(noteId: string) {
|
||||||
const noteTitle = await tree.getNoteTitle(noteId);
|
const noteTitle = await tree.getNoteTitle(noteId);
|
||||||
@ -100,7 +103,11 @@ function AddLinkDialogComponent({ text: _text, textTypeWidget }: AddLinkDialogPr
|
|||||||
footer={<Button text={t("add_link.button_add_link")} keyboardShortcut="Enter" />}
|
footer={<Button text={t("add_link.button_add_link")} keyboardShortcut="Enter" />}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
onShown={onShown}
|
onShown={onShown}
|
||||||
onHidden={() => setSuggestion(null)}
|
onHidden={() => {
|
||||||
|
setSuggestion(null);
|
||||||
|
setShown(false);
|
||||||
|
}}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<FormGroup label={t("add_link.note")}>
|
<FormGroup label={t("add_link.note")}>
|
||||||
<NoteAutocomplete
|
<NoteAutocomplete
|
||||||
@ -151,17 +158,8 @@ function AddLinkDialogComponent({ text: _text, textTypeWidget }: AddLinkDialogPr
|
|||||||
|
|
||||||
export default class AddLinkDialog extends ReactBasicWidget {
|
export default class AddLinkDialog extends ReactBasicWidget {
|
||||||
|
|
||||||
private props: AddLinkDialogProps = {};
|
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return <AddLinkDialogComponent {...this.props} />;
|
return <AddLinkDialogComponent />;
|
||||||
}
|
|
||||||
|
|
||||||
async showAddLinkDialogEvent({ textTypeWidget, text = "" }: EventData<"showAddLinkDialog">) {
|
|
||||||
this.props.text = text;
|
|
||||||
this.props.textTypeWidget = textTypeWidget;
|
|
||||||
this.doRender();
|
|
||||||
await openDialog(this.$widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import { EventData } from "../../components/app_context";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import Modal from "../react/Modal";
|
import Modal from "../react/Modal";
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
@ -12,50 +11,52 @@ import Button from "../react/Button";
|
|||||||
import bulk_action from "../../services/bulk_action";
|
import bulk_action from "../../services/bulk_action";
|
||||||
import toast from "../../services/toast";
|
import toast from "../../services/toast";
|
||||||
import RenameNoteBulkAction from "../bulk_actions/note/rename_note";
|
import RenameNoteBulkAction from "../bulk_actions/note/rename_note";
|
||||||
import { RawHtmlBlock } from "../react/RawHtml";
|
|
||||||
import FNote from "../../entities/fnote";
|
import FNote from "../../entities/fnote";
|
||||||
import froca from "../../services/froca";
|
import froca from "../../services/froca";
|
||||||
import useTriliumEvent from "../react/hooks";
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
interface BulkActionProps {
|
function BulkActionComponent() {
|
||||||
bulkActionNote?: FNote | null;
|
const [ selectedOrActiveNoteIds, setSelectedOrActiveNoteIds ] = useState<string[]>();
|
||||||
selectedOrActiveNoteIds?: string[];
|
const [ bulkActionNote, setBulkActionNote ] = useState<FNote | null>();
|
||||||
}
|
|
||||||
|
|
||||||
function BulkActionComponent({ selectedOrActiveNoteIds, bulkActionNote }: BulkActionProps) {
|
|
||||||
const [ includeDescendants, setIncludeDescendants ] = useState(false);
|
const [ includeDescendants, setIncludeDescendants ] = useState(false);
|
||||||
const [ affectedNoteCount, setAffectedNoteCount ] = useState(0);
|
const [ affectedNoteCount, setAffectedNoteCount ] = useState(0);
|
||||||
const [ existingActions, setExistingActions ] = useState<RenameNoteBulkAction[]>([]);
|
const [ existingActions, setExistingActions ] = useState<RenameNoteBulkAction[]>([]);
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
|
|
||||||
if (!selectedOrActiveNoteIds || !bulkActionNote) {
|
useTriliumEvent("openBulkActionsDialog", async ({ selectedOrActiveNoteIds }) => {
|
||||||
return;
|
setSelectedOrActiveNoteIds(selectedOrActiveNoteIds);
|
||||||
}
|
setBulkActionNote(await froca.getNote("_bulkAction"));
|
||||||
|
setShown(true);
|
||||||
useEffect(() => {
|
|
||||||
server.post<BulkActionAffectedNotes>("bulk-action/affected-notes", {
|
|
||||||
noteIds: selectedOrActiveNoteIds,
|
|
||||||
includeDescendants
|
|
||||||
}).then(({ affectedNoteCount }) => setAffectedNoteCount(affectedNoteCount));
|
|
||||||
}, [ selectedOrActiveNoteIds, includeDescendants ]);
|
|
||||||
|
|
||||||
function refreshExistingActions() {
|
|
||||||
setExistingActions(bulk_action.parseActions(bulkActionNote!));
|
|
||||||
}
|
|
||||||
|
|
||||||
useEffect(() => refreshExistingActions(), []);
|
|
||||||
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
|
||||||
if (loadResults.getAttributeRows().find((row) =>
|
|
||||||
row.type === "label" && row.name === "action" && row.noteId === "_bulkAction")) {
|
|
||||||
refreshExistingActions();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
return ( selectedOrActiveNoteIds &&
|
if (selectedOrActiveNoteIds && bulkActionNote) {
|
||||||
|
useEffect(() => {
|
||||||
|
server.post<BulkActionAffectedNotes>("bulk-action/affected-notes", {
|
||||||
|
noteIds: selectedOrActiveNoteIds,
|
||||||
|
includeDescendants
|
||||||
|
}).then(({ affectedNoteCount }) => setAffectedNoteCount(affectedNoteCount));
|
||||||
|
}, [ selectedOrActiveNoteIds, includeDescendants ]);
|
||||||
|
|
||||||
|
function refreshExistingActions() {
|
||||||
|
setExistingActions(bulk_action.parseActions(bulkActionNote!));
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => refreshExistingActions(), []);
|
||||||
|
useTriliumEvent("entitiesReloaded", ({ loadResults }) => {
|
||||||
|
if (loadResults.getAttributeRows().find((row) =>
|
||||||
|
row.type === "label" && row.name === "action" && row.noteId === "_bulkAction")) {
|
||||||
|
refreshExistingActions();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className="bulk-actions-dialog"
|
className="bulk-actions-dialog"
|
||||||
size="xl"
|
size="xl"
|
||||||
title={t("bulk_actions.bulk_actions")}
|
title={t("bulk_actions.bulk_actions")}
|
||||||
footer={<Button text={t("bulk_actions.execute_bulk_actions")} primary />}
|
footer={<Button text={t("bulk_actions.execute_bulk_actions")} primary />}
|
||||||
|
show={shown}
|
||||||
onSubmit={async () => {
|
onSubmit={async () => {
|
||||||
await server.post("bulk-action/execute", {
|
await server.post("bulk-action/execute", {
|
||||||
noteIds: selectedOrActiveNoteIds,
|
noteIds: selectedOrActiveNoteIds,
|
||||||
@ -65,6 +66,7 @@ function BulkActionComponent({ selectedOrActiveNoteIds, bulkActionNote }: BulkAc
|
|||||||
toast.showMessage(t("bulk_actions.bulk_actions_executed"), 3000);
|
toast.showMessage(t("bulk_actions.bulk_actions_executed"), 3000);
|
||||||
closeActiveDialog();
|
closeActiveDialog();
|
||||||
}}
|
}}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
>
|
>
|
||||||
<h4>{t("bulk_actions.affected_notes")}: <span>{affectedNoteCount}</span></h4>
|
<h4>{t("bulk_actions.affected_notes")}: <span>{affectedNoteCount}</span></h4>
|
||||||
<FormCheckbox
|
<FormCheckbox
|
||||||
@ -114,19 +116,8 @@ function ExistingActionsList({ existingActions }: { existingActions?: RenameNote
|
|||||||
|
|
||||||
export default class BulkActionsDialog extends ReactBasicWidget {
|
export default class BulkActionsDialog extends ReactBasicWidget {
|
||||||
|
|
||||||
private props: BulkActionProps = {};
|
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return <BulkActionComponent {...this.props} />
|
return <BulkActionComponent />
|
||||||
}
|
|
||||||
|
|
||||||
async openBulkActionsDialogEvent({ selectedOrActiveNoteIds }: EventData<"openBulkActionsDialog">) {
|
|
||||||
this.props = {
|
|
||||||
selectedOrActiveNoteIds,
|
|
||||||
bulkActionNote: await froca.getNote("_bulkAction")
|
|
||||||
};
|
|
||||||
this.doRender();
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { useRef, useState } from "preact/compat";
|
import { useRef, useState } from "preact/compat";
|
||||||
import appContext, { EventData } from "../../components/app_context";
|
import appContext from "../../components/app_context";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import Modal from "../react/Modal";
|
import Modal from "../react/Modal";
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
@ -15,16 +15,32 @@ import tree from "../../services/tree";
|
|||||||
import branches from "../../services/branches";
|
import branches from "../../services/branches";
|
||||||
import toast from "../../services/toast";
|
import toast from "../../services/toast";
|
||||||
import NoteList from "../react/NoteList";
|
import NoteList from "../react/NoteList";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
interface CloneToDialogProps {
|
function CloneToDialogComponent() {
|
||||||
clonedNoteIds?: string[];
|
const [ clonedNoteIds, setClonedNoteIds ] = useState<string[]>();
|
||||||
}
|
|
||||||
|
|
||||||
function CloneToDialogComponent({ clonedNoteIds }: CloneToDialogProps) {
|
|
||||||
const [ prefix, setPrefix ] = useState("");
|
const [ prefix, setPrefix ] = useState("");
|
||||||
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
const autoCompleteRef = useRef<HTMLInputElement>(null);
|
const autoCompleteRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useTriliumEvent("cloneNoteIdsTo", ({ noteIds }) => {
|
||||||
|
if (!noteIds || noteIds.length === 0) {
|
||||||
|
noteIds = [appContext.tabManager.getActiveContextNoteId() ?? ""];
|
||||||
|
}
|
||||||
|
|
||||||
|
const clonedNoteIds: string[] = [];
|
||||||
|
|
||||||
|
for (const noteId of noteIds) {
|
||||||
|
if (!clonedNoteIds.includes(noteId)) {
|
||||||
|
clonedNoteIds.push(noteId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setClonedNoteIds(clonedNoteIds);
|
||||||
|
setShown(true);
|
||||||
|
});
|
||||||
|
|
||||||
function onSubmit() {
|
function onSubmit() {
|
||||||
if (!clonedNoteIds) {
|
if (!clonedNoteIds) {
|
||||||
return;
|
return;
|
||||||
@ -49,6 +65,8 @@ function CloneToDialogComponent({ clonedNoteIds }: CloneToDialogProps) {
|
|||||||
footer={<Button text={t("clone_to.clone_to_selected_note")} keyboardShortcut="Enter" />}
|
footer={<Button text={t("clone_to.clone_to_selected_note")} keyboardShortcut="Enter" />}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
onShown={() => triggerRecentNotes(autoCompleteRef.current)}
|
onShown={() => triggerRecentNotes(autoCompleteRef.current)}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<h5>{t("clone_to.notes_to_clone")}</h5>
|
<h5>{t("clone_to.notes_to_clone")}</h5>
|
||||||
<NoteList style={{ maxHeight: "200px", overflow: "auto" }} noteIds={clonedNoteIds} />
|
<NoteList style={{ maxHeight: "200px", overflow: "auto" }} noteIds={clonedNoteIds} />
|
||||||
@ -68,28 +86,8 @@ function CloneToDialogComponent({ clonedNoteIds }: CloneToDialogProps) {
|
|||||||
|
|
||||||
export default class CloneToDialog extends ReactBasicWidget {
|
export default class CloneToDialog extends ReactBasicWidget {
|
||||||
|
|
||||||
private props: CloneToDialogProps = {};
|
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return <CloneToDialogComponent {...this.props} />;
|
return <CloneToDialogComponent />;
|
||||||
}
|
|
||||||
|
|
||||||
async cloneNoteIdsToEvent({ noteIds }: EventData<"cloneNoteIdsTo">) {
|
|
||||||
if (!noteIds || noteIds.length === 0) {
|
|
||||||
noteIds = [appContext.tabManager.getActiveContextNoteId() ?? ""];
|
|
||||||
}
|
|
||||||
|
|
||||||
const clonedNoteIds: string[] = [];
|
|
||||||
|
|
||||||
for (const noteId of noteIds) {
|
|
||||||
if (!clonedNoteIds.includes(noteId)) {
|
|
||||||
clonedNoteIds.push(noteId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props = { clonedNoteIds };
|
|
||||||
this.doRender();
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { openDialog } from "../../services/dialog.js";
|
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
||||||
import Modal from "../react/Modal.jsx";
|
import Modal from "../react/Modal.jsx";
|
||||||
import { t } from "../../services/i18n.js";
|
import { t } from "../../services/i18n.js";
|
||||||
@ -7,10 +6,18 @@ import { CommandNames } from "../../components/app_context.js";
|
|||||||
import RawHtml from "../react/RawHtml.jsx";
|
import RawHtml from "../react/RawHtml.jsx";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import keyboard_actions from "../../services/keyboard_actions.js";
|
import keyboard_actions from "../../services/keyboard_actions.js";
|
||||||
|
import useTriliumEvent from "../react/hooks.jsx";
|
||||||
|
|
||||||
function HelpDialogComponent() {
|
function HelpDialogComponent() {
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
|
useTriliumEvent("showCheatsheet", () => setShown(true));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal title={t("help.title")} className="help-dialog use-tn-links" minWidth="90%" size="lg" scrollable>
|
<Modal
|
||||||
|
title={t("help.title")} className="help-dialog use-tn-links" minWidth="90%" size="lg" scrollable
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
|
>
|
||||||
<div className="help-cards row row-cols-md-3 g-3">
|
<div className="help-cards row row-cols-md-3 g-3">
|
||||||
<Card title={t("help.noteNavigation")}>
|
<Card title={t("help.noteNavigation")}>
|
||||||
<ul>
|
<ul>
|
||||||
@ -161,7 +168,4 @@ export default class HelpDialog extends ReactBasicWidget {
|
|||||||
return <HelpDialogComponent />;
|
return <HelpDialogComponent />;
|
||||||
}
|
}
|
||||||
|
|
||||||
showCheatsheetEvent() {
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,17 @@
|
|||||||
import { useRef } from "react";
|
import { useRef } from "react";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog.js";
|
import { closeActiveDialog } from "../../services/dialog.js";
|
||||||
import { t } from "../../services/i18n.js";
|
import { t } from "../../services/i18n.js";
|
||||||
import utils from "../../services/utils.js";
|
import utils from "../../services/utils.js";
|
||||||
import Button from "../react/Button.js";
|
import Button from "../react/Button.js";
|
||||||
import Modal from "../react/Modal.js";
|
import Modal from "../react/Modal.js";
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
import ReactBasicWidget from "../react/ReactBasicWidget.js";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
import useTriliumEvent from "../react/hooks.jsx";
|
||||||
|
|
||||||
function IncorrectCpuArchDialogComponent() {
|
function IncorrectCpuArchDialogComponent() {
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
const downloadButtonRef = useRef<HTMLButtonElement>(null);
|
const downloadButtonRef = useRef<HTMLButtonElement>(null);
|
||||||
|
useTriliumEvent("showCpuArchWarning", () => setShown(true));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@ -33,6 +37,8 @@ function IncorrectCpuArchDialogComponent() {
|
|||||||
<Button text={t("cpu_arch_warning.continue_anyway")}
|
<Button text={t("cpu_arch_warning.continue_anyway")}
|
||||||
onClick={() => closeActiveDialog()} />
|
onClick={() => closeActiveDialog()} />
|
||||||
</>}
|
</>}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<p>{utils.isMac() ? t("cpu_arch_warning.message_macos") : t("cpu_arch_warning.message_windows")}</p>
|
<p>{utils.isMac() ? t("cpu_arch_warning.message_macos") : t("cpu_arch_warning.message_windows")}</p>
|
||||||
<p>{t("cpu_arch_warning.recommendation")}</p>
|
<p>{t("cpu_arch_warning.recommendation")}</p>
|
||||||
@ -46,8 +52,4 @@ export default class IncorrectCpuArchDialog extends ReactBasicWidget {
|
|||||||
return <IncorrectCpuArchDialogComponent />
|
return <IncorrectCpuArchDialogComponent />
|
||||||
}
|
}
|
||||||
|
|
||||||
showCpuArchWarningEvent() {
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useRef, useState } from "preact/compat";
|
import { useCallback, useRef, useState } from "preact/compat";
|
||||||
import appContext from "../../components/app_context";
|
import appContext from "../../components/app_context";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import server from "../../services/server";
|
import server from "../../services/server";
|
||||||
import toast from "../../services/toast";
|
import toast from "../../services/toast";
|
||||||
@ -8,6 +8,7 @@ import utils from "../../services/utils";
|
|||||||
import Modal from "../react/Modal";
|
import Modal from "../react/Modal";
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
import Button from "../react/Button";
|
import Button from "../react/Button";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
interface RenderMarkdownResponse {
|
interface RenderMarkdownResponse {
|
||||||
htmlContent: string;
|
htmlContent: string;
|
||||||
@ -16,6 +17,25 @@ interface RenderMarkdownResponse {
|
|||||||
function MarkdownImportDialogComponent() {
|
function MarkdownImportDialogComponent() {
|
||||||
const markdownImportTextArea = useRef<HTMLTextAreaElement>(null);
|
const markdownImportTextArea = useRef<HTMLTextAreaElement>(null);
|
||||||
let [ text, setText ] = useState("");
|
let [ text, setText ] = useState("");
|
||||||
|
let [ shown, setShown ] = useState(false);
|
||||||
|
|
||||||
|
const triggerImport = useCallback(() => {
|
||||||
|
if (appContext.tabManager.getActiveContextNoteType() !== "text") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils.isElectron()) {
|
||||||
|
const { clipboard } = utils.dynamicRequire("electron");
|
||||||
|
const text = clipboard.readText();
|
||||||
|
|
||||||
|
convertMarkdownToHtml(text);
|
||||||
|
} else {
|
||||||
|
setShown(true);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useTriliumEvent("importMarkdownInline", triggerImport);
|
||||||
|
useTriliumEvent("pasteMarkdownIntoText", triggerImport);
|
||||||
|
|
||||||
async function sendForm() {
|
async function sendForm() {
|
||||||
await convertMarkdownToHtml(text);
|
await convertMarkdownToHtml(text);
|
||||||
@ -28,6 +48,8 @@ function MarkdownImportDialogComponent() {
|
|||||||
className="markdown-import-dialog" title={t("markdown_import.dialog_title")} size="lg"
|
className="markdown-import-dialog" title={t("markdown_import.dialog_title")} size="lg"
|
||||||
footer={<Button className="markdown-import-button" text={t("markdown_import.import_button")} onClick={sendForm} keyboardShortcut="Ctrl+Space" />}
|
footer={<Button className="markdown-import-button" text={t("markdown_import.import_button")} onClick={sendForm} keyboardShortcut="Ctrl+Space" />}
|
||||||
onShown={() => markdownImportTextArea.current?.focus()}
|
onShown={() => markdownImportTextArea.current?.focus()}
|
||||||
|
onHidden={() => setShown(false) }
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<p>{t("markdown_import.modal_body_text")}</p>
|
<p>{t("markdown_import.modal_body_text")}</p>
|
||||||
<textarea ref={markdownImportTextArea} value={text}
|
<textarea ref={markdownImportTextArea} value={text}
|
||||||
@ -49,26 +71,6 @@ export default class MarkdownImportDialog extends ReactBasicWidget {
|
|||||||
return <MarkdownImportDialogComponent />;
|
return <MarkdownImportDialogComponent />;
|
||||||
}
|
}
|
||||||
|
|
||||||
async importMarkdownInlineEvent() {
|
|
||||||
if (appContext.tabManager.getActiveContextNoteType() !== "text") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (utils.isElectron()) {
|
|
||||||
const { clipboard } = utils.dynamicRequire("electron");
|
|
||||||
const text = clipboard.readText();
|
|
||||||
|
|
||||||
convertMarkdownToHtml(text);
|
|
||||||
} else {
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async pasteMarkdownIntoTextEvent() {
|
|
||||||
// BC with keyboard shortcuts command
|
|
||||||
await this.importMarkdownInlineEvent();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function convertMarkdownToHtml(markdownContent: string) {
|
async function convertMarkdownToHtml(markdownContent: string) {
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
import Modal from "../react/Modal";
|
import Modal from "../react/Modal";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import { EventData } from "../../components/app_context";
|
|
||||||
import NoteList from "../react/NoteList";
|
import NoteList from "../react/NoteList";
|
||||||
import FormGroup from "../react/FormGroup";
|
import FormGroup from "../react/FormGroup";
|
||||||
import NoteAutocomplete from "../react/NoteAutocomplete";
|
import NoteAutocomplete from "../react/NoteAutocomplete";
|
||||||
@ -13,15 +12,19 @@ import tree from "../../services/tree";
|
|||||||
import froca from "../../services/froca";
|
import froca from "../../services/froca";
|
||||||
import branches from "../../services/branches";
|
import branches from "../../services/branches";
|
||||||
import toast from "../../services/toast";
|
import toast from "../../services/toast";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
interface MoveToDialogProps {
|
function MoveToDialogComponent() {
|
||||||
movedBranchIds?: string[];
|
const [ movedBranchIds, setMovedBranchIds ] = useState<string[]>();
|
||||||
}
|
|
||||||
|
|
||||||
function MoveToDialogComponent({ movedBranchIds }: MoveToDialogProps) {
|
|
||||||
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
const [ suggestion, setSuggestion ] = useState<Suggestion | null>(null);
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
const autoCompleteRef = useRef<HTMLInputElement>(null);
|
const autoCompleteRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useTriliumEvent("moveBranchIdsTo", ({ branchIds }) => {
|
||||||
|
setMovedBranchIds(branchIds);
|
||||||
|
setShown(true);
|
||||||
|
});
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
const notePath = suggestion?.notePath;
|
const notePath = suggestion?.notePath;
|
||||||
if (!notePath) {
|
if (!notePath) {
|
||||||
@ -49,6 +52,8 @@ function MoveToDialogComponent({ movedBranchIds }: MoveToDialogProps) {
|
|||||||
footer={<Button text={t("move_to.move_button")} keyboardShortcut="Enter" />}
|
footer={<Button text={t("move_to.move_button")} keyboardShortcut="Enter" />}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
onShown={() => triggerRecentNotes(autoCompleteRef.current)}
|
onShown={() => triggerRecentNotes(autoCompleteRef.current)}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<h5>{t("move_to.notes_to_move")}</h5>
|
<h5>{t("move_to.notes_to_move")}</h5>
|
||||||
<NoteList branchIds={movedBranchIds} />
|
<NoteList branchIds={movedBranchIds} />
|
||||||
@ -65,17 +70,8 @@ function MoveToDialogComponent({ movedBranchIds }: MoveToDialogProps) {
|
|||||||
|
|
||||||
export default class MoveToDialog extends ReactBasicWidget {
|
export default class MoveToDialog extends ReactBasicWidget {
|
||||||
|
|
||||||
private props: MoveToDialogProps = {};
|
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return <MoveToDialogComponent {...this.props} />;
|
return <MoveToDialogComponent />;
|
||||||
}
|
|
||||||
|
|
||||||
async moveBranchIdsToEvent({ branchIds }: EventData<"moveBranchIdsTo">) {
|
|
||||||
const movedBranchIds = branchIds;
|
|
||||||
this.props = { movedBranchIds };
|
|
||||||
this.doRender();
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,16 @@
|
|||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
import Modal from "../react/Modal";
|
import Modal from "../react/Modal";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import Button from "../react/Button";
|
import Button from "../react/Button";
|
||||||
import appContext from "../../components/app_context";
|
import appContext from "../../components/app_context";
|
||||||
|
import { useState } from "preact/hooks";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
function PasswordNotSetDialogComponent() {
|
function PasswordNotSetDialogComponent() {
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
|
useTriliumEvent("showPasswordNotSet", () => setShown(true));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
size="md" className="password-not-set-dialog"
|
size="md" className="password-not-set-dialog"
|
||||||
@ -14,6 +19,8 @@ function PasswordNotSetDialogComponent() {
|
|||||||
closeActiveDialog();
|
closeActiveDialog();
|
||||||
appContext.triggerCommand("showOptions", { section: "_optionsPassword" });
|
appContext.triggerCommand("showOptions", { section: "_optionsPassword" });
|
||||||
}} />}
|
}} />}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<p>{t("password_not_set.body1")}</p>
|
<p>{t("password_not_set.body1")}</p>
|
||||||
<p>{t("password_not_set.body2")}</p>
|
<p>{t("password_not_set.body2")}</p>
|
||||||
@ -27,8 +34,4 @@ export default class PasswordNotSetDialog extends ReactBasicWidget {
|
|||||||
return <PasswordNotSetDialogComponent />;
|
return <PasswordNotSetDialogComponent />;
|
||||||
}
|
}
|
||||||
|
|
||||||
showPasswordNotSetEvent() {
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
import { useRef, useState } from "preact/hooks";
|
import { useRef, useState } from "preact/hooks";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import Button from "../react/Button";
|
import Button from "../react/Button";
|
||||||
import FormTextBox from "../react/FormTextBox";
|
import FormTextBox from "../react/FormTextBox";
|
||||||
import Modal from "../react/Modal";
|
import Modal from "../react/Modal";
|
||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
import protected_session from "../../services/protected_session";
|
import protected_session from "../../services/protected_session";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
function ProtectedSessionPasswordDialogComponent() {
|
function ProtectedSessionPasswordDialogComponent() {
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
const [ password, setPassword ] = useState("");
|
const [ password, setPassword ] = useState("");
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
useTriliumEvent("showProtectedSessionPasswordDialog", () => setShown(true));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className="protected-session-password-dialog"
|
className="protected-session-password-dialog"
|
||||||
@ -20,6 +24,8 @@ function ProtectedSessionPasswordDialogComponent() {
|
|||||||
footer={<Button text={t("protected_session_password.start_button")} />}
|
footer={<Button text={t("protected_session_password.start_button")} />}
|
||||||
onSubmit={() => protected_session.setupProtectedSession(password)}
|
onSubmit={() => protected_session.setupProtectedSession(password)}
|
||||||
onShown={() => inputRef.current?.focus()}
|
onShown={() => inputRef.current?.focus()}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<label htmlFor="protected-session-password" className="col-form-label">{t("protected_session_password.form_label")}</label>
|
<label htmlFor="protected-session-password" className="col-form-label">{t("protected_session_password.form_label")}</label>
|
||||||
<FormTextBox
|
<FormTextBox
|
||||||
@ -39,10 +45,6 @@ export default class ProtectedSessionPasswordDialog extends ReactBasicWidget {
|
|||||||
return <ProtectedSessionPasswordDialogComponent />;
|
return <ProtectedSessionPasswordDialogComponent />;
|
||||||
}
|
}
|
||||||
|
|
||||||
showProtectedSessionPasswordDialogEvent() {
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
closeProtectedSessionPasswordDialogEvent() {
|
closeProtectedSessionPasswordDialogEvent() {
|
||||||
closeActiveDialog();
|
closeActiveDialog();
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
import appContext, { EventData } from "../../components/app_context";
|
import appContext from "../../components/app_context";
|
||||||
import dialog, { closeActiveDialog, openDialog } from "../../services/dialog";
|
import dialog, { closeActiveDialog } from "../../services/dialog";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import server from "../../services/server";
|
import server from "../../services/server";
|
||||||
import toast from "../../services/toast";
|
import toast from "../../services/toast";
|
||||||
@ -14,14 +14,19 @@ import { formatDateTime } from "../../utils/formatters";
|
|||||||
import link from "../../services/link";
|
import link from "../../services/link";
|
||||||
import RawHtml from "../react/RawHtml";
|
import RawHtml from "../react/RawHtml";
|
||||||
import ws from "../../services/ws";
|
import ws from "../../services/ws";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
interface RecentChangesDialogProps {
|
function RecentChangesDialogComponent() {
|
||||||
ancestorNoteId?: string;
|
const [ ancestorNoteId, setAncestorNoteId ] = useState<string>();
|
||||||
}
|
|
||||||
|
|
||||||
function RecentChangesDialogComponent({ ancestorNoteId }: RecentChangesDialogProps) {
|
|
||||||
const [ groupedByDate, setGroupedByDate ] = useState<Map<String, RecentChangesRow[]>>();
|
const [ groupedByDate, setGroupedByDate ] = useState<Map<String, RecentChangesRow[]>>();
|
||||||
const [ needsRefresh, setNeedsRefresh ] = useState<boolean>(false);
|
const [ needsRefresh, setNeedsRefresh ] = useState(false);
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
|
|
||||||
|
useTriliumEvent("showRecentChanges", ({ ancestorNoteId }) => {
|
||||||
|
setNeedsRefresh(true);
|
||||||
|
setAncestorNoteId(ancestorNoteId ?? hoisted_note.getHoistedNoteId());
|
||||||
|
setShown(true);
|
||||||
|
});
|
||||||
|
|
||||||
if (!groupedByDate || needsRefresh) {
|
if (!groupedByDate || needsRefresh) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -43,7 +48,7 @@ function RecentChangesDialogComponent({ ancestorNoteId }: RecentChangesDialogPro
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
return (ancestorNoteId &&
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={t("recent_changes.title")}
|
title={t("recent_changes.title")}
|
||||||
className="recent-changes-dialog"
|
className="recent-changes-dialog"
|
||||||
@ -61,6 +66,8 @@ function RecentChangesDialogComponent({ ancestorNoteId }: RecentChangesDialogPro
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<div className="recent-changes-content">
|
<div className="recent-changes-content">
|
||||||
{groupedByDate?.size
|
{groupedByDate?.size
|
||||||
@ -152,18 +159,8 @@ function DeletedNoteLink({ change }: { change: RecentChangesRow }) {
|
|||||||
|
|
||||||
export default class RecentChangesDialog extends ReactBasicWidget {
|
export default class RecentChangesDialog extends ReactBasicWidget {
|
||||||
|
|
||||||
private props: RecentChangesDialogProps = {};
|
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return <RecentChangesDialogComponent {...this.props} />
|
return <RecentChangesDialogComponent />
|
||||||
}
|
|
||||||
|
|
||||||
async showRecentChangesEvent({ ancestorNoteId }: EventData<"showRecentChanges">) {
|
|
||||||
this.props = {
|
|
||||||
ancestorNoteId: ancestorNoteId ?? hoisted_note.getHoistedNoteId()
|
|
||||||
};
|
|
||||||
this.doRender();
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import type { RevisionPojo, RevisionItem } from "@triliumnext/commons";
|
import type { RevisionPojo, RevisionItem } from "@triliumnext/commons";
|
||||||
import appContext, { EventData } from "../../components/app_context";
|
import appContext from "../../components/app_context";
|
||||||
import FNote from "../../entities/fnote";
|
import FNote from "../../entities/fnote";
|
||||||
import dialog, { closeActiveDialog, openDialog } from "../../services/dialog";
|
import dialog, { closeActiveDialog } from "../../services/dialog";
|
||||||
import froca from "../../services/froca";
|
import froca from "../../services/froca";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import server from "../../services/server";
|
import server from "../../services/server";
|
||||||
@ -18,26 +18,35 @@ import { CSSProperties } from "preact/compat";
|
|||||||
import open from "../../services/open";
|
import open from "../../services/open";
|
||||||
import ActionButton from "../react/ActionButton";
|
import ActionButton from "../react/ActionButton";
|
||||||
import options from "../../services/options";
|
import options from "../../services/options";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
interface RevisionsDialogProps {
|
function RevisionsDialogComponent() {
|
||||||
note?: FNote;
|
const [ note, setNote ] = useState<FNote>();
|
||||||
}
|
const [ revisions, setRevisions ] = useState<RevisionItem[]>();
|
||||||
|
|
||||||
function RevisionsDialogComponent({ note }: RevisionsDialogProps) {
|
|
||||||
const [ revisions, setRevisions ] = useState<RevisionItem[]>([]);
|
|
||||||
const [ currentRevision, setCurrentRevision ] = useState<RevisionItem>();
|
const [ currentRevision, setCurrentRevision ] = useState<RevisionItem>();
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
|
|
||||||
if (note) {
|
useTriliumEvent("showRevisions", async ({ noteId }) => {
|
||||||
useEffect(() => {
|
const note = await getNote(noteId);
|
||||||
|
if (note) {
|
||||||
|
setNote(note);
|
||||||
|
setShown(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (note?.noteId) {
|
||||||
server.get<RevisionItem[]>(`notes/${note.noteId}/revisions`).then(setRevisions);
|
server.get<RevisionItem[]>(`notes/${note.noteId}/revisions`).then(setRevisions);
|
||||||
}, [ note.noteId ]);
|
} else {
|
||||||
}
|
setRevisions(undefined);
|
||||||
|
}
|
||||||
|
}, [ note?.noteId ]);
|
||||||
|
|
||||||
if (revisions?.length && !currentRevision) {
|
if (revisions?.length && !currentRevision) {
|
||||||
setCurrentRevision(revisions[0]);
|
setCurrentRevision(revisions[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (note &&
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className="revisions-dialog"
|
className="revisions-dialog"
|
||||||
size="xl"
|
size="xl"
|
||||||
@ -49,7 +58,7 @@ function RevisionsDialogComponent({ note }: RevisionsDialogProps) {
|
|||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
const text = t("revisions.confirm_delete_all");
|
const text = t("revisions.confirm_delete_all");
|
||||||
|
|
||||||
if (await dialog.confirm(text)) {
|
if (note && await dialog.confirm(text)) {
|
||||||
await server.remove(`notes/${note.noteId}/revisions`);
|
await server.remove(`notes/${note.noteId}/revisions`);
|
||||||
|
|
||||||
closeActiveDialog();
|
closeActiveDialog();
|
||||||
@ -59,11 +68,16 @@ function RevisionsDialogComponent({ note }: RevisionsDialogProps) {
|
|||||||
}
|
}
|
||||||
footer={<RevisionFooter note={note} />}
|
footer={<RevisionFooter note={note} />}
|
||||||
footerStyle={{ paddingTop: 0, paddingBottom: 0 }}
|
footerStyle={{ paddingTop: 0, paddingBottom: 0 }}
|
||||||
|
onHidden={() => {
|
||||||
|
setShown(false);
|
||||||
|
setNote(undefined);
|
||||||
|
}}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<RevisionsList
|
<RevisionsList
|
||||||
revisions={revisions}
|
revisions={revisions ?? []}
|
||||||
onSelect={(revisionId) => {
|
onSelect={(revisionId) => {
|
||||||
const correspondingRevision = revisions.find((r) => r.revisionId === revisionId);
|
const correspondingRevision = (revisions ?? []).find((r) => r.revisionId === revisionId);
|
||||||
if (correspondingRevision) {
|
if (correspondingRevision) {
|
||||||
setCurrentRevision(correspondingRevision);
|
setCurrentRevision(correspondingRevision);
|
||||||
}
|
}
|
||||||
@ -239,7 +253,7 @@ function RevisionContent({ revisionItem, fullRevision }: { revisionItem?: Revisi
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function RevisionFooter({ note }: { note: FNote }) {
|
function RevisionFooter({ note }: { note?: FNote }) {
|
||||||
if (!note) {
|
if (!note) {
|
||||||
return <></>;
|
return <></>;
|
||||||
}
|
}
|
||||||
@ -268,18 +282,8 @@ function RevisionFooter({ note }: { note: FNote }) {
|
|||||||
|
|
||||||
export default class RevisionsDialog extends ReactBasicWidget {
|
export default class RevisionsDialog extends ReactBasicWidget {
|
||||||
|
|
||||||
private props: RevisionsDialogProps = {};
|
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return <RevisionsDialogComponent {...this.props} />
|
return <RevisionsDialogComponent />
|
||||||
}
|
|
||||||
|
|
||||||
async showRevisionsEvent({ noteId }: EventData<"showRevisions">) {
|
|
||||||
this.props = {
|
|
||||||
note: await getNote(noteId) ?? undefined
|
|
||||||
};
|
|
||||||
this.doRender();
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { useState } from "preact/hooks";
|
import { useState } from "preact/hooks";
|
||||||
import { EventData } from "../../components/app_context";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import Button from "../react/Button";
|
import Button from "../react/Button";
|
||||||
import FormCheckbox from "../react/FormCheckbox";
|
import FormCheckbox from "../react/FormCheckbox";
|
||||||
@ -10,13 +9,21 @@ import Modal from "../react/Modal";
|
|||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
import server from "../../services/server";
|
import server from "../../services/server";
|
||||||
import FormGroup from "../react/FormGroup";
|
import FormGroup from "../react/FormGroup";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
function SortChildNotesDialogComponent({ parentNoteId }: { parentNoteId?: string }) {
|
function SortChildNotesDialogComponent() {
|
||||||
|
const [ parentNoteId, setParentNoteId ] = useState<string>();
|
||||||
const [ sortBy, setSortBy ] = useState("title");
|
const [ sortBy, setSortBy ] = useState("title");
|
||||||
const [ sortDirection, setSortDirection ] = useState("asc");
|
const [ sortDirection, setSortDirection ] = useState("asc");
|
||||||
const [ foldersFirst, setFoldersFirst ] = useState(false);
|
const [ foldersFirst, setFoldersFirst ] = useState(false);
|
||||||
const [ sortNatural, setSortNatural ] = useState(false);
|
const [ sortNatural, setSortNatural ] = useState(false);
|
||||||
const [ sortLocale, setSortLocale ] = useState("");
|
const [ sortLocale, setSortLocale ] = useState("");
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
|
|
||||||
|
useTriliumEvent("sortChildNotes", ({ node }) => {
|
||||||
|
setParentNoteId(node.data.noteId);
|
||||||
|
setShown(true);
|
||||||
|
});
|
||||||
|
|
||||||
async function onSubmit() {
|
async function onSubmit() {
|
||||||
await server.put(`notes/${parentNoteId}/sort-children`, {
|
await server.put(`notes/${parentNoteId}/sort-children`, {
|
||||||
@ -31,12 +38,14 @@ function SortChildNotesDialogComponent({ parentNoteId }: { parentNoteId?: string
|
|||||||
closeActiveDialog();
|
closeActiveDialog();
|
||||||
}
|
}
|
||||||
|
|
||||||
return (parentNoteId &&
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className="sort-child-notes-dialog"
|
className="sort-child-notes-dialog"
|
||||||
title={t("sort_child_notes.sort_children_by")}
|
title={t("sort_child_notes.sort_children_by")}
|
||||||
size="lg" maxWidth={500}
|
size="lg" maxWidth={500}
|
||||||
onSubmit={onSubmit}
|
onSubmit={onSubmit}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
footer={<Button text={t("sort_child_notes.sort")} keyboardShortcut="Enter" />}
|
footer={<Button text={t("sort_child_notes.sort")} keyboardShortcut="Enter" />}
|
||||||
>
|
>
|
||||||
<h5>{t("sort_child_notes.sorting_criteria")}</h5>
|
<h5>{t("sort_child_notes.sorting_criteria")}</h5>
|
||||||
@ -88,17 +97,8 @@ function SortChildNotesDialogComponent({ parentNoteId }: { parentNoteId?: string
|
|||||||
|
|
||||||
export default class SortChildNotesDialog extends ReactBasicWidget {
|
export default class SortChildNotesDialog extends ReactBasicWidget {
|
||||||
|
|
||||||
private parentNoteId?: string;
|
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return <SortChildNotesDialogComponent parentNoteId={this.parentNoteId} />;
|
return <SortChildNotesDialogComponent />;
|
||||||
}
|
}
|
||||||
|
|
||||||
async sortChildNotesEvent({ node }: EventData<"sortChildNotes">) {
|
|
||||||
this.parentNoteId = node.data.noteId;
|
|
||||||
this.doRender();
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
@ -1,5 +1,5 @@
|
|||||||
import { useEffect, useState } from "preact/compat";
|
import { useEffect, useState } from "preact/compat";
|
||||||
import { closeActiveDialog, openDialog } from "../../services/dialog";
|
import { closeActiveDialog } from "../../services/dialog";
|
||||||
import { t } from "../../services/i18n";
|
import { t } from "../../services/i18n";
|
||||||
import Button from "../react/Button";
|
import Button from "../react/Button";
|
||||||
import FormCheckbox from "../react/FormCheckbox";
|
import FormCheckbox from "../react/FormCheckbox";
|
||||||
@ -9,18 +9,21 @@ import Modal from "../react/Modal";
|
|||||||
import ReactBasicWidget from "../react/ReactBasicWidget";
|
import ReactBasicWidget from "../react/ReactBasicWidget";
|
||||||
import options from "../../services/options";
|
import options from "../../services/options";
|
||||||
import importService from "../../services/import.js";
|
import importService from "../../services/import.js";
|
||||||
import { EventData } from "../../components/app_context";
|
|
||||||
import tree from "../../services/tree";
|
import tree from "../../services/tree";
|
||||||
|
import useTriliumEvent from "../react/hooks";
|
||||||
|
|
||||||
interface UploadAttachmentsDialogProps {
|
function UploadAttachmentsDialogComponent() {
|
||||||
parentNoteId?: string;
|
const [ parentNoteId, setParentNoteId ] = useState<string>();
|
||||||
}
|
|
||||||
|
|
||||||
function UploadAttachmentsDialogComponent({ parentNoteId }: UploadAttachmentsDialogProps) {
|
|
||||||
const [ files, setFiles ] = useState<FileList | null>(null);
|
const [ files, setFiles ] = useState<FileList | null>(null);
|
||||||
const [ shrinkImages, setShrinkImages ] = useState(options.is("compressImages"));
|
const [ shrinkImages, setShrinkImages ] = useState(options.is("compressImages"));
|
||||||
const [ isUploading, setIsUploading ] = useState(false);
|
const [ isUploading, setIsUploading ] = useState(false);
|
||||||
const [ description, setDescription ] = useState<string | undefined>(undefined);
|
const [ description, setDescription ] = useState<string | undefined>(undefined);
|
||||||
|
const [ shown, setShown ] = useState(false);
|
||||||
|
|
||||||
|
useTriliumEvent("showUploadAttachmentsDialog", ({ noteId }) => {
|
||||||
|
setParentNoteId(noteId);
|
||||||
|
setShown(true);
|
||||||
|
});
|
||||||
|
|
||||||
if (parentNoteId) {
|
if (parentNoteId) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -29,14 +32,14 @@ function UploadAttachmentsDialogComponent({ parentNoteId }: UploadAttachmentsDia
|
|||||||
}, [parentNoteId]);
|
}, [parentNoteId]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return (parentNoteId &&
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
className="upload-attachments-dialog"
|
className="upload-attachments-dialog"
|
||||||
size="lg"
|
size="lg"
|
||||||
title={t("upload_attachments.upload_attachments_to_note")}
|
title={t("upload_attachments.upload_attachments_to_note")}
|
||||||
footer={<Button text={t("upload_attachments.upload")} primary disabled={!files || isUploading} />}
|
footer={<Button text={t("upload_attachments.upload")} primary disabled={!files || isUploading} />}
|
||||||
onSubmit={async () => {
|
onSubmit={async () => {
|
||||||
if (!files) {
|
if (!files || !parentNoteId) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,6 +49,8 @@ function UploadAttachmentsDialogComponent({ parentNoteId }: UploadAttachmentsDia
|
|||||||
setIsUploading(false);
|
setIsUploading(false);
|
||||||
closeActiveDialog();
|
closeActiveDialog();
|
||||||
}}
|
}}
|
||||||
|
onHidden={() => setShown(false)}
|
||||||
|
show={shown}
|
||||||
>
|
>
|
||||||
<FormGroup label={t("upload_attachments.choose_files")} description={description}>
|
<FormGroup label={t("upload_attachments.choose_files")} description={description}>
|
||||||
<FormFileUpload onChange={setFiles} multiple />
|
<FormFileUpload onChange={setFiles} multiple />
|
||||||
@ -64,16 +69,8 @@ function UploadAttachmentsDialogComponent({ parentNoteId }: UploadAttachmentsDia
|
|||||||
|
|
||||||
export default class UploadAttachmentsDialog extends ReactBasicWidget {
|
export default class UploadAttachmentsDialog extends ReactBasicWidget {
|
||||||
|
|
||||||
private props: UploadAttachmentsDialogProps = {};
|
|
||||||
|
|
||||||
get component() {
|
get component() {
|
||||||
return <UploadAttachmentsDialogComponent {...this.props} />;
|
return <UploadAttachmentsDialogComponent />;
|
||||||
}
|
|
||||||
|
|
||||||
showUploadAttachmentsDialogEvent({ noteId }: EventData<"showUploadAttachmentsDialog">) {
|
|
||||||
this.props = { parentNoteId: noteId };
|
|
||||||
this.doRender();
|
|
||||||
openDialog(this.$widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user