change modal on error

This commit is contained in:
Mateusz Gruszczyński
2026-08-05 10:38:17 +02:00
parent 73286d921b
commit c4d04adb40
5 changed files with 25 additions and 8 deletions
Generated
+1 -1
View File
@@ -2581,7 +2581,7 @@ dependencies = [
[[package]]
name = "rustpad"
version = "0.2.39"
version = "0.2.40"
dependencies = [
"argon2",
"aws-config",
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "rustpad"
version = "0.2.39"
version = "0.2.40"
edition = "2024"
rust-version = "1.94"
description = "Collaborative Markdown notepad built with Axum, WebSockets and SQLite, PostgreSQL and MySQL"
+11 -3
View File
@@ -27,6 +27,7 @@ import { bindNoteFiles } from "@rustpad/note-files";
import { currentShareUrl, readEditorState, writeEditorState } from "@rustpad/url-state";
import { toast } from "@rustpad/toast";
import { getTheme } from "@rustpad/theme";
import { isResourceAccessError } from "@rustpad/security";
export function startNoteEditor(adapter) {
const editor = document.querySelector("#editor"), preview = document.querySelector("#preview"), editorWorkspace = document.querySelector("#editor-workspace"), gutter = document.querySelector("#line-gutter"), ownerLabels = document.querySelector("#owner-labels"), authorshipLayer = document.querySelector("#authorship-layer");
@@ -1353,7 +1354,6 @@ export function startNoteEditor(adapter) {
onError: message => {
hideConnectionNotice();
const friendly = /read-only access/i.test(message) ? "This note is read only. Enter the password or ask the owner to grant write access." : message;
document.querySelector("#password-error").textContent = friendly;
if (/read-only access/i.test(message)) {
toast(friendly);
accessLevel.textContent = "Access: read only";
@@ -1368,9 +1368,17 @@ export function startNoteEditor(adapter) {
if (saveState.textContent === "Saving…") saveState.textContent = "Save failed";
if (/nickname|session|account/i.test(message)) {
if (!identityDialog.open) identityDialog.showModal();
} else if (info?.protected && !passwordDialog.open) {
passwordDialog.showModal();
return;
}
if (info?.protected && isResourceAccessError(message)) {
resourceUnlocked = false;
setDocumentReadOnly(true, "Password required");
document.querySelector("#password-error").textContent = friendly;
if (!passwordDialog.open) passwordDialog.showModal();
document.querySelector("#open-password")?.focus();
return;
}
toast(friendly);
},
});
socket.connect();
+8
View File
@@ -7,6 +7,14 @@
* See LICENSE file in repository root for details.
*/
const RESOURCE_ACCESS_ERROR_PATTERN = /(?:invalid password|password required|authentication required|access expired or revoked)/i;
export function isResourceAccessError(error) {
const status = Number(error?.status);
const message = typeof error === "string" ? error : error?.message;
return status === 401 || RESOURCE_ACCESS_ERROR_PATTERN.test(String(message || ""));
}
export function safeAppUrl(value, fallback = "/") {
try {
const url = new URL(String(value || ""), location.origin);
+4 -3
View File
@@ -15,7 +15,7 @@ import { copyText } from "@rustpad/clipboard";
import { getNickname, getAccessToken, getAuthToken, getGuestId, setAccessToken } from "@rustpad/session";
import { bindIdentityDialog, validateCurrentSession } from "@rustpad/auth-ui";
import { askConfirm } from "@rustpad/modal";
import { safeAppUrl } from "@rustpad/security";
import { isResourceAccessError, safeAppUrl } from "@rustpad/security";
import { toast } from "@rustpad/toast";
const parts = location.pathname.split("/").filter(Boolean);
@@ -116,7 +116,8 @@ function connectWorkspaceWatch() {
if (message.type === "error") {
workspaceWatchIntentionalClose = true;
socket.close();
if (/password/i.test(message.message || "")) lockWorkspaceForPassword(message.message);
if (isResourceAccessError(message.message)) lockWorkspaceForPassword(message.message);
else document.querySelector("#workspace-error").textContent = message.message || "Workspace connection error";
}
});
socket.addEventListener("close", () => {
@@ -234,7 +235,7 @@ async function openWorkspace() {
if (dialog.open) dialog.close();
connectWorkspaceWatch();
} catch (e) {
if (info?.protected || e.message.toLowerCase().includes("password")) {
if (info?.protected && isResourceAccessError(e)) {
lockWorkspaceForPassword(e.message);
} else if (e.status === 403 || e.status === 404) {
await showSystemNotFound();