From 2926d5613d5679e760ff3f754edaf3e4c97d6df5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Loi=CC=88c=20Correnson?= <loic.correnson@cea.fr>
Date: Mon, 17 Feb 2020 18:06:45 +0100
Subject: [PATCH] [ivette] remove multitool support

---
 ivette/backup/Configure.js      | 155 -----------
 ivette/backup/Display.js        |  34 ---
 ivette/backup/FileMenu.js       |  37 ---
 ivette/backup/Home.js           | 134 ----------
 ivette/backup/Project.js        | 101 -------
 ivette/backup/ivette/index.js   | 455 --------------------------------
 ivette/backup/ivette/plugins.js | 247 -----------------
 ivette/backup/ivette/stores.js  | 152 -----------
 ivette/backup/ivette/views.js   |  42 ---
 ivette/backup/style.css         |  50 ----
 10 files changed, 1407 deletions(-)
 delete mode 100644 ivette/backup/Configure.js
 delete mode 100644 ivette/backup/Display.js
 delete mode 100644 ivette/backup/FileMenu.js
 delete mode 100644 ivette/backup/Home.js
 delete mode 100644 ivette/backup/Project.js
 delete mode 100644 ivette/backup/ivette/index.js
 delete mode 100644 ivette/backup/ivette/plugins.js
 delete mode 100644 ivette/backup/ivette/stores.js
 delete mode 100644 ivette/backup/ivette/views.js
 delete mode 100644 ivette/backup/style.css

diff --git a/ivette/backup/Configure.js b/ivette/backup/Configure.js
deleted file mode 100644
index b91206cb19d..00000000000
--- a/ivette/backup/Configure.js
+++ /dev/null
@@ -1,155 +0,0 @@
-// --------------------------------------------------------------------------
-// --- Module Configuration View
-// --------------------------------------------------------------------------
-
-import _ from 'lodash' ;
-import React from 'react' ;
-import Dome from 'dome' ;
-import Dialogs from 'dome/dialogs' ;
-import { Catch } from 'dome/errors' ;
-import { Label } from 'dome/controls/labels' ;
-import Box from 'dome/layout/boxes' ;
-import Toolbar from 'dome/layout/toolbars' ;
-import Dispatch from 'dome/layout/dispatch' ;
-import Form from 'dome/layout/forms' ;
-import Ivette from '@ivette' ;
-import Project from './Project' ;
-
-// --------------------------------------------------------------------------
-// --- Configuration View
-// --------------------------------------------------------------------------
-
-export default function Configure()
-{
-
-  const [ state, setState ] = Project.useState();
-  const configure = state.configure ;
-  if (!configure) return null;
-
-  const { module, value, error, modified=false, copied } = configure ;
-  const valueId = value && value.id ;
-  const savedId = module && module.id ;
-  const isFresh = Ivette.isFresh(valueId);
-  const borrowed_label = copied && module.label ;
-  const borrowed_title = copied && module.title ;
-
-  const validIdent = (id) =>
-        id === savedId ||
-        (!Ivette.isValid(id) ? 'Invalid identifier (not a filename)' :
-         !Ivette.isFresh(id) ? 'Already used identifier' :
-         true) ;
-
-  const validLabel = borrowed_label && ((label) => label !== borrowed_label) ;
-  const validTitle = borrowed_title && ((title) => title !== borrowed_title) ;
-
-  const onChange = (value,error) => {
-    Object.assign( configure, { modified: true, value, error } );
-    setState({ configure });
-  };
-
-  const onReload = () => {
-    setState({ configure: {
-      module,
-      copied: configure.copied,
-      value: Project.initConfigValue(configure.module)
-    }});
-  };
-
-  const closeWith = (current) => {
-    setState({
-      current,
-      configure: undefined,
-      frame: configure.onClose || 'home'
-    });
-  };
-
-  const onClose = () => closeWith( state.current );
-
-  const onApply = () => {
-    if ( value && !error && !module.locked()) {
-      let commit = Ivette.commitModule( module, value );
-      module.synchronize(commit)
-        .catch(onError)
-        .finally(() => closeWith( configure.copied ? module : undefined ));
-    } else {
-      closeWith( undefined );
-    }
-  };
-
-  const onError = (err) => Dialogs.showMessageBox({
-    kind: 'warning',
-    title: 'Module Management Error',
-    message: 'An error occurs during a module operation:\n' + err,
-    buttons: [{ label:'Ok' }]
-  });
-
-  const onRemove = () => Dialogs.showMessageBox({
-    kind: 'warning',
-    title: 'Remove Module',
-    message: 'Definitively remove this Module from your Project ?',
-    defaultValue: false,
-    cancelValue: false,
-    buttons: [
-      { value:false, label:'No' },
-      { value:true,  label:'Remove' }
-    ]
-  }).then( (ok) => {
-    if (ok) {
-      let removal = Ivette.removeModule( configure.module );
-      module.synchronize(removal)
-        .catch(onError)
-        .finally(() => closeWith( undefined ));
-    }
-  });
-
-  return (
-    <Box.Vfill>
-      <Dispatch.Item id='ivette.toolbar.configure'>
-        <Toolbar.Separator/>
-        <Toolbar.Button
-          kind='positive' icon='CHECK'
-          label='Apply' title='Apply modifications'
-          enabled={modified || isFresh}
-          disabled={error || module.locked()}
-          onClick={onApply} />
-        <Toolbar.Inset/>
-        <Label>{ isFresh && 'New' } Module Configuration </Label>
-        <Toolbar.Filler/>
-        <Toolbar.Button
-          kind='negative' icon='TRASH'
-          label='Remove' title='Remove module'
-          disabled={isFresh}
-          enabled={valueId === savedId}
-          onClick={onRemove} />
-        <Toolbar.Button
-          icon='RELOAD' title='Reset configuration'
-          enabled={modified}
-          onClick={onReload} />
-        <Toolbar.Button
-          kind='cancel'
-          icon='CIRC.CLOSE' title='Cancel modifications'
-          onClick={onClose} />
-      </Dispatch.Item>
-      <Form.Form
-        value={value}
-        error={error}
-        onChange={onChange} >
-        <Form.FieldCode
-          path='id' label='Module'
-          validate={validIdent}
-          placeholder={valueId} />
-        <Form.FieldText
-          path='label' label='Display Name'
-          validate={validLabel} />
-        <Form.FieldTextArea
-          path='title' label='Description'
-          validate={validTitle} rows={3} />
-        <Form.Select path='config'>
-          <Catch label='Plugin Config'>{ module.renderConfig() }</Catch>
-        </Form.Select>
-      </Form.Form>
-    </Box.Vfill>
-  );
-}
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/Display.js b/ivette/backup/Display.js
deleted file mode 100644
index 140f47ea5a9..00000000000
--- a/ivette/backup/Display.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// --------------------------------------------------------------------------
-// --- Module Control View
-// --------------------------------------------------------------------------
-
-import _ from 'lodash' ;
-import React from 'react' ;
-import Dome from 'dome' ;
-import { Catch } from 'dome/errors' ;
-import { Label } from 'dome/controls/labels' ;
-import Toolbar from 'dome/layout/toolbars' ;
-import Dispatch from 'dome/layout/dispatch' ;
-import Project from './Project' ;
-import { ProvideModule } from '@ivette' ;
-
-// --------------------------------------------------------------------------
-// --- Current Module Display
-// --------------------------------------------------------------------------
-
-export default function Display()
-{
-  const [ { current } ] = Project.useState();
-  if (!current)
-    return <Label>No module selected.</Label> ;
-  else
-    return (
-      <ProvideModule module={current}>
-        <Catch label='Plugin Main View'>
-          <Dome.Render>{current.renderMain}</Dome.Render>
-        </Catch>
-      </ProvideModule>
-    );
-}
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/FileMenu.js b/ivette/backup/FileMenu.js
deleted file mode 100644
index c2bf7131c3f..00000000000
--- a/ivette/backup/FileMenu.js
+++ /dev/null
@@ -1,37 +0,0 @@
-// --------------------------------------------------------------------------
-// --- File Menu
-// --------------------------------------------------------------------------
-
-import fs from 'fs' ;
-import path from 'path' ;
-import Dome from 'dome' ;
-import Dialogs from 'dome/dialogs' ;
-import Project from './Project' ;
-import Ivette from '@ivette' ;
-
-// --------------------------------------------------------------------------
-// --- Actions
-// --------------------------------------------------------------------------
-
-function openProject()
-{
-  console.log('OPEN PROJECT…');
-}
-
-// --------------------------------------------------------------------------
-// --- Menu Items
-// --------------------------------------------------------------------------
-
-Dome.addMenuItem({
-  menu: 'File',
-  id: 'ivette.menu.file.open',
-  label: 'Open Project…',
-  onClick: openProject
-});
-
-Dome.onUpdate(() => {
-  let enabled = Ivette.isProjectLocked();
-  Dome.setMenuItem({ id: 'ivette.menu.file.open', enabled });
-});
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/Home.js b/ivette/backup/Home.js
deleted file mode 100644
index 93c98808a6c..00000000000
--- a/ivette/backup/Home.js
+++ /dev/null
@@ -1,134 +0,0 @@
-// --------------------------------------------------------------------------
-// --- Project Home View
-// --------------------------------------------------------------------------
-
-import React from 'react' ;
-import Dome from 'dome' ;
-import Toolbar from 'dome/layout/toolbars' ;
-import { Scroll, Hpack, Vbox, Vfill, Hfill } from 'dome/layout/boxes' ;
-import { Splitter } from 'dome/layout/splitters' ;
-import { Title, Label, Code, Descr } from 'dome/controls/labels' ;
-import { Button, IconButton } from 'dome/controls/buttons' ;
-import Ivette from '@ivette' ;
-import Project from './Project' ;
-
-// --------------------------------------------------------------------------
-// --- Generic Dongle
-// --------------------------------------------------------------------------
-
-function Dongle({ id, label, title, selected, onSelect, children })
-{
-  const wident = id && <Code className='ivette-dongle-id' label={id}/> ;
-  const wlabel = label && <Label label={label} /> ;
-  const wdescr = title && <Descr label={title} /> ;
-  const classes = 'ivette-dongle'
-        + (onSelect ? ' ivette-dongle-selectable' : '')
-        + (selected ? ' ivette-dongle-selected' : '') ;
-  return (
-    <Hfill className={classes}
-           onClick={onSelect} >
-      {wident}
-      <Vfill>
-        {wlabel}
-        {wdescr}
-      </Vfill>
-      { children }
-    </Hfill>
-  );
-}
-
-// --------------------------------------------------------------------------
-// --- Module Dongle
-// --------------------------------------------------------------------------
-
-function ModuleDongle({ module, current, configure })
-{
-  let selected = module === current ;
-  let configuring = configure && configure.modified ;
-  let configured = configuring && configure.value && configure.value.id === module.id ;
-  let SELECT = () => Project.setState({ current: module });
-  let DISPLAY = () => Project.setState({ current: module, frame:'display' });
-  let CONFIGURE = () => {
-    if (configured) Project.setConfigure();
-    else if (!configuring) Project.setConfiguring(module);
-  };
-  return (
-    <Dongle id={module.id}
-            label={module.label}
-            title={module.title}
-            selected={selected}
-            onSelect={SELECT} >
-      <Toolbar.ButtonGroup>
-        <Toolbar.Button
-          icon='DISPLAY' title={'Display ' + module.id}
-          onClick={DISPLAY} />
-        <Toolbar.Button
-          icon='SETTINGS' title={'Configure ' + module.id}
-          disabled={configuring && !configured}
-          onClick={CONFIGURE} />
-      </Toolbar.ButtonGroup>
-    </Dongle>
-  );
-}
-
-// --------------------------------------------------------------------------
-// --- Plugin Dongle
-// --------------------------------------------------------------------------
-
-function PluginDongle({ plugin, configure })
-{
-  const CREATE = () => Project.setConfiguring( Ivette.newModule(plugin) );
-  return (
-    <Dongle label={plugin.label} title={plugin.title} >
-      <Button icon='CIRC.PLUS' label='New'
-              title='Create a new Module from this plugin'
-              kind='positive'
-              style={{ width:80, height: 32 }}
-              disabled={configure && configure.modified}
-              onClick={CREATE} />
-    </Dongle>
-  );
-}
-
-// --------------------------------------------------------------------------
-// --- Main View
-// --------------------------------------------------------------------------
-
-export default function Home()
-{
-  const [ { current,configure } , setState ] = Project.useState();
-  const PROJECT = Ivette.getProjectDirectory();
-
-  const MODULES= Ivette.getModules().map((module) => (
-          <ModuleDongle
-            key={'M' + module.id}
-            module={module}
-            current={current}
-            configure={configure}
-            />
-        ));
-
-  const PLUGINS= Ivette.getPlugins().map((plugin) => (
-          <PluginDongle
-            key={'P' + plugin.id}
-            plugin={plugin}
-            configure={configure}
-            />
-        ));
-
-  return (
-    <Scroll>
-      <Vbox>
-        {PROJECT ? <Title label='Project'/> : null}
-        {PROJECT ? <div className='ivette-project'><Code>{PROJECT}</Code></div> : null}
-        {MODULES.length ? <Title label='Modules'/> : null}
-        {MODULES}
-        {MODULES.length ? <div style={{height: 32}}/> : null}
-        {PLUGINS.length ? <Title label='Plugins'/> : null}
-        {PLUGINS}
-      </Vbox>
-    </Scroll>
-  );
-}
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/Project.js b/ivette/backup/Project.js
deleted file mode 100644
index 67e6fa68443..00000000000
--- a/ivette/backup/Project.js
+++ /dev/null
@@ -1,101 +0,0 @@
-// --------------------------------------------------------------------------
-// --- Current State of Project
-// --------------------------------------------------------------------------
-
-import _ from 'lodash' ;
-import React from 'react' ;
-import Dome from 'dome' ;
-import Dialogs from 'dome/dialogs' ;
-import System from 'dome/system' ;
-import Ivette from '@ivette' ;
-import { Module } from '@ivette/plugins' ;
-
-// --------------------------------------------------------------------------
-// --- Global State
-// --------------------------------------------------------------------------
-
-/*
-  - 'frame': currently displayed frame in main window
-  - 'current': currently selected module object
-  - 'configure.module': original configured module
-  - 'configure.value': edited module properties
-  - 'configure.error': edited module errors
-  - 'configure.copied': true if the the target is a fresh copy from another module
-  - 'configure.modified': true if the value has been edited
- */
-
-const project = new Dome.State({ frame: 'home' });
-
-export const setState = project.setState ;
-export const useState = project.useState ;
-
-const mkSetFrame = (frame) => () => project.setState({frame});
-export const setHome = mkSetFrame('home');
-export const setDisplay = mkSetFrame('display');
-export const setConfigure = mkSetFrame('configure');
-
-// --------------------------------------------------------------------------
-// --- Module Helpers
-// --------------------------------------------------------------------------
-
-export function initConfigValue( module )
-{
-  let { id, label, descr } = module ;
-  let config = _.cloneDeep( module.config );
-  return { id, label, descr, config };
-}
-
-export function setConfiguring( module, onClose )
-{
-  if (module instanceof Module) {
-    let value = initConfigValue( module );
-    setState({
-      frame: 'configure',
-      configure: Object.assign( { onClose }, { value, module } )
-    });
-  } else
-    console.err( 'Not a plugin instance' , module );
-}
-
-// --------------------------------------------------------------------------
-// --- Module Helpers
-// --------------------------------------------------------------------------
-
-export function lookupProject() {
-
-  let argv = System.argv();
-  let commandProject = Ivette.lookupProject( argv[0] );
-  if (commandProject) return commandProject ;
-
-  let previousProject = Ivette.lookupProject( Dome.getGlobalSetting('ivette.working.project') );
-  if (previousProject) return previousProject ;
-
-  let workingProject = Ivette.lookupProject( System.getWorking() );
-  if (workingProject) return workingProject ;
-
-  return undefined ;
-}
-
-export function loadProject( dir )
-{
-  if (!dir) return ;
-  Dome.setGlobalSetting('ivette.working.project',dir);
-  let setup = Ivette.loadProject( dir );
-  setup.then( (errors) => errors && errors.length && Dialogs.showMessageBox({
-    kind: 'error',
-    message: 'Error(s) when loading project:\n' + errors.join('\n'),
-    buttons: [{ label: 'Ok' }]
-  })).finally(Dome.update);
-}
-
-// --------------------------------------------------------------------------
-// --- Exports Default
-// --------------------------------------------------------------------------
-
-export default {
-  useState, setState, setHome, setConfigure, setDisplay,
-  setConfiguring, initConfigValue,
-  lookupProject, loadProject
-};
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/ivette/index.js b/ivette/backup/ivette/index.js
deleted file mode 100644
index c9520ab74cf..00000000000
--- a/ivette/backup/ivette/index.js
+++ /dev/null
@@ -1,455 +0,0 @@
-/** @module @ivette */
-
-import _ from 'lodash' ;
-import React from 'react' ;
-import Dome from 'dome' ;
-import System from 'dome/system' ;
-import { Module, Factory, CONFIG, UPDATE } from './plugins' ;
-import { Registry } from './stores' ;
-
-// --------------------------------------------------------------------------
-// --- Plugin & Module Registries
-// --------------------------------------------------------------------------
-
-const pluginsRegistry = new Registry('plugin');
-const modulesRegistry = new Registry('module');
-
-/**
-   @method
-   @summary Registered Plugins.
-   @return {Class[]} an array of `Plugin` classes
- */
-export const getPlugins = () => pluginsRegistry.elements() ;
-
-/**
-   @method
-   @summary Registered Modules.
-   @return {Plugin[]} an array of `Plugin` instances
- */
-export const getModules = () => modulesRegistry.elements() ;
-
-/**
-   @method
-   @summary Returns a module by id.
- */
-export const getModule = (id) => modulesRegistry.get(id);
-
-// --------------------------------------------------------------------------
-// --- Register Plugin
-// --------------------------------------------------------------------------
-
-const checkModule = ( m ) => {
-  if (!(m instanceof Module))
-    throw `Invalid Plugin '${m}'` ;
-};
-
-const checkPlugin = ( P ) => checkModule( P.prototype );
-const getPluginId = ( m ) => m.constructor.id ;
-
-/**
-   @summary Register a (new) plugin.
-   @param {PLUGIN|Class<Module>} Plugin -
-   [plugin specification](module-@ivette_plugins.html#~PLUGIN) or
-   [module class](module-@ivette_plugins.html#Module)
-   @description
-
-   Register a new plugin in the Ivette system.
-
-   It is recommand to use a [PLUGIN](module-@ivette_plugins.html#~PLUGIN)
-   object for plugin specification.
-   If a class is provided, it shall extends the [Module](module-@ivette_plugins.html#Module)
-   base class and shall have static properties `id`, `label`
-   and `title` defined.
-
-   Unless your are in development mode (which implies hot module reloading),
-   it is not permitted to register two plugins with the same identifier,
-   and an error would be emitted on the console in turn.
- */
-function registerPlugin( spec )
-{
-  const ThePlugin = typeof(spec)==='object' ? Factory(spec) : spec ;
-  checkPlugin( ThePlugin );
-  const id = ThePlugin.id ;
-  if (!id)
-    throw `Invalid plugin: missing identifier` ;
-  if (!System.DEVEL && pluginsRegistry.get(id))
-    throw `Duplicate plugin '${id}'` ;
-  pluginsRegistry.add( ThePlugin );
-  if (System.DEVEL) modulesRegistry.forEach( (module) => {
-    // Propagates changes from HMR
-    if (module.constructor.id === ThePlugin.id) Object.setPrototypeOf( module , ThePlugin.prototype );
-  });
-}
-
-// --------------------------------------------------------------------------
-// --- Project Directory
-// --------------------------------------------------------------------------
-
-let projectDirectory ;
-
-const getProjectDir = () => {
-  if (!projectDirectory) return projectDirectory;
-  let cwd = System.getWorkingDir();
-  return cwd ? System.join( cwd , '.ivette' ) : undefined ;
-};
-const getProjectIndex = () => System.join( getProjectDir(), 'index.json' );
-const getModuleSession = (mid) => System.join( getProjectDir(), 'modules', mid );
-const getModuleConfig = (mid) => System.join( getProjectDir() , 'config.json' );
-
-/** @method
-    @summary Check is fome module is locked.
-    @return {boolean} */
-export const isProjectLocked = () => (
-  modulesRegistry.find((m) => m.locked()) !== undefined
-);
-
-/**
-   @method
-   @summary Returns current project directory.
-   @return {string} absolute path or undefined */
-export const getProjectDirectory = () => projectDirectory;
-
-/**
-    @summary Find enclosing project.
-    @param {string} path - a file path to starts with
-    @return {string} project directory holding that path
-    @description
-    Looks for the closest directory with name `"*.ivette"`
-    containing the given path, or the closest directory with a `.ivette`
-    file at root.
-    Returns `undefined` if not found.
-*/
-export function lookupProject( path ) {
-  try {
-    path = System.resolve(path);
-    let prev ;
-    while( prev !== path )
-    {
-      if (System.extname(path) === '.ivette' && System.isDirectory(path))
-        return path;
-      let here = System.join( path, '.ivette' );
-      if (System.isDirectory(here))
-        return here;
-      prev = path ;
-      path = System.dirname(path);
-    }
-  } catch(_err) { }
-  return undefined ;
-}
-
-// --------------------------------------------------------------------------
-// --- Project Index
-// --------------------------------------------------------------------------
-
-const saveIndex = async () => {
-  let modules = modulesRegistry.elements().map((m) => m.id);
-  let indexFile = getProjectIndex();
-  let indexJSON = JSON.stringify({ modules });
-  await System.mkDir( projectDirectory , { recursive: true });
-  await System.writeFile( indexFile , indexJSON );
-};
-
-const loadIndex = () => {
-  let indexFile = getProjectIndex();
-  if (System.isFile(indexFile)) {
-    return System.readFile( indexFile ).then((content) => {
-      try {
-        return JSON.parse(content);
-      } catch(err) {
-        console.warn('[Ivette] invalid index.json:',err);
-        return {};
-      }
-    });
-  } else {
-    return Promise.resolve({});
-  }
-};
-
-// --------------------------------------------------------------------------
-// --- Module Helpers
-// --------------------------------------------------------------------------
-
-export const isFresh = (id) => modulesRegistry.isFresh(id);
-export const isValid = (id) => modulesRegistry.isValid(id);
-
-/**
-   @summary Creates a fresh Plugin instance.
-   @param {Class} Plugin - a class extending Plugin
-   @return {Plugin} a fresh module instance
-   @description
-   The returned module has a fresh identifier but is not yet registered.
- */
-export function newModule( Plugin )
-{
-  checkPlugin( Plugin );
-  let module = new Plugin();
-  module.id = modulesRegistry.fresh( Plugin.id );
-  return module;
-}
-
-/**
-   @summary Creates a fresh duplicate of a Plugin instance.
-   @param {Module} module - the instance to duplicate
-   @return {Module} a fresh module instance
-   @description
-   The returned module has a fresh identifier but is not yet registered.
-   It inherits from the original `module` configuration, with tagged label and title.
- */
-export function duplicateModule( module )
-{
-  let { label, title, constructor: Plugin } = module ;
-  checkPlugin( Plugin );
-  let duplicate = new Plugin();
-  duplicate.id = modulesRegistry.fresh( module.id );
-  duplicate.label = label && label + " (copy)" ;
-  duplicate.title = title && title + " (duplicated)" ;
-  duplicate.config = _.cloneDeep(module.config);
-  return duplicate ;
-}
-
-/**
-   @summary Unregister a module (if registered).
-   @param {Module} module - the module to remove
-   @return {Promise} resolved when the module has been removed (from disk)
-   @description
-
-   Remove a module from the current project.
-   If the module is locked, an exception if raised.
-   The function does nothing if the module is not registered.
-   The promise is resolved when the module session directory has been fully removed.
- */
-function removeModule( module )
-{
-  checkModule( module );
-  if (module.locked()) throw `Try to remove locked module '${module}'` ;
-  modulesRegistry.remove( module.id );
-  if (module.session)
-    return System.rmDir( module.session, { recursive: true } ).then(saveIndex);
-  else
-    return saveIndex();
-}
-
-// --------------------------------------------------------------------------
-// --- Commit Module
-// --------------------------------------------------------------------------
-
-/**
-   @summary Commit module updates.
-   @param {Module} module - the module to update
-   @param {object} update - the module fields to update with
-   @param {string} [update.id] - new identifier
-   @param {string} [update.label] - new display name
-   @param {string} [update.title] - new short description
-   @param {object} [update.config] - new configuration
-   @return {Promise} resolved when the module has been commited (on disk)
-   @description
-
-   The module is registered in the current project, or updated if already present.
-   Its session directory is created or renamed if necessary.
-   Finally, the module is emitted a `Plugin.CONFIG` event.
-
- */
-export function commitModule( module, { id, label, title, config } )
-{
-  checkModule( module );
-  if (module.locked()) throw `Try to commit locked module '${id}'` ;
-
-  const oldId = module.id ;
-  const newId = id || oldId ;
-
-  // Update registry
-  let index ; // Promise
-  if ( newId !== oldId ) {
-    module.id = newId ;
-    modulesRegistry.remove( oldId );
-    modulesRegistry.add( module );
-    index = saveIndex();
-  } else {
-    if (!modulesRegistry.get( newId )) {
-      modulesRegistry.add( module );
-      index = saveIndex();
-    }
-  }
-
-  // Update module
-  if (label !== undefined) module.label = label;
-  if (title !== undefined) module.title = title;
-  if (config !== undefined) module.config = config ;
-
-  // Setup session directory
-  let setup ; // Promise
-  let oldSession = module.session ;
-  let newSession = System.join( projectDirectory, 'modules', newId );
-  if ( newSession !== oldSession ) {
-    module.session = newSession ;
-    if (System.exists( oldSession ))
-      setup = System.rename( oldSession, newSession );
-    else
-      setup = System.mkDir( newSession, { recursive:true } );
-  } else {
-    if (!System.exists( newSession ))
-      setup = System.mkDir( newSession , { recursive:true } );
-    else
-      setup = Promise.resolve();
-  }
-
-  // Backup config
-  let configFile = System.join( module.session , 'config.json' );
-  if (!id || !label || !title || !config || !System.exists(configFile))
-  {
-    let plugin = getPluginId( module );
-    let configJSON = JSON.stringify({ id, label, title, plugin, config });
-    setup.then(() => System.writeFile( configFile , configJSON ));
-  }
-
-  // Batch updates and finally emit config event
-  return Promise.all([index,setup]).finally(() => module.emit( CONFIG ));
-}
-
-// --------------------------------------------------------------------------
-// --- Project Management
-// --------------------------------------------------------------------------
-
-function loadProjectModule(id)
-{
-  if (modulesRegistry.get(id))
-    return Promise.reject('Duplicate module');
-  let session = System.join( projectDirectory, 'modules', id );
-  let configFile = System.join( session , 'config.json' );
-  return System.readFile( configFile )
-    .then( (configJSON) => {
-      let moduleConfig = JSON.parse(configJSON);
-      let { label, title, plugin, config } = moduleConfig ;
-      let P = pluginsRegistry.get( plugin );
-      if (!P) throw `Invalid plugin identifier ('${plugin}')` ;
-      let module = new P();
-      module.id = id ;
-      module.label = label ;
-      module.title = title ;
-      module.config = config ;
-      modulesRegistry.add( module );
-      module.emit( CONFIG );
-    });
-}
-
-function reportLoadModule(id) {
-  return loadProjectModule(id)
-    .then(() => undefined)
-    .catch((err) => `Error with module ${id}: ${err}`);
-}
-
-/** Change project directory.
-    @param {string} path - the directory of the project
-    @return {Promise} returning an array of errors
-*/
-export function loadProject( path ) {
-  if (isProjectLocked()) throw 'Try to close locked project' ;
-  if (!path) throw 'Try to open empty project' ;
-  projectDirectory = path ;
-  modulesRegistry.clear();
-  return loadIndex()
-    .then(({ modules=[] }) => Promise.all(modules.map(reportLoadModule)))
-    .then((errors) => errors.filter((e) => e !== undefined));
-}
-
-// --------------------------------------------------------------------------
-// --- Plugin Hooks
-// --------------------------------------------------------------------------
-
-const ModuleContext = React.createContext();
-
-/**
-   @class
-   @summary Set the current module for children components.
-   @property {Module} module - the current module (can be `'undefined'`)
-   @property {React.Children} children - content to be rendered with the current module
- */
-export const ProvideModule = ({ module, children }) => (
-  <ModuleContext.Provider value={module}>
-    {children}
-  </ModuleContext.Provider>
-);
-
-/**
-   @method
-   @summary Use the current module (Custom React Hook).
-   @return {Module} the current module
-   @description
-   Convenient method to obtain the current module. Does _not_ update on events.
-*/
-export const useModule = () => React.useContext(ModuleContext);
-
-/**
-   @method
-   @summary Listen to (current) module event (Custom React Hook).
-   @parameter {string} event - the plugin event to listen on
-   @parameter {function} callback - the callback on event
-   @return {Plugin} the plugin instance of the current module
-   @description
-   Same as `Dome.useEmitter(module,event,callback)` with the current module.
-   The hook itself does not force update, unless the callback does.
-*/
-export const useEvent = (event,callback) => {
-  let module = React.useContext(ModuleContext);
-  Dome.useEmitter( module, event, callback );
-};
-
-/**
-   @method
-   @summary Use the current module with optional update on events (Custom React Hook).
-   @parameter {string} [events...] - the event(s) to listen on, in addition to `UPDATE`
-   @return {Module} the current module
-   @description
-   Convenient method to obtain the current module and connect to updating events.
-*/
-export const useUpdate = (...events) => {
-  let module = React.useContext(ModuleContext);
-  let callback = Dome.useForceUpdate();
-  React.useEffect(() => {
-    if (module) {
-      events.push(UPDATE);
-      events.forEach((evt) => module.on(evt,callback));
-      return () => events.forEach((evt) => module.off(evt,callback));
-    } else
-      return undefined;
-  });
-  return module ;
-};
-
-/**
-   @method
-   @summary Returns the current module configuration (Custom React Hook).
-   @return {Module} the plugin configuration (up-to-date)
-   @description
-   Equivalent to `useUpdate(CONFIG).config` unless there is no current module.
-*/
-export const useConfig = () => {
-  let m = useUpdate(CONFIG);
-  return m && m.config;
-};
-
-// --------------------------------------------------------------------------
-// --- Export Default
-// --------------------------------------------------------------------------
-
-export default {
-  registerPlugin,
-  getPlugins,
-  getModules,
-  isProjectLocked,
-  getProjectDirectory,
-  loadProject,
-  lookupProject,
-  isFresh, isValid,
-  newModule,
-  duplicateModule,
-  commitModule,
-  removeModule,
-  ProvideModule,
-  useModule,
-  useEvent,
-  useUpdate,
-  useConfig
-};
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/ivette/plugins.js b/ivette/backup/ivette/plugins.js
deleted file mode 100644
index 90cd687daf8..00000000000
--- a/ivette/backup/ivette/plugins.js
+++ /dev/null
@@ -1,247 +0,0 @@
-// --------------------------------------------------------------------------
-// ---  Plugin Base Class
-// --------------------------------------------------------------------------
-
-/** @module @ivette/plugins */
-
-import _ from 'lodash' ;
-import React from 'react' ;
-import Dome from 'dome' ;
-import EventEmitter from 'events' ;
-
-/**
-    @event
-    @description
-    Triggered when a module is asked for killing its pending jobs.
-*/
-export const KILL = 'ivette.kill' ;
-
-/**
-   @event
-   @description
-   Triggered when a module enters in locked state
-*/
-export const LOCK = 'ivette.lock' ;
-
-/**
-    @event
-    @description
-    Triggered when a module is back to unlocked state
-*/
-export const UNLOCK = 'ivette.unlock' ;
-
-/**
-    @event
-    @description
-    Triggered when a plugin has been configured
-*/
-export const CONFIG = 'ivette.config' ;
-
-/**
-    @event
-    @description
-    Triggered when a plugin has been updated
-*/
-export const UPDATE = 'ivette.update' ;
-
-/**
-   @summary Base class for Module instances.
-   @property {string} id - Module identifier
-   @property {string} [label] - Module display name
-   @property {string} [title] - Module short description
-   @property {object} config - Module configuration object
-   @property {string} session - Module session directory
-   @description
-   Each Ivette module is associated to a global object maintaining its internal state.
-   A `Plugin` is a class responsible for creating and managing the internal state of a module.
-   It is also responsible for rendering the module main view, its toolbar and sidebar items,
-   and configuration fields.
-*/
-export class Module extends EventEmitter {
-
-  constructor() {
-    super();
-    this.config = {} ;
-    let _lock = { sem: 0 } ;
-    let _LOCKED = () => _lock.sem > 0 ;
-    let _LOCK = () => {
-      if (_lock.sem == 0) this.emit(LOCK);
-      _lock.sem++;
-    } ;
-    let _UNLOCK = () => {
-      _lock.sem--;
-      if (_lock.sem == 0) this.emit(UNLOCK);
-      if (_lock.sem < 0) {
-        console.warn(`[Ivette:${this.id}] unbalanced lock/unlock`,this.id);
-        _lock.sem = 0 ;
-      }
-    } ;
-    let _SYNCHRO = (p,k) => {
-      _LOCK() ;
-      if (k) this.once(KILL,k);
-      p.finally(() => {
-        if (k) this.off(KILL,k);
-        _UNLOCK();
-      });
-      return p;
-    } ;
-    this.lock = _LOCK ;
-    this.unlock = _UNLOCK ;
-    this.locked = _LOCKED ;
-    this.synchronize = _SYNCHRO ;
-    this.renderMain = this.renderMain.bind(this);
-    this.renderConfig = this.renderConfig.bind(this);
-  }
-
-  // --------------------------------------------------------------------------
-  // --- Locking
-  // --------------------------------------------------------------------------
-
-  /**
-     @summary Lock the plugin.
-     @description
-     Prevents the module from being re-configured.
-     Nested calls to `lock/unlock` shall be well balanced.
-     It is preferrable to use `this.synchronize()` instead.
-     Emits the signal `'ivette.lock'` unless already locked.
-  */
-  lock() {} // privately defined by constructor
-
-  /**
-     @summary Unlock the plugin.
-     @description
-     Cancel the last `lock()` call effect.
-     Nested calls to `lock/unlock` shall be well balanced.
-     It is preferrable to use `this.synchronize()` instead.
-     Emits the signal `'ivette.unlock'` when actually unlocked.
-  */
-  unlock() {} // privately defined by constructor
-
-  /** Whether the module is currenly locked or not.
-      @return {boolean} the locked status of the module. */
-  locked() {} // privately defined by constructor
-
-  /**
-     @summary Lock the module until a promise is pending.
-     @param {Promise} job - the promise to lock on
-     @param {function} kill - a callback to kill the job
-     @return {Promise} the job, for chaining
-     @description
-     Locks the module and wait for the promise to terminate
-     (normally or with an error) before unlocking.  The callback is triggered
-     if the module is asked to be killed while the job is still running.
-  */
-  synchronize() {} // privately defined by constructor
-
-  /**
-     @summary Promise awaiting until unlocked.
-     @return {Promise} awaiting promise
-     @description
-     The returned promise is resolved once the
-     plugin is unlocked. It is immediately resolved
-     if not locked.
-  */
-  wait() {
-    if ( !this.locked() ) {
-      return Promise.resolved();
-    } else {
-      return new Promise((resolve,reject) => this.once(UNLOCK,resolve));
-    }
-  }
-
-  /**
-     @summary Interrupts pending tasks.
-     @description
-     Emits the `'ivette.kill'` signal.
-     Any currently running job shall be interrupted,
-     and the module shall eventually be unlocked.
-     @return {Promise} a promise resolved once unlocked
-  */
-  kill() {
-    this.emit(KILL);
-    return this.wait();
-  }
-
-  // --------------------------------------------------------------------------
-  // --- Render
-  // --------------------------------------------------------------------------
-
-  /**
-     @summary Emits the `@ivette.plugins.UPDATE` event.
-   */
-  update() {
-    this.emit(UPDATE);
-  }
-
-  /**
-     @summary Main view for the plugin.
-     @return {React.Children} the main view for the module
-     @description
-     See also the '@ivette/views' for defining sidebars and toolbars.
-  */
-  renderMain() {
-    return null;
-  }
-
-  /**
-     @summary Configuration view for the plugin.
-     @return {React.Children} form fields for configuring the plugin
-  */
-  renderConfig() {
-    return null;
-  }
-
-}
-
-// --------------------------------------------------------------------------
-// --- Plugin Factory
-// --------------------------------------------------------------------------
-
-/**
-   @typedef PLUGIN
-   @summary Plugin Specification
-   @property {string} id - plugin identifier
-   @property {string} [label] - display name
-   @property {string} [title] - short description
-   @property {function} [initializer] - module initializer
-   @property {React.Element} [mainView] - main view
-   @property {React.Element} [configView] - configuration view
-   @description
-
-   Properties for [registerPlugin](module-@ivette.html#registerPlugin)
-   specification.
-
-   The `initializer` function, when specified,
-   is invoked once on each plugin instance.
-   The initializer function can be written as follows:
-   - `initializer() { ... this.XXX ... }`
-   - `initializer: function() { ... this.XXX ... }`
-   - `initializer: (module) => { ... module.XXX ... }`
-
-   Typical usage of `initializer` is to initialize specific module properties
-   and register static callbacks on module events like `CONFIG` and `KILL`.
-*/
-
-export function Factory(spec) {
-  const { id, label, title, mainView, configView, initializer } = spec;
-
-  class Plugin extends Module {
-    constructor() {
-      super();
-      initializer && initializer.apply(this, [this]);
-    }
-    renderMain() { return mainView; }
-    renderConfig() { return configView; }
-  };
-  Plugin.id = id;
-  Plugin.label = label;
-  Plugin.title = title;
-
-  return Plugin;
-}
-
-// --------------------------------------------------------------------------
-
-export default { Module, Factory, KILL, LOCK, UNLOCK, CONFIG, UPDATE } ;
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/ivette/stores.js b/ivette/backup/ivette/stores.js
deleted file mode 100644
index 201516c5d51..00000000000
--- a/ivette/backup/ivette/stores.js
+++ /dev/null
@@ -1,152 +0,0 @@
-// --------------------------------------------------------------------------
-// --- Items Registry
-// --------------------------------------------------------------------------
-
-/** @module @ivette/stores */
-
-import _ from 'lodash' ;
-
-const ALL = () => true ;
-const IDENT = /^[a-zA-Z0-9_-]+$/ ;
-const SUFFIX = /-[0-9]+$/ ;
-const PADDING = (n) => n<10 ? "0"+n : n ;
-
-/**
-   @summary Base class for registries.
- */
-export class Registry
-{
-
-  /** @param {string} prefix - fresh identifier prefix */
-  constructor( prefix ) {
-    this.items = {} ;
-    this.prefix = prefix ;
-  }
-
-  /**
-      @summary Valid identifiers (letters, digits, dashes and underscores).
-      @return {boolean} `true` if the identifier is valid
-   */
-  isValid(id) {
-    return typeof(id)=='string' && id.match( IDENT );
-  }
-
-  /**
-     @summary Test for freshness identifier.
-     @return {boolean} `true` if the identifier is not yet attributed
-  */
-  isFresh(id) {
-    return !this.items[id] ;
-  }
-
-  /**
-      @summary Creates an identifier.
-      @param {string} [id] - the base identifier to starts with
-      @return {string} a fresh identifier
-      @description
-      Returns a fresh identifier with format `<base>-<n>` where
-      the base is extracted from `id` (without its `-<n>` suffix, if any).
-      The default base is the registry prefix, if any.
-  */
-  fresh(id) {
-    let base = this.prefix ;
-    if (id) {
-      let m = SUFFIX.exec(id);
-      base = m ? id.substring(0,m.index) : id ;
-    }
-    base += '-' ;
-    let kid = 1 ;
-    for( ;; ) {
-      var a = base + PADDING(kid++) ;
-      if (!this.items[a]) break ;
-    }
-    return a ;
-  }
-
-  /**
-      @summary Iterates ovee the registry.
-      @param {function} job - called with `job(item,id)` in unspecified order
-      @description
-      If the iteratee returns `false`, the iteration is interrupted.
-  */
-  forEach(job) { _.forEach( this.items , (item,id) => job(item,id) );
-  }
-
-  /**
-      @summary Iterates ovee the registry.
-      @param {function} test - called with `test(item,id)` in unspecified order
-      @description
-      Returns the first item such that `test(item,id)` returns a truthy value.
-      Returns `undefined` otherwise.
-  */
-  find(test) { _.find( this.items , (item,id) => test(item,id) ); }
-
-  /**
-     Select items from the registry
-     @param {object} [options] - filter and ordering options
-     @return {item[]} the selected array of items
-     @description
-Available options are:
-- `filter:(item) => boolean` to select some itmes (default: all)
-- `sortBy:function | function[] | field | field[]` to sort items by (default: by identifier)
-
-Sorting is done by loadsh [sortBy](https://lodash.com/docs/4.17.11#sortBy) method.
-  */
-  elements( options )
-  {
-    const filter = (options && options.filter) || ALL ;
-    const sortBy = (options && options.sortBy) || 'id' ;
-    const pool = [];
-    _.forEach( this.items, (item) => {
-      if (filter(item)) pool.push(item);
-    });
-    return _.sortBy(pool,sortBy);
-  }
-
-  /** Register a new item
-      @param {object} - the item to register in
-      @param {once} - register only fresh items
-      @description
-Each object shall define the following properties:
-- `id:string` item identifier (default to `fresh()`)
-- `label:string` _optional_ item display name
-- `title:string` _optional_ item short description
-  */
-  add( item, once=false ) {
-    if (!item.id) item.id = this.fresh();
-    if (!this.isValid(item.id)) {
-      console.warn( `[Ivette:${this.prefix}] invalid identifier (${item.id})` );
-      return ;
-    }
-    if (once && !this.isFresh(item.id)) {
-      console.warn( `[Ivette:${this.prefix}] duplicate identifier (${item.id})` );
-      return ;
-    }
-    this.items[item.id] = item ;
-  }
-
-  /** Retrieve an item by id
-      @param {string} id - item identifier
-      @return {object} the associated item
-  */
-  get(id) { return id ? this.items[id] : undefined; }
-
-  /** Remove an item by id
-      @param {string} id - item identifier
-   */
-  remove( id ) {
-    if (id && this.items[id]) {
-      delete this.items[id];
-    }
-  }
-
-  /** Remove all items */
-  clear() {
-    this.items = {};
-  }
-
-}
-
-export default { Registry };
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/ivette/views.js b/ivette/backup/ivette/views.js
deleted file mode 100644
index 4b80dfc0ee5..00000000000
--- a/ivette/backup/ivette/views.js
+++ /dev/null
@@ -1,42 +0,0 @@
-// --------------------------------------------------------------------------
-// ---  Lab View Component
-// --------------------------------------------------------------------------
-
-/** @module @ivette/views */
-
-import _ from 'lodash' ;
-import React from 'react' ;
-import { Catch } from 'dome/errors' ;
-import { Item } from 'dome/layout/dispatch' ;
-
-import Ivette from '@ivette' ;
-
-/**
-   @class
-   @summary Defines the plugin toolbar
-   @description
-   Shall be defined once inside main plugin rendering.
-*/
-export const PluginToolbar = ({children}) => (
-  <Item id='ivette.toolbar.display'>
-    <Catch label='Plugin Toolbar'>{ children }</Catch>
-  </Item>
-);
-
-/**
-   @class
-   @summary Defines the plugin toolbar
-   @description
-   Shall be defined once inside main plugin rendering.
-*/
-export const PluginSidebar = ({children}) => (
-  <Item id='ivette.sidebar.display'>
-    <Catch label='Plugin Sidevar'>{ children }</Catch>
-  </Item>
-);
-
-// --------------------------------------------------------------------------
-
-export default { PluginSidebar, PluginToolbar };
-
-// --------------------------------------------------------------------------
diff --git a/ivette/backup/style.css b/ivette/backup/style.css
deleted file mode 100644
index 96b0490f3cd..00000000000
--- a/ivette/backup/style.css
+++ /dev/null
@@ -1,50 +0,0 @@
-/* -------------------------------------------------------------------------- */
-/* --- Ivette Styling                                                     --- */
-/* -------------------------------------------------------------------------- */
-
-.ivette-dongle {
-    flex-wrap: nowrap ;
-    margin: 8px ;
-    padding: 6px ;
-    max-width: 480px ;
-    background: #ddd ;
-    border: thin solid darkgrey ;
-    border-radius: 8px ;
-}
-
-.ivette-dongle-id {
-    min-width: 80px ;
-}
-
-.ivette-project {
-    margin: 6px 6px 18px 6px ;
-    padding: 3px ;
-}
-
-.ivette-dongle-selectable:hover {
-    background: orange ;
-}
-
-.dome-window-inactive .ivette-dongle {
-    background: #eee ;
-}
-
-.dome-window-active .ivette-dongle-selected {
-    background: #ffcd00 ;
-}
-
-.ivette-plugin-item {
-    margin: 2px ;
-    padding: 0px 6px ;
-    background: lightgrey ;
-    border: thin solid darkgrey ;
-    border-radius: 10px ;
-    align-items: baseline ;
-}
-
-.ivette-dongle-cancel {
-    position: relative ;
-    visibility: hidden ;
-    top: 15px ;
-    height: 18px ;
-}
-- 
GitLab