359 lines
13 KiB
JavaScript
359 lines
13 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||
|
||
import { createRoot, createSignal, createState, createEffect } from 'solid-js';
|
||
|
||
function createLocalState(initState) {
|
||
const [state, setState] = createState(initState);
|
||
if (localStorage.odoodockerssh) { setState(JSON.parse(localStorage.odoodockerssh)); }
|
||
createEffect(() => localStorage.odoodockerssh = JSON.stringify(state));
|
||
return [state, setState];
|
||
}
|
||
|
||
const initialState = {
|
||
address: '', port: '', username: '', key: '', database: '',
|
||
databases: [], modules: '', serverlog: '', connected: false, stop: false
|
||
};
|
||
const [isConnected, setIsConnected] = createSignal(false);
|
||
|
||
const OdooDockerSshAdminConfig = () => {
|
||
const [state, setState] = createLocalState(initialState);
|
||
const [passphrase, setPassphrase] = createSignal('');
|
||
const valueSet = ({target}) => setState(target.name, target.value);
|
||
|
||
let cantConnect = !(state.address && state.username && state.key && state.port);
|
||
|
||
const connect = () => {
|
||
fetch('/connect',
|
||
{method: 'POST',
|
||
body: JSON.stringify({
|
||
address: state.address,
|
||
port: state.port,
|
||
username: state.username,
|
||
key: state.key,
|
||
password: passphrase()
|
||
}),
|
||
headers:{ 'Content-Type': 'application/json'}})
|
||
.then(response => {
|
||
setIsConnected(response.status == 200);
|
||
return response.json();
|
||
})
|
||
.then(body => humane.log(body))
|
||
};
|
||
const disconnect = () => {
|
||
fetch ('/disconnect')
|
||
.then(response => {
|
||
setIsConnected(!(response.status == 200));
|
||
return response.json();
|
||
})
|
||
.then(body => humane.log(body))
|
||
};
|
||
|
||
return <div>
|
||
<h2>🛠 Configuration
|
||
<span style="margin-left: 0.5em;">
|
||
<$ when={(isConnected())}>🔵</$>
|
||
<$ when={(!isConnected())}>🔴</$>
|
||
</span>
|
||
</h2>
|
||
<form name="configuration-form">
|
||
<div class="row">
|
||
<div class="col-4">
|
||
<label for="address">Hôte / Adressse IP</label>
|
||
<input name="address" type="text" required
|
||
value={(state.address)} onChange={valueSet} />
|
||
<label for="port">Port</label>
|
||
<input name="port" type="text" pattern="\d+" placeholder="Exemple : 22"
|
||
value={(state.port)} onChange={valueSet}/>
|
||
</div>
|
||
<div class="col-4">
|
||
<label for="username">Identifiant</label>
|
||
<input name="username" type="text" required
|
||
value={(state.username)} onChange={valueSet}/>
|
||
</div>
|
||
<div class="col-4">
|
||
<label for="key">Clé privée</label>
|
||
<textarea name="key" placeholder="Please paste your private key"
|
||
value={(state.key)} onChange={valueSet}/>
|
||
<label for="password">Mot de passe clé</label>
|
||
<input name="password" type="password" required value={(passphrase())}
|
||
onInput={({target}) => setPassphrase(target.value)} />
|
||
</div>
|
||
</div>
|
||
<button type="button" class="button outline primary" onClick={connect}>🔗 Connecter</button>
|
||
<button type="button" class="button outline secondary" onClick={disconnect}>🔴 Déconnecter</button>
|
||
</form>
|
||
</div>
|
||
};
|
||
|
||
const OdooDockerSshAdminDatabases = () => {
|
||
const [state, setState] = createLocalState(initialState);
|
||
const valueSet = ({target}) => setState(target.name, target.value);
|
||
|
||
const add = (e) => {
|
||
e.preventDefault();
|
||
if (state.database) {
|
||
let database = {name: state.database, checked: false};
|
||
setState(['databases', [...state.databases, database]], ['database', '']);
|
||
}
|
||
};
|
||
const inverseCheck = () => {
|
||
let databases = state.databases.map((db) => Object.assign({}, db));
|
||
setState('databases', databases.map((db) => Object.assign(db, {checked: !db.checked})));
|
||
};
|
||
const allCheck = () => {
|
||
let databases = state.databases.map((db) => Object.assign({}, db));
|
||
setState('databases', databases.map((db) => Object.assign(db, {checked: true})));
|
||
};
|
||
const noCheck = () => {
|
||
let databases = state.databases.map((db) => Object.assign({}, db));
|
||
setState('databases', databases.map((db) => Object.assign(db, {checked: false})));
|
||
};
|
||
const toggle = ({target: {checked}}, name) => {
|
||
setState('databases', db => db.name === name, {name: name, checked: checked});
|
||
};
|
||
const remove = (name) => {
|
||
setState('databases', state.databases.filter(db => db.name !== name));
|
||
};
|
||
|
||
return <div>
|
||
<h2>📙 Bases de données</h2>
|
||
<p>Merci de renseigner toutes les bases de votre domaine ici. Pour effectuer une installation ou mise à jour de module, sélectionnez les bases sur lesquelles agir.</p>
|
||
<div class="row">
|
||
<div class="col-12" >
|
||
<button type="button" class="button outline" onClick={inverseCheck}>☑ Inverser la sélection</button>
|
||
<button type="button" class="button dark" onClick={allCheck}>☑ Sélectionner tout</button>
|
||
<button type="button" class="button dark" onClick={noCheck}>◻ Sélectionner aucun</button>
|
||
<ul class="database-list">
|
||
<$ each={ state.databases }>{ (database, index) =>
|
||
<li>
|
||
<input type="checkbox" checked={(database.checked)}
|
||
onClick={(e) => toggle(e, database.name)} />
|
||
<span>{(database.name)}</span>
|
||
<button type="button" class="button outline"
|
||
onClick={() => remove(database.name)}>X</button>
|
||
</li>
|
||
}
|
||
</$>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col-12" >
|
||
<form name="database-form">
|
||
<div class="row">
|
||
<div class="col-8" >
|
||
<input type="text" name="database" placeholder="Nom de la base de données"
|
||
value={(state.database)} onInput={valueSet}/>
|
||
</div>
|
||
<div class="col-4" >
|
||
<button type="submit" class="button outline primary"
|
||
disabled={(!state.database)} onClick={add}>
|
||
➕ Ajouter
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
};
|
||
|
||
const OdooDockerSshAdminActions = () => {
|
||
const [state, setState] = createLocalState(initialState);
|
||
|
||
const cmdFetch = (cmd) => {
|
||
return () => {
|
||
if (!isConnected()) {
|
||
humane.log('Non connecté : impossible de lancer une commande.');
|
||
} else {
|
||
humane.log('Commande lancée, veuillez patienter.');
|
||
fetch('/cmd/' + cmd)
|
||
.then(response => response.json())
|
||
.then(body => {
|
||
humane.log('Commande terminée.');
|
||
setState('serverlog', state.serverlog + body);
|
||
})
|
||
}
|
||
};
|
||
};
|
||
|
||
const webStart = cmdFetch('webstart');
|
||
const webStop = cmdFetch('webstop');
|
||
const webRestart = cmdFetch('webrestart');
|
||
const odooStart = cmdFetch('odoostart');
|
||
const stop = cmdFetch('odoostop');
|
||
const odooRestart = cmdFetch('odoorestart');
|
||
const dbStart = cmdFetch('dbstart');
|
||
const dbStop = cmdFetch('dbstop');
|
||
const dbRestart = cmdFetch('dbrestart');
|
||
|
||
return <div>
|
||
<h2>🚩 Actions</h2>
|
||
<div class="row">
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={odooStart}>
|
||
⏩ Odoo : démarrer
|
||
</button>
|
||
</div>
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={stop}>
|
||
⏹ Odoo : arrêter
|
||
</button>
|
||
</div>
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={odooRestart}>
|
||
🔄 Odoo : redémarrer
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={webStart}>
|
||
⏩ Frontal : démarrer
|
||
</button>
|
||
</div>
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={webStop}>
|
||
⏹ Frontal : arrêter
|
||
</button>
|
||
</div>
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={webRestart}>
|
||
🔄 Frontal : redémarrer
|
||
</button>
|
||
</div>
|
||
</div>
|
||
<div class="row">
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={dbStart}>
|
||
⏩ Moteur de base de données : démarrer
|
||
</button>
|
||
</div>
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={dbStop}>
|
||
⏹ Moteur de base de données : arrêter
|
||
</button>
|
||
</div>
|
||
<div class="col">
|
||
<button type="button" class="button clear" onClick={dbRestart}>
|
||
🔄 Moteur de base de données : redémarrer
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
};
|
||
|
||
const OdooDockerSshAdminModules = () => {
|
||
const [state, setState] = createLocalState(initialState);
|
||
const valueSet = ({target}) => setState(target.name, target.value);
|
||
|
||
const checkedDatabases = (databases) => {
|
||
let names = databases.filter((db) => db.checked).map((db) => db.name);
|
||
return names.length ? names.join(', ') : 'Aucune base sélectionnée';
|
||
};
|
||
|
||
const odooCmd = (action) => {
|
||
return () => {
|
||
if (!isConnected()) {
|
||
humane.log('Non connecté : impossible de lancer une commande Odoo.');
|
||
} else {
|
||
humane.log('Commande lancée, veuillez patienter.');
|
||
fetch('/odooaction', {
|
||
method: 'POST',
|
||
body: JSON.stringify({
|
||
stop: state.stop,
|
||
databases: state.databases.filter((db) => db.checked).map((db) => db.name),
|
||
modules: state.modules,
|
||
action: action
|
||
}),
|
||
headers: {'Content-Type': 'application/json'}
|
||
})
|
||
.then(response => {
|
||
if (response.status != 200) { humane.log('Erreur : voyez le retour serveur'); }
|
||
return response.json();
|
||
})
|
||
.then(body => {
|
||
humane.log('Commande terminée.');
|
||
setState('serverlog', state.serverlog + body);
|
||
})
|
||
}
|
||
};
|
||
};
|
||
|
||
return <div>
|
||
<h2>🗄 Modules</h2>
|
||
<form name="modules-form">
|
||
<p>Bases sélectionnées : {checkedDatabases(state.databases)}</p>
|
||
<div class="row">
|
||
<div class="col-6">
|
||
<label for="modules">Liste de modules, séparés par des virgules</label>
|
||
<input name="modules" type="text" required placeholder="account,crm"
|
||
value={(state.modules)} onInput={valueSet}/>
|
||
</div>
|
||
<div class="col-6">
|
||
<label for="stop">❗ Arrêt serveur préalable ?</label>
|
||
<input type="checkbox" name="stop" checked={(state.stop)}
|
||
onChange={(e) => setState('stop', e.target.checked)} />
|
||
</div>
|
||
</div>
|
||
<button type="button" class="button primary outline" onClick={odooCmd('install')}>
|
||
Installer
|
||
</button>
|
||
<button type="button" class="button primary" onClick={odooCmd('update')}>
|
||
Mettre à jour
|
||
</button>
|
||
</form>
|
||
</div>
|
||
};
|
||
|
||
const OdooDockerSshAdminServerLog = () => {
|
||
const [state, setState] = createLocalState(initialState);
|
||
const serverlogClean = () => setState('serverlog', '');
|
||
|
||
return <div>
|
||
<h2>🖥 Retour serveur</h2>
|
||
<div class="row">
|
||
<div class="col-11">
|
||
<textarea name="serverlog" class="serverlog" rows="20" readonly>{(state.serverlog)}</textarea>
|
||
</div>
|
||
<div class="col-1">
|
||
<button type="button" onClick={serverlogClean}>💢 Nettoyer</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
};
|
||
|
||
const OdooDockerSshAdmin = () => {
|
||
const [visibleTab, setVisibleTab] = createSignal('configuration');
|
||
const getClassName = (name) => visibleTab() === name ? 'active' : '';
|
||
|
||
return <>
|
||
<h1>Odoo Docker SSH Admin</h1>
|
||
<nav class="tabs is-full">
|
||
<a onClick={() => setVisibleTab('configuration')} className={(getClassName('configuration'))}>
|
||
🛠 Configuration
|
||
</a>
|
||
<a onClick={() => setVisibleTab('actions')} className={(getClassName('actions'))}>
|
||
🚩 Actions
|
||
</a>
|
||
<a onClick={() => setVisibleTab('databases')} className={(getClassName('databases'))}>
|
||
📙 Bases de données
|
||
</a>
|
||
<a onClick={() => setVisibleTab('modules')} className={(getClassName('modules'))}>
|
||
🗄 Modules
|
||
</a>
|
||
<a onClick={() => setVisibleTab('serverlog')} className={(getClassName('serverlog'))}>
|
||
🖥 Retour serveur
|
||
</a>
|
||
</nav>
|
||
<$ when={(visibleTab() === 'configuration')}><OdooDockerSshAdminConfig /></$>
|
||
<$ when={(visibleTab() === 'databases')}><OdooDockerSshAdminDatabases /></$>
|
||
<$ when={(visibleTab() === 'modules')}><OdooDockerSshAdminModules /></$>
|
||
<$ when={(visibleTab() === 'actions')}><OdooDockerSshAdminActions /></$>
|
||
<$ when={(visibleTab() === 'serverlog')}><OdooDockerSshAdminServerLog /></$>
|
||
</>
|
||
}
|
||
createRoot(() => document.body.appendChild(<OdooDockerSshAdmin />));
|