mirror of
https://github.com/mickael-kerjean/filestash.git
synced 2024-04-21 12:32:08 +00:00
chore (eslint): lint frontend
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
import rxjs, { ajax } from "../lib/rx.js";
|
||||
import { loadScript, init as initCSS } from "../helpers/loader.js";
|
||||
import { init as initCSS } from "../helpers/loader.js";
|
||||
import { report } from "../helpers/log.js";
|
||||
import { $error } from "./common.js";
|
||||
|
||||
@@ -45,5 +44,5 @@ async function setup_history() {
|
||||
}
|
||||
|
||||
async function setup_css() {
|
||||
return initCSS()
|
||||
return initCSS();
|
||||
}
|
||||
|
||||
@@ -8,7 +8,9 @@ class ComponentBreadcrumb extends HTMLDivElement {
|
||||
super();
|
||||
if (new window.URL(location.href).searchParams.get("nav") === "false") return null;
|
||||
|
||||
const htmlLogout = isRunningFromAnIframe ? "" : `
|
||||
const htmlLogout = isRunningFromAnIframe
|
||||
? ""
|
||||
: `
|
||||
<a href="/logout" data-link>
|
||||
<img class="component_icon" draggable="false" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0ODkuODg4IDQ4OS44ODgiIHN0eWxlPSJlbmFibGUtYmFja2dyb3VuZDpuZXcgMCAwIDQ4OS44ODggNDg5Ljg4ODsiPgogIDxwYXRoIGZpbGw9IiM2ZjZmNmYiIGQ9Ik0yNS4zODMsMjkwLjVjLTcuMi03Ny41LDI1LjktMTQ3LjcsODAuOC0xOTIuM2MyMS40LTE3LjQsNTMuNC0yLjUsNTMuNCwyNWwwLDBjMCwxMC4xLTQuOCwxOS40LTEyLjYsMjUuNyAgICBjLTM4LjksMzEuNy02Mi4zLDgxLjctNTYuNiwxMzYuOWM3LjQsNzEuOSw2NSwxMzAuMSwxMzYuOCwxMzguMWM5My43LDEwLjUsMTczLjMtNjIuOSwxNzMuMy0xNTQuNWMwLTQ4LjYtMjIuNS05Mi4xLTU3LjYtMTIwLjYgICAgYy03LjgtNi4zLTEyLjUtMTUuNi0xMi41LTI1LjZsMCwwYzAtMjcuMiwzMS41LTQyLjYsNTIuNy0yNS42YzUwLjIsNDAuNSw4Mi40LDEwMi40LDgyLjQsMTcxLjhjMCwxMjYuOS0xMDcuOCwyMjkuMi0yMzYuNywyMTkuOSAgICBDMTIyLjE4Myw0ODEuOCwzNS4yODMsMzk2LjksMjUuMzgzLDI5MC41eiBNMjQ0Ljg4MywwYy0xOCwwLTMyLjUsMTQuNi0zMi41LDMyLjV2MTQ5LjdjMCwxOCwxNC42LDMyLjUsMzIuNSwzMi41ICAgIHMzMi41LTE0LjYsMzIuNS0zMi41VjMyLjVDMjc3LjM4MywxNC42LDI2Mi44ODMsMCwyNDQuODgzLDB6IiAvPgo8L3N2Zz4K" alt="power">
|
||||
</a>
|
||||
@@ -18,18 +20,17 @@ class ComponentBreadcrumb extends HTMLDivElement {
|
||||
const htmlPathChunks = paths.map((chunk, idx) => {
|
||||
const label = idx === 0 ? "Filestash" : chunk;
|
||||
const link = paths.slice(0, idx + 1).join("/") + "/";
|
||||
const minify = function() {
|
||||
if (idx === 0) return false;
|
||||
else if (paths.length <= (document.body.clientWidth > 800 ? 5 : 4)) return false;
|
||||
else if (idx > paths.length - (document.body.clientWidth > 1000 ? 4 : 3)) return false;
|
||||
return true;
|
||||
}();
|
||||
// const minify = (function() {
|
||||
// if (idx === 0) return false;
|
||||
// else if (paths.length <= (document.body.clientWidth > 800 ? 5 : 4)) return false;
|
||||
// else if (idx > paths.length - (document.body.clientWidth > 1000 ? 4 : 3)) return false;
|
||||
// return true;
|
||||
// }());
|
||||
const limitSize = (word, highlight = false) => {
|
||||
if (highlight === true && word.length > 30) return word.substring(0, 12).trim() + "..." +
|
||||
word.substring(word.length - 10, word.length).trim();
|
||||
if (highlight === true && word.length > 30) { return word.substring(0, 12).trim() + "..." +
|
||||
word.substring(word.length - 10, word.length).trim(); }
|
||||
else if (word.length > 27) return word.substring(0, 20).trim() + "...";
|
||||
return word;
|
||||
|
||||
};
|
||||
const isLast = idx === paths.length - 1;
|
||||
if (isLast) return `
|
||||
|
||||
@@ -214,7 +214,7 @@ export function $renderInput(options = {}) {
|
||||
`);
|
||||
$select.value = value || props.default;
|
||||
attrs.map((setAttribute) => setAttribute($select));
|
||||
(options || []).map((name) => {
|
||||
(options || []).forEach((name) => {
|
||||
const $option = createElement(`
|
||||
<option></option>
|
||||
`);
|
||||
@@ -274,7 +274,7 @@ export function $renderInput(options = {}) {
|
||||
`);
|
||||
$input.value = `unknown element type ${type}`;
|
||||
$input.setAttribute("name", path.join("."));
|
||||
}}
|
||||
} }
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class Loader extends window.HTMLElement {
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: calc(50% - 200px);`
|
||||
top: calc(50% - 200px);`;
|
||||
return `
|
||||
<div class="component_loader">
|
||||
<svg width="120px" height="120px" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createElement, nop } from "../lib/skeleton/index.js";
|
||||
import rxjs, { applyMutation } from "../lib/rx.js";
|
||||
import { animate } from "../lib/animate.js";
|
||||
import { qs, qsa } from "../lib/dom.js";
|
||||
|
||||
import { ApplicationError } from "../lib/error.js";
|
||||
import { CSS } from "../helpers/loader.js";
|
||||
|
||||
export default class Modal {
|
||||
@@ -11,7 +11,7 @@ export default class Modal {
|
||||
}
|
||||
}
|
||||
|
||||
const createModal = async () => createElement(`
|
||||
const createModal = async() => createElement(`
|
||||
<div class="component_modal" id="modal-box">
|
||||
<style>${await CSS(import.meta.url, "modal.css")}</style>
|
||||
<div>
|
||||
@@ -35,9 +35,9 @@ class ModalComponent extends window.HTMLElement {
|
||||
const { onQuit = nop, withButtonsLeft = null, withButtonsRight = null } = opts;
|
||||
|
||||
// feature: build the dom
|
||||
qs($modal, `[data-bind="body"]`).replaceChildren($node);
|
||||
qs($modal, "[data-bind=\"body\"]").replaceChildren($node);
|
||||
this.replaceChildren($modal);
|
||||
qsa($modal, `.component_popup > div.buttons > button`).forEach(($button, i) => {
|
||||
qsa($modal, ".component_popup > div.buttons > button").forEach(($button, i) => {
|
||||
let currentLabel = null;
|
||||
if (i === 0) currentLabel = withButtonsLeft;
|
||||
else if (i === 1) currentLabel = withButtonsRight;
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ApplicationError } from "../lib/error.js";
|
||||
import { animate, slideYIn, slideYOut } from "../lib/animate.js";
|
||||
import { CSS } from "../helpers/loader.js";
|
||||
|
||||
const createNotification = async (msg, type) => createElement(`
|
||||
const createNotification = async(msg, type) => createElement(`
|
||||
<span class="component_notification">
|
||||
<style>${await CSS(import.meta.url, "notification.css")}</style>
|
||||
<div class="no-select">
|
||||
@@ -20,10 +20,6 @@ const createNotification = async (msg, type) => createElement(`
|
||||
class NotificationComponent extends window.HTMLElement {
|
||||
buffer = [];
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
async trigger(message, type) {
|
||||
if (this.buffer.length > 20) this.buffer.pop(); // failsafe
|
||||
this.buffer.push({ message, type });
|
||||
@@ -44,7 +40,7 @@ class NotificationComponent extends window.HTMLElement {
|
||||
keyframes: slideYIn(50),
|
||||
time: 100,
|
||||
});
|
||||
const ids = []
|
||||
const ids = [];
|
||||
await Promise.race([
|
||||
new Promise((done) => ids.push(window.setTimeout(done, this.buffer.length === 1 ? 8000 : 800))),
|
||||
new Promise((done) => ids.push(window.setTimeout(() => $notification.querySelector(".close").onclick = done, 1000))),
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
export function generateSkeleton(n) {
|
||||
let tmpl = `<div class="component_skeleton"></div>`;
|
||||
const tmpl = "<div class=\"component_skeleton\"></div>";
|
||||
let html = "";
|
||||
for (let i=0; i<n; i++) {
|
||||
for (let i = 0; i < n; i++) {
|
||||
html += tmpl;
|
||||
}
|
||||
return html;
|
||||
|
||||
@@ -7,7 +7,7 @@ export { onDestroy } from "./lifecycle.js";
|
||||
let pageLoader;
|
||||
|
||||
export default async function($root, routes, opts = {}) {
|
||||
window.addEventListener("pagechange", async () => {
|
||||
window.addEventListener("pagechange", async() => {
|
||||
try {
|
||||
const route = currentRoute(routes, "");
|
||||
const [ctrl] = await Promise.all([
|
||||
|
||||
+3
-2
@@ -6,7 +6,7 @@
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"check": "tsc && eslint .",
|
||||
"test": "NODE_OPTIONS=--experimental-vm-modules NODE_NO_WARNINGS=1 npx jest"
|
||||
"test": "npx jest"
|
||||
},
|
||||
"author": "Mickael Kerjean",
|
||||
"license": "AGPL",
|
||||
@@ -71,7 +71,8 @@
|
||||
"no-return-assign": ["off"],
|
||||
"brace-style": ["off"],
|
||||
"no-useless-escape": ["off"],
|
||||
"comma-dangle": [0]
|
||||
"comma-dangle": ["off"],
|
||||
"curly": ["off"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
let htmlSelect = "";
|
||||
|
||||
class BoxItem extends window.HTMLDivElement {
|
||||
constructor() {
|
||||
super();
|
||||
@@ -31,7 +29,7 @@ class BoxItem extends window.HTMLDivElement {
|
||||
|
||||
toggleSelection(opt = {}) {
|
||||
const { tmpl, isSelected = !this.classList.contains("active") } = opt;
|
||||
let $icon = this.querySelector(".icon");
|
||||
const $icon = this.querySelector(".icon");
|
||||
if (isSelected) {
|
||||
this.classList.add("active");
|
||||
if (tmpl) $icon.innerHTML = tmpl;
|
||||
|
||||
@@ -18,6 +18,6 @@ export default AdminHOC(async function(render) {
|
||||
|
||||
effect(getRelease().pipe(
|
||||
rxjs.map(({ html }) => html),
|
||||
stateMutation(qs($page, `[data-bind="about"]`), "innerHTML"),
|
||||
stateMutation(qs($page, "[data-bind=\"about\"]"), "innerHTML"),
|
||||
));
|
||||
});
|
||||
|
||||
@@ -19,6 +19,6 @@ export default AdminHOC(async function(render) {
|
||||
render(transition($page));
|
||||
await initConfig();
|
||||
|
||||
componentStorageBackend(createRender(qs($page, `[data-bind="backend"]`)));
|
||||
componentAuthenticationMiddleware(createRender(qs($page, `[data-bind="authentication_middleware"]`)));
|
||||
componentStorageBackend(createRender(qs($page, "[data-bind=\"backend\"]")));
|
||||
componentAuthenticationMiddleware(createRender(qs($page, "[data-bind=\"authentication_middleware\"]")));
|
||||
});
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
import { createElement } from "../../lib/skeleton/index.js";
|
||||
import rxjs, { effect, applyMutation, applyMutations, onClick } from "../../lib/rx.js";
|
||||
import ajax from "../../lib/ajax.js";
|
||||
import { createForm, mutateForm } from "../../lib/form.js";
|
||||
import { qs, qsa } from "../../lib/dom.js";
|
||||
import { formTmpl } from "../../components/form.js";
|
||||
import { generateSkeleton } from "../../components/skeleton.js";
|
||||
import { get as getConfig } from "../../model/config.js";
|
||||
|
||||
import {
|
||||
initMiddleware, initStorage, getState,
|
||||
getMiddlewareAvailable, getMiddlewareEnabled, toggleMiddleware,
|
||||
getBackendAvailable, getBackendEnabled,
|
||||
} from "./ctrl_backend_state.js";
|
||||
import { formObjToJSON$, renderLeaf } from "./helper_form.js";
|
||||
import { renderLeaf } from "./helper_form.js";
|
||||
import { get as getAdminConfig, save as saveConfig } from "./model_config.js";
|
||||
|
||||
import "./component_box-item.js";
|
||||
@@ -42,7 +40,7 @@ export default async function(render) {
|
||||
`))),
|
||||
rxjs.tap(() => {
|
||||
qs($page, "h2").classList.remove("hidden");
|
||||
qs($page, `.box-container`).innerHTML = "";
|
||||
qs($page, ".box-container").innerHTML = "";
|
||||
}),
|
||||
applyMutations(qs($page, ".box-container"), "appendChild"),
|
||||
rxjs.share(),
|
||||
@@ -53,10 +51,10 @@ export default async function(render) {
|
||||
effect(init$.pipe(
|
||||
rxjs.concatMap(() => getMiddlewareEnabled()),
|
||||
rxjs.filter((backend) => !!backend),
|
||||
rxjs.tap((backend) => qsa($page, `[is="box-item"]`).forEach(($button) => {
|
||||
$button.getAttribute("data-label") === backend ?
|
||||
$button.classList.add("active") :
|
||||
$button.classList.remove("active");
|
||||
rxjs.tap((backend) => qsa($page, "[is=\"box-item\"]").forEach(($button) => {
|
||||
$button.getAttribute("data-label") === backend
|
||||
? $button.classList.add("active")
|
||||
: $button.classList.remove("active");
|
||||
})),
|
||||
));
|
||||
|
||||
@@ -78,10 +76,10 @@ export default async function(render) {
|
||||
params: JSON.parse(cfg?.middleware?.identity_provider?.params?.value || "{}"),
|
||||
})),
|
||||
)),
|
||||
rxjs.concatMap(async ([availableSpecs, idpState = {}]) => {
|
||||
rxjs.concatMap(async([availableSpecs, idpState = {}]) => {
|
||||
const { type, params } = idpState;
|
||||
const idps = []
|
||||
for (let key in availableSpecs) {
|
||||
const idps = [];
|
||||
for (const key in availableSpecs) {
|
||||
let idpSpec = availableSpecs[key];
|
||||
delete idpSpec.type;
|
||||
if (key === type) idpSpec = mutateForm(idpSpec, params);
|
||||
@@ -95,7 +93,7 @@ export default async function(render) {
|
||||
}
|
||||
return idps;
|
||||
}),
|
||||
applyMutations(qs($page, `[data-bind="idp"]`), "appendChild"),
|
||||
applyMutations(qs($page, "[data-bind=\"idp\"]"), "appendChild"),
|
||||
rxjs.share(),
|
||||
);
|
||||
effect(setupIDPForm$);
|
||||
@@ -104,15 +102,15 @@ export default async function(render) {
|
||||
effect(setupIDPForm$.pipe(
|
||||
rxjs.concatMap(() => getMiddlewareEnabled()),
|
||||
rxjs.tap((currentMiddleware) => {
|
||||
qsa($page, `[data-bind="idp"] .formbuilder`).forEach(($node) => {
|
||||
$node.getAttribute("id") === currentMiddleware ?
|
||||
$node.classList.remove("hidden") :
|
||||
$node.classList.add("hidden");
|
||||
qsa($page, "[data-bind=\"idp\"] .formbuilder").forEach(($node) => {
|
||||
$node.getAttribute("id") === currentMiddleware
|
||||
? $node.classList.remove("hidden")
|
||||
: $node.classList.add("hidden");
|
||||
});
|
||||
const $attrMap = qs($page, `[data-bind="attribute-mapping"]`);
|
||||
currentMiddleware ?
|
||||
$attrMap.classList.remove("hidden") :
|
||||
$attrMap.classList.add("hidden");
|
||||
const $attrMap = qs($page, "[data-bind=\"attribute-mapping\"]");
|
||||
currentMiddleware
|
||||
? $attrMap.classList.remove("hidden")
|
||||
: $attrMap.classList.add("hidden");
|
||||
|
||||
qsa($page, ".box-item").forEach(($button) => {
|
||||
const $icon = qs($button, ".icon");
|
||||
@@ -124,20 +122,20 @@ export default async function(render) {
|
||||
$button.classList.remove("active");
|
||||
$icon.style.transform = "";
|
||||
}
|
||||
})
|
||||
});
|
||||
}),
|
||||
));
|
||||
|
||||
// feature: setup the attribute mapping form
|
||||
const setupAMForm$ = init$.pipe(
|
||||
rxjs.mapTo({
|
||||
"attribute_mapping": {
|
||||
"related_backend": {
|
||||
"type": "text",
|
||||
"datalist": [],
|
||||
"multi": true,
|
||||
"autocomplete": false,
|
||||
"value": "",
|
||||
attribute_mapping: {
|
||||
related_backend: {
|
||||
type: "text",
|
||||
datalist: [],
|
||||
multi: true,
|
||||
autocomplete: false,
|
||||
value: "",
|
||||
},
|
||||
// dynamic form here is generated reactively from the value of the "related_backend" field
|
||||
}
|
||||
@@ -150,8 +148,8 @@ export default async function(render) {
|
||||
return spec;
|
||||
}),
|
||||
)),
|
||||
rxjs.concatMap(async (specs) => await createForm(specs, formTmpl({}))),
|
||||
applyMutation(qs($page, `[data-bind="attribute-mapping"]`), "replaceChildren"),
|
||||
rxjs.concatMap(async(specs) => await createForm(specs, formTmpl({}))),
|
||||
applyMutation(qs($page, "[data-bind=\"attribute-mapping\"]"), "replaceChildren"),
|
||||
rxjs.share(),
|
||||
);
|
||||
effect(setupAMForm$);
|
||||
@@ -160,14 +158,14 @@ export default async function(render) {
|
||||
effect(setupAMForm$.pipe(
|
||||
rxjs.switchMap(() => rxjs.merge(
|
||||
getBackendEnabled(),
|
||||
rxjs.fromEvent(qs(document, `[data-bind="backend-enabled"]`), "input").pipe(
|
||||
rxjs.fromEvent(qs(document, "[data-bind=\"backend-enabled\"]"), "input").pipe(
|
||||
rxjs.debounceTime(500),
|
||||
rxjs.mergeMap(() => getState().pipe(rxjs.map(({ connections }) => connections))),
|
||||
),
|
||||
)),
|
||||
rxjs.map((connections) => connections.map(({ label }) => label)),
|
||||
rxjs.tap((datalist) => {
|
||||
const $input = $page.querySelector(`[name="attribute_mapping.related_backend"]`);
|
||||
const $input = $page.querySelector("[name=\"attribute_mapping.related_backend\"]");
|
||||
$input.setAttribute("datalist", datalist.join(","));
|
||||
$input.refresh();
|
||||
}),
|
||||
@@ -177,16 +175,16 @@ export default async function(render) {
|
||||
effect(setupAMForm$.pipe(
|
||||
rxjs.switchMap(() => rxjs.merge(
|
||||
// case 1: user is typing in the related backend field
|
||||
rxjs.fromEvent(qs($page, `[name="attribute_mapping.related_backend"]`), "input").pipe(
|
||||
rxjs.fromEvent(qs($page, "[name=\"attribute_mapping.related_backend\"]"), "input").pipe(
|
||||
rxjs.map((e) => e.target.value),
|
||||
),
|
||||
// case 2: user is adding / removing a storage backend
|
||||
getBackendEnabled().pipe(
|
||||
rxjs.map(() => qs($page, `[name="attribute_mapping.related_backend"]`).value)
|
||||
rxjs.map(() => qs($page, "[name=\"attribute_mapping.related_backend\"]").value)
|
||||
),
|
||||
// case 3: user is changing the storage backend label
|
||||
rxjs.fromEvent(qs(document, `[data-bind="backend-enabled"]`), "input").pipe(
|
||||
rxjs.map(() => qs($page, `[name="attribute_mapping.related_backend"]`).value),
|
||||
rxjs.fromEvent(qs(document, "[data-bind=\"backend-enabled\"]"), "input").pipe(
|
||||
rxjs.map(() => qs($page, "[name=\"attribute_mapping.related_backend\"]").value),
|
||||
),
|
||||
)),
|
||||
rxjs.map((value) => value.split(",").map((val) => (val || "").trim()).filter((t) => !!t)),
|
||||
@@ -194,15 +192,15 @@ export default async function(render) {
|
||||
rxjs.map(({ connections }) => connections),
|
||||
rxjs.first(),
|
||||
rxjs.map((enabledBackends) => inputBackends
|
||||
.map((label) => enabledBackends.find((b) => b.label === label))
|
||||
.filter((label) => !!label)),
|
||||
.map((label) => enabledBackends.find((b) => b.label === label))
|
||||
.filter((label) => !!label)),
|
||||
)),
|
||||
rxjs.mergeMap((backends) => getBackendAvailable().pipe(rxjs.first(), rxjs.map((specs) => {
|
||||
// we don't want to show the "normal" form but a flat version of it
|
||||
// so we're getting rid of anything that could make some magic happen like toggle and
|
||||
// ids which enable those interactions
|
||||
for (let key in specs) {
|
||||
for (let input in specs[key]) {
|
||||
for (const key in specs) {
|
||||
for (const input in specs[key]) {
|
||||
if (specs[key][input]["type"] === "enable") {
|
||||
delete specs[key][input];
|
||||
} else if ("id" in specs[key][input]) {
|
||||
@@ -213,11 +211,11 @@ export default async function(render) {
|
||||
return [backends, specs];
|
||||
}))),
|
||||
rxjs.map(([backends, formSpec]) => {
|
||||
let spec = {};
|
||||
const spec = {};
|
||||
backends.forEach(({ label, type }) => {
|
||||
if (formSpec[type]) spec[label] = JSON.parse(JSON.stringify(formSpec[type]));
|
||||
});
|
||||
return spec
|
||||
return spec;
|
||||
}),
|
||||
rxjs.mergeMap((spec) => getAdminConfig().pipe(
|
||||
rxjs.first(),
|
||||
@@ -225,9 +223,9 @@ export default async function(render) {
|
||||
rxjs.map((cfg) => {
|
||||
// transform the form state from legacy format (= an object struct which was replicating the spec object)
|
||||
// to the new format which leverage the dom (= or the input name attribute to be precise) to store the entire schema
|
||||
let state = {};
|
||||
for (let key1 in cfg) {
|
||||
for (let key2 in cfg[key1]) {
|
||||
const state = {};
|
||||
for (const key1 in cfg) {
|
||||
for (const key2 in cfg[key1]) {
|
||||
state[`${key1}.${key2}`] = cfg[key1][key2];
|
||||
}
|
||||
}
|
||||
@@ -235,12 +233,12 @@ export default async function(render) {
|
||||
}),
|
||||
)),
|
||||
rxjs.map(([formSpec, formState]) => mutateForm(formSpec, formState)),
|
||||
rxjs.mergeMap(async (formSpec) => await createForm(formSpec, formTmpl({
|
||||
renderLeaf: () => createElement(`<label></label>`),
|
||||
rxjs.mergeMap(async(formSpec) => await createForm(formSpec, formTmpl({
|
||||
renderLeaf: () => createElement("<label></label>"),
|
||||
}))),
|
||||
rxjs.tap(($node) => {
|
||||
let $relatedBackendField;
|
||||
$page.querySelectorAll(`[data-bind="attribute-mapping"] fieldset`).forEach(($el, i) => {
|
||||
$page.querySelectorAll("[data-bind=\"attribute-mapping\"] fieldset").forEach(($el, i) => {
|
||||
if (i === 0) $relatedBackendField = $el;
|
||||
else $el.remove();
|
||||
});
|
||||
|
||||
@@ -6,8 +6,7 @@ import { formTmpl } from "../../components/form.js";
|
||||
import { generateSkeleton } from "../../components/skeleton.js";
|
||||
|
||||
import { initStorage, getState, getBackendAvailable, getBackendEnabled, addBackendEnabled, removeBackendEnabled } from "./ctrl_backend_state.js";
|
||||
import { formObjToJSON$ } from "./helper_form.js";
|
||||
import { get as getAdminConfig, save as saveConfig } from "./model_config.js";
|
||||
import { save as saveConfig } from "./model_config.js";
|
||||
|
||||
import "./component_box-item.js";
|
||||
|
||||
@@ -26,11 +25,11 @@ export default async function(render) {
|
||||
|
||||
// feature: setup the buttons
|
||||
const init$ = getBackendAvailable().pipe(
|
||||
rxjs.tap(() => qs($page, `[data-bind="backend-available"]`).innerHTML = ""),
|
||||
rxjs.tap(() => qs($page, "[data-bind=\"backend-available\"]").innerHTML = ""),
|
||||
rxjs.mergeMap((specs) => Promise.all(Object.keys(specs).map((label) => createElement(`
|
||||
<div is="box-item" data-label="${label}"></div>
|
||||
`)))),
|
||||
applyMutations(qs($page, `[data-bind="backend-available"]`), "appendChild"),
|
||||
applyMutations(qs($page, "[data-bind=\"backend-available\"]"), "appendChild"),
|
||||
rxjs.share(),
|
||||
);
|
||||
effect(init$);
|
||||
@@ -45,10 +44,10 @@ export default async function(render) {
|
||||
});
|
||||
return enabledSet;
|
||||
}),
|
||||
rxjs.tap((backends) => qsa($page, `[is="box-item"]`).forEach(($button) => {
|
||||
backends.has($button.getAttribute("data-label")) ?
|
||||
$button.classList.add("active") :
|
||||
$button.classList.remove("active");
|
||||
rxjs.tap((backends) => qsa($page, "[is=\"box-item\"]").forEach(($button) => {
|
||||
backends.has($button.getAttribute("data-label"))
|
||||
? $button.classList.add("active")
|
||||
: $button.classList.remove("active");
|
||||
})),
|
||||
));
|
||||
|
||||
@@ -63,10 +62,12 @@ export default async function(render) {
|
||||
// feature: setup form
|
||||
const setupForm$ = getBackendEnabled().pipe(
|
||||
// initialise the forms
|
||||
rxjs.mergeMap((enabled) => Promise.all(enabled.map(({ type, label }) => createForm({ [type]: {
|
||||
"": { type: "text", placeholder: "Label", value: label },
|
||||
}}, formTmpl({
|
||||
renderLeaf: () => createElement(`<label></label>`),
|
||||
rxjs.mergeMap((enabled) => Promise.all(enabled.map(({ type, label }) => createForm({
|
||||
[type]: {
|
||||
"": { type: "text", placeholder: "Label", value: label },
|
||||
}
|
||||
}, formTmpl({
|
||||
renderLeaf: () => createElement("<label></label>"),
|
||||
renderNode: ({ label, format }) => {
|
||||
const $fieldset = createElement(`
|
||||
<fieldset>
|
||||
@@ -86,15 +87,15 @@ export default async function(render) {
|
||||
},
|
||||
}))))),
|
||||
rxjs.map((nodeList) => {
|
||||
if (nodeList.length === 0) return [createElement(`
|
||||
if (nodeList.length === 0) { return [createElement(`
|
||||
<div class="alert">
|
||||
You need to select at least 1 storage backend
|
||||
</div>
|
||||
`)];
|
||||
`)]; }
|
||||
return nodeList;
|
||||
}),
|
||||
rxjs.tap(() => qs($page, `[data-bind="backend-enabled"]`).innerHTML = ""),
|
||||
applyMutations(qs($page, `[data-bind="backend-enabled"]`), "appendChild"),
|
||||
rxjs.tap(() => qs($page, "[data-bind=\"backend-enabled\"]").innerHTML = ""),
|
||||
applyMutations(qs($page, "[data-bind=\"backend-enabled\"]"), "appendChild"),
|
||||
rxjs.share(),
|
||||
);
|
||||
effect(setupForm$);
|
||||
|
||||
@@ -25,11 +25,11 @@ export function addBackendEnabled(type) {
|
||||
existingLabels.add(obj.label.toLowerCase());
|
||||
});
|
||||
|
||||
let label = "", i = 1;
|
||||
let label = ""; let i = 1;
|
||||
while (true) {
|
||||
label = type + (i === 1 ? "" : ` ${i}`);
|
||||
if (existingLabels.has(label) === false) break;
|
||||
i+=1;
|
||||
i += 1;
|
||||
}
|
||||
|
||||
const b = backendsEnabled$.value.concat({ type, label });
|
||||
@@ -74,7 +74,7 @@ export function getState() {
|
||||
formObjToJSON$(),
|
||||
rxjs.map((config) => { // connections
|
||||
const connections = [];
|
||||
const formData = new FormData(qs(document, `[data-bind="backend-enabled"]`));
|
||||
const formData = new FormData(qs(document, "[data-bind=\"backend-enabled\"]"));
|
||||
for (const [type, label] of formData.entries()) {
|
||||
connections.push({ type, label });
|
||||
}
|
||||
@@ -83,8 +83,8 @@ export function getState() {
|
||||
}),
|
||||
rxjs.map((config) => { // middleware
|
||||
const authType = document
|
||||
.querySelector(`[data-bind="authentication_middleware"] [is="box-item"].active`)
|
||||
?.getAttribute("data-label");
|
||||
.querySelector("[data-bind=\"authentication_middleware\"] [is=\"box-item\"].active")
|
||||
?.getAttribute("data-label");
|
||||
|
||||
config.middleware = {
|
||||
identity_provider: { type: null },
|
||||
@@ -92,7 +92,7 @@ export function getState() {
|
||||
};
|
||||
if (!authType) return config;
|
||||
|
||||
let formValues = [...new FormData(document.querySelector(`[data-bind="idp"]`))];
|
||||
let formValues = [...new FormData(document.querySelector("[data-bind=\"idp\"]"))];
|
||||
config.middleware.identity_provider = {
|
||||
type: authType,
|
||||
params: JSON.stringify(
|
||||
@@ -109,7 +109,7 @@ export function getState() {
|
||||
),
|
||||
};
|
||||
|
||||
formValues = [...new FormData(document.querySelector(`[data-bind="attribute-mapping"]`))];
|
||||
formValues = [...new FormData(document.querySelector("[data-bind=\"attribute-mapping\"]"))];
|
||||
config.middleware.attribute_mapping = {
|
||||
related_backend: formValues.shift()[1],
|
||||
params: JSON.stringify(formValues.reduce((acc, [key, value]) => {
|
||||
|
||||
@@ -7,7 +7,7 @@ import componentAuditor from "./ctrl_log_audit.js";
|
||||
import transition from "./animate.js";
|
||||
import AdminHOC from "./decorator.js";
|
||||
|
||||
export default AdminHOC(async function (render) {
|
||||
export default AdminHOC(async function(render) {
|
||||
const $page = createElement(`
|
||||
<div class="component_logpage sticky">
|
||||
<h2>Logging</h2>
|
||||
|
||||
@@ -34,7 +34,7 @@ export default function(render) {
|
||||
effect(setup$.pipe(
|
||||
rxjs.first(),
|
||||
rxjs.tap(() => updateLoop($page, audit$)),
|
||||
))
|
||||
));
|
||||
}
|
||||
|
||||
function updateLoop($page, audit$) {
|
||||
@@ -47,7 +47,7 @@ function updateLoop($page, audit$) {
|
||||
|
||||
// feature2: update to the query form
|
||||
effect(rxjs.of(null).pipe(
|
||||
useForm$(() => qsa($page, `form [name]`)),
|
||||
useForm$(() => qsa($page, "form [name]")),
|
||||
rxjs.tap(() => setLoader(true)),
|
||||
rxjs.debounceTime(1000),
|
||||
rxjs.first(),
|
||||
|
||||
@@ -33,7 +33,7 @@ export default function(render) {
|
||||
|
||||
// feature2: form change
|
||||
effect(setup$.pipe(
|
||||
useForm$(() => qsa($form, `[name]`)),
|
||||
useForm$(() => qsa($form, "[name]")),
|
||||
rxjs.combineLatestWith(getAdminConfig().pipe(rxjs.first())),
|
||||
rxjs.map(([formState, formSpec]) => {
|
||||
const fstate = Object.fromEntries(Object.entries(formState).map(([key, value]) => ([
|
||||
@@ -50,7 +50,7 @@ export default function(render) {
|
||||
}),
|
||||
saveConfig(),
|
||||
rxjs.catchError((err) => {
|
||||
notification.error(err && err.message || t("Oops"));
|
||||
notification.error((err && err.message) || t("Oops"));
|
||||
return rxjs.EMPTY;
|
||||
}),
|
||||
));
|
||||
|
||||
@@ -43,7 +43,7 @@ export default async function(render) {
|
||||
rxjs.switchMap((creds) => authenticate$(creds).pipe(
|
||||
rxjs.catchError((err) => {
|
||||
if (err instanceof AjaxError) {
|
||||
switch(err.code()) {
|
||||
switch (err.code()) {
|
||||
case "INTERNAL_SERVER_ERROR":
|
||||
ctrlError(err)(render);
|
||||
return rxjs.EMPTY;
|
||||
|
||||
@@ -4,7 +4,6 @@ import { qs, qsa } from "../../lib/dom.js";
|
||||
import { createForm, mutateForm } from "../../lib/form.js";
|
||||
import { formTmpl } from "../../components/form.js";
|
||||
import { generateSkeleton } from "../../components/skeleton.js";
|
||||
import notification from "../../components/notification.js";
|
||||
import { get as getConfig } from "../../model/config.js";
|
||||
|
||||
import { get as getAdminConfig, save as saveConfig, initConfig } from "./model_config.js";
|
||||
@@ -39,21 +38,22 @@ export default AdminHOC(async function(render) {
|
||||
</div>
|
||||
`);
|
||||
},
|
||||
renderLeaf, autocomplete: false,
|
||||
renderLeaf,
|
||||
autocomplete: false,
|
||||
});
|
||||
|
||||
// feature: setup the form
|
||||
const init$ = config$.pipe(
|
||||
rxjs.mergeMap((formSpec) => createForm(formSpec, tmpl)),
|
||||
rxjs.map(($form) => [$form]),
|
||||
applyMutation(qs($container, `[data-bind="form"]`), "replaceChildren"),
|
||||
applyMutation(qs($container, "[data-bind=\"form\"]"), "replaceChildren"),
|
||||
rxjs.share(),
|
||||
);
|
||||
effect(init$);
|
||||
|
||||
// feature: handle form change
|
||||
effect(init$.pipe(
|
||||
useForm$(() => qsa($container, `[data-bind="form"] [name]`)),
|
||||
useForm$(() => qsa($container, "[data-bind=\"form\"] [name]")),
|
||||
rxjs.combineLatestWith(config$.pipe(rxjs.first())),
|
||||
rxjs.map(([formState, formSpec]) => mutateForm(formSpec, formState)),
|
||||
reshapeConfigBeforeSave,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { createElement, createRender, onDestroy } from "../../lib/skeleton/index.js";
|
||||
import rxjs, { effect, stateMutation, applyMutation, preventDefault } from "../../lib/rx.js";
|
||||
import { createElement, createRender } from "../../lib/skeleton/index.js";
|
||||
import rxjs, { effect, applyMutation, preventDefault } from "../../lib/rx.js";
|
||||
import { qs } from "../../lib/dom.js";
|
||||
import { ApplicationError } from "../../lib/error.js";
|
||||
import { transition, animate, zoomIn, slideXOut, slideXIn } from "../../lib/animate.js";
|
||||
@@ -35,7 +35,7 @@ export default async function(render) {
|
||||
else if (step === 2) return WithShell(componentStep2);
|
||||
throw new ApplicationError("INTERNAL_ERROR", "Assumption failed");
|
||||
}),
|
||||
rxjs.tap((ctrl) => ctrl(createRender(qs($page, `[data-bind="multistep-form"]`)))),
|
||||
rxjs.tap((ctrl) => ctrl(createRender(qs($page, "[data-bind=\"multistep-form\"]")))),
|
||||
rxjs.catchError((err) => ctrlError(err)(render)),
|
||||
));
|
||||
};
|
||||
@@ -92,10 +92,9 @@ const reshapeConfigBeforeSave = rxjs.pipe(
|
||||
config["connections"] = publicConfig["connections"];
|
||||
return config;
|
||||
}),
|
||||
)
|
||||
);
|
||||
|
||||
function componentStep2(render) {
|
||||
const deps = [];
|
||||
const $page = createElement(`
|
||||
<div id="step2">
|
||||
<h4>
|
||||
@@ -112,7 +111,7 @@ function componentStep2(render) {
|
||||
effect(getDeps().pipe(
|
||||
rxjs.mergeMap((deps) => deps),
|
||||
rxjs.map(({ name_success, name_failure, pass, severe, message }) => ({
|
||||
className: (severe ? "severe" : "") + " " +(pass ? "yes" : "no"),
|
||||
className: (severe ? "severe" : "") + " " + (pass ? "yes" : "no"),
|
||||
label: pass ? name_success : name_failure,
|
||||
extraLabel: pass ? "" : ": " + message,
|
||||
})),
|
||||
@@ -121,11 +120,11 @@ function componentStep2(render) {
|
||||
<span>${label}</span>${extraLabel}
|
||||
</div>
|
||||
`)),
|
||||
applyMutation(qs($page, `[data-bind="dependencies"]`), "appendChild"),
|
||||
))
|
||||
applyMutation(qs($page, "[data-bind=\"dependencies\"]"), "appendChild"),
|
||||
));
|
||||
|
||||
// feature: navigate previous step
|
||||
effect(rxjs.fromEvent(qs($page, `[data-bind="previous"]`), "click").pipe(
|
||||
effect(rxjs.fromEvent(qs($page, "[data-bind=\"previous\"]"), "click").pipe(
|
||||
rxjs.tap(() => stepper$.next(1))
|
||||
));
|
||||
|
||||
@@ -162,12 +161,12 @@ function componentStep2(render) {
|
||||
withButtonsRight: "OK",
|
||||
onQuit: () => next(config),
|
||||
});
|
||||
qs($modal, `[type="checkbox"]`).oninput = (e) => {
|
||||
qs($modal, "[type=\"checkbox\"]").oninput = (e) => {
|
||||
if (!e.target.checked) return;
|
||||
qs(document, "component-modal > div").click();
|
||||
}
|
||||
};
|
||||
})),
|
||||
rxjs.filter(() => qs($modal, `[type="checkbox"]`).checked),
|
||||
rxjs.filter(() => qs($modal, "[type=\"checkbox\"]").checked),
|
||||
rxjs.map((config) => {
|
||||
config["log"]["telemetry"] = true;
|
||||
return config;
|
||||
|
||||
@@ -6,7 +6,7 @@ import "../../components/loader.js";
|
||||
|
||||
export default function HOC(ctrlPage) {
|
||||
const ctrlLoading = (render) => {
|
||||
render(createElement(`<component-loader inlined></component-loader>`));
|
||||
render(createElement("<component-loader inlined></component-loader>"));
|
||||
};
|
||||
|
||||
return (render) => {
|
||||
@@ -14,6 +14,6 @@ export default function HOC(ctrlPage) {
|
||||
|
||||
return (render) => {
|
||||
WithShell(ctrlLoading)(render);
|
||||
}
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -26,14 +26,14 @@ export function useForm$($inputNodeList) {
|
||||
rxjs.mergeMap(($el) => rxjs.fromEvent($el, "input")),
|
||||
rxjs.map((e) => ({
|
||||
name: e.target.getAttribute("name"),
|
||||
value: function() {
|
||||
switch(e.target.getAttribute("type")) {
|
||||
value: (function() {
|
||||
switch (e.target.getAttribute("type")) {
|
||||
case "checkbox":
|
||||
return e.target.checked;
|
||||
default:
|
||||
return e.target.value;
|
||||
}
|
||||
}(),
|
||||
}()),
|
||||
})),
|
||||
rxjs.scan((store, keyValue) => {
|
||||
store[keyValue.name] = keyValue.value;
|
||||
@@ -45,7 +45,7 @@ export function useForm$($inputNodeList) {
|
||||
export function formObjToJSON$() {
|
||||
const formObjToJSON = (o, level = 0) => {
|
||||
const obj = Object.assign({}, o);
|
||||
Object.keys(obj).map((key) => {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const t = obj[key];
|
||||
if ("label" in t && "type" in t && "default" in t && "value" in t) {
|
||||
obj[key] = obj[key].value;
|
||||
@@ -54,6 +54,6 @@ export function formObjToJSON$() {
|
||||
}
|
||||
});
|
||||
return obj;
|
||||
}
|
||||
};
|
||||
return rxjs.map(formObjToJSON);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import rxjs from "../../lib/rx.js";
|
||||
import ajax from "../../lib/ajax.js";
|
||||
|
||||
import { getBackends as _getBackends } from "../../model/backend.js";
|
||||
import { isSaving } from "./model_config.js";
|
||||
|
||||
@@ -12,7 +12,7 @@ const config$ = isSaving$.pipe(
|
||||
})),
|
||||
rxjs.map((res) => res.responseJSON.result),
|
||||
rxjs.shareReplay(1),
|
||||
)
|
||||
);
|
||||
|
||||
export async function initConfig() {
|
||||
if (isSaving$.value === true) isSaving$.next(false);
|
||||
|
||||
@@ -2,7 +2,7 @@ import rxjs from "../../lib/rx.js";
|
||||
import ajax from "../../lib/ajax.js";
|
||||
|
||||
const log$ = ajax({
|
||||
url: url(1024*100), // fetch the last 100kb by default
|
||||
url: url(1024 * 100), // fetch the last 100kb by default
|
||||
responseType: "text",
|
||||
}).pipe(
|
||||
rxjs.map(({ response }) => response),
|
||||
|
||||
@@ -7,29 +7,29 @@ export function getDeps() {
|
||||
formObjToJSON$(),
|
||||
rxjs.map(({ constant }) => ([
|
||||
{
|
||||
"name_success": "SSL is configured properly",
|
||||
"name_failure": "SSL is not configured properly",
|
||||
"pass": window.location.protocol !== "http:",
|
||||
"severe": true,
|
||||
"message": "This can lead to data leaks. Please use a SSL certificate",
|
||||
name_success: "SSL is configured properly",
|
||||
name_failure: "SSL is not configured properly",
|
||||
pass: window.location.protocol !== "http:",
|
||||
severe: true,
|
||||
message: "This can lead to data leaks. Please use a SSL certificate",
|
||||
}, {
|
||||
"name_success": "Application is running as '" + constant.user.value + "'",
|
||||
"name_failure": "Application is running as root",
|
||||
"pass": constant.user !== "root",
|
||||
"severe": true,
|
||||
"message": "This is dangerous, you should use another user with less privileges",
|
||||
name_success: "Application is running as '" + constant.user.value + "'",
|
||||
name_failure: "Application is running as root",
|
||||
pass: constant.user !== "root",
|
||||
severe: true,
|
||||
message: "This is dangerous, you should use another user with less privileges",
|
||||
}, {
|
||||
"name_success": "Emacs is installed",
|
||||
"name_failure": "Emacs is not installed",
|
||||
"pass": !!constant.emacs,
|
||||
"severe": false,
|
||||
"message": "If you want to use all the org-mode features of Filestash, you need to install emacs",
|
||||
name_success: "Emacs is installed",
|
||||
name_failure: "Emacs is not installed",
|
||||
pass: !!constant.emacs,
|
||||
severe: false,
|
||||
message: "If you want to use all the org-mode features of Filestash, you need to install emacs",
|
||||
}, {
|
||||
"name_success": "Pdftotext is installed",
|
||||
"name_failure": "Pdftotext is not installed",
|
||||
"pass": !!constant.pdftotext,
|
||||
"severe": false,
|
||||
"message": "You won't be able to search through PDF documents without it",
|
||||
name_success: "Pdftotext is installed",
|
||||
name_failure: "Pdftotext is not installed",
|
||||
pass: !!constant.pdftotext,
|
||||
severe: false,
|
||||
message: "You won't be able to search through PDF documents without it",
|
||||
},
|
||||
])),
|
||||
);
|
||||
|
||||
@@ -34,13 +34,13 @@ export default function(err) {
|
||||
render($page);
|
||||
|
||||
// feature: show error details
|
||||
effect(rxjs.fromEvent(qs($page, `button[data-bind="details"]`), "click").pipe(
|
||||
effect(rxjs.fromEvent(qs($page, "button[data-bind=\"details\"]"), "click").pipe(
|
||||
rxjs.mapTo(["hidden"]),
|
||||
applyMutation(qs($page, "pre"), "classList", "toggle")
|
||||
));
|
||||
|
||||
// feature: refresh button
|
||||
effect(rxjs.fromEvent(qs($page, `button[data-bind="refresh"]`), "click").pipe(
|
||||
effect(rxjs.fromEvent(qs($page, "button[data-bind=\"refresh\"]"), "click").pipe(
|
||||
rxjs.tap(() => location.reload())
|
||||
));
|
||||
|
||||
|
||||
@@ -14,13 +14,3 @@ export default function(render) {
|
||||
`);
|
||||
render($page);
|
||||
}
|
||||
|
||||
const tmp = () => {
|
||||
const { previous } = history.state;
|
||||
if (!previous) return;
|
||||
|
||||
const path = previous.split("/").slice(2)
|
||||
};
|
||||
|
||||
|
||||
const cleanupPath = (path = "") => path.split("/").slice(2);
|
||||
|
||||
@@ -32,7 +32,7 @@ export default async function(render) {
|
||||
type: files[i].type,
|
||||
size: files[i].size,
|
||||
time: files[i].time,
|
||||
link: (files[i].type === "file"? "/view" : "/files") + path + files[i].name + (files[i].type === "file" ? "" : "/"),
|
||||
link: (files[i].type === "file" ? "/view" : "/files") + path + files[i].name + (files[i].type === "file" ? "" : "/"),
|
||||
}));
|
||||
}
|
||||
qs($page, ".list").appendChild($fs);
|
||||
|
||||
Reference in New Issue
Block a user