mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-28 03:05:35 +01:00
fix (rewrite): edge cases around cache invalidation
This commit is contained in:
parent
cefb67ca62
commit
bd64529e4a
5 changed files with 45 additions and 38 deletions
|
|
@ -1,6 +1,6 @@
|
|||
import { createElement, onDestroy } from "../lib/skeleton/index.js";
|
||||
import rxjs, { effect, onClick } from "../lib/rx.js";
|
||||
import { fromHref, toHref } from "../lib/skeleton/router.js";
|
||||
import { navigate, fromHref, toHref } from "../lib/skeleton/router.js";
|
||||
import { qs, qsa } from "../lib/dom.js";
|
||||
import { settingsGet, settingsSave } from "../lib/store.js";
|
||||
import { loadCSS } from "../helpers/loader.js";
|
||||
|
|
@ -73,7 +73,7 @@ export default async function ctrlSidebar(render) {
|
|||
}
|
||||
onDestroy(() => {
|
||||
$page.classList.remove("search");
|
||||
state.$cache = $files.firstElementChild.cloneNode(true);
|
||||
state.$cache = $files.firstElementChild?.cloneNode(true);
|
||||
state.scrollTop = $page.firstElementChild.scrollTop
|
||||
});
|
||||
const chunk = new pathChunk();
|
||||
|
|
@ -84,11 +84,13 @@ export default async function ctrlSidebar(render) {
|
|||
const path = chunk.toString(i);
|
||||
try {
|
||||
const $list = await createListOfFiles(path, arr[i+1], fullpath);
|
||||
const $anchor = i === 0 ?
|
||||
$tree :
|
||||
qs($tree, `[data-path="${chunk.toString(i)}"]`);
|
||||
const $anchor = i === 0 ? $tree : qs($tree, `[data-path="${chunk.toString(i)}"]`);
|
||||
$anchor.appendChild($list);
|
||||
} catch(err) { console.error("ERROR", i, err) }
|
||||
} catch(err) { // cache isn't reliable, kill everything and refresh
|
||||
$files.remove();
|
||||
await cache().remove("/", false);
|
||||
navigate(location.pathname + location.hash + location.search);
|
||||
}
|
||||
}
|
||||
$files.replaceChildren($tree);
|
||||
$page.firstElementChild.scrollTop = state.scrollTop;
|
||||
|
|
@ -96,11 +98,13 @@ export default async function ctrlSidebar(render) {
|
|||
// feature: smart refresh whenever something happen
|
||||
let cleaners = [];
|
||||
cleaners.push(hooks.ls.listen(async ({ path }) => {
|
||||
const $list = await createListOfFiles(path);
|
||||
try {
|
||||
const $ul = qs($page, `[data-path="${path}"] ul`);
|
||||
const $list = await createListOfFiles(path);
|
||||
$ul.replaceWith($list);
|
||||
} catch (err) {}
|
||||
} catch (err) { // happens when the cache can't be rely on
|
||||
$files.replaceChildren($list);
|
||||
}
|
||||
}));
|
||||
cleaners.push(hooks.mutation.listen(async ({ op, path }) => {
|
||||
if (["mv", "mkdir", "rm"].indexOf(op) === -1) return;
|
||||
|
|
@ -113,11 +117,13 @@ export default async function ctrlSidebar(render) {
|
|||
onDestroy(() => cleaners.map((fn) => fn()));
|
||||
|
||||
// feature: highlight current selection
|
||||
const $active = qs($page, `[data-path="${chunk.toString()}"] a`);
|
||||
$active.classList.add("active");
|
||||
if (checkVisible($active) === false) {
|
||||
$active.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
try {
|
||||
const $active = qs($page, `[data-path="${chunk.toString()}"] a`);
|
||||
$active.classList.add("active");
|
||||
if (checkVisible($active) === false) {
|
||||
$active.scrollIntoView({ behavior: "smooth" });
|
||||
}
|
||||
} catch(err) {}
|
||||
|
||||
// feature: quick search
|
||||
effect(rxjs.fromEvent(qs($page, "h3 input"), "keydown").pipe(
|
||||
|
|
|
|||
|
|
@ -19,13 +19,7 @@ export default function(opts) {
|
|||
}
|
||||
return res;
|
||||
}),
|
||||
rxjs.catchError((err) => {
|
||||
if (err.status === 401) {
|
||||
location.href = toHref("/login?next=" + location.pathname + location.hash + location.search);
|
||||
return rxjs.EMPTY;
|
||||
}
|
||||
return rxjs.throwError(processError(err.xhr, err))
|
||||
}),
|
||||
rxjs.catchError((err) => rxjs.throwError(processError(err.xhr, err))),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ export default function(render) {
|
|||
|
||||
effect(deleteSession().pipe(
|
||||
rxjs.mergeMap(setup_config),
|
||||
rxjs.tap(() => navigate(toHref("/"))),
|
||||
rxjs.tap(() => window.CONFIG["logout"] ? location.href = CONFIG["logout"] : navigate(toHref("/"))),
|
||||
rxjs.catchError(ctrlError(render)),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import ajax from "../../lib/ajax.js";
|
||||
import { getSession } from "../../model/session.js";
|
||||
|
||||
class ICache {
|
||||
constructor() {}
|
||||
|
|
@ -173,30 +173,34 @@ class IndexDBCache extends ICache {
|
|||
|
||||
let cache = null;
|
||||
|
||||
export function clearCache(path) {
|
||||
console.log("TODO: clear cache");
|
||||
// cache.clear(path);
|
||||
export async function clearCache(path) { // TODO: remove useless function
|
||||
await cache.remove(path, false);
|
||||
}
|
||||
|
||||
export async function init() {
|
||||
const setup_cache = () => {
|
||||
cache = new InMemoryCache();
|
||||
if (!("indexedDB" in window)) return initCacheState();
|
||||
if (!("indexedDB" in window)) return;
|
||||
|
||||
cache = new IndexDBCache();
|
||||
return Promise.all([cache.db, initCacheState()]).catch((err) => {
|
||||
return cache.db.catch((err) => {
|
||||
if (err === "INDEXEDDB_NOT_SUPPORTED") {
|
||||
// Firefox in private mode act like if it supports indexedDB but
|
||||
// is throwing that string as an error if you try to use it ...
|
||||
// so we fallback with our basic ram cache
|
||||
cache = new DataFromMemory();
|
||||
return initCacheState();
|
||||
return;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
}
|
||||
const setup_session = () => {
|
||||
return Promise.resolve();
|
||||
const setup_session = async () => {
|
||||
if (!backendID) {
|
||||
try {
|
||||
const session = await getSession().toPromise();
|
||||
backendID = session.backendID;
|
||||
} catch (err) {}
|
||||
}
|
||||
};
|
||||
|
||||
return Promise.all([setup_cache(), setup_session()]);
|
||||
|
|
@ -214,11 +218,3 @@ export function currentBackend() {
|
|||
export function currentShare() {
|
||||
return new window.URL(location.href).searchParams.get("share") || "";
|
||||
}
|
||||
|
||||
async function initCacheState() {
|
||||
if (!backendID) {
|
||||
const { responseJSON } = await ajax({ url: "/api/session", responseType: "json" }).toPromise();
|
||||
backendID = responseJSON.result.backendID;
|
||||
}
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,10 @@
|
|||
import { toHref, navigate } from "../../lib/skeleton/router.js";
|
||||
import rxjs from "../../lib/rx.js";
|
||||
import ajax from "../../lib/ajax.js";
|
||||
import { basename, forwardURLParams } from "../../lib/path.js";
|
||||
import notification from "../../components/notification.js";
|
||||
import assert from "../../lib/assert.js";
|
||||
import { AjaxError } from "../../lib/error.js";
|
||||
import t from "../../locales/index.js";
|
||||
|
||||
import { currentPath } from "./helper.js";
|
||||
|
|
@ -28,6 +30,14 @@ const handleError = rxjs.catchError((err) => {
|
|||
notification.error(err);
|
||||
throw err;
|
||||
});
|
||||
const handleErrorRedirectLogin = rxjs.catchError((err) => {
|
||||
if (err instanceof AjaxError && err.err().status === 401) {
|
||||
navigate(toHref("/login?next=" + location.pathname + location.hash + location.search));
|
||||
return rxjs.EMPTY;
|
||||
}
|
||||
throw err;
|
||||
});
|
||||
|
||||
const trimDirectorySuffix = (name) => name.replace(new RegExp("/$"), "");
|
||||
|
||||
export const touch = (path) => ajax({
|
||||
|
|
@ -75,6 +85,7 @@ export const ls = (path) => {
|
|||
method: "GET",
|
||||
responseType: "json",
|
||||
}).pipe(
|
||||
handleErrorRedirectLogin,
|
||||
rxjs.map(({ responseJSON }) => ({
|
||||
files: responseJSON.results,
|
||||
permissions: responseJSON.permissions,
|
||||
|
|
|
|||
Loading…
Reference in a new issue