chore(client/ts): port some dialogs

This commit is contained in:
Elian Doran 2025-03-15 22:14:21 +02:00
parent 1bf16bfa22
commit 182bccad39
No known key found for this signature in database
5 changed files with 62 additions and 27 deletions

View File

@ -6,15 +6,15 @@ import appContext from "../components/app_context.js";
import { t } from "./i18n.js";
interface UploadFilesOptions {
safeImport: boolean;
shrinkImages: boolean;
textImportedAsText: boolean;
codeImportedAsCode: boolean;
explodeArchives: boolean;
replaceUnderscoresWithSpaces: boolean;
safeImport?: boolean;
shrinkImages: "true" | "false";
textImportedAsText?: boolean;
codeImportedAsCode?: boolean;
explodeArchives?: boolean;
replaceUnderscoresWithSpaces?: boolean;
}
export async function uploadFiles(entityType: string, parentNoteId: string, files: string[], options: UploadFilesOptions) {
export async function uploadFiles(entityType: string, parentNoteId: string, files: string[] | File[], options: UploadFilesOptions) {
if (!["notes", "attachments"].includes(entityType)) {
throw new Error(`Unrecognized import entity type '${entityType}'.`);
}

View File

@ -27,14 +27,19 @@ const TPL = `
</div>`;
export default class ProtectedSessionPasswordDialog extends BasicWidget {
private modal!: bootstrap.Modal;
private $passwordForm!: JQuery<HTMLElement>;
private $passwordInput!: JQuery<HTMLElement>;
doRender() {
this.$widget = $(TPL);
this.modal = Modal.getOrCreateInstance(this.$widget);
this.modal = Modal.getOrCreateInstance(this.$widget[0]);
this.$passwordForm = this.$widget.find(".protected-session-password-form");
this.$passwordInput = this.$widget.find(".protected-session-password");
this.$passwordForm.on("submit", () => {
const password = this.$passwordInput.val();
const password = String(this.$passwordInput.val());
this.$passwordInput.val("");
protectedSessionService.setupProtectedSession(password);

View File

@ -1,6 +1,6 @@
import { formatDateTime } from "../../utils/formatters.js";
import { t } from "../../services/i18n.js";
import appContext from "../../components/app_context.js";
import appContext, { type EventData } from "../../components/app_context.js";
import BasicWidget from "../basic_widget.js";
import dialogService from "../../services/dialog.js";
import froca from "../../services/froca.js";
@ -28,10 +28,23 @@ const TPL = `
</div>
</div>`;
// TODO: Deduplicate with server.
interface RecentChangesRow {
noteId: string;
date: string;
}
export default class RecentChangesDialog extends BasicWidget {
private ancestorNoteId?: string;
private modal!: bootstrap.Modal;
private $content!: JQuery<HTMLElement>;
private $eraseDeletedNotesNow!: JQuery<HTMLElement>;
doRender() {
this.$widget = $(TPL);
this.modal = Modal.getOrCreateInstance(this.$widget);
this.modal = Modal.getOrCreateInstance(this.$widget[0]);
this.$content = this.$widget.find(".recent-changes-content");
this.$eraseDeletedNotesNow = this.$widget.find(".erase-deleted-notes-now-button");
@ -44,7 +57,7 @@ export default class RecentChangesDialog extends BasicWidget {
});
}
async showRecentChangesEvent({ ancestorNoteId }) {
async showRecentChangesEvent({ ancestorNoteId }: EventData<"showRecentChanges">) {
this.ancestorNoteId = ancestorNoteId;
await this.refresh();
@ -57,7 +70,7 @@ export default class RecentChangesDialog extends BasicWidget {
this.ancestorNoteId = hoistedNoteService.getHoistedNoteId();
}
const recentChangesRows = await server.get(`recent-changes/${this.ancestorNoteId}`);
const recentChangesRows = await server.get<RecentChangesRow[]>(`recent-changes/${this.ancestorNoteId}`);
// preload all notes into cache
await froca.getNotes(
@ -110,7 +123,7 @@ export default class RecentChangesDialog extends BasicWidget {
}
} else {
const note = await froca.getNote(change.noteId);
const notePath = note.getBestNotePathString();
const notePath = note?.getBestNotePathString();
if (notePath) {
$noteLink = await linkService.createLink(notePath, {
@ -118,7 +131,7 @@ export default class RecentChangesDialog extends BasicWidget {
showNotePath: true
});
} else {
$noteLink = $("<span>").text(note.title);
$noteLink = $("<span>").text(note?.title ?? "");
}
}
@ -131,9 +144,7 @@ export default class RecentChangesDialog extends BasicWidget {
appContext.tabManager.getActiveContext().setNote(change.noteId);
}
})
.addClass(() => {
if (change.current_isDeleted) return "deleted-note";
})
.toggleClass("deleted-note", !!change.current_isDeleted)
.append($("<span>").text(formattedTime).attr("title", change.date))
.append($noteLink.addClass("note-title"))
);
@ -143,7 +154,7 @@ export default class RecentChangesDialog extends BasicWidget {
}
}
groupByDate(rows) {
groupByDate(rows: RecentChangesRow[]) {
const groupedByDate = new Map();
for (const row of rows) {

View File

@ -1,3 +1,4 @@
import type { EventData } from "../../components/app_context.js";
import { t } from "../../services/i18n.js";
import server from "../../services/server.js";
import utils from "../../services/utils.js";
@ -79,6 +80,10 @@ const TPL = `<div class="sort-child-notes-dialog modal mx-auto" tabindex="-1" ro
</div>`;
export default class SortChildNotesDialog extends BasicWidget {
private parentNoteId?: string;
private $form!: JQuery<HTMLElement>;
doRender() {
this.$widget = $(TPL);
this.$form = this.$widget.find(".sort-child-notes-form");
@ -96,7 +101,7 @@ export default class SortChildNotesDialog extends BasicWidget {
});
}
async sortChildNotesEvent({ node }) {
async sortChildNotesEvent({ node }: EventData<"sortChildNotes">) {
this.parentNoteId = node.data.noteId;
utils.openDialog(this.$widget);

View File

@ -5,6 +5,7 @@ import importService from "../../services/import.js";
import options from "../../services/options.js";
import BasicWidget from "../basic_widget.js";
import { Modal, Tooltip } from "bootstrap";
import type { EventData } from "../../components/app_context.js";
const TPL = `
<div class="upload-attachments-dialog modal fade mx-auto" tabindex="-1" role="dialog">
@ -42,6 +43,15 @@ const TPL = `
</div>`;
export default class UploadAttachmentsDialog extends BasicWidget {
private parentNoteId: string | null;
private modal!: bootstrap.Modal;
private $form!: JQuery<HTMLElement>;
private $noteTitle!: JQuery<HTMLElement>;
private $fileUploadInput!: JQuery<HTMLInputElement>;
private $uploadButton!: JQuery<HTMLElement>;
private $shrinkImagesCheckbox!: JQuery<HTMLElement>;
constructor() {
super();
@ -50,7 +60,7 @@ export default class UploadAttachmentsDialog extends BasicWidget {
doRender() {
this.$widget = $(TPL);
this.modal = Modal.getOrCreateInstance(this.$widget);
this.modal = Modal.getOrCreateInstance(this.$widget[0]);
this.$form = this.$widget.find(".upload-attachment-form");
this.$noteTitle = this.$widget.find(".upload-attachment-note-title");
@ -61,7 +71,9 @@ export default class UploadAttachmentsDialog extends BasicWidget {
this.$form.on("submit", () => {
// disabling so that import is not triggered again.
this.$uploadButton.attr("disabled", "disabled");
this.uploadAttachments(this.parentNoteId);
if (this.parentNoteId) {
this.uploadAttachments(this.parentNoteId);
}
return false;
});
@ -73,12 +85,12 @@ export default class UploadAttachmentsDialog extends BasicWidget {
}
});
Tooltip.getOrCreateInstance(this.$widget.find('[data-bs-toggle="tooltip"]'), {
Tooltip.getOrCreateInstance(this.$widget.find('[data-bs-toggle="tooltip"]')[0], {
html: true
});
}
async showUploadAttachmentsDialogEvent({ noteId }) {
async showUploadAttachmentsDialogEvent({ noteId }: EventData<"showUploadAttachmentsDialog">) {
this.parentNoteId = noteId;
this.$fileUploadInput.val("").trigger("change"); // to trigger upload button disabling listener below
@ -89,10 +101,12 @@ export default class UploadAttachmentsDialog extends BasicWidget {
utils.openDialog(this.$widget);
}
async uploadAttachments(parentNoteId) {
const files = Array.from(this.$fileUploadInput[0].files); // shallow copy since we're resetting the upload button below
async uploadAttachments(parentNoteId: string) {
const files = Array.from(this.$fileUploadInput[0].files ?? []); // shallow copy since we're resetting the upload button below
const boolToString = ($el) => ($el.is(":checked") ? "true" : "false");
function boolToString($el: JQuery<HTMLElement>): "true" | "false" {
return ($el.is(":checked") ? "true" : "false");
}
const options = {
shrinkImages: boolToString(this.$shrinkImagesCheckbox)