mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-15 12:55:41 +01:00
refactoring (admin): eslint
This commit is contained in:
parent
6ce0680a18
commit
e8efec712f
5 changed files with 304 additions and 261 deletions
|
|
@ -13,7 +13,7 @@ import { t } from "../locales/";
|
|||
|
||||
function AdminOnly(WrappedComponent) {
|
||||
let initIsAdmin = null;
|
||||
return function(props) {
|
||||
return function AdminOnlyComponent(props) {
|
||||
const [isAdmin, setIsAdmin] = useState(initIsAdmin);
|
||||
|
||||
const refresh = () => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable max-len */
|
||||
import React from "react";
|
||||
import { FormBuilder, Icon, Input, Alert } from "../../components/";
|
||||
import { Backend, Config } from "../../model/";
|
||||
|
|
@ -7,41 +8,42 @@ import { t } from "../../locales/";
|
|||
import "./backend.scss";
|
||||
|
||||
export class BackendPage extends React.Component {
|
||||
constructor(props){
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
backend_enabled: [],
|
||||
backend_available: [],
|
||||
auth_available: ["LDAP", "SAML", "OpenID", "External"],
|
||||
auth_enabled: null,
|
||||
config: null
|
||||
config: null,
|
||||
};
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
componentDidMount() {
|
||||
Promise.all([
|
||||
Backend.all(),
|
||||
Config.all()
|
||||
Config.all(),
|
||||
]).then((data) => {
|
||||
let [backend, config] = data;
|
||||
const [backend, config] = data;
|
||||
this.setState({
|
||||
backend_available: backend,
|
||||
backend_enabled: window.CONFIG["connections"].filter((b) => b).map((conn) => {
|
||||
return createFormBackend(backend, conn);
|
||||
}),
|
||||
config: config
|
||||
config: config,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onChange(e){
|
||||
this.setState({refresh: Math.random()}); // refresh the screen to refresh the mutation
|
||||
// that have happenned down the stack
|
||||
onChange(e) {
|
||||
// refresh the screen to refresh the mutation
|
||||
// that have happenned down the stack
|
||||
this.setState({ refresh: Math.random() });
|
||||
|
||||
let json = FormObjToJSON(this.state.config);
|
||||
const json = FormObjToJSON(this.state.config);
|
||||
json.connections = this.state.backend_enabled.map((backend) => {
|
||||
let data = FormObjToJSON(backend, (obj, key) => {
|
||||
if(obj[key].enabled === true){
|
||||
const data = FormObjToJSON(backend, (obj, key) => {
|
||||
if (obj[key].enabled === true) {
|
||||
obj[key] = obj[key].value || obj[key].default;
|
||||
} else {
|
||||
delete obj[key];
|
||||
|
|
@ -61,41 +63,41 @@ export class BackendPage extends React.Component {
|
|||
});
|
||||
}
|
||||
|
||||
addBackend(backend_id){
|
||||
addBackend(backend_id) {
|
||||
this.setState({
|
||||
backend_enabled: this.state.backend_enabled.concat(
|
||||
createFormBackend(this.state.backend_available, {
|
||||
type: backend_id,
|
||||
label: backend_id.toUpperCase()
|
||||
})
|
||||
)
|
||||
label: backend_id.toUpperCase(),
|
||||
}),
|
||||
),
|
||||
}, this.onChange.bind(this));
|
||||
}
|
||||
|
||||
removeBackend(n){
|
||||
removeBackend(n) {
|
||||
this.setState({
|
||||
backend_enabled: this.state.backend_enabled.filter((_, i) => i !== n)
|
||||
backend_enabled: this.state.backend_enabled.filter((_, i) => i !== n),
|
||||
}, this.onChange.bind(this));
|
||||
}
|
||||
|
||||
onClickAuthAvailable(auth){
|
||||
onClickAuthAvailable(auth) {
|
||||
this.setState({
|
||||
auth_enabled: this.state.auth_enabled === auth ? null : auth
|
||||
auth_enabled: this.state.auth_enabled === auth ? null : auth,
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
render() {
|
||||
const update = (value, struct) => {
|
||||
struct.enabled = value;
|
||||
this.setState({refresh: Math.random()});
|
||||
if(value === false){
|
||||
this.setState({ refresh: Math.random() });
|
||||
if (value === false) {
|
||||
struct.value = null;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
const enable = (struct) => {
|
||||
if(typeof struct.value === "string"){
|
||||
if (typeof struct.value === "string") {
|
||||
struct.enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
|
@ -112,117 +114,131 @@ export class BackendPage extends React.Component {
|
|||
return auth_key === this.state.auth_enabled;
|
||||
};
|
||||
|
||||
const renderForm = ($input, props, struct, onChange) => {
|
||||
let $checkbox = (
|
||||
<Input type="checkbox" checked={enable(struct)}
|
||||
style={{ width: "inherit", marginRight: "6px", top: "6px" }}
|
||||
onChange={(e) => onChange(update.bind(this, e.target.checked))} />
|
||||
);
|
||||
if (struct.label === "label") {
|
||||
$checkbox = null;
|
||||
} else if (struct.readonly === true) {
|
||||
$checkbox = null;
|
||||
}
|
||||
return (
|
||||
<label className={"no-select input_type_" + props.params["type"]}>
|
||||
<div>
|
||||
<span>
|
||||
{ $checkbox }
|
||||
{ format(struct.label) }:
|
||||
</span>
|
||||
<div style={{ width: "100%" }}>
|
||||
{ $input }
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="nothing"></span>
|
||||
<div style={{ width: "100%" }}>
|
||||
{
|
||||
struct.description ? (<div className="description">{struct.description}</div>) : null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="component_dashboard">
|
||||
<h2>Enabled Backends</h2>
|
||||
<div className="box-container">
|
||||
{
|
||||
Object.keys(this.state.backend_available)
|
||||
.sort((a, b) => a > b)
|
||||
.map((backend_available, index) => (
|
||||
<div key={index} onClick={this.addBackend.bind(this, backend_available)}
|
||||
className={"box-item pointer no-select" + (isActiveBackend(backend_available) ? " active": "")}>
|
||||
<div>
|
||||
{ backend_available }
|
||||
<span className="no-select">
|
||||
<span className="icon">+</span>
|
||||
</span>
|
||||
</div>
|
||||
<h2>Enabled Backends</h2>
|
||||
<div className="box-container">
|
||||
{
|
||||
Object.keys(this.state.backend_available)
|
||||
.sort((a, b) => a > b)
|
||||
.map((backend_available, index) => (
|
||||
<div key={index}
|
||||
onClick={this.addBackend.bind(this, backend_available)}
|
||||
className={"box-item pointer no-select" + (isActiveBackend(backend_available) ? " active": "")}>
|
||||
<div>
|
||||
{ backend_available }
|
||||
<span className="no-select">
|
||||
<span className="icon">+</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
<h2>Authentication Middleware</h2>
|
||||
|
||||
<Alert>
|
||||
Integrate Filestash with your identity management system
|
||||
</Alert>
|
||||
|
||||
<div className="box-container">
|
||||
{
|
||||
this.state.auth_available.map((auth) => (
|
||||
<div onClick={this.onClickAuthAvailable.bind(this, auth)} key={auth}
|
||||
className={"box-item pointer no-select" + (isActiveAuth(auth) ? " active": "")}>
|
||||
<div>
|
||||
{ auth }
|
||||
<span className="no-select">
|
||||
<span className="icon">
|
||||
{ isActiveAuth(auth) === false ? "+" :
|
||||
<Icon name="delete" /> }
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
|
||||
<h2>Authentication Middleware</h2>
|
||||
|
||||
<Alert>
|
||||
Integrate Filestash with your identity management system
|
||||
</Alert>
|
||||
|
||||
<div className="box-container">
|
||||
{
|
||||
this.state.auth_available.map((auth) => (
|
||||
<div onClick={this.onClickAuthAvailable.bind(this, auth)} key={auth}
|
||||
className={"box-item pointer no-select" + (isActiveAuth(auth) ? " active": "")}>
|
||||
<div>
|
||||
{ auth }
|
||||
<span className="no-select">
|
||||
<span className="icon">
|
||||
{ isActiveAuth(auth) === false ? "+" : <Icon name="delete" /> }
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))
|
||||
this.state.auth_enabled !== null && (
|
||||
<React.Fragment>
|
||||
<Alert className="success">
|
||||
<i>
|
||||
<strong>Register your interest:
|
||||
<a href={`mailto:mickael@kerjean.me?Subject=Filestash - Authentication Middleware - ${this.state.auth_enabled}`}>
|
||||
mickael@kerjean.me
|
||||
</a>
|
||||
</strong>
|
||||
</i>
|
||||
</Alert>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
|
||||
{
|
||||
this.state.auth_enabled !== null && (
|
||||
<React.Fragment>
|
||||
<Alert className="success">
|
||||
<i><strong>Register your interest: <a href={`mailto:mickael@kerjean.me?Subject=Filestash - Authentication Middleware - ${this.state.auth_enabled}`}>mickael@kerjean.me</a></strong></i>
|
||||
</Alert>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
<h2>Backend Configuration</h2>
|
||||
|
||||
<h2>Backend Configuration</h2>
|
||||
|
||||
{
|
||||
this.state.backend_enabled.length !== 0 ? <div>
|
||||
<form>
|
||||
{
|
||||
this.state.backend_enabled.map((backend_enable, index) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
<div className="icons no-select" onClick={this.removeBackend.bind(this, index)}>
|
||||
<Icon name="delete" />
|
||||
</div>
|
||||
<FormBuilder onChange={this.onChange.bind(this)}
|
||||
idx={index}
|
||||
key={index}
|
||||
form={{"": backend_enable}}
|
||||
autoComplete="new-password"
|
||||
render={ ($input, props, struct, onChange) => {
|
||||
let $checkbox = (
|
||||
<Input type="checkbox" style={{width: "inherit", marginRight: "6px", top: "6px"}}
|
||||
checked={enable(struct)} onChange={(e) => onChange(update.bind(this, e.target.checked))}/>
|
||||
);
|
||||
if(struct.label === "label"){
|
||||
$checkbox = null;
|
||||
} else if(struct.readonly === true) {
|
||||
$checkbox = null;
|
||||
}
|
||||
return (
|
||||
<label className={"no-select input_type_" + props.params["type"]}>
|
||||
<div>
|
||||
<span>
|
||||
{ $checkbox }
|
||||
{ format(struct.label) }:
|
||||
</span>
|
||||
<div style={{width: "100%"}}>
|
||||
{ $input }
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="nothing"></span>
|
||||
<div style={{width: "100%"}}>
|
||||
{
|
||||
struct.description ? (<div className="description">{struct.description}</div>) : null
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
}} />
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</form>
|
||||
</div> : <Alert>You need to enable a backend first.</Alert>
|
||||
}
|
||||
{
|
||||
this.state.backend_enabled.length !== 0 ? (
|
||||
<div>
|
||||
<form>
|
||||
{
|
||||
this.state.backend_enabled.map((backend_enable, index) => {
|
||||
return (
|
||||
<div key={index}>
|
||||
<div className="icons no-select"
|
||||
onClick={this.removeBackend.bind(this, index)}>
|
||||
<Icon name="delete" />
|
||||
</div>
|
||||
<FormBuilder onChange={this.onChange.bind(this)}
|
||||
idx={index}
|
||||
key={index}
|
||||
form={{ "": backend_enable }}
|
||||
autoComplete="new-password"
|
||||
render={renderForm} />
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</form>
|
||||
</div>
|
||||
) : <Alert>You need to enable a backend first.</Alert>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React, { useState, useRef } from "react";
|
||||
import { Redirect } from "react-router";
|
||||
import React, { useState, useEffect, useRef } from "react";
|
||||
|
||||
import { Input, Button, Container, Icon } from "../../components/";
|
||||
import { Admin } from "../../model/";
|
||||
|
|
@ -9,36 +8,36 @@ import { t } from "../../locales/";
|
|||
export function LoginPage({ reload = nop }) {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [hasError, setHasError] = useState(false);
|
||||
const $input = useRef();
|
||||
const marginTop = () => ({ marginTop: `${parseInt(window.innerHeight / 3)}px` })
|
||||
const $input = useRef(null);
|
||||
const marginTop = () => ({ marginTop: `${parseInt(window.innerHeight / 3)}px` });
|
||||
const authenticate = (e) => {
|
||||
e.preventDefault();
|
||||
setIsLoading(true);
|
||||
Admin.login($input.current.ref.value)
|
||||
.then(() => reload())
|
||||
.catch(() => {
|
||||
.catch(() => {
|
||||
$input.current.ref.value = "";
|
||||
setIsLoading(false)
|
||||
setIsLoading(false);
|
||||
setHasError(true);
|
||||
setTimeout(() => {
|
||||
setHasError(false);
|
||||
}, 500);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
useRef(() => {
|
||||
useEffect(() => {
|
||||
$input.current.ref.focus();
|
||||
}, []);
|
||||
|
||||
|
||||
return (
|
||||
<Container maxWidth="300px" className="sharepage_component">
|
||||
<form className={hasError ? "error" : ""} onSubmit={authenticate} style={marginTop()}>
|
||||
<form className={hasError ? "error" : ""}
|
||||
onSubmit={authenticate} style={marginTop()}>
|
||||
<Input ref={$input} type="password" placeholder={ t("Password") } />
|
||||
<Button theme="transparent">
|
||||
<Icon name={isLoading ? "loading" : "arrow_right"}/>
|
||||
</Button>
|
||||
</form>
|
||||
</Container>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,71 +1,76 @@
|
|||
import React, { useState, useEffect } from "react";
|
||||
import { FormBuilder } from "../../components/";
|
||||
import { Config } from "../../model/";
|
||||
import { format, notify, nop } from "../../helpers";
|
||||
import { notify, nop } from "../../helpers";
|
||||
import { t } from "../../locales/";
|
||||
|
||||
export function SettingsPage({ isSaving = nop }) {
|
||||
const [form, setForm] = useState({});
|
||||
const format = (name) => {
|
||||
if(typeof name !== "string"){
|
||||
if (typeof name !== "string") {
|
||||
return "N/A";
|
||||
}
|
||||
return name
|
||||
.split("_")
|
||||
.map((word) => {
|
||||
if(word.length < 1){
|
||||
if (word.length < 1) {
|
||||
return word;
|
||||
}
|
||||
return word[0].toUpperCase() + word.substring(1);
|
||||
})
|
||||
.join(" ");
|
||||
}
|
||||
};
|
||||
const onChange = (_form) => {
|
||||
_form.connections = window.CONFIG.connections;
|
||||
delete _form.constant;
|
||||
refresh(Math.random())
|
||||
isSaving(true)
|
||||
refresh(Math.random());
|
||||
isSaving(true);
|
||||
Config.save(_form, true, () => {
|
||||
isSaving(false)
|
||||
isSaving(false);
|
||||
}, (err) => {
|
||||
isSaving(false)
|
||||
isSaving(false);
|
||||
notify.send(err && err.message || t("Oops"), "error");
|
||||
});
|
||||
}
|
||||
const [_, refresh] = useState(null);
|
||||
};
|
||||
const refresh = useState(null)[1];
|
||||
|
||||
useEffect(() => {
|
||||
Config.all().then((c) => {
|
||||
delete c.constant; // The constant key contains read only global variable that are
|
||||
// application wide truth => not editable from the admin area
|
||||
setForm(c)
|
||||
// The constant key contains read only global variable that are
|
||||
// application wide truth => not editable from the admin area
|
||||
delete c.constant;
|
||||
setForm(c);
|
||||
});
|
||||
}, []);
|
||||
|
||||
const renderForm = ($input, props, struct, onChange) => (
|
||||
<label className={"no-select input_type_" + props.params["type"]}>
|
||||
<div>
|
||||
<span>
|
||||
{ format(struct.label) }:
|
||||
</span>
|
||||
<div style={{ width: "100%" }}>
|
||||
{ $input }
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="nothing"></span>
|
||||
<div style={{ width: "100%" }}>
|
||||
{ struct.description && (
|
||||
<div className="description">{struct.description}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
);
|
||||
|
||||
return (
|
||||
<form className="sticky">
|
||||
<FormBuilder
|
||||
form={form}
|
||||
onChange={onChange}
|
||||
autoComplete="new-password"
|
||||
render={ ($input, props, struct, onChange) => (
|
||||
<label className={"no-select input_type_" + props.params["type"]}>
|
||||
<div>
|
||||
<span>
|
||||
{ format(struct.label) }:
|
||||
</span>
|
||||
<div style={{width: "100%"}}>
|
||||
{ $input }
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<span className="nothing"></span>
|
||||
<div style={{width: "100%"}}>
|
||||
{ struct.description ? (<div className="description">{struct.description}</div>) : null }
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
)} />
|
||||
</form>
|
||||
render={renderForm} />
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,16 @@
|
|||
/* eslint-disable max-len */
|
||||
import React, { createRef } from "react";
|
||||
import ReactCSSTransitionGroup from "react-addons-css-transition-group";
|
||||
|
||||
import { Input, Button, Container, Icon, NgIf, Loader, CSSTransition } from "../../components/";
|
||||
import { Input, Button, Icon, NgIf, Loader } from "../../components/";
|
||||
import { Config, Admin } from "../../model/";
|
||||
import { notify, FormObjToJSON, alert, prompt } from "../../helpers";
|
||||
import { notify, FormObjToJSON, alert } from "../../helpers";
|
||||
import { bcrypt_password } from "../../helpers/bcrypt";
|
||||
//import ReactCSSTransitionGroup from "react-addons-css-transition-group";
|
||||
|
||||
import "./setup.scss";
|
||||
|
||||
export class SetupPage extends React.Component {
|
||||
constructor(props){
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
busy: false,
|
||||
|
|
@ -23,28 +24,33 @@ export class SetupPage extends React.Component {
|
|||
};
|
||||
|
||||
Config.all().then((config) => {
|
||||
if(config.log.telemetry.value === true) return;
|
||||
if (config.log.telemetry.value === true) return;
|
||||
this.unlisten = this.props.history.listen((location, action) => {
|
||||
this.unlisten();
|
||||
alert.now((
|
||||
<div>
|
||||
<p style={{textAlign: "justify"}}>
|
||||
Help making this software better by sending crash reports and anonymous usage statistics
|
||||
</p>
|
||||
<form onSubmit={start.bind(this)} style={{fontSize: "0.9em", marginTop: "10px"}}>
|
||||
<label>
|
||||
<Input type="checkbox" style={{width: "inherit", marginRight: "10px"}} onChange={(e) => this.enableLog(e.target.checked)} defaultChecked={config.log.telemetry.value} />
|
||||
I accept but the data is not to be share with any third party
|
||||
</label>
|
||||
</form>
|
||||
<p style={{ textAlign: "justify" }}>
|
||||
Help making this software better by sending crash reports and
|
||||
anonymous usage statistics
|
||||
</p>
|
||||
<form onSubmit={start.bind(this)}
|
||||
style={{ fontSize: "0.9em", marginTop: "10px" }}>
|
||||
<label>
|
||||
<Input type="checkbox"
|
||||
style={{ width: "inherit", marginRight: "10px" }}
|
||||
onChange={(e) => this.enableLog(e.target.checked)}
|
||||
defaultChecked={config.log.telemetry.value} />
|
||||
I accept but the data is not to be share with any third party
|
||||
</label>
|
||||
</form>
|
||||
</div>
|
||||
));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
onAdminPassword(p, done){
|
||||
this.setState({busy: true});
|
||||
onAdminPassword(p, done) {
|
||||
this.setState({ busy: true });
|
||||
Config.all().then((config) => {
|
||||
return bcrypt_password(p).then((hash) => {
|
||||
config = FormObjToJSON(config);
|
||||
|
|
@ -52,22 +58,22 @@ export class SetupPage extends React.Component {
|
|||
config.auth.admin = hash;
|
||||
Config.save(config, false)
|
||||
.then(() => Admin.login(p))
|
||||
.then(() => this.setState({busy: false}, done))
|
||||
.then(() => this.setState({ busy: false }, done))
|
||||
.catch((err) => {
|
||||
this.setState({busy: false});
|
||||
this.setState({ busy: false });
|
||||
notify.send(err && err.message, "error");
|
||||
});
|
||||
}).catch((err) => {
|
||||
this.setState({busy: false});
|
||||
this.setState({ busy: false });
|
||||
notify.send("Hash error: " + JSON.stringify(err), "error");
|
||||
});
|
||||
}).catch((err) => {
|
||||
notify.send(err && err.message, "error");
|
||||
this.setState({busy: false});
|
||||
this.setState({ busy: false });
|
||||
});
|
||||
}
|
||||
|
||||
enableLog(value){
|
||||
enableLog(value) {
|
||||
Config.all().then((config) => {
|
||||
config = FormObjToJSON(config);
|
||||
config.connections = window.CONFIG.connections;
|
||||
|
|
@ -76,49 +82,49 @@ export class SetupPage extends React.Component {
|
|||
});
|
||||
};
|
||||
|
||||
summaryCall(){
|
||||
this.setState({busy: true});
|
||||
summaryCall() {
|
||||
this.setState({ busy: true });
|
||||
return Config.all().then((config) => {
|
||||
this.setState({busy: false});
|
||||
this.setState({ busy: false });
|
||||
return [
|
||||
{
|
||||
"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"
|
||||
"message": "This can lead to data leaks. Please use a SSL certificate",
|
||||
}, {
|
||||
"name_success": "Application is running as '" + objectGet(config, ["constant", "user", "value"]) + "'",
|
||||
"name_failure": "Application is running as root",
|
||||
"pass": objectGet(config, ["constant", "user", "value"]) !== "root",
|
||||
"severe": true,
|
||||
"message": "This is dangerous, you should use another user with less privileges"
|
||||
"message": "This is dangerous, you should use another user with less privileges",
|
||||
}, {
|
||||
"name_success": "Emacs is installed",
|
||||
"name_failure": "Emacs is not installed",
|
||||
"pass": objectGet(config, ["constant", "emacs", "value"]),
|
||||
"severe": false,
|
||||
"message": "If you want to use all the org-mode features of Filestash, you need to install emacs"
|
||||
"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": objectGet(config, ["constant", "pdftotext", "value"]),
|
||||
"severe": false,
|
||||
"message": "You won't be able to search through PDF documents without it"
|
||||
}
|
||||
"message": "You won't be able to search through PDF documents without it",
|
||||
},
|
||||
];
|
||||
}).catch((err) => {
|
||||
notify.send(err && err.message, "error");
|
||||
this.setState({busy: false});
|
||||
this.setState({ busy: false });
|
||||
});
|
||||
}
|
||||
|
||||
render(){
|
||||
render() {
|
||||
return (
|
||||
<div className="component_setup">
|
||||
<MultiStepForm loading={this.state.busy}
|
||||
onAdminPassword={this.onAdminPassword.bind(this)}
|
||||
summaryCall={this.summaryCall.bind(this)} />
|
||||
<MultiStepForm loading={this.state.busy}
|
||||
onAdminPassword={this.onAdminPassword.bind(this)}
|
||||
summaryCall={this.summaryCall.bind(this)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -126,86 +132,101 @@ export class SetupPage extends React.Component {
|
|||
|
||||
|
||||
class MultiStepForm extends React.Component {
|
||||
constructor(props){
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
current: parseInt(window.location.hash.replace("#", "")) || 0,
|
||||
answer_password: "",
|
||||
has_answered_password: false,
|
||||
deps: []
|
||||
deps: [],
|
||||
};
|
||||
this.$input = createRef()
|
||||
this.$input = createRef();
|
||||
}
|
||||
|
||||
componentDidMount(){
|
||||
if(this.state.current === 1){
|
||||
componentDidMount() {
|
||||
if (this.state.current === 1) {
|
||||
this.props.summaryCall().then((deps) => {
|
||||
this.setState({deps: deps});
|
||||
this.setState({ deps: deps });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onAdminPassword(e){
|
||||
onAdminPassword(e) {
|
||||
e.preventDefault();
|
||||
this.props.onAdminPassword(this.state.answer_password, () => {
|
||||
this.setState({has_answered_password: true});
|
||||
this.setState({ has_answered_password: true });
|
||||
this.onStepChange(1);
|
||||
});
|
||||
}
|
||||
|
||||
onStepChange(n){
|
||||
this.setState({current: n}, () => {
|
||||
if(n === 1) this.componentDidMount();
|
||||
onStepChange(n) {
|
||||
this.setState({ current: n }, () => {
|
||||
if (n === 1) this.componentDidMount();
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
const hideMenu = <style dangerouslySetInnerHTML={{__html: ".component_menu_sidebar{transform: translateX(-300px)}"}} />;
|
||||
if(this.state.current === 0) {
|
||||
const hideMenu = (
|
||||
<style dangerouslySetInnerHTML={{
|
||||
__html: ".component_menu_sidebar{transform: translateX(-300px)}",
|
||||
}} />
|
||||
);
|
||||
if (this.state.current === 0) {
|
||||
return (
|
||||
<div id="step1">
|
||||
<FormStage navleft={false} navright={this.state.has_answered_password === true} current={this.state.current} onStepChange={this.onStepChange.bind(this)}>
|
||||
Admin Password
|
||||
</FormStage>
|
||||
<CSSTransition transitionName="stepper-form" transitionEnterTimeout={600} transitionAppearTimeout={600} transitionAppear={true} transitionEnter={true} transitionLeave={false}>
|
||||
<div key={this.state.current}>
|
||||
<p>Create your instance admin password: </p>
|
||||
<form onSubmit={this.onAdminPassword.bind(this)}>
|
||||
<Input ref={this.$input} type="password" placeholder="Password" value={this.state.answer_password} onChange={(e) => this.setState({answer_password: e.target.value})}/>
|
||||
<Button theme="transparent">
|
||||
<Icon name={this.props.loading ? "loading" : "arrow_right"}/>
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</CSSTransition>
|
||||
{hideMenu}
|
||||
<FormStage navleft={false} navright={this.state.has_answered_password === true}
|
||||
current={this.state.current} onStepChange={this.onStepChange.bind(this)}>
|
||||
Admin Password
|
||||
</FormStage>
|
||||
<ReactCSSTransitionGroup transitionName="stepper-form"
|
||||
transitionEnterTimeout={600}
|
||||
transitionAppearTimeout={600} transitionAppear={true} transitionEnter={true}
|
||||
transitionLeave={false}>
|
||||
<div key={this.state.current}>
|
||||
<p>Create your instance admin password: </p>
|
||||
<form onSubmit={this.onAdminPassword.bind(this)}>
|
||||
<Input ref={this.$input} type="password" placeholder="Password"
|
||||
onChange={(e) => this.setState({ answer_password: e.target.value })}
|
||||
value={this.state.answer_password} />
|
||||
<Button theme="transparent">
|
||||
<Icon name={this.props.loading ? "loading" : "arrow_right"}/>
|
||||
</Button>
|
||||
</form>
|
||||
</div>
|
||||
</ReactCSSTransitionGroup>
|
||||
{hideMenu}
|
||||
</div>
|
||||
);
|
||||
} else if(this.state.current === 1) {
|
||||
} else if (this.state.current === 1) {
|
||||
return (
|
||||
<div id="step2">
|
||||
<FormStage navleft={true} navright={false} current={this.state.current} onStepChange={this.onStepChange.bind(this)}>
|
||||
Summary
|
||||
</FormStage>
|
||||
<CSSTransition transitionName="stepper-form" transitionEnterTimeout={600} transitionAppearTimeout={600} transitionAppear={true} transitionEnter={true} transitionLeave={false}>
|
||||
<div key={this.state.current}>
|
||||
<NgIf cond={!!this.props.loading}>
|
||||
<Loader/>
|
||||
<div style={{textAlign: "center"}}>Verifying</div>
|
||||
</NgIf>
|
||||
<NgIf cond={!this.props.loading}>
|
||||
{
|
||||
this.state.deps.map((dep, idx) => {
|
||||
return (
|
||||
<div className={"component_dependency_installed" + (dep.pass ? " yes" : " no") + (dep.severe ? " severe" : "")} key={idx}>
|
||||
<span>{dep.pass ? dep.name_success : dep.name_failure}</span>{dep.pass ? null : ": " + dep.message}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</NgIf>
|
||||
</div>
|
||||
</CSSTransition>
|
||||
<FormStage navleft={true} navright={false} current={this.state.current}
|
||||
onStepChange={this.onStepChange.bind(this)}>
|
||||
Summary
|
||||
</FormStage>
|
||||
<ReactCSSTransitionGroup transitionName="stepper-form" transitionEnterTimeout={600}
|
||||
transitionAppearTimeout={600} transitionAppear={true} transitionEnter={true}
|
||||
transitionLeave={false}>
|
||||
<div key={this.state.current}>
|
||||
<NgIf cond={!!this.props.loading}>
|
||||
<Loader/>
|
||||
<div style={{ textAlign: "center" }}>Verifying</div>
|
||||
</NgIf>
|
||||
<NgIf cond={!this.props.loading}>
|
||||
{
|
||||
this.state.deps.map((dep, idx) => {
|
||||
return (
|
||||
<div className={"component_dependency_installed" + (dep.pass ? " yes" : " no") + (dep.severe ? " severe" : "")} key={idx}>
|
||||
<span>
|
||||
{dep.pass ? dep.name_success : dep.name_failure}
|
||||
</span>{dep.pass ? null : ": " + dep.message}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</NgIf>
|
||||
</div>
|
||||
</ReactCSSTransitionGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
@ -216,17 +237,19 @@ class MultiStepForm extends React.Component {
|
|||
const FormStage = (props) => {
|
||||
return (
|
||||
<h4>
|
||||
{ props.navleft === true ? <Icon name="arrow_left" onClick={() => props.onStepChange(props.current - 1)}/> : null}
|
||||
{ props.children }
|
||||
{ props.navright === true ? <Icon name="arrow_right" onClick={() => props.onStepChange(props.current + 1)}/> : null }
|
||||
{ props.navleft === true &&
|
||||
<Icon name="arrow_left" onClick={() => props.onStepChange(props.current - 1)}/> }
|
||||
{ props.children }
|
||||
{ props.navright === true &&
|
||||
<Icon name="arrow_right" onClick={() => props.onStepChange(props.current + 1)}/> }
|
||||
</h4>
|
||||
);
|
||||
};
|
||||
|
||||
function objectGet(obj, paths){
|
||||
function objectGet(obj, paths) {
|
||||
let value = obj;
|
||||
for(let i=0; i<paths.length; i++){
|
||||
if(typeof value !== "object") return null;
|
||||
for (let i=0; i<paths.length; i++) {
|
||||
if (typeof value !== "object") return null;
|
||||
value = value[paths[i]];
|
||||
}
|
||||
return value;
|
||||
|
|
|
|||
Loading…
Reference in a new issue