From 90ea94ba9df81d171cbf6eb51bbab5856005eae9 Mon Sep 17 00:00:00 2001
From: daxid <david.rouquet@tetras-libre.fr>
Date: Wed, 18 Jan 2023 09:49:22 +0100
Subject: [PATCH] initialize app structure

---
 launcher.ipynb              | 41 +++++++++++++++++++++++++++++++
 src/__init__.py             |  0
 src/appli.py                | 49 +++++++++++++++++++++++++++++++++++++
 src/callbacks.py            | 11 +++++++++
 src/components/__init__.py  |  0
 src/components/component.py |  6 +++++
 src/components/window.py    | 25 +++++++++++++++++++
 src/data.py                 |  5 ++++
 src/view.py                 |  7 ++++++
 9 files changed, 144 insertions(+)
 create mode 100644 launcher.ipynb
 create mode 100644 src/__init__.py
 create mode 100644 src/appli.py
 create mode 100644 src/callbacks.py
 create mode 100644 src/components/__init__.py
 create mode 100644 src/components/component.py
 create mode 100644 src/components/window.py
 create mode 100644 src/data.py
 create mode 100644 src/view.py

diff --git a/launcher.ipynb b/launcher.ipynb
new file mode 100644
index 0000000..e85c91c
--- /dev/null
+++ b/launcher.ipynb
@@ -0,0 +1,41 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "id": "1d7eebc2-9325-42ae-8269-47b3091e052c",
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from src.data import Data\n",
+    "from src.view import View\n",
+    "from src.appli import Appli\n",
+    "\n",
+    "data = Data()\n",
+    "layout = View(data).layout\n",
+    "appli = Appli(layout, data)"
+   ]
+  }
+ ],
+ "metadata": {
+  "kernelspec": {
+   "display_name": "Python 3 (ipykernel)",
+   "language": "python",
+   "name": "python3"
+  },
+  "language_info": {
+   "codemirror_mode": {
+    "name": "ipython",
+    "version": 3
+   },
+   "file_extension": ".py",
+   "mimetype": "text/x-python",
+   "name": "python",
+   "nbconvert_exporter": "python",
+   "pygments_lexer": "ipython3",
+   "version": "3.8.6"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/src/__init__.py b/src/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/appli.py b/src/appli.py
new file mode 100644
index 0000000..53c0b7f
--- /dev/null
+++ b/src/appli.py
@@ -0,0 +1,49 @@
+from jupyter_dash import JupyterDash as Dash
+import dash_bootstrap_components as dbc
+from src.callbacks import register_callbacks
+
+
+class Appli:
+    def __init__(self, layout, data):
+        server_url, host, port, proxy, base_path = self._get_tl_config()
+        app = Dash(
+            server_url=server_url, 
+            requests_pathname_prefix=base_path,
+        )
+        app.layout = layout
+        app.data = data
+        register_callbacks(app)
+        app.run_server(mode="inline", host=host, port=port, proxy=proxy)
+
+        
+    def _get_tl_config(self):
+        import socket, errno, os
+        # Find a free port
+        host = "0.0.0.0"
+        port = 8050
+        end = 9999
+        found = False
+        while not found:
+            with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
+                try:
+                    s.bind((host, port))
+                    found = True
+                except socket.error as e:
+                    if e.errno == errno.EADDRINUSE:
+                        port = port + 1
+                        if (port > end):
+                            raise "No available APP port"
+                    else:
+                        raise e
+        if (os.getenv("HOST", None) is not None):
+            proto = os.getenv("PROTO")
+            actualhost = os.getenv("JUPYTER_HOST", os.getenv("VOILA_HOST", ""))
+            localport = os.getenv("PORT", 80)
+            intermediatehost = os.getenv("HOST", "localhost")
+            base_path = f"/{actualhost}/app_proxy/{port}/"
+            proxified= f"{proto}://{intermediatehost}:{localport}{base_path}"
+            localurl = f"http://{host}:{port}"
+            proxy = f"{localurl}::{proxified}"
+            return ((proxified, host, port, proxy, base_path))
+        return ((f"http://localhost:{port}", host, port, None, "/"))
+    
diff --git a/src/callbacks.py b/src/callbacks.py
new file mode 100644
index 0000000..c855b16
--- /dev/null
+++ b/src/callbacks.py
@@ -0,0 +1,11 @@
+from dash import Output, Input
+
+
+def register_callbacks(app):
+    @app.callback(
+        Output(component_id="my-output", component_property="children"),
+        Input(component_id="my-input", component_property="value")
+    )
+    def update_output_div(input_value):
+        return f"Output: {input_value}"
+    
\ No newline at end of file
diff --git a/src/components/__init__.py b/src/components/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/src/components/component.py b/src/components/component.py
new file mode 100644
index 0000000..aad8f9a
--- /dev/null
+++ b/src/components/component.py
@@ -0,0 +1,6 @@
+class Component:
+    def __init__(self, data):
+        self.data = data
+        
+    def build(self):
+        raise Error("Not implemented")
diff --git a/src/components/window.py b/src/components/window.py
new file mode 100644
index 0000000..6cf5e61
--- /dev/null
+++ b/src/components/window.py
@@ -0,0 +1,25 @@
+from src.components.component import Component
+from dash import html, dcc
+
+class Window(Component):
+
+    def build(self):
+        return self._layout()
+    
+    def _layout(self):
+        return html.Div(children=
+            [
+                html.H6("Change the value in the text box to see callbacks in action!"),
+                html.Div(children=
+                    [
+                        "Input: ",
+                        dcc.Input(
+                            id="my-input", 
+                            value=self.data.initial_value, 
+                            type="text"
+                        )
+                    ]),
+                html.Br(),
+                html.Div(id="my-output")
+            ]
+        )
diff --git a/src/data.py b/src/data.py
new file mode 100644
index 0000000..5a954a4
--- /dev/null
+++ b/src/data.py
@@ -0,0 +1,5 @@
+class Data:  
+    
+    def __init__(self):
+        self.initial_value = "my initial value"
+        
\ No newline at end of file
diff --git a/src/view.py b/src/view.py
new file mode 100644
index 0000000..36fafbe
--- /dev/null
+++ b/src/view.py
@@ -0,0 +1,7 @@
+from src.components.window import Window
+
+
+class View:
+    def __init__(self, data):
+        self.layout = Window(data).build()
+        
\ No newline at end of file
-- 
GitLab