odsa/index.jsx

359 lines
13 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/* 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 />));