mirror of
https://github.com/mickael-kerjean/filestash
synced 2025-12-15 12:55:41 +01:00
parent
8c00161f73
commit
f30787785c
43 changed files with 310 additions and 134 deletions
|
|
@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
|
|||
import { Input, Button, Modal, NgIf } from './';
|
||||
import { alert } from '../helpers/';
|
||||
import { Popup } from './popup';
|
||||
import { t } from '../locales/';
|
||||
|
||||
export class ModalAlert extends Popup {
|
||||
constructor(props){
|
||||
|
|
@ -22,7 +23,7 @@ export class ModalAlert extends Popup {
|
|||
|
||||
onSubmit(e){
|
||||
this.setState({appear: false}, () => {
|
||||
requestAnimationFrame(() => this.state.fn())
|
||||
requestAnimationFrame(() => this.state.fn && this.state.fn());
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ export class ModalAlert extends Popup {
|
|||
|
||||
modalContentFooter(){
|
||||
return (
|
||||
<Button type="submit" theme="emphasis" onClick={this.onSubmit.bind(this)}>OK</Button>
|
||||
<Button type="submit" theme="emphasis" onClick={this.onSubmit.bind(this)}>{ t("OK") }</Button>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
|
|||
import { Input, Button, Modal, NgIf } from './';
|
||||
import { confirm } from '../helpers/';
|
||||
import { Popup } from './popup';
|
||||
import { t } from '../locales/';
|
||||
|
||||
export class ModalConfirm extends Popup{
|
||||
constructor(props){
|
||||
|
|
@ -44,8 +45,8 @@ export class ModalConfirm extends Popup{
|
|||
modalContentFooter(){
|
||||
return (
|
||||
<div>
|
||||
<Button type="button" onClick={this.no.bind(this)}>NO</Button>
|
||||
<Button type="submit" theme="emphasis" onClick={this.yes.bind(this)}>YES</Button>
|
||||
<Button type="button" onClick={this.no.bind(this)}>{ t("NO") } </Button>
|
||||
<Button type="submit" theme="emphasis" onClick={this.yes.bind(this)}>{ t("YES") }</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { browserHistory, Redirect } from 'react-router';
|
|||
import { Session, Admin } from '../model/';
|
||||
import { Container, Loader, Icon, NgIf } from '../components/';
|
||||
import { memory, currentShare } from '../helpers/';
|
||||
import { t } from '../locales/';
|
||||
|
||||
import '../pages/error.scss';
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ export function ErrorPage(WrappedComponent){
|
|||
|
||||
render(){
|
||||
if(this.state.error !== null){
|
||||
const message = this.state.error.message || "There is nothing in here";
|
||||
const message = this.state.error.message || t("There is nothing in here");
|
||||
return (
|
||||
<div>
|
||||
<Link onClick={this.navigate.bind(this)} to={`/${window.location.search}`} className="backnav">
|
||||
|
|
@ -86,8 +87,8 @@ export function ErrorPage(WrappedComponent){
|
|||
</Link>
|
||||
<Container>
|
||||
<div className="error-page">
|
||||
<h1>Oops!</h1>
|
||||
<h2>{message}</h2>
|
||||
<h1>{ t("Oops!") }</h1>
|
||||
<h2>{ message }</h2>
|
||||
</div>
|
||||
</Container>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
|
|||
|
||||
import { Input, Textarea, Select, Enabler } from './';
|
||||
import { FormObjToJSON, format, autocomplete, notify } from '../helpers/';
|
||||
import { t } from '../locales/';
|
||||
|
||||
import "./formbuilder.scss";
|
||||
|
||||
|
|
@ -113,7 +114,7 @@ export class FormBuilder extends React.Component {
|
|||
const FormElement = (props) => {
|
||||
const id = props.id !== undefined ? {id: props.id} : {};
|
||||
let struct = props.params;
|
||||
let $input = ( <Input onChange={(e) => props.onChange(e.target.value)} {...id} name={struct.label} type="text" defaultValue={struct.value} placeholder={struct.placeholder} /> );
|
||||
let $input = ( <Input onChange={(e) => props.onChange(e.target.value)} {...id} name={struct.label} type="text" defaultValue={struct.value} placeholder={ t(struct.placeholder) } /> );
|
||||
switch(props.params["type"]){
|
||||
case "text":
|
||||
const onTextChange = (value) => {
|
||||
|
|
@ -124,7 +125,7 @@ const FormElement = (props) => {
|
|||
};
|
||||
|
||||
const list_id = struct.datalist ? "list_"+Math.random() : null;
|
||||
$input = ( <Input list={list_id} onChange={(e) => onTextChange(e.target.value)} {...id} name={struct.label} type="text" value={struct.value || ""} placeholder={struct.placeholder} readOnly={struct.readonly}/> );
|
||||
$input = ( <Input list={list_id} onChange={(e) => onTextChange(e.target.value)} {...id} name={struct.label} type="text" value={struct.value || ""} placeholder={ t(struct.placeholder) } readOnly={struct.readonly}/> );
|
||||
if(list_id != null){
|
||||
const filtered = function(multi, datalist, currentValue){
|
||||
if(multi !== true || currentValue == null) return datalist;
|
||||
|
|
@ -156,7 +157,7 @@ const FormElement = (props) => {
|
|||
value = value === "" ? null : parseInt(value);
|
||||
props.onChange(value);
|
||||
};
|
||||
$input = ( <Input onChange={(e) => onNumberChange(e.target.value)} {...id} name={struct.label} type="number" value={struct.value === null ? "" : struct.value} placeholder={struct.placeholder} /> );
|
||||
$input = ( <Input onChange={(e) => onNumberChange(e.target.value)} {...id} name={struct.label} type="number" value={struct.value === null ? "" : struct.value} placeholder={ t(struct.placeholder) } /> );
|
||||
break;
|
||||
case "password":
|
||||
const onPasswordChange = (value) => {
|
||||
|
|
@ -165,7 +166,7 @@ const FormElement = (props) => {
|
|||
}
|
||||
props.onChange(value);
|
||||
};
|
||||
$input = ( <Input onChange={(e) => onPasswordChange(e.target.value)} {...id} name={struct.label} type="password" value={struct.value || ""} placeholder={struct.placeholder} /> );
|
||||
$input = ( <Input onChange={(e) => onPasswordChange(e.target.value)} {...id} name={struct.label} type="password" value={struct.value || ""} placeholder={ t(struct.placeholder) } /> );
|
||||
break;
|
||||
case "long_password":
|
||||
const onLongPasswordChange = (value) => {
|
||||
|
|
@ -175,11 +176,11 @@ const FormElement = (props) => {
|
|||
props.onChange(value);
|
||||
};
|
||||
$input = (
|
||||
<Textarea {...id} disabledEnter={true} value={struct.value || ""} onChange={(e) => onLongPasswordChange(e.target.value)} type="text" rows="1" name={struct.label} placeholder={struct.placeholder} autoComplete="new-password" />
|
||||
<Textarea {...id} disabledEnter={true} value={struct.value || ""} onChange={(e) => onLongPasswordChange(e.target.value)} type="text" rows="1" name={struct.label} placeholder={ t(struct.placeholder) } autoComplete="new-password" />
|
||||
);
|
||||
break;
|
||||
case "long_text":
|
||||
$input = ( <Textarea {...id} disabledEnter={true} value={struct.value || ""} onChange={(e) => props.onChange(e.target.value)} type="text" rows="3" name={struct.label} placeholder={struct.placeholder} autoComplete="new-password" /> );
|
||||
$input = ( <Textarea {...id} disabledEnter={true} value={struct.value || ""} onChange={(e) => props.onChange(e.target.value)} type="text" rows="3" name={struct.label} placeholder={ t(struct.placeholder) } autoComplete="new-password" /> );
|
||||
break;
|
||||
case "bcrypt":
|
||||
const onBcryptChange = (value) => {
|
||||
|
|
@ -191,7 +192,7 @@ const FormElement = (props) => {
|
|||
.then((bcrypt) => bcrypt.bcrypt_password(value))
|
||||
.then((hash) => props.onChange(hash));
|
||||
};
|
||||
$input = ( <Input onChange={(e) => onBcryptChange(e.target.value)} {...id} name={struct.label} type="password" defaultValue={struct.value || ""} placeholder={struct.placeholder} /> );
|
||||
$input = ( <Input onChange={(e) => onBcryptChange(e.target.value)} {...id} name={struct.label} type="password" defaultValue={struct.value || ""} placeholder={ t(struct.placeholder) } /> );
|
||||
break;
|
||||
case "hidden":
|
||||
$input = ( <Input name={struct.label} type="hidden" defaultValue={struct.value} /> );
|
||||
|
|
@ -200,16 +201,16 @@ const FormElement = (props) => {
|
|||
$input = ( <Input onChange={(e) => props.onChange(e.target.checked)} {...id} name={struct.label} type="checkbox" checked={struct.value === null ? !!struct.default : struct.value} /> );
|
||||
break;
|
||||
case "select":
|
||||
$input = ( <Select onChange={(e) => props.onChange(e.target.value)} {...id} name={struct.label} choices={struct.options} value={struct.value === null ? struct.default : struct.value} placeholder={struct.placeholder} />);
|
||||
$input = ( <Select onChange={(e) => props.onChange(e.target.value)} {...id} name={struct.label} choices={struct.options} value={struct.value === null ? struct.default : struct.value} placeholder={ t(struct.placeholder) } />);
|
||||
break;
|
||||
case "enable":
|
||||
$input = ( <Enabler onChange={(e) => props.onChange(e.target.checked)} {...id} name={struct.label} target={props.target} defaultValue={struct.value === null ? struct.default : struct.value} /> );
|
||||
break;
|
||||
case "date":
|
||||
$input = ( <Input onChange={(e) => props.onChange(e.target.value)} {...id} name={struct.label} type="date" defaultValue={struct.value || ""} placeholder={struct.placeholder} /> );
|
||||
$input = ( <Input onChange={(e) => props.onChange(e.target.value)} {...id} name={struct.label} type="date" defaultValue={struct.value || ""} placeholder={ t(struct.placeholder) } /> );
|
||||
break;
|
||||
case "datetime":
|
||||
$input = ( <Input onChange={(e) => props.onChange(e.target.value)} {...id} name={struct.label} type="datetime-local" defaultValue={struct.value || ""} placeholder={struct.placeholder} /> );
|
||||
$input = ( <Input onChange={(e) => props.onChange(e.target.value)} {...id} name={struct.label} type="datetime-local" defaultValue={struct.value || ""} placeholder={ t(struct.placeholder) } /> );
|
||||
break;
|
||||
case "image":
|
||||
$input = ( <img {...id} src={struct.value} /> );
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import { debounce } from '../helpers/';
|
||||
import { Icon, Loader, NgIf } from './';
|
||||
import { t } from '../locales/';
|
||||
import './mapshot.scss';
|
||||
|
||||
export class MapShot extends React.Component {
|
||||
|
|
@ -93,7 +94,7 @@ export class MapShot extends React.Component {
|
|||
<div ref="$wrapper" className={"component_mapshot"+(this.state.tile_loaded === 9 ? " loaded" : "")+(this.state.error === true ? " error": "")} style={{height: (this.state.tile_size*3)+"px"}}>
|
||||
<div className="wrapper">
|
||||
<div className="mapshot_placeholder error">
|
||||
<span><div>ERROR</div></span>
|
||||
<span><div>t("ERROR")</div></span>
|
||||
</div>
|
||||
<div className="mapshot_placeholder loading">
|
||||
<Loader/>
|
||||
|
|
@ -122,5 +123,4 @@ export class MapShot extends React.Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
|||
|
||||
import { NgIf, Icon } from './';
|
||||
import { notify } from '../helpers/';
|
||||
import { t } from '../locales/';
|
||||
import './notification.scss';
|
||||
|
||||
export class Notification extends React.Component {
|
||||
|
|
@ -71,7 +72,7 @@ export class Notification extends React.Component {
|
|||
<NgIf key={this.state.message_text+this.state.message_type+this.state.appear} cond={this.state.appear === true} className="no-select">
|
||||
<div className={"component_notification--container "+(this.state.message_type || 'info')}>
|
||||
<div className="message">
|
||||
{ this.state.message_text }
|
||||
{ t(this.state.message_text || "") }
|
||||
</div>
|
||||
<div className="close" onClick={this.cancelAnimation.bind(this)}>
|
||||
<Icon name="close" />
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
.buttons{
|
||||
margin: 15px -20px 0 -20px;
|
||||
display: flex;
|
||||
|
||||
> div {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
|
|
@ -19,6 +20,9 @@
|
|||
width: 50%;
|
||||
margin-left: auto;
|
||||
}
|
||||
button{
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
.modal-error-message{
|
||||
color: var(--error);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
|
|||
import { Input, Button, Modal, NgIf } from './';
|
||||
import { prompt } from '../helpers/';
|
||||
import { Popup } from './popup';
|
||||
import { t } from '../locales/';
|
||||
|
||||
export class ModalPrompt extends Popup {
|
||||
constructor(props){
|
||||
|
|
@ -45,8 +46,8 @@ export class ModalPrompt extends Popup {
|
|||
modalContentFooter(){
|
||||
return (
|
||||
<div>
|
||||
<Button type="button" onClick={this.onCancel.bind(this)}>CANCEL</Button>
|
||||
<Button type="submit" theme="emphasis" onClick={this.onSubmit.bind(this)}>OK</Button>
|
||||
<Button type="button" onClick={this.onCancel.bind(this)}>{ t("CANCEL") }</Button>
|
||||
<Button type="submit" theme="emphasis" onClick={this.onSubmit.bind(this)}>{ t("OK") }</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import Path from 'path';
|
|||
import { Files } from '../model/';
|
||||
import { confirm, notify, upload } from '../helpers/';
|
||||
import { Icon, NgIf } from './';
|
||||
import { t } from '../locales/';
|
||||
import './upload_queue.scss';
|
||||
|
||||
const MAX_POOL_SIZE = 15;
|
||||
|
|
@ -76,7 +77,7 @@ export class UploadQueue extends React.Component {
|
|||
|
||||
if(navigator && navigator.clipboard){
|
||||
navigator.clipboard.writeText(path);
|
||||
notify.send("Copied to clipboard", "info");
|
||||
notify.send(t("Copied to clipboard"), "info");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -282,15 +283,15 @@ export class UploadQueue extends React.Component {
|
|||
speedStr = " ~ " + humanFileSize(avgSpeed) + "/s";
|
||||
}
|
||||
if (this.state.running) {
|
||||
return "Running..." + speedStr;
|
||||
return t("Running")+"..." + speedStr;
|
||||
}
|
||||
return "Done" + speedStr;
|
||||
return t("Done") + speedStr;
|
||||
}
|
||||
|
||||
onClose() {
|
||||
if(this.state.running) {
|
||||
confirm.now(
|
||||
"Abort current uploads?",
|
||||
t("Abort current uploads?"),
|
||||
() => {
|
||||
this.setState({
|
||||
running: false,
|
||||
|
|
@ -332,7 +333,7 @@ export class UploadQueue extends React.Component {
|
|||
<NgIf cond={totalFiles > 0}>
|
||||
<div className="component_upload_queue">
|
||||
<h2>
|
||||
CURRENT UPLOAD
|
||||
{ t("CURRENT UPLOAD") }
|
||||
<div className="count_block">
|
||||
<span className="completed">{finished.length}</span>
|
||||
<span className="grandTotal">{totalFiles}</span>
|
||||
|
|
@ -344,7 +345,7 @@ export class UploadQueue extends React.Component {
|
|||
{this.renderRows(
|
||||
finished,
|
||||
"done",
|
||||
(_) => (<div className="file_state file_state_done">Done</div>),
|
||||
(_) => (<div className="file_state file_state_done">{ t("Done") }</div>),
|
||||
)}
|
||||
{this.renderRows(
|
||||
currents,
|
||||
|
|
@ -362,7 +363,7 @@ export class UploadQueue extends React.Component {
|
|||
processes,
|
||||
"todo",
|
||||
(_) => (
|
||||
<div className="file_state file_state_todo">Waiting</div>
|
||||
<div className="file_state file_state_todo">{ t("Waiting") }</div>
|
||||
)
|
||||
)}
|
||||
{this.renderRows(
|
||||
|
|
@ -371,9 +372,9 @@ export class UploadQueue extends React.Component {
|
|||
(p) => (
|
||||
(p.err && p.err.message == 'aborted')
|
||||
?
|
||||
<div className="file_state file_state_error">Aborted</div>
|
||||
<div className="file_state file_state_error">{ t("Aborted") }</div>
|
||||
:
|
||||
<div className="file_state file_state_error">Error</div>
|
||||
<div className="file_state file_state_error">{ t("Error") }</div>
|
||||
),
|
||||
(p) => (
|
||||
<Icon name="refresh" onClick={(e) => this.retryFiles(p)} ></Icon>
|
||||
|
|
|
|||
|
|
@ -15,3 +15,4 @@ export function decrypt(text, key){
|
|||
new aesjs.ModeOfOperation.ctr(keyBytes, new aesjs.Counter(5)).decrypt(textBytes)
|
||||
));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import ReactDOM from 'react-dom';
|
|||
import Router from './router';
|
||||
|
||||
import { Config, Log } from "./model/";
|
||||
import { http_get } from "./helpers/ajax";
|
||||
import load from "little-loader";
|
||||
|
||||
import './assets/css/reset.scss';
|
||||
|
|
@ -36,7 +37,7 @@ window.addEventListener("DOMContentLoaded", () => {
|
|||
return Promise.resolve();
|
||||
}
|
||||
|
||||
Promise.all([Config.refresh(), setup_xdg_open()]).then(() => {
|
||||
Promise.all([Config.refresh(), setup_xdg_open(), translation()]).then(() => {
|
||||
const timeSinceBoot = new Date() - window.initTime;
|
||||
if(timeSinceBoot >= 1500){
|
||||
const timeoutToAvoidFlickering = timeSinceBoot > 2500 ? 0 : 500;
|
||||
|
|
@ -74,3 +75,18 @@ function setup_xdg_open(){
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
function translation(){
|
||||
const userLanguage = navigator.language.split("-")[0];
|
||||
const selectedLanguage = [
|
||||
"fr",
|
||||
// add new locales here
|
||||
].indexOf(userLanguage) === -1 ? "en" : userLanguage;
|
||||
|
||||
if(selectedLanguage === "en"){
|
||||
return Promise.resolve();
|
||||
}
|
||||
return http_get("/assets/locales/"+selectedLanguage+".json").then((d) => {
|
||||
window.LNG = d;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
108
client/locales/fr.json
Normal file
108
client/locales/fr.json
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
{
|
||||
"A_FILE_NAMED_{{VALUE}}_WAS_CREATED": "Un fichier nommé \"{{VALUE}}\" a été créé",
|
||||
"A_FOLDER_NAMED_{{VALUE}}_WAS_CREATED": "Un dossier nommé \"{{VALUE}}\" a été créé",
|
||||
"ABORTED": "avorté",
|
||||
"ABORT_CURRENT_UPLOADS?": "Annuler les téléchargements en cours?",
|
||||
"ACTIVITY": "activité",
|
||||
"ADMIN_CONSOLE": "console administrateur",
|
||||
"ADVANCED": "avancée",
|
||||
"ALL_DONE": "Tout est bon!",
|
||||
"ALREADY_EXIST": "existe déjà",
|
||||
"BEAUTIFUL_URL": "id_du_lien",
|
||||
"CAMERA": "appareil",
|
||||
"CAN_RESHARE": "peut repartager",
|
||||
"CANCEL": "annuler",
|
||||
"CANNOT_ESTABLISH_A_CONNECTION": "Impossible d'établir une connexion",
|
||||
"CANT_LOAD_THIS_PICTURE": "impossible de charger cette image",
|
||||
"CANT_USE_FILESYSTEM": "Impossible d'utiliser le système de fichiers",
|
||||
"CODE": "code",
|
||||
"CONFIGURE": "configuration",
|
||||
"CONFIRM_BY_TYPING": "confirmez en écrivant",
|
||||
"CONNECT": "connection",
|
||||
"COPIED_TO_CLIPBOARD": "Copié dans le presse-papier",
|
||||
"TRAFFIC_CONGESTION_TRY_AGAIN_LATER": "Congestion, réessayez plus tard",
|
||||
"CREATE_A_NEW_LINK": "créer un lien partagé",
|
||||
"CURRENT": "en cours",
|
||||
"CURRENT_UPLOAD": "en cours",
|
||||
"CUSTOM_LINK_URL": "URL du lien personnalisé",
|
||||
"DASHBOARD": "dashboard",
|
||||
"DATE": "date",
|
||||
"DISPLAY_HIDDEN_FILES": "afficher les fichiers cachés",
|
||||
"DO_YOU_WANT_TO_SAVE_THE_CHANGES": "voulez-vous enregistrer les modifications?",
|
||||
"DOESNT_MATCH": "ne correspond pas",
|
||||
"DONE": "terminé",
|
||||
"DOWNLOAD": "Télécharger",
|
||||
"DROP_HERE_TO_UPLOAD": "glisser-déposer pour charger vos fichiers et dossiers",
|
||||
"EDITOR": "éditeur",
|
||||
"EXISTING_LINKS": "liens existants",
|
||||
"EXPIRATION": "expiration",
|
||||
"EXPORT_AS_{{VALUE}}": "exporter au format {{VALUE}}",
|
||||
"HIDE_HIDDEN_FILES": "masquer les fichiers cachés",
|
||||
"EMPTY": "vide",
|
||||
"ENDPOINT": "endpoint",
|
||||
"ENCRYPTION_KEY": "clé de cryptage",
|
||||
"ERROR": "erreur",
|
||||
"FREQUENTLY_ACCESS_FOLDERS_WILL_BE_SHOWN_HERE": "les dossiers d'accès fréquents apparaîtront ici",
|
||||
"HOST_KEY": "clé d'hôte",
|
||||
"HOSTNAME*": "nom d'hôte*",
|
||||
"INCORRECT_PASSWORD": "mot de passe incorrect",
|
||||
"INFO": "Information",
|
||||
"INTERNAL_ERROR_CANT_CREATE_A_{{VALUE}}": "erreur interne: vous ne pouvez pas créer un {{VALUE}}",
|
||||
"INVALID_PASSWORD": "mot de passe incorrect",
|
||||
"INVALID_ACCOUNT": "compte invalide",
|
||||
"LOCATION": "position",
|
||||
"MISSING_DEPENDENCY": "dépendance manquante",
|
||||
"NAVIGATE": "naviguer",
|
||||
"NEW_FILE": "Nouveau Fichier",
|
||||
"NEW_FILE::SHORT": "Nouv. Fichier",
|
||||
"NEW_DIRECTORY": "Nouveau Dossier",
|
||||
"NEW_DIRECTORY::SHORT": "Nouv. Dossier",
|
||||
"NO": "non",
|
||||
"NOT_ALLOWED": "interdit",
|
||||
"NOT_AUTHORISED": "autorisation manquante",
|
||||
"NOT_FOUND": "introuvable",
|
||||
"NOT_IMPLEMENTED": "non implémenté",
|
||||
"NOT_SUPPORTED": "non supporté",
|
||||
"NOT_VALID": "pas valide",
|
||||
"NUMBER_OF_CONNECTIONS": "nombre de connexion",
|
||||
"OK": "ok",
|
||||
"OOPS": "oops!",
|
||||
"ONLY_FOR_USERS": "uniquement pour certains utilisateurs",
|
||||
"PASSPHRASE": "mot de passe de clef",
|
||||
"PATH": "chemin",
|
||||
"PERMISSION_DENIED": "autorisation refusée",
|
||||
"PROPERTIES": "propriétés",
|
||||
"PORT": "port",
|
||||
"PASSWORD": "mot de passe",
|
||||
"PASSWORD_CANT_BE_EMPTY": "le mot de passe ne peut pas être vide",
|
||||
"PICK_A_MASTER_PASSWORD": "choisissez un mot de passe principal",
|
||||
"POWERED_BY": "propulsé par",
|
||||
"PROTECT_ACCESS_WITH_A_PASSWORD": "protéger l'accès avec un mot de passe",
|
||||
"REGION": "région",
|
||||
"REMEMBER_ME": "se souvenir de moi",
|
||||
"REMOVE": "supprimer",
|
||||
"RESTRICTIONS": "restrictions",
|
||||
"RUNNING": "en cours",
|
||||
"SAVE_CURRENT_FILE": "enregistrer le fichier actuel",
|
||||
"SEARCH": "recherche",
|
||||
"SETTINGS": "réglage",
|
||||
"SORT_BY_TYPE": "trier par type",
|
||||
"SORT_BY_DATE": "trier par date",
|
||||
"SORT_BY_NAME": "trier par nom",
|
||||
"SUPPORT": "support",
|
||||
"THERE_IS_NOTHING_HERE": "il n'y a rien ici",
|
||||
"THE_LINK_WAS_COPIED_IN_THE_CLIPBOARD": "le lien a été copié dans le presse-papiers",
|
||||
"THE_LINK_WONT_BE_VALID_AFTER": "le lien ne sera plus valide après",
|
||||
"THE_FILE_{{VALUE}}_WAS_RENAMED": "le fichier \"{{VALUE}}\" a été renommé",
|
||||
"THE_FILE_{{VALUE}}_WAS_DELETED": "le fichier \"{{VALUE}}\" a été supprimé",
|
||||
"TIMEOUT": "trop long",
|
||||
"TODO": "todo",
|
||||
"UPLOADER": "uploader",
|
||||
"USERNAME": "nom d'utilisateur",
|
||||
"VIEWER": "viewer",
|
||||
"WAITING": "attente",
|
||||
"YES": "oui",
|
||||
"YOU_CANT_DO_THAT": "vous ne pouvez pas faire :)",
|
||||
"YOUR_EMAIL_ADDRESS": "votre adresse email",
|
||||
"YOUR_MASTER_PASSWORD": "votre mot de passe principal"
|
||||
}
|
||||
15
client/locales/index.js
Normal file
15
client/locales/index.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export function t(str = "", replacementString, requestedKey){
|
||||
const calculatedKey = str.toUpperCase().replace(/ /g, "_").replace(/[^a-zA-Z0-9\-\_\*\{\}\?]/g, "").replace(/\_+$/, "");
|
||||
const value = requestedKey === undefined ? window.LNG && window.LNG[calculatedKey] : window.LNG && window.LNG[requestedKey];
|
||||
return reformat(
|
||||
value || str || "",
|
||||
str
|
||||
).replace("{{VALUE}}", replacementString);
|
||||
}
|
||||
|
||||
function reformat(translated, initial){
|
||||
if(initial[0] && initial[0].toLowerCase() === initial[0]){
|
||||
return translated || "";
|
||||
}
|
||||
return (translated[0] && translated[0].toUpperCase() + translated.substring(1)) || "";
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import { Icon, LoadingPage } from '../components/';
|
|||
import { Config, Admin } from '../model';
|
||||
import { notify } from '../helpers/';
|
||||
import { HomePage, DashboardPage, ConfigPage, LogPage, PluginPage, SupportPage, SetupPage, LoginPage } from './adminpage/';
|
||||
import { t } from '../locales/';
|
||||
|
||||
|
||||
function AdminOnly(WrappedComponent){
|
||||
|
|
@ -85,26 +86,26 @@ const SideMenu = (props) => {
|
|||
<Icon name="arrow_left" />
|
||||
<img src="/assets/logo/android-chrome-512x512.png" />
|
||||
</NavLink>
|
||||
<h2>Admin console</h2>
|
||||
<h2>{ t("Admin console") }</h2>
|
||||
<ul>
|
||||
<li>
|
||||
<NavLink activeClassName="active" to={props.url + "/dashboard"}>
|
||||
Dashboard
|
||||
{ t("Dashboard") }
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink activeClassName="active" to={props.url + "/configure"}>
|
||||
Configure
|
||||
{ t("Configure") }
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink activeClassName="active" to={props.url + "/activity"}>
|
||||
Activity
|
||||
{ t("Activity") }
|
||||
</NavLink>
|
||||
</li>
|
||||
<li>
|
||||
<NavLink activeClassName="active" to={props.url + "/support"}>
|
||||
Support
|
||||
{ t("Support") }
|
||||
</NavLink>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from 'react';
|
|||
import { FormBuilder, Loader, Button, Icon } from '../../components/';
|
||||
import { Config, Log } from '../../model/';
|
||||
import { FormObjToJSON, notify, format } from '../../helpers/';
|
||||
import { t } from '../../locales/';
|
||||
|
||||
import "./logger.scss";
|
||||
|
||||
|
|
@ -84,7 +85,7 @@ export class LogPage extends React.Component {
|
|||
}
|
||||
</pre>
|
||||
<div>
|
||||
<a href={Log.url()} download={filename()}><Button className="primary">Download</Button></a>
|
||||
<a href={Log.url()} download={filename()}><Button className="primary">{ t("Download") }</Button></a>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { Redirect } from 'react-router';
|
|||
|
||||
import { Input, Button, Container, Icon, Loader } from '../../components/';
|
||||
import { Config, Admin } from '../../model/';
|
||||
import { t } from '../../locales/';
|
||||
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
||||
|
||||
export class LoginPage extends React.Component {
|
||||
|
|
@ -42,7 +43,7 @@ export class LoginPage extends React.Component {
|
|||
return (
|
||||
<Container maxWidth="300px" className="sharepage_component">
|
||||
<form className={this.state.error ? "error" : ""} onSubmit={this.authenticate.bind(this)} style={marginTop()}>
|
||||
<Input ref="$input" type="password" placeholder="Password" />
|
||||
<Input ref="$input" type="password" placeholder={ t("Password") } />
|
||||
<Button theme="transparent">
|
||||
<Icon name={this.state.loading ? "loading" : "arrow_right"}/>
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
|||
|
||||
import { ModalPrompt } from '../../components/';
|
||||
import { memory, prompt, notify } from '../../helpers/';
|
||||
import { t } from '../../locales/';
|
||||
|
||||
const CREDENTIALS_CACHE = "credentials",
|
||||
CREDENTIALS_KEY = "credentials_key";
|
||||
|
|
@ -53,9 +54,9 @@ export class Credentials extends React.Component {
|
|||
|
||||
promptForExistingPassword(){
|
||||
prompt.now(
|
||||
"Your Master Password",
|
||||
t("Your Master Password"),
|
||||
(key) => {
|
||||
if(!key.trim()) return Promise.reject("Password can\'t be empty");
|
||||
if(!key.trim()) return Promise.reject(t("Password can\'t be empty"));
|
||||
this.setState({key: key});
|
||||
memory.set(CREDENTIALS_KEY, key);
|
||||
return this.hidrate_credentials(key);
|
||||
|
|
@ -69,9 +70,9 @@ export class Credentials extends React.Component {
|
|||
}
|
||||
promptForNewPassword(){
|
||||
prompt.now(
|
||||
"Pick a Master Password",
|
||||
t("Pick a Master Password"),
|
||||
(key) => {
|
||||
if(!key.trim()) return Promise.reject("Password can\'t be empty");
|
||||
if(!key.trim()) return Promise.reject(t("Password can\'t be empty"));
|
||||
memory.set(CREDENTIALS_KEY, key);
|
||||
this.setState({key: key}, () => {
|
||||
this.saveCreds(this.props.credentials);
|
||||
|
|
@ -93,7 +94,7 @@ export class Credentials extends React.Component {
|
|||
this.props.onCredentialsFound(credentials);
|
||||
return Promise.resolve();
|
||||
}catch(e){
|
||||
return Promise.reject({message: "Incorrect password"});
|
||||
return Promise.reject({message: t("Incorrect password")});
|
||||
}
|
||||
})
|
||||
.catch((err) => notify.send(err && err.message, "error"))
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react';
|
||||
import './forkme.scss';
|
||||
import { t } from '../../locales/';
|
||||
|
||||
export const ForkMe = (props) => {
|
||||
return (
|
||||
|
|
@ -19,7 +20,7 @@ export const PoweredByFilestash = () => {
|
|||
if(!window.CONFIG["fork_button"]) return null;
|
||||
return (
|
||||
<div className="component_poweredbyfilestash">
|
||||
Powered by <strong><a href="https://www.filestash.app">Filestash</a></strong>
|
||||
{ t('Powered by') } <strong><a href="https://www.filestash.app">Filestash</a></strong>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React from "react";
|
|||
import { Container, Card, NgIf, Input, Button, Textarea, FormBuilder } from "../../components/";
|
||||
import { gid, settings_get, settings_put, createFormBackend, FormObjToJSON } from "../../helpers/";
|
||||
import { Session, Backend } from "../../model/";
|
||||
import { t } from "../../locales/";
|
||||
import "./form.scss";
|
||||
|
||||
export class Form extends React.Component {
|
||||
|
|
@ -136,7 +137,7 @@ export class Form extends React.Component {
|
|||
} else if(struct.label === "advanced") return (
|
||||
<label style={{color: "rgba(0,0,0,0.4)"}}>
|
||||
{ $input }
|
||||
advanced
|
||||
{ t("Advanced") }
|
||||
</label>
|
||||
);
|
||||
return (
|
||||
|
|
@ -150,7 +151,7 @@ export class Form extends React.Component {
|
|||
);
|
||||
})
|
||||
}
|
||||
<Button theme="emphasis">CONNECT</Button>
|
||||
<Button theme="emphasis">{ t("CONNECT") }</Button>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@
|
|||
button.emphasis{
|
||||
margin-top: 10px;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
.third-party{
|
||||
text-align: center;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
import React from 'react';
|
||||
import { t } from '../../locales/';
|
||||
import './rememberme.scss';
|
||||
|
||||
export const RememberMe = (props) => {
|
||||
if(CONFIG.remember_me !== false){
|
||||
return (
|
||||
<label className="no-select component_rememberme">
|
||||
<input checked={props.state} onChange={(e) => props.onChange(e.target.checked)} type="checkbox"/> Remember me
|
||||
<input checked={props.state} onChange={(e) => props.onChange(e.target.checked)} type="checkbox"/> { t("Remember me") }
|
||||
</label>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Files } from '../model/';
|
|||
import { notify, upload } from '../helpers/';
|
||||
import Path from 'path';
|
||||
import { Observable } from "rxjs/Observable";
|
||||
import { t } from '../locales/';
|
||||
|
||||
export const sort = function(files, type){
|
||||
if(type === 'name'){
|
||||
|
|
@ -73,7 +74,7 @@ export const onCreate = function(path, type, file){
|
|||
if(type === 'file'){
|
||||
return Files.touch(path, file)
|
||||
.then(() => {
|
||||
notify.send('A file named "'+Path.basename(path)+'" was created', 'success');
|
||||
notify.send(t('A file named "{{VALUE}}" was created', Path.basename(path)), 'success');
|
||||
return Promise.resolve();
|
||||
})
|
||||
.catch((err) => {
|
||||
|
|
@ -82,34 +83,34 @@ export const onCreate = function(path, type, file){
|
|||
});
|
||||
}else if(type === 'directory'){
|
||||
return Files.mkdir(path)
|
||||
.then(() => notify.send('A folder named "'+Path.basename(path)+'" was created', 'success'))
|
||||
.then(() => notify.send(t('A folder named "{{VALUE}}" was created"', Path.basename(path)), 'success'))
|
||||
.catch((err) => notify.send(err, 'error'));
|
||||
}else{
|
||||
return Promise.reject({message: 'internal error: can\'t create a '+type.toString(), code: 'UNKNOWN_TYPE'});
|
||||
return Promise.reject({message: t('internal error: can\'t create a {{VALUE}}', type.toString()), code: 'UNKNOWN_TYPE'});
|
||||
}
|
||||
};
|
||||
|
||||
export const onRename = function(from, to, type){
|
||||
return Files.mv(from, to, type)
|
||||
.then(() => notify.send('The file "'+Path.basename(from)+'" was renamed', 'success'))
|
||||
.then(() => notify.send(t('The file "{{VALUE}}" was renamed', Path.basename(from)), 'success'))
|
||||
.catch((err) => notify.send(err, 'error'));
|
||||
};
|
||||
|
||||
export const onDelete = function(path, type){
|
||||
return Files.rm(path, type)
|
||||
.then(() => notify.send('The file "'+Path.basename(path)+'" was deleted', 'success'))
|
||||
.then(() => notify.send(t('The file {{VALUE}} was deleted"', Path.basename(path)), 'success'))
|
||||
.catch((err) => notify.send(err, 'error'));
|
||||
};
|
||||
|
||||
export const onMultiDelete = function(arrOfPath){
|
||||
return Promise.all(arrOfPath.map((p) => Files.rm(p)))
|
||||
.then(() => notify.send('All done!', 'success'))
|
||||
.then(() => notify.send(t('All done!'), 'success'))
|
||||
.catch((err) => notify.send(err, 'error'));
|
||||
}
|
||||
|
||||
export const onMultiRename = function(arrOfPath){
|
||||
return Promise.all(arrOfPath.map((p) => Files.mv(p[0], p[1])))
|
||||
.then(() => notify.send('All done!', 'success'))
|
||||
.then(() => notify.send(t('All done!'), 'success'))
|
||||
.catch((err) => notify.send(err, 'error'));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { notify, debounce, goToFiles, goToViewer, event, settings_get, settings_
|
|||
import { BreadCrumb, FileSystem, FrequentlyAccess, Submenu } from './filespage/';
|
||||
import { MobileFileUpload } from './filespage/filezone';
|
||||
import InfiniteScroll from 'react-infinite-scroller';
|
||||
import { t } from '../locales/';
|
||||
|
||||
const PAGE_NUMBER_INIT = 2;
|
||||
const LOAD_PER_SCROLL = 48;
|
||||
|
|
@ -109,9 +110,9 @@ export class FilesPage extends React.Component {
|
|||
this.setState({show_hidden: !this.state.show_hidden}, () => {
|
||||
settings_put("filespage_show_hidden", this.state.show_hidden);
|
||||
if(!!this.state.show_hidden){
|
||||
notify.send("Display hidden files", "info");
|
||||
notify.send(t("Display hidden files"), "info");
|
||||
}else{
|
||||
notify.send("Hide hidden files", "info");
|
||||
notify.send(t("Hide hidden files"), "info");
|
||||
}
|
||||
});
|
||||
this.onRefresh();
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { Container, NgIf, Icon } from '../../components/';
|
|||
import { NewThing } from './thing-new';
|
||||
import { ExistingThing } from './thing-existing';
|
||||
import { FileZone } from './filezone';
|
||||
import { t } from '../../locales/';
|
||||
|
||||
@DropTarget('__NATIVE_FILE__', {}, (connect, monitor) => ({
|
||||
connectDropFile: connect.dropTarget(),
|
||||
|
|
@ -40,7 +41,7 @@ export class FileSystem extends React.PureComponent {
|
|||
<p className="empty_image">
|
||||
<Icon name={this.props.isSearch ? "search" : "file"}/>
|
||||
</p>
|
||||
<p>There is nothing here</p>
|
||||
<p>{ t("There is nothing here") }</p>
|
||||
</NgIf>
|
||||
</Container>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
|||
import { DropTarget } from 'react-dnd';
|
||||
|
||||
import { EventEmitter, Icon } from '../../components/';
|
||||
import { t } from '../../locales/';
|
||||
import './filezone.scss';
|
||||
|
||||
@EventEmitter
|
||||
|
|
@ -23,7 +24,7 @@ export class FileZone extends React.Component{
|
|||
render(){
|
||||
return this.props.connectDropFile(
|
||||
<div className={"component_filezone "+(this.props.fileIsOver ? "hover" : "")}>
|
||||
DROP HERE TO UPLOAD
|
||||
{ t("DROP HERE TO UPLOAD") }
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
margin-bottom: 10px;
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
text-transform: uppercase;
|
||||
&.hover{
|
||||
background: var(--emphasis-primary);
|
||||
border: 2px dashed var(--primary);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
|||
import { Container, Icon, NgIf } from '../../components/';
|
||||
import { Link } from 'react-router-dom';
|
||||
import Path from 'path';
|
||||
import { t } from '../../locales/';
|
||||
|
||||
import './frequently_access.scss';
|
||||
|
||||
|
|
@ -36,7 +37,7 @@ export class FrequentlyAccess extends React.Component {
|
|||
<svg aria-hidden="true" focusable="false" data-icon="layer-group" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M12.41 148.02l232.94 105.67c6.8 3.09 14.49 3.09 21.29 0l232.94-105.67c16.55-7.51 16.55-32.52 0-40.03L266.65 2.31a25.607 25.607 0 0 0-21.29 0L12.41 107.98c-16.55 7.51-16.55 32.53 0 40.04zm487.18 88.28l-58.09-26.33-161.64 73.27c-7.56 3.43-15.59 5.17-23.86 5.17s-16.29-1.74-23.86-5.17L70.51 209.97l-58.1 26.33c-16.55 7.5-16.55 32.5 0 40l232.94 105.59c6.8 3.08 14.49 3.08 21.29 0L499.59 276.3c16.55-7.5 16.55-32.5 0-40zm0 127.8l-57.87-26.23-161.86 73.37c-7.56 3.43-15.59 5.17-23.86 5.17s-16.29-1.74-23.86-5.17L70.29 337.87 12.41 364.1c-16.55 7.5-16.55 32.5 0 40l232.94 105.59c6.8 3.08 14.49 3.08 21.29 0L499.59 404.1c16.55-7.5 16.55-32.5 0-40z"></path>
|
||||
</svg>
|
||||
Frequently access folders will be shown here
|
||||
{ t("Frequently access folders will be shown here") }
|
||||
</NgIf>
|
||||
</Container>
|
||||
</ReactCSSTransitionGroup>
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
|
|||
import { NgIf, Icon, Button } from '../../components/';
|
||||
import { Share } from '../../model/';
|
||||
import { randomString, notify, absoluteToRelative, copyToClipboard, filetype } from '../../helpers/';
|
||||
import { t } from '../../locales/';
|
||||
import './share.scss';
|
||||
|
||||
export class ShareComponent extends React.Component {
|
||||
|
|
@ -93,7 +94,7 @@ export class ShareComponent extends React.Component {
|
|||
|
||||
copyLinkInClipboard(link){
|
||||
copyToClipboard(link);
|
||||
notify.send("The link was copied in the clipboard", "INFO");
|
||||
notify.send(t("The link was copied in the clipboard"), "INFO");
|
||||
}
|
||||
|
||||
onRegisterLink(e){
|
||||
|
|
@ -187,31 +188,31 @@ export class ShareComponent extends React.Component {
|
|||
|
||||
return (
|
||||
<div className="component_share">
|
||||
<h2>Create a New Link</h2>
|
||||
<h2>{ t("Create a New Link") }</h2>
|
||||
|
||||
<div className="share--content link-type no-select">
|
||||
{ this.props.type === "file" ? null :
|
||||
<div onClick={this.updateState.bind(this, 'role', 'uploader')} className={this.state.role === "uploader" ? "active" : ""}>
|
||||
Uploader
|
||||
{ t("Uploader") }
|
||||
</div>
|
||||
}
|
||||
<div onClick={this.updateState.bind(this, 'role', 'viewer')} className={this.state.role === "viewer" ? "active" : ""}>
|
||||
Viewer
|
||||
{ t("Viewer") }
|
||||
</div>
|
||||
<div onClick={this.updateState.bind(this, 'role', 'editor')} className={this.state.role === "editor" ? "active" : ""}>
|
||||
Editor
|
||||
{ t("Editor") }
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<NgIf cond={this.state.role === null && !!this.state.existings && this.state.existings.length > 0}>
|
||||
<h2>Existing Links</h2>
|
||||
<h2>{ t("Existing Links") }</h2>
|
||||
<div className="share--content existing-links" style={{"maxHeight": this.state.existings && this.state.existings.length > 5 ? '90px' : 'inherit'}}>
|
||||
{
|
||||
this.state.existings && this.state.existings.map((link, i) => {
|
||||
return (
|
||||
<div className="link-details" key={i}>
|
||||
<span onClick={this.copyLinkInClipboard.bind(this, window.location.origin+"/s/"+link.id)} className="copy role">
|
||||
{link.role}
|
||||
{ t(link.role) }
|
||||
</span>
|
||||
<span onClick={this.copyLinkInClipboard.bind(this, window.location.origin+"/s/"+link.id)} className="copy path">{beautifulPath(this.props.path, link.path)}</span>
|
||||
<Icon onClick={this.onDeleteLink.bind(this, link.id)} name="delete"/>
|
||||
|
|
@ -224,24 +225,24 @@ export class ShareComponent extends React.Component {
|
|||
</NgIf>
|
||||
|
||||
<NgIf cond={this.state.role !== null}>
|
||||
<h2>Restrictions</h2>
|
||||
<h2>{ t("Restrictions") }</h2>
|
||||
<div className="share--content advanced-settings no-select">
|
||||
<SuperCheckbox value={this.state.users} label="Only for users" placeholder="name0@email.com,name1@email.com" onChange={this.updateState.bind(this, 'users')} inputType="text"/>
|
||||
<SuperCheckbox value={this.state.password} label="Password" placeholder="protect access with a password" onChange={this.updateState.bind(this, 'password')} inputType="password"/>
|
||||
<SuperCheckbox value={this.state.users} label={ t("Only for users") } placeholder="name0@email.com,name1@email.com" onChange={this.updateState.bind(this, 'users')} inputType="text"/>
|
||||
<SuperCheckbox value={this.state.password} label={ t("Password") } placeholder={ t("protect access with a password") } onChange={this.updateState.bind(this, 'password')} inputType="password"/>
|
||||
</div>
|
||||
|
||||
<h2 className="no-select pointer" onClick={this.updateState.bind(this, 'show_advanced', !this.state.show_advanced)}>
|
||||
Advanced
|
||||
{ t("Advanced") }
|
||||
<NgIf type="inline" cond={!!this.state.show_advanced}><Icon name="arrow_top"/></NgIf>
|
||||
<NgIf type="inline" cond={!this.state.show_advanced}><Icon name="arrow_bottom"/></NgIf>
|
||||
</h2>
|
||||
<div className="share--content advanced-settings no-select">
|
||||
<NgIf cond={this.state.show_advanced === true}>
|
||||
<SuperCheckbox value={datify(this.state.expire)} label="Expiration" placeholder="The link won't be valid after" onChange={this.updateState.bind(this, 'expire')} inputType="date"/>
|
||||
<SuperCheckbox value={datify(this.state.expire)} label={ t("Expiration") } placeholder={ t("The link won't be valid after") } onChange={this.updateState.bind(this, 'expire')} inputType="date"/>
|
||||
<NgIf cond={this.state.role === "editor" && this.props.type !== "file"}>
|
||||
<SuperCheckbox value={this.state.can_share} label="Can Reshare" onChange={this.updateState.bind(this, 'can_share')}/>
|
||||
<SuperCheckbox value={this.state.can_share} label={ t("Can Reshare") } onChange={this.updateState.bind(this, 'can_share')}/>
|
||||
</NgIf>
|
||||
<SuperCheckbox value={this.state.url} label="Custom Link url" placeholder="beautiful_url" onChange={(val) => this.updateState('url', urlify(val))} inputType="text"/>
|
||||
<SuperCheckbox value={this.state.url} label={ t("Custom Link url") } placeholder={ t("beautiful_url") } onChange={(val) => this.updateState('url', urlify(val))} inputType="text"/>
|
||||
</NgIf>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
|||
|
||||
import { Card, NgIf, Icon, EventEmitter, Dropdown, DropdownButton, DropdownList, DropdownItem, Container } from '../../components/';
|
||||
import { pathBuilder, debounce, prompt } from '../../helpers/';
|
||||
import { t } from '../../locales/';
|
||||
import "./submenu.scss";
|
||||
|
||||
@EventEmitter
|
||||
|
|
@ -49,7 +50,7 @@ export class Submenu extends React.Component {
|
|||
}
|
||||
onDelete(arrayOfPaths){
|
||||
prompt.now(
|
||||
"Confirm by typing \"remove\"",
|
||||
t("Confirm by typing") + " \"remove\"",
|
||||
(answer) => {
|
||||
if(answer !== "remove"){
|
||||
return Promise.resolve();
|
||||
|
|
@ -116,14 +117,14 @@ export class Submenu extends React.Component {
|
|||
<Container>
|
||||
<div className={"menubar no-select "+(this.state.search_input_visible ? "search_focus" : "")}>
|
||||
<NgIf cond={this.props.accessRight.can_create_file !== false && this.props.selected.length === 0} onClick={this.onNew.bind(this, 'file')} type="inline">
|
||||
New File
|
||||
{ window.innerWidth < 500 && t("New File").length > 10 ? t("New File", null, "NEW_FILE::SHORT") : t("New File") }
|
||||
</NgIf>
|
||||
<NgIf cond={this.props.accessRight.can_create_directory !== false && this.props.selected.length === 0} onClick={this.onNew.bind(this, 'directory')} type="inline">
|
||||
New Directory
|
||||
{ window.innerWidth < 500 && t("New Directory").length > 10 ? t("New Directory", null, "NEW_DIRECTORY::SHORT") : t("New Directory") }
|
||||
</NgIf>
|
||||
<NgIf cond={this.props.selected.length > 0} type="inline" onMouseDown={this.onDelete.bind(this, this.props.selected)}>
|
||||
<ReactCSSTransitionGroup transitionName="submenuwithSelection" transitionLeave={false} transitionEnter={false} transitionAppear={true} transitionAppearTimeout={10000}>
|
||||
<span>Remove</span>
|
||||
<span>{ t("Remove") }</span>
|
||||
</ReactCSSTransitionGroup>
|
||||
</NgIf>
|
||||
|
||||
|
|
@ -132,9 +133,9 @@ export class Submenu extends React.Component {
|
|||
<Icon name="sort"/>
|
||||
</DropdownButton>
|
||||
<DropdownList>
|
||||
<DropdownItem name="type" icon={this.props.sort === "type" ? "check" : null}> Sort By Type </DropdownItem>
|
||||
<DropdownItem name="date" icon={this.props.sort === "date" ? "check" : null}> Sort By Date </DropdownItem>
|
||||
<DropdownItem name="name" icon={this.props.sort === "name" ? "check" : null}> Sort By Name </DropdownItem>
|
||||
<DropdownItem name="type" icon={this.props.sort === "type" ? "check" : null}> { t("Sort By Type") } </DropdownItem>
|
||||
<DropdownItem name="date" icon={this.props.sort === "date" ? "check" : null}> { t("Sort By Date") } </DropdownItem>
|
||||
<DropdownItem name="name" icon={this.props.sort === "name" ? "check" : null}> { t("Sort By Name") } </DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
<div className="view list-grid" onClick={this.onViewChange.bind(this)}><Icon name={this.props.view === "grid" ? "list" : "grid"}/></div>
|
||||
|
|
@ -149,8 +150,8 @@ export class Submenu extends React.Component {
|
|||
</NgIf>
|
||||
</label>
|
||||
<NgIf cond={this.state.search_input_visible !== null} type="inline">
|
||||
<input ref="$input" onBlur={this.closeIfEmpty.bind(this, false)} style={{"width": this.state.search_input_visible ? "180px" : "0px"}} value={this.state.search_keyword} onChange={(e) => this.onSearchKeypress(e.target.value, true)} type="text" id="search" placeholder="search" name="search" autoComplete="off" />
|
||||
<label htmlFor="search" className="hidden">search</label>
|
||||
<input ref="$input" onBlur={this.closeIfEmpty.bind(this, false)} style={{"width": this.state.search_input_visible ? "180px" : "0px"}} value={this.state.search_keyword} onChange={(e) => this.onSearchKeypress(e.target.value, true)} type="text" id="search" placeholder={ t("search") } name="search" autoComplete="off" />
|
||||
<label htmlFor="search" className="hidden">{ t("search") }</label>
|
||||
</NgIf>
|
||||
</form>
|
||||
</NgIf>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import { Card, NgIf, Icon, EventEmitter, Button, img_placeholder } from '../../c
|
|||
import { pathBuilder, basename, filetype, prompt, alert, leftPad, getMimeType, debounce, memory } from '../../helpers/';
|
||||
import { Files } from '../../model/';
|
||||
import { ShareComponent } from './share';
|
||||
import { t } from '../../locales/';
|
||||
|
||||
const fileSource = {
|
||||
beginDrag(props, monitor, component) {
|
||||
|
|
@ -167,7 +168,7 @@ export class ExistingThing extends React.Component {
|
|||
|
||||
onDeleteRequest(filename){
|
||||
prompt.now(
|
||||
"Confirm by typing \""+this._confirm_delete_text()+"\"",
|
||||
t("Confirm by typing") +" \""+this._confirm_delete_text()+"\"",
|
||||
(answer) => { // click on ok
|
||||
if(answer === this._confirm_delete_text()){
|
||||
this.setState({icon: 'loading'});
|
||||
|
|
@ -178,7 +179,7 @@ export class ExistingThing extends React.Component {
|
|||
);
|
||||
return Promise.resolve();
|
||||
}else{
|
||||
return Promise.reject("Doesn't match");
|
||||
return Promise.reject(t("Doesn't match"));
|
||||
}
|
||||
},
|
||||
() => { /* click on cancel */ });
|
||||
|
|
@ -192,7 +193,7 @@ export class ExistingThing extends React.Component {
|
|||
this.props.file.type
|
||||
);
|
||||
}else{
|
||||
this.setState({delete_error: "Doesn't match"});
|
||||
this.setState({delete_error: t("Doesn't match")});
|
||||
}
|
||||
}
|
||||
onDeleteCancel(){
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { Redirect } from 'react-router';
|
|||
import { Share } from '../model/';
|
||||
import { notify, basename, filetype, findParams } from '../helpers/';
|
||||
import { Loader, Input, Button, Container, ErrorPage, Icon, NgIf } from '../components/';
|
||||
import { t } from '../locales/';
|
||||
import './error.scss';
|
||||
import './sharepage.scss';
|
||||
|
||||
|
|
@ -79,7 +80,7 @@ export class SharePage extends React.Component {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
notify.send("You can't do that :)", "error");
|
||||
notify.send(t("You can't do that :)"), "error");
|
||||
}else if(filetype(this.state.path) === "directory"){
|
||||
return ( <Redirect to={`/files/?share=${this.state.share}`} /> );
|
||||
}else{
|
||||
|
|
@ -95,7 +96,7 @@ export class SharePage extends React.Component {
|
|||
return (
|
||||
<Container maxWidth="300px" className="sharepage_component">
|
||||
<form className={className} onSubmit={(e) => this.submitProof(e, "code", this.refs.$input.ref.value)} style={marginTop()}>
|
||||
<Input ref="$input" type="text" placeholder="Code" />
|
||||
<Input ref="$input" type="text" placeholder={ t("Code") } />
|
||||
<Button theme="transparent">
|
||||
<Icon name={this.state.loading ? "loading" : "arrow_right"}/>
|
||||
</Button>
|
||||
|
|
@ -106,7 +107,7 @@ export class SharePage extends React.Component {
|
|||
return (
|
||||
<Container maxWidth="300px" className="sharepage_component">
|
||||
<form className={className} onSubmit={(e) => this.submitProof(e, "password", this.refs.$input.ref.value)} style={marginTop()}>
|
||||
<Input ref="$input" type="password" placeholder="Password" />
|
||||
<Input ref="$input" type="password" placeholder={ t("Password") } />
|
||||
<Button theme="transparent">
|
||||
<Icon name={this.state.loading ? "loading" : "arrow_right"}/>
|
||||
</Button>
|
||||
|
|
@ -117,7 +118,7 @@ export class SharePage extends React.Component {
|
|||
return (
|
||||
<Container maxWidth="300px" className="sharepage_component">
|
||||
<form className={className} onSubmit={(e) => this.submitProof(e, "email", this.refs.$input.ref.value)} style={marginTop()}>
|
||||
<Input ref="$input" type="text" placeholder="Your email address" />
|
||||
<Input ref="$input" type="text" placeholder={ t("Your email address") } />
|
||||
<Button theme="transparent">
|
||||
<Icon name={this.state.loading ? "loading" : "arrow_right"}/>
|
||||
</Button>
|
||||
|
|
@ -128,8 +129,8 @@ export class SharePage extends React.Component {
|
|||
|
||||
return (
|
||||
<div className="error-page">
|
||||
<h1>Oops!</h1>
|
||||
<h2>There's nothing in here</h2>
|
||||
<h1>{ t("Oops!") }</h1>
|
||||
<h2>{ t("There is nothing in here") }</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,10 +3,11 @@ import React from 'react';
|
|||
import { MenuBar } from './menubar';
|
||||
import { NgIf, Icon } from '../../components/';
|
||||
import './filedownloader.scss';
|
||||
import { t } from '../../locales/';
|
||||
|
||||
export class FileDownloader extends React.Component{
|
||||
constructor(props){
|
||||
super(props)
|
||||
super(props);
|
||||
this.state = {loading: false, id: null};
|
||||
}
|
||||
|
||||
|
|
@ -16,7 +17,7 @@ export class FileDownloader extends React.Component{
|
|||
loading: true,
|
||||
id: window.setInterval(function(){
|
||||
if(/download=yes/.test(document.cookie) === false){
|
||||
this.setState({loading: false})
|
||||
this.setState({loading: false});
|
||||
window.clearInterval(this.state.id);
|
||||
}
|
||||
}.bind(this), 80)
|
||||
|
|
@ -24,7 +25,7 @@ export class FileDownloader extends React.Component{
|
|||
}
|
||||
|
||||
componentWillUnmount(){
|
||||
window.clearInterval(this.state.id)
|
||||
window.clearInterval(this.state.id);
|
||||
}
|
||||
|
||||
render(){
|
||||
|
|
@ -33,7 +34,7 @@ export class FileDownloader extends React.Component{
|
|||
<div className="download_button">
|
||||
<a download={this.props.filename} href={this.props.data}>
|
||||
<NgIf onClick={this.onClick.bind(this)} cond={!this.state.loading}>
|
||||
DOWNLOAD
|
||||
{ t("DOWNLOAD") }
|
||||
</NgIf>
|
||||
</a>
|
||||
<NgIf cond={this.state.loading}>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
a > div {
|
||||
font-size: 17px;
|
||||
display: inline-block;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
// loading
|
||||
> div {
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { confirm, currentShare } from '../../helpers/';
|
|||
import { Editor } from './editor';
|
||||
import { MenuBar } from './menubar';
|
||||
import { OrgTodosViewer, OrgEventsViewer } from './org_viewer';
|
||||
|
||||
import { t } from '../../locales/';
|
||||
|
||||
import './ide.scss';
|
||||
|
||||
|
|
@ -32,7 +32,7 @@ export class IDE extends React.Component {
|
|||
if(this.props.needSaving === false) return true;
|
||||
confirm.now(
|
||||
<div style={{textAlign: "center", paddingBottom: "5px"}}>
|
||||
Do you want to save the changes ?
|
||||
{ t("Do you want to save the changes ?") }
|
||||
</div>,
|
||||
() =>{
|
||||
return this.save()
|
||||
|
|
@ -121,15 +121,15 @@ export class IDE extends React.Component {
|
|||
<Icon name={/download=yes/.test(document.cookie) ? "loading_white" : "download_white"}/>
|
||||
</DropdownButton>
|
||||
<DropdownList>
|
||||
<DropdownItem name="na"><a download={this.props.filename} href={this.props.url}>Save current file</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/html"+this.props.path}>Export as HTML</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/application/pdf"+this.props.path}>Export as PDF</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/markdown"+this.props.path}>Export as Markdown</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/plain"+this.props.path}>Export as Text</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "tex")} href={"/api/export/"+(currentShare() || "private")+"/text/x-latex"+this.props.path}>Export as Latex</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "ics")} href={"/api/export/"+(currentShare() || "private")+"/text/calendar"+this.props.path}>Export as Calendar</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "odt")} href={"/api/export/"+(currentShare() || "private")+"/application/vnd.oasis.opendocument.text"+this.props.path}>Export as Open office</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "pdf")} href={"/api/export/"+(currentShare() || "private")+"/application/pdf"+this.props.path+"?mode=beamer"}>Export as Beamer</a></DropdownItem>
|
||||
<DropdownItem name="na"><a download={this.props.filename} href={this.props.url}>{ t("Save current file") }</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/html"+this.props.path}>{ t("Export as {{VALUE}}", "HTML") }</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/application/pdf"+this.props.path}>{ t("Export as {{VALUE}}", "PDF") }</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/markdown"+this.props.path}>{ t("Export as {{VALUE}}", "Markdown") }</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} href={"/api/export/"+(currentShare() || "private")+"/text/plain"+this.props.path}>{ t("Export as {{VALUE}}", "TXT") }</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "tex")} href={"/api/export/"+(currentShare() || "private")+"/text/x-latex"+this.props.path}>{ t("Export as {{VALUE}}", "Latex") }</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "ics")} href={"/api/export/"+(currentShare() || "private")+"/text/calendar"+this.props.path}>{ t("Export as {{VALUE}}", "ical") }</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "odt")} href={"/api/export/"+(currentShare() || "private")+"/application/vnd.oasis.opendocument.text"+this.props.path}>{ t("Export as {{VALUE}}", "Open office") }</a></DropdownItem>
|
||||
<DropdownItem name="na"><a target={this.props.needSaving ? "_blank" : "_self"} download={changeExt(this.props.filename, "pdf")} href={"/api/export/"+(currentShare() || "private")+"/application/pdf"+this.props.path+"?mode=beamer"}>{ t("Export as {{VALUE}}", "Beamer") }</a></DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
|
|||
import { withRouter } from 'react-router-dom';
|
||||
|
||||
import { NgIf, Icon, EventReceiver, MapShot, Button } from '../../components/';
|
||||
import { t } from '../../locales/';
|
||||
import './image_exif.scss';
|
||||
|
||||
class Exif extends React.Component {
|
||||
|
|
@ -152,19 +153,19 @@ export class SmallExif extends Exif{
|
|||
return (
|
||||
<div className="component_metadata">
|
||||
<div>
|
||||
<span className="label no-select">Date: </span>
|
||||
<span className="label no-select">{ t("Date") }: </span>
|
||||
<span className="value">{this.formatDate("-")}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="label no-select">Location: </span>
|
||||
<span className="label no-select">{ t("Location") }: </span>
|
||||
<span className="value small"><a href={"https://www.google.com/maps/search/?api=1&query="+display_location(this.state.location)}>{display_location(this.state.location)}</a></span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="label no-select">Settings: </span>
|
||||
<span className="label no-select">{ t("Settings") }: </span>
|
||||
<span className="value">{display_settings(this.state.aperture, this.state.shutter, this.state.iso)}</span>
|
||||
</div>
|
||||
<div>
|
||||
<span className="label no-select">Camera: </span>
|
||||
<span className="label no-select">{ t("Camera") }: </span>
|
||||
<span className="value">{display_camera(this.state.model,this.state.focal)}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { MenuBar } from './menubar';
|
|||
import { Bundle, Icon, NgIf, Loader, EventEmitter, EventReceiver } from '../../components/';
|
||||
import { alert } from '../../helpers/';
|
||||
import { Pager } from './pager';
|
||||
import { t } from '../../locales/';
|
||||
import './imageviewer.scss';
|
||||
import './pager.scss';
|
||||
|
||||
|
|
@ -104,7 +105,7 @@ export class ImageViewer extends React.Component{
|
|||
</div>
|
||||
<div className={"images_aside scroll-y"+(this.state.show_exif ? " open": "")}>
|
||||
<div className="header">
|
||||
<div>Info</div>
|
||||
<div>{ t("Info") }</div>
|
||||
<div style={{flex: 1}}>
|
||||
<Icon name="close" onClick={this.toggleExif.bind(this)} />
|
||||
</div>
|
||||
|
|
@ -230,7 +231,7 @@ class ImageFancy extends React.Component {
|
|||
if(this.state.isError){
|
||||
return (
|
||||
<span className="error">
|
||||
<div><div className="label">Can't load this picture</div></div>
|
||||
<div><div className="label">{ t("Can't load this picture") }</div></div>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { Modal, Container, NgIf, Icon, Dropdown, DropdownButton, DropdownList, D
|
|||
import { extractEvents, extractTodos } from '../../helpers/org';
|
||||
import { leftPad } from '../../helpers/common';
|
||||
import { debounce } from '../../helpers/';
|
||||
import { t } from '../../locales/';
|
||||
import './org_viewer.scss';
|
||||
|
||||
export class OrgEventsViewer extends React.Component {
|
||||
|
|
@ -256,13 +257,13 @@ class OrgViewer extends React.Component {
|
|||
<h1>{this.props.title}</h1>
|
||||
<NgIf className="search" cond={this.props.headlines.length > 0}>
|
||||
<label className={this.state.search.length > 0 ? "active" : ""}>
|
||||
<input type="text" onChange={(e) => this.search(e.target.value)} placeholder="Search ..."/>
|
||||
<input type="text" onChange={(e) => this.search(e.target.value)} placeholder={t("Search")+" ..."}/>
|
||||
<Icon name="search" />
|
||||
</label>
|
||||
</NgIf>
|
||||
</div>
|
||||
<NgIf cond={this.props.headlines.length === 0} className="nothing">
|
||||
Nothing
|
||||
{ t("empty") }
|
||||
</NgIf>
|
||||
<NgIf cond={this.props.headlines.length > 0}>
|
||||
<StickyContainer className="container" style={{height: window.innerHeight > 750 ? 545 : window.innerHeight - 202}}>
|
||||
|
|
@ -407,8 +408,8 @@ class Headline extends React.Component {
|
|||
<Icon name="more" />
|
||||
</DropdownButton>
|
||||
<DropdownList>
|
||||
<DropdownItem name="navigate" icon="arrow_right"> Navigate </DropdownItem>
|
||||
<DropdownItem name="properties"> Properties </DropdownItem>
|
||||
<DropdownItem name="navigate" icon="arrow_right"> { t("Navigate") } </DropdownItem>
|
||||
<DropdownItem name="properties"> { t("Properties") } </DropdownItem>
|
||||
</DropdownList>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -17,13 +17,14 @@ var (
|
|||
ErrPermissionDenied error = NewError("Permission Denied", 403)
|
||||
ErrNotValid error = NewError("Not Valid", 405)
|
||||
ErrConflict error = NewError("Already exist", 409)
|
||||
ErrNotReachable error = NewError("Cannot Reach Destination", 502)
|
||||
ErrNotReachable error = NewError("Cannot establish a connection", 502)
|
||||
ErrInvalidPassword = NewError("Invalid Password", 403)
|
||||
ErrNotImplemented = NewError("Not Implemented", 501)
|
||||
ErrNotSupported = NewError("This feature is not supported", 501)
|
||||
ErrNotSupported = NewError("Not supported", 501)
|
||||
ErrFilesystemError = NewError("Can't use filesystem", 503)
|
||||
ErrMissingDependency = NewError("Missing dependency", 424)
|
||||
ErrNotAuthorized = NewError("Not authorized", 401)
|
||||
ErrNotAuthorized = NewError("Not authorised", 401)
|
||||
ErrAuthenticationFailed = NewError("Invalid account", 400)
|
||||
ErrCongestion = NewError("Traffic congestion, try again later", 500)
|
||||
ErrTimeout = NewError("Timeout", 500)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ func SessionAuthenticate(ctx App, res http.ResponseWriter, req *http.Request) {
|
|||
|
||||
home, err := model.GetHome(backend, session["path"])
|
||||
if err != nil {
|
||||
SendErrorResult(res, ErrInvalidPassword)
|
||||
SendErrorResult(res, ErrAuthenticationFailed)
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ func (f Ftp) Init(params map[string]string, app *App) (IBackend, error) {
|
|||
return backend, err
|
||||
}
|
||||
if _, err := client.ReadDir("/"); err != nil {
|
||||
return backend, err
|
||||
return backend, ErrAuthenticationFailed
|
||||
}
|
||||
backend = &Ftp{client}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -193,7 +193,7 @@ func (s S3Backend) Cat(path string) (io.ReadCloser, error) {
|
|||
} else if awsErr.Code() == "InvalidArgument" && strings.Contains(awsErr.Message(), "secret key was invalid") {
|
||||
return nil, NewError("This file is encrypted file, you need the correct key!", 400)
|
||||
} else if awsErr.Code() == "AccessDenied" {
|
||||
return nil, NewError("Access denied", 403)
|
||||
return nil, ErrNotAllowed
|
||||
}
|
||||
return nil ,err
|
||||
}
|
||||
|
|
@ -223,7 +223,7 @@ func (s S3Backend) Rm(path string) error {
|
|||
client := s3.New(s.createSession(p.bucket))
|
||||
|
||||
if p.bucket == "" {
|
||||
return NewError("Doesn't exist", 404)
|
||||
return ErrNotFound
|
||||
}
|
||||
|
||||
objs, err := client.ListObjects(&s3.ListObjectsInput{
|
||||
|
|
@ -276,7 +276,7 @@ func (s S3Backend) Mv(from string, to string) error {
|
|||
client := s3.New(s.createSession(f.bucket))
|
||||
|
||||
if f.path == "" {
|
||||
return NewError("Can't move this", 403)
|
||||
return ErrNotImplemented
|
||||
}
|
||||
|
||||
input := &s3.CopyObjectInput{
|
||||
|
|
@ -303,7 +303,7 @@ func (s S3Backend) Touch(path string) error {
|
|||
client := s3.New(s.createSession(p.bucket))
|
||||
|
||||
if p.bucket == "" {
|
||||
return NewError("Can't do that on S3", 403)
|
||||
return ErrNotValid
|
||||
}
|
||||
|
||||
input := &s3.PutObjectInput{
|
||||
|
|
@ -324,7 +324,7 @@ func (s S3Backend) Save(path string, file io.Reader) error {
|
|||
p := s.path(path)
|
||||
|
||||
if p.bucket == "" {
|
||||
return NewError("Can't do that on S3", 403)
|
||||
return ErrNotValid
|
||||
}
|
||||
uploader := s3manager.NewUploader(s.createSession(path))
|
||||
input := s3manager.UploadInput{
|
||||
|
|
|
|||
|
|
@ -93,13 +93,13 @@ func (s Sftp) Init(params map[string]string, app *App) (IBackend, error) {
|
|||
|
||||
client, err := ssh.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
return &s, NewError("Connection denied", 502)
|
||||
return &s, ErrAuthenticationFailed
|
||||
}
|
||||
s.SSHClient = client
|
||||
|
||||
session, err := sftp.NewClient(s.SSHClient)
|
||||
if err != nil {
|
||||
return &s, NewError("Can't establish connection", 502)
|
||||
return &s, err
|
||||
}
|
||||
s.SFTPClient = session
|
||||
SftpCache.Set(params, &s)
|
||||
|
|
|
|||
|
|
@ -66,11 +66,12 @@ let config = {
|
|||
}
|
||||
}),
|
||||
new CopyWebpackPlugin([
|
||||
{ from: 'manifest.json', to: "assets/" },
|
||||
{ from: 'worker/*.js', to: "assets/" },
|
||||
{ from: 'assets/logo/*' },
|
||||
{ from: 'assets/icons/*' },
|
||||
{ from: 'assets/fonts/*' }
|
||||
{ from: "locales/*.json", to: "assets/" },
|
||||
{ from: "manifest.json", to: "assets/" },
|
||||
{ from: "worker/*.js", to: "assets/" },
|
||||
{ from: "assets/logo/*" },
|
||||
{ from: "assets/icons/*" },
|
||||
{ from: "assets/fonts/*" }
|
||||
], { context: path.join(__dirname, 'client') }),
|
||||
//new BundleAnalyzerPlugin()
|
||||
]
|
||||
|
|
|
|||
Loading…
Reference in a new issue