diff --git a/CHANGELOG.md b/CHANGELOG.md
index 44ec4f15..565b6c20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,8 @@
- Refreshed the OAuth2 Admin UI.
+- Added auto "draft" to allow restoring previous record state in case of accidental reload or power outage.
+
## v0.14.5
diff --git a/ui/src/components/records/RecordFileThumb.svelte b/ui/src/components/records/RecordFileThumb.svelte
index f609ede3..900a82ff 100644
--- a/ui/src/components/records/RecordFileThumb.svelte
+++ b/ui/src/components/records/RecordFileThumb.svelte
@@ -2,7 +2,6 @@
import ApiClient from "@/utils/ApiClient";
import CommonHelper from "@/utils/CommonHelper";
import PreviewPopup from "@/components/base/PreviewPopup.svelte";
- import { privateFilesCollectionsCache } from "@/stores/collections";
export let record = null;
export let filename = "";
@@ -14,16 +13,7 @@
let token = "";
let isLoadingToken = false;
- $: withToken =
- typeof $privateFilesCollectionsCache[record?.collectionId] !== "undefined"
- ? $privateFilesCollectionsCache[record?.collectionId]
- : true;
-
- $: if (withToken) {
- loadFileToken();
- } else {
- token = "";
- }
+ loadFileToken();
$: type = CommonHelper.getFileType(filename);
@@ -39,7 +29,7 @@
isLoadingToken = true;
try {
- token = await ApiClient.getAdminFileToken();
+ token = await ApiClient.getAdminFileToken(record.collectionId);
} catch (err) {
console.warn("File token failure:", err);
}
diff --git a/ui/src/components/records/RecordUpsertPanel.svelte b/ui/src/components/records/RecordUpsertPanel.svelte
index edd9daca..ed27479f 100644
--- a/ui/src/components/records/RecordUpsertPanel.svelte
+++ b/ui/src/components/records/RecordUpsertPanel.svelte
@@ -92,6 +92,9 @@
initialDraft = getDraft();
if (!initialDraft || areRecordsEqual(record, initialDraft)) {
initialDraft = null;
+ } else {
+ delete initialDraft.password;
+ delete initialDraft.passwordConfirm;
}
originalSerializedData = JSON.stringify(record);
@@ -482,7 +485,7 @@
{#if collection?.isAuth}
-
+
{#if collection?.schema?.length}
diff --git a/ui/src/components/records/fields/AuthFields.svelte b/ui/src/components/records/fields/AuthFields.svelte
index e79d5995..cf2409e4 100644
--- a/ui/src/components/records/fields/AuthFields.svelte
+++ b/ui/src/components/records/fields/AuthFields.svelte
@@ -9,6 +9,7 @@
export let collection = new Collection();
export let record = new Record();
+ export let isNew = record.$isNew;
let originalUsername = record.username || null;
@@ -28,15 +29,15 @@
-
+
@@ -69,7 +70,7 @@
- {#if !record.$isNew}
+ {#if !isNew}
{/if}
- {#if record.$isNew || changePasswordToggle}
+ {#if isNew || changePasswordToggle}
@@ -131,7 +132,7 @@
id={uniqueId}
bind:checked={record.verified}
on:change|preventDefault={(e) => {
- if (record.$isNew) {
+ if (isNew) {
return; // no confirmation required
}
confirm(
diff --git a/ui/src/components/records/fields/FileField.svelte b/ui/src/components/records/fields/FileField.svelte
index d3c8e263..fb3fa20c 100644
--- a/ui/src/components/records/fields/FileField.svelte
+++ b/ui/src/components/records/fields/FileField.svelte
@@ -6,6 +6,7 @@
import Field from "@/components/base/Field.svelte";
import UploadedFilePreview from "@/components/base/UploadedFilePreview.svelte";
import RecordFileThumb from "@/components/records/RecordFileThumb.svelte";
+ import { onMount } from "svelte";
export let record;
export let value = "";
@@ -16,6 +17,7 @@
let fileInput;
let filesListElem;
let isDragOver = false;
+ let fileToken = "";
// normalize uploadedFiles type
$: if (!Array.isArray(uploadedFiles)) {
@@ -93,6 +95,10 @@
uploadedFiles = uploadedFiles;
}
+
+ onMount(async () => {
+ fileToken = await ApiClient.getAdminFileToken(record.collectionId);
+ });
{
@@ -82,7 +82,7 @@ export async function loadCollections(activeId = null) {
}
function refreshProtectedFilesCollectionsCache() {
- privateFilesCollectionsCache.update((cache) => {
+ protectedFilesCollectionsCache.update((cache) => {
collections.update((current) => {
for (let c of current) {
cache[c.id] = !!c.schema?.find((f) => f.type == "file" && f.options?.protected);
diff --git a/ui/src/utils/ApiClient.js b/ui/src/utils/ApiClient.js
index 87d2006b..8ac8ace0 100644
--- a/ui/src/utils/ApiClient.js
+++ b/ui/src/utils/ApiClient.js
@@ -1,10 +1,13 @@
import PocketBase, { LocalAuthStore, Admin, isTokenExpired } from "pocketbase";
// ---
-import CommonHelper from "@/utils/CommonHelper";
-import { replace } from "svelte-spa-router";
-import { addErrorToast } from "@/stores/toasts";
-import { setErrors } from "@/stores/errors";
-import { setAdmin } from "@/stores/admin";
+import CommonHelper from "@/utils/CommonHelper";
+import { replace } from "svelte-spa-router";
+import { get } from "svelte/store";
+import { addErrorToast } from "@/stores/toasts";
+import { setErrors } from "@/stores/errors";
+import { setAdmin } from "@/stores/admin";
+import { protectedFilesCollectionsCache } from "@/stores/collections";
+
const adminFileTokenKey = "pb_admin_file_token";
@@ -17,7 +20,7 @@ PocketBase.prototype.logout = function(redirect = true) {
this.authStore.clear();
if (redirect) {
- replace('/login');
+ replace("/login");
}
};
@@ -28,7 +31,7 @@ PocketBase.prototype.logout = function(redirect = true) {
* @param {Boolean} notify Whether to add a toast notification.
* @param {String} defaultMsg Default toast notification message if the error doesn't have one.
*/
-PocketBase.prototype.errorResponseHandler = function(err, notify = true, defaultMsg = '') {
+PocketBase.prototype.errorResponseHandler = function(err, notify = true, defaultMsg = "") {
if (!err || !(err instanceof Error) || err.isAbort) {
return;
}
@@ -61,15 +64,28 @@ PocketBase.prototype.errorResponseHandler = function(err, notify = true, default
// forbidden
if (statusCode === 403) {
this.cancelAllRequests();
- return replace('/');
+ return replace("/");
}
};
/**
* @return {Promise}
*/
-PocketBase.prototype.getAdminFileToken = async function() {
- let token = localStorage.getItem(adminFileTokenKey) || '';
+PocketBase.prototype.getAdminFileToken = async function(collectionId = "") {
+ let needToken = true;
+
+ if (collectionId) {
+ const protectedCollections = get(protectedFilesCollectionsCache);
+ needToken = typeof protectedCollections[collectionId] !== "undefined"
+ ? protectedCollections[collectionId]
+ : true;
+ }
+
+ if (!needToken) {
+ return "";
+ }
+
+ let token = localStorage.getItem(adminFileTokenKey) || "";
// request a new token only if the previous one is missing or will expire soon
if (!token || isTokenExpired(token, 15)) {