diff --git a/public/assets/lib/store.js b/public/assets/lib/store.js index e22df458..a5ee21b1 100644 --- a/public/assets/lib/store.js +++ b/public/assets/lib/store.js @@ -3,7 +3,8 @@ export function settingsGet(initialValues, prefix = "") { let currentSettings = {}; Object.keys(initialValues).forEach((key) => { const settingsKey = prefix ? `${prefix}_${key}` : key; - currentSettings[key] = raw[settingsKey]; + if (settingsKey in raw) currentSettings[key] = raw[settingsKey]; + else currentSettings[key] = initialValues[key]; }); return currentSettings; } diff --git a/public/assets/pages/filespage/ctrl_submenu.js b/public/assets/pages/filespage/ctrl_submenu.js index 70df225b..7f8167d2 100644 --- a/public/assets/pages/filespage/ctrl_submenu.js +++ b/public/assets/pages/filespage/ctrl_submenu.js @@ -134,32 +134,31 @@ function componentLeft(render, { $scroll }) { onClick(qs($page, `[data-action="tag"]`)).pipe(rxjs.tap(() => { componentTag(createModal(modalOpt)); })), - onClick(qs($page, `[data-action="rename"]`)).pipe( - rxjs.mergeMap(() => componentRename( + onClick(qs($page, `[data-action="rename"]`)).pipe(rxjs.mergeMap(() => { + const path = expandSelection()[0].path; + return rxjs.from(componentRename( createModal(modalOpt), - basename(expandSelection()[0].path.replace(new RegExp("/$"), "")), - )), - rxjs.mergeMap((val) => { // TODO: migrate to transcient impl - const path = expandSelection()[0].path; + basename(path.replace(new RegExp("/$"), "")), + )).pipe(rxjs.mergeMap((val) => { const [basepath, filename] = extractPath(path); clearSelection(); clearCache(path); clearCache(basepath + val); return mv(path, basepath + val); - }), - ), - onClick(qs($page, `[data-action="delete"]`)).pipe( - rxjs.mergeMap(() => componentDelete( + })); + })), + onClick(qs($page, `[data-action="delete"]`)).pipe(rxjs.mergeMap(() => { + const path = expandSelection()[0].path; + return rxjs.from(componentDelete( createModal(modalOpt), - basename(expandSelection()[0].path.replace(new RegExp("/$"), "")).substr(0, 15), - )), - rxjs.mergeMap((val) => { // TODO: migrate to transcient impl + basename(path.replace(new RegExp("/$"), "")).substr(0, 15), + )).pipe(rxjs.mergeMap(() =>{ const selection = expandSelection()[0].path; clearSelection(); - clearCache(selection); + clearCache(path); return rm(selection); - }), - ), + })); + })), )), )); @@ -174,14 +173,16 @@ function componentLeft(render, { $scroll }) { `))), rxjs.mergeMap(($page) => rxjs.merge( - onClick(qs($page, `[data-action="delete"]`)).pipe( - rxjs.mergeMap(() => componentDelete(createModal(modalOpt), "remove")), - rxjs.mergeMap((val) => { - const selections = expandSelection().map(({ path }) => path); + onClick(qs($page, `[data-action="delete"]`)).pipe(rxjs.mergeMap(() => { + const paths = expandSelection().map(({ path }) => path); + return rxjs.from(componentDelete( + createModal(modalOpt), + "remove", + )).pipe(rxjs.mergeMap((val) => { clearSelection(); - return rm(...selections); - }), - ), + return rm(...paths); + })); + })), )), )); } @@ -203,9 +204,20 @@ function componentRight(render) { rxjs.share(), ); + const defaultLayout = (view) => { + switch (view) { + case "grid": return `grid`; + case "list": return `list`; + default: throw new Error("NOT_IMPLEMENTED"); + } + }; + const defaultSort = () => { + return `sort`; + }; effect(getSelection$().pipe( rxjs.filter((selections) => selections.length === 0), - rxjs.map(() => render(createFragment(` + rxjs.mergeMap(() => getState$().pipe(rxjs.first())), + rxjs.map(({ view, sort }) => render(createFragment(`
`); - render($modal, ({ id }) => { + render($modal, (id) => { if (id !== 1) return; }); } diff --git a/public/assets/pages/filespage/model_files.js b/public/assets/pages/filespage/model_files.js index 9f73b495..d3e56c80 100644 --- a/public/assets/pages/filespage/model_files.js +++ b/public/assets/pages/filespage/model_files.js @@ -1,6 +1,8 @@ import rxjs from "../../lib/rx.js"; import ajax from "../../lib/ajax.js"; +import { basename } from "../../lib/path.js"; import notification from "../../components/notification.js"; +import t from "../../locales/index.js"; import { currentPath } from "./helper.js"; import { setPermissions } from "./model_acl.js"; @@ -20,34 +22,48 @@ import { ls as middlewareLs } from "./model_virtual_layer.js"; * 3. the new file is being persisted in the screen if the API call is a success */ -const withNotification = rxjs.catchError((err) => { +const handleSuccess = (text) => rxjs.tap(() => notification.info(text)); +const handleError = rxjs.catchError((err) => { notification.error(err); throw err; }); +const trimDirectorySuffix = (name) => name.replace(new RegExp("/$"), ""); export const touch = (path) => ajax({ url: `api/files/touch?path=${encodeURIComponent(path)}`, method: "POST", responseType: "json", -}).pipe(withNotification); +}).pipe( + handleSuccess(t("A file named '{{VALUE}}' was created", basename(path))), + handleError, +); export const mkdir = (path) => ajax({ url: `api/files/mkdir?path=${encodeURIComponent(path)}`, method: "POST", responseType: "json", -}).pipe(withNotification); +}).pipe( + handleSuccess(t("A folder named '{{VALUE}}' was created", basename(trimDirectorySuffix(path)))), + handleError, +); export const rm = (...paths) => rxjs.forkJoin(paths.map((path) => ajax({ url: `api/files/rm?path=${encodeURIComponent(path)}`, method: "POST", responseType: "json", -}).pipe(withNotification))); +}))).pipe( + handleSuccess(paths.length > 1 ? t("All Done!") : t("The file '{{VALUE}}' was deleted", basename(trimDirectorySuffix(paths[0])))), + handleError, +); export const mv = (from, to) => ajax({ url: `api/files/mv?from=${encodeURIComponent(from)}&to=${encodeURIComponent(to)}`, method: "POST", responseType: "json", -}).pipe(withNotification); +}).pipe( + handleSuccess(t("The file '{{VALUE}}' was renamed", basename(trimDirectorySuffix(from)))), + handleError, +); export const save = (path) => rxjs.of(null).pipe(rxjs.delay(1000)); diff --git a/public/assets/pages/filespage/state_config.js b/public/assets/pages/filespage/state_config.js index b7d5eece..bc71bccc 100644 --- a/public/assets/pages/filespage/state_config.js +++ b/public/assets/pages/filespage/state_config.js @@ -1,16 +1,23 @@ import { onDestroy } from "../../lib/skeleton/index.js"; import rxjs, { effect, preventDefault } from "../../lib/rx.js"; import { settingsGet, settingsSave } from "../../lib/store.js"; +import { get as getConfig } from "./model_config.js"; -const state$ = new rxjs.BehaviorSubject({ - view: "grid", - sort: "type", - show_hidden: false, - order: null, - search: "", +const state$ = new rxjs.BehaviorSubject(null); + +getConfig().subscribe((config) => { + state$.next(settingsGet({ + view: config.default_view || "grid", + show_hidden: config.display_hidden || false, + sort: config.default_sort || "type", + order: null, + search: "", + }, "filespage")); }); -export const getState$ = () => state$.asObservable(); +export const getState$ = () => state$.asObservable().pipe( + rxjs.filter((state) => state !== null), +); export const setState = (...args) => { const obj = { ...state$.value }; @@ -22,7 +29,12 @@ export const setState = (...args) => { } if (!hasChange) return state$.next(obj); - settingsSave(state$.value, "filespage"); + settingsSave({ + view: state$.value.view, + show_hidden: state$.value.show_hidden, + sort: state$.value.sort, + order: state$.value.order, + }, "filespage"); } effect(rxjs.fromEvent(window, "keydown").pipe(