diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 00000000..26e44f99
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,3 @@
+[run]
+concurrency = multiprocessing,thread
+source = optuna_dashboard/
diff --git a/.github/workflows/gh-pages.yml b/.github/workflows/gh-pages.yml
new file mode 100644
index 00000000..311d606f
--- /dev/null
+++ b/.github/workflows/gh-pages.yml
@@ -0,0 +1,49 @@
+on:
+ push:
+ branches: ["main"]
+ workflow_dispatch:
+
+permissions:
+ contents: read
+ pages: write
+ id-token: write
+
+# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
+# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
+concurrency:
+ group: "pages"
+ cancel-in-progress: false
+
+jobs:
+ publish-gh-pages:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v3
+ - name: Install Rust toolchains
+ uses: dtolnay/rust-toolchain@stable
+ - name: Install wasm-pack
+ run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
+ - name: Setup Node
+ uses: actions/setup-node@v2
+ with:
+ node-version: '18'
+ - name: Build standalone_app
+ env:
+ PUBLIC_PATH: /optuna-dashboard/public/
+ run: make MODE="prd" standalone_app/public/bundle.js
+ - name: Create publish directory
+ run: |
+ mkdir gh-publish
+ cp -r standalone_app/public gh-publish/public
+ cp standalone_app/favicon.ico gh-publish/favicon.ico
+ cp standalone_app/github-pages.html gh-publish/index.html
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v2
+ with:
+ path: './gh-publish'
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v2
diff --git a/.github/workflows/python-coverage.yml b/.github/workflows/python-coverage.yml
new file mode 100644
index 00000000..4bda6350
--- /dev/null
+++ b/.github/workflows/python-coverage.yml
@@ -0,0 +1,48 @@
+name: python coverage
+
+on:
+ push:
+ branches:
+ - master
+ pull_request: {}
+
+jobs:
+ coverage:
+ runs-on: ubuntu-latest
+
+ # Not intended for forks.
+ if: github.repository == 'optuna/optuna-dashboard'
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v3
+
+ - name: Setup Python
+ uses: actions/setup-python@v4
+ with:
+ python-version: '3.10'
+ architecture: x64
+
+ - name: Install dependencies
+ run: |
+ python -m pip install --progress-bar off --upgrade pip setuptools
+ pip install --progress-bar off .[optional]
+ pip install --progress-bar off .[test]
+ pip install --progress-bar off "optuna>=3.0.0"
+ pip install --progress-bar off .
+ echo 'import coverage; coverage.process_startup()' > sitecustomize.py
+ - name: Tests
+ env:
+ PYTHONPATH: . # To invoke sitecutomize.py
+ COVERAGE_PROCESS_START: .coveragerc # https://coverage.readthedocs.io/en/6.4.1/subprocess.html
+ COVERAGE_COVERAGE: yes # https://github.com/nedbat/coveragepy/blob/65bf33fc03209ffb01bbbc0d900017614645ee7a/coverage/control.py#L255-L261
+ run: |
+ coverage run --source=optuna_dashboard -m pytest python_tests
+ coverage combine
+ coverage xml
+ - name: Upload coverage to Codecov
+ uses: codecov/codecov-action@v3
+ with:
+ token: ${{ secrets.CODECOV_TOKEN }}
+ file: ./coverage.xml
+ fail_ci_if_error: true
diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml
index 612ddb59..8fee4e44 100644
--- a/.github/workflows/python-tests.yml
+++ b/.github/workflows/python-tests.yml
@@ -45,7 +45,8 @@ jobs:
# python_tests requires optuna>=3.0.0 since it imports FloatDistribution
run: |
python -m pip install --progress-bar off --upgrade pip setuptools
- pip install streamlit boto3 moto[s3] pytest
+ pip install --progress-bar off .[optional]
+ pip install --progress-bar off .[test]
pip install --progress-bar off "optuna>=3.0.0"
pip install --progress-bar off .
- run: pytest python_tests
@@ -61,7 +62,8 @@ jobs:
- name: Install dependencies
run: |
python -m pip install --progress-bar off --upgrade pip setuptools
- pip install streamlit boto3 moto[s3] pytest
+ pip install --progress-bar off .[optional]
+ pip install --progress-bar off .[test]
pip install --progress-bar off .
python -m pip install --progress-bar off --upgrade git+https://github.com/optuna/optuna.git
- run: pytest python_tests
diff --git a/.gitignore b/.gitignore
index dde468fc..49c137e0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,9 +28,16 @@ docs/_generated/
rustlib/target/
rustlib/pkg/
+# Test
+.coverage
+.coverage.*
+coverage.xml
+
# Others
.envrc
.idea/
.vscode/
.DS_Store
tmp/
+examples/preferential-optimization/artifact/
+
diff --git a/README.md b/README.md
index 4b38f863..62edd6c8 100644
--- a/README.md
+++ b/README.md
@@ -45,6 +45,8 @@ Listening on http://localhost:8080/
Hit Ctrl-C to quit.
```
+
+
Please check out [our documentation](https://optuna-dashboard.readthedocs.io/en/latest/getting-started.html) for more details.
## Using an official Docker image
@@ -75,27 +77,26 @@ $ docker run -it --rm -p 8080:8080 ghcr.io/optuna/optuna-dashboard postgresql+ps
+## Browser-only version (Experimental)
+
+
+
+We’ve developed the version that operates solely within your web browser, which internally uses SQLite3 Wasm and Rust.
+There’s no need to install Python or any other dependencies.
+Simply open the following URL in your browser, drag and drop your SQLite3 file onto the page, and you’re ready to view your Optuna studies!
+
+https://optuna.github.io/optuna-dashboard/
+
+*Please note that only a subset of features is available. However, you can still check the optimization history, hyperparameter importances, and etc. in graphs and tables.*
+
## VS Code Extension (Experimental)
You can install the VS Code extension via [Visual Studio Marketplace](https://marketplace.visualstudio.com/items?itemName=Optuna.optuna-dashboard#overview).
-
+
Please right-click the SQLite3 files (`*.db` or `*.sqlite3`) in the VS Code file explorer and select the "Open in Optuna Dashboard" command from the dropdown menu.
-
-## Features
-
-### Manage Studies
-
-You can create and delete studies from Dashboard.
-
-
-
-### Visualize with Interactive Graphs & Rich Trials Data Grid
-
-You can check the optimization history, hyperparameter importances, etc. in graphs and tables.
-
-
+This extension leverages the browser-only version of Optuna Dashboard, so the same limitations apply.
## Submitting patches
diff --git a/docs/_static/browser-app.gif b/docs/_static/browser-app.gif
new file mode 100644
index 00000000..a4f6c464
Binary files /dev/null and b/docs/_static/browser-app.gif differ
diff --git a/docs/_static/optuna-dashboard.gif b/docs/_static/optuna-dashboard.gif
new file mode 100644
index 00000000..aea24d5a
Binary files /dev/null and b/docs/_static/optuna-dashboard.gif differ
diff --git a/docs/getting-started.rst b/docs/getting-started.rst
index e45b6f86..295dd55c 100644
--- a/docs/getting-started.rst
+++ b/docs/getting-started.rst
@@ -1,6 +1,13 @@
Getting Started
===============
+.. figure:: _static/optuna-dashboard.gif
+ :alt: Optuna Dashboard
+ :align: center
+ :width: 800px
+
+ Optuna Dashboard
+
Installation
------------
@@ -172,6 +179,42 @@ or
$ uwsgi --http :8080 --workeers 4 --wsgi-file wsgi.py
+Browser-only version (Experimental)
+-----------------------------------
+
+.. figure:: _static/browser-app.gif
+ :alt: GIF animation for the browser-only version
+ :align: center
+ :width: 800px
+
+ Browser-only version of Optuna Dashboard, powered by Wasm.
+
+We've developed the version that operates solely within your web browser.
+There's no need to install Python or any other dependencies.
+Simply open the following URL in your browser, drag and drop your SQLite3 file onto the page, and you're ready to view your Optuna studies!
+
+https://optuna.github.io/optuna-dashboard/
+
+.. warning::
+
+ Currently, only a subset of features is available. However, you can still check the optimization history, hyperparameter importances, and etc. in graphs and tables.
+
+VS Code Extension (Experimental)
+--------------------------------
+
+You can install the VS Code extension via `Visual Studio Marketplace `_.
+
+.. figure:: _static/vscode-extension.png
+ :alt: Screenshot for the VS Code Extension
+ :align: center
+ :width: 800px
+
+ VS Code Extension
+
+To use, right-click the SQLite3 files (``*.db`` or ``*.sqlite3``) in the file explorer and select the "Open in Optuna Dashboard" from the dropdown menu.
+This extension leverages the browser-only version of Optuna Dashboard, so the same limitations apply.
+
+
Google Colaboratory
-------------------
@@ -201,14 +244,3 @@ you can use ``google.colab.output()`` function as follows:
output.serve_kernel_port_as_window(port, path='/dashboard/')
Then please open http://localhost:8081/dashboard to browse.
-
-VS Code (Experimental)
-----------------------
-
-You can install the VS Code extension via `Visual Studio Marketplace `_.
-
-.. image:: _static/vscode-extension.png
- :alt: Screenshot for the VS Code Extension
- :align: center
-
-Please right-click the SQLite3 files (`*.db` or `*.sqlite3`) in the file explorer and select the "Open in Optuna Dashboard" command from the dropdown menu.
diff --git a/optuna_dashboard/ts/components/AppDrawer.tsx b/optuna_dashboard/ts/components/AppDrawer.tsx
index cdf331bc..184ec606 100644
--- a/optuna_dashboard/ts/components/AppDrawer.tsx
+++ b/optuna_dashboard/ts/components/AppDrawer.tsx
@@ -233,21 +233,19 @@ export const AppDrawer: FC<{
)}
- {!isPreferential && (
-
-
-
-
-
-
-
-
- )}
+
+
+
+
+
+
+
+
Trial {trial.number}
}
/>
-
- Objective Values = [{trial.values?.join(", ")}]
-
+ {studyDetail?.is_preferential ? null : (
+
+ Objective Values = [{trial.values?.join(", ")}]
+
+ )}
Params = [
{trial.params
diff --git a/optuna_dashboard/ts/components/GraphContour.tsx b/optuna_dashboard/ts/components/GraphContour.tsx
index d7e2aa13..c75e1500 100644
--- a/optuna_dashboard/ts/components/GraphContour.tsx
+++ b/optuna_dashboard/ts/components/GraphContour.tsx
@@ -11,6 +11,7 @@ import {
useTheme,
Box,
} from "@mui/material"
+import blue from "@mui/material/colors/blue"
import { plotlyDarkTemplate } from "./PlotlyDarkMode"
import { useMergedUnionSearchSpace } from "../searchSpace"
@@ -211,32 +212,62 @@ const plotContour = (
}
})
+ if (!study.is_preferential) {
+ const plotData: Partial[] = [
+ {
+ type: "contour",
+ x: xIndices,
+ y: yIndices,
+ z: zValues,
+ colorscale: "Blues",
+ connectgaps: true,
+ hoverinfo: "none",
+ line: {
+ smoothing: 1.3,
+ },
+ reversescale: study.directions[objectiveId] !== "minimize",
+ // https://github.com/plotly/react-plotly.js/issues/251
+ // @ts-ignore
+ contours: {
+ coloring: "heatmap",
+ },
+ },
+ {
+ type: "scatter",
+ x: xValues,
+ y: yValues,
+ marker: { line: { width: 2.0, color: "Grey" }, color: "black" },
+ mode: "markers",
+ showlegend: false,
+ },
+ ]
+ plotly.react(plotDomId, plotData, layout)
+ return
+ }
+
+ layout.legend = {
+ y: 0.8,
+ }
+ const bestTrialIndices = study.best_trials.map((trial) => trial.number)
const plotData: Partial[] = [
{
- type: "contour",
- x: xIndices,
- y: yIndices,
- z: zValues,
- colorscale: "Blues",
- connectgaps: true,
- hoverinfo: "none",
- line: {
- smoothing: 1.3,
- },
- reversescale: study.directions[objectiveId] !== "minimize",
- // https://github.com/plotly/react-plotly.js/issues/251
- // @ts-ignore
- contours: {
- coloring: "heatmap",
+ type: "scatter",
+ x: xValues.filter((_, i) => bestTrialIndices.includes(i)),
+ y: yValues.filter((_, i) => bestTrialIndices.includes(i)),
+ marker: {
+ line: { width: 2.0, color: "Grey" },
+ color: blue[200],
},
+ name: "best trials",
+ mode: "markers",
},
{
type: "scatter",
- x: xValues,
- y: yValues,
+ x: xValues.filter((_, i) => !bestTrialIndices.includes(i)),
+ y: yValues.filter((_, i) => !bestTrialIndices.includes(i)),
marker: { line: { width: 2.0, color: "Grey" }, color: "black" },
+ name: "others",
mode: "markers",
- showlegend: false,
},
]
plotly.react(plotDomId, plotData, layout)
diff --git a/optuna_dashboard/ts/components/PreferentialAnalytics.tsx b/optuna_dashboard/ts/components/PreferentialAnalytics.tsx
new file mode 100644
index 00000000..d8623f97
--- /dev/null
+++ b/optuna_dashboard/ts/components/PreferentialAnalytics.tsx
@@ -0,0 +1,68 @@
+import React, { FC } from "react"
+import {
+ Box,
+ Card,
+ CardContent,
+ Paper,
+ Typography,
+ useTheme,
+} from "@mui/material"
+import Grid2 from "@mui/material/Unstable_Grid2"
+import { DataGrid, DataGridColumn } from "./DataGrid"
+import { BestTrialsCard } from "./BestTrialsCard"
+import { useStudyDetailValue, useStudySummaryValue } from "../state"
+import { Contour } from "./GraphContour"
+
+export const PreferentialAnalytics: FC<{ studyId: number }> = ({ studyId }) => {
+ const theme = useTheme()
+ const studySummary = useStudySummaryValue(studyId)
+ const studyDetail = useStudyDetailValue(studyId)
+
+ const userAttrs = studySummary?.user_attrs || studyDetail?.user_attrs || []
+ const userAttrColumns: DataGridColumn[] = [
+ { field: "key", label: "Key", sortable: true },
+ { field: "value", label: "Value", sortable: true },
+ ]
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Study User Attributes
+
+
+ columns={userAttrColumns}
+ rows={userAttrs}
+ keyField={"key"}
+ dense={true}
+ initialRowsPerPage={5}
+ rowsPerPageOption={[5, 10, { label: "All", value: -1 }]}
+ />
+
+
+
+
+
+ )
+}
diff --git a/optuna_dashboard/ts/components/StudyDetail.tsx b/optuna_dashboard/ts/components/StudyDetail.tsx
index c3f9da0a..15cb7cf8 100644
--- a/optuna_dashboard/ts/components/StudyDetail.tsx
+++ b/optuna_dashboard/ts/components/StudyDetail.tsx
@@ -31,6 +31,7 @@ import { TrialList } from "./TrialList"
import { StudyHistory } from "./StudyHistory"
import { PreferentialTrials } from "./PreferentialTrials"
import { PreferenceHistory } from "./PreferenceHistory"
+import { PreferentialAnalytics } from "./PreferentialAnalytics"
interface ParamTypes {
studyId: string
@@ -99,7 +100,9 @@ export const StudyDetail: FC<{
)
} else if (page === "analytics") {
- content = (
+ content = isPreferential ? (
+
+ ) : (
Hyperparameter Relationships
diff --git a/pyproject.toml b/pyproject.toml
index d9c0082c..0555f701 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -41,6 +41,18 @@ docs = [
"sphinx_rtd_theme",
]
+test = [
+ "coverage",
+ "pytest",
+ "moto[s3]",
+]
+
+optional = [
+ "streamlit",
+ "boto3",
+]
+
+
[project.scripts]
optuna-dashboard = "optuna_dashboard._cli:main"
diff --git a/standalone_app/github-pages.html b/standalone_app/github-pages.html
new file mode 100644
index 00000000..609c5c30
--- /dev/null
+++ b/standalone_app/github-pages.html
@@ -0,0 +1,19 @@
+
+
+
+
+ Optuna Dashboard (Wasm ver.)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/standalone_app/package-lock.json b/standalone_app/package-lock.json
index fcf2a381..dee5635d 100644
--- a/standalone_app/package-lock.json
+++ b/standalone_app/package-lock.json
@@ -28,6 +28,7 @@
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.1",
"@types/react-router-dom": "^5.3.3",
+ "compression-webpack-plugin": "^10.0.0",
"esbuild-loader": "^3.0.1",
"prettier": "^2.8.8",
"ts-loader": "^9.4.2",
@@ -1366,6 +1367,45 @@
"url": "https://github.com/sponsors/epoberezkin"
}
},
+ "node_modules/ajv-formats": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependencies": {
+ "ajv": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "ajv": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/ajv-formats/node_modules/ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/ajv-formats/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
"node_modules/ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
@@ -1552,6 +1592,79 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
+ "node_modules/compression-webpack-plugin": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-10.0.0.tgz",
+ "integrity": "sha512-wLXLIBwpul/ALcm7Aj+69X0pYT3BYt6DdPn3qrgBIh9YejV9Bju9ShhlAsjujLyWMo6SAweFIWaUoFmXZNuNrg==",
+ "dev": true,
+ "dependencies": {
+ "schema-utils": "^4.0.0",
+ "serialize-javascript": "^6.0.0"
+ },
+ "engines": {
+ "node": ">= 14.15.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ },
+ "peerDependencies": {
+ "webpack": "^5.1.0"
+ }
+ },
+ "node_modules/compression-webpack-plugin/node_modules/ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/epoberezkin"
+ }
+ },
+ "node_modules/compression-webpack-plugin/node_modules/ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "dependencies": {
+ "fast-deep-equal": "^3.1.3"
+ },
+ "peerDependencies": {
+ "ajv": "^8.8.2"
+ }
+ },
+ "node_modules/compression-webpack-plugin/node_modules/json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "node_modules/compression-webpack-plugin/node_modules/schema-utils": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
+ "dev": true,
+ "dependencies": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ },
+ "engines": {
+ "node": ">= 12.13.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/webpack"
+ }
+ },
"node_modules/convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
@@ -2498,6 +2611,15 @@
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
+ "node_modules/require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
@@ -3997,6 +4119,35 @@
"uri-js": "^4.2.2"
}
},
+ "ajv-formats": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz",
+ "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==",
+ "dev": true,
+ "requires": {
+ "ajv": "^8.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ }
+ }
+ },
"ajv-keywords": {
"version": "3.5.2",
"resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz",
@@ -4123,6 +4274,57 @@
"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
"dev": true
},
+ "compression-webpack-plugin": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/compression-webpack-plugin/-/compression-webpack-plugin-10.0.0.tgz",
+ "integrity": "sha512-wLXLIBwpul/ALcm7Aj+69X0pYT3BYt6DdPn3qrgBIh9YejV9Bju9ShhlAsjujLyWMo6SAweFIWaUoFmXZNuNrg==",
+ "dev": true,
+ "requires": {
+ "schema-utils": "^4.0.0",
+ "serialize-javascript": "^6.0.0"
+ },
+ "dependencies": {
+ "ajv": {
+ "version": "8.12.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
+ "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.1",
+ "json-schema-traverse": "^1.0.0",
+ "require-from-string": "^2.0.2",
+ "uri-js": "^4.2.2"
+ }
+ },
+ "ajv-keywords": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz",
+ "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==",
+ "dev": true,
+ "requires": {
+ "fast-deep-equal": "^3.1.3"
+ }
+ },
+ "json-schema-traverse": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz",
+ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==",
+ "dev": true
+ },
+ "schema-utils": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz",
+ "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==",
+ "dev": true,
+ "requires": {
+ "@types/json-schema": "^7.0.9",
+ "ajv": "^8.9.0",
+ "ajv-formats": "^2.1.1",
+ "ajv-keywords": "^5.1.0"
+ }
+ }
+ }
+ },
"convert-source-map": {
"version": "1.9.0",
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz",
@@ -4829,6 +5031,12 @@
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
},
+ "require-from-string": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
+ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
+ "dev": true
+ },
"resolve": {
"version": "1.22.2",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.2.tgz",
diff --git a/standalone_app/package.json b/standalone_app/package.json
index ae01f27f..05b5390f 100644
--- a/standalone_app/package.json
+++ b/standalone_app/package.json
@@ -14,6 +14,7 @@
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.1",
"@types/react-router-dom": "^5.3.3",
+ "compression-webpack-plugin": "^10.0.0",
"esbuild-loader": "^3.0.1",
"prettier": "^2.8.8",
"ts-loader": "^9.4.2",
@@ -30,11 +31,11 @@
"@sqlite.org/sqlite-wasm": "^3.41.2-build11",
"module-workers-polyfill": "^0.3.2",
"notistack": "^3.0.1",
+ "optuna": "../rustlib/pkg",
"plotly.js-dist-min": "^2.22.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.11.0",
- "recoil": "^0.7.7",
- "optuna": "../rustlib/pkg"
+ "recoil": "^0.7.7"
}
}
diff --git a/standalone_app/webpack.config.js b/standalone_app/webpack.config.js
index 39caaf7e..1e876959 100644
--- a/standalone_app/webpack.config.js
+++ b/standalone_app/webpack.config.js
@@ -3,6 +3,10 @@ const path = require('path');
const mode = process.env.NODE_ENV === 'production' ? 'production' : 'development';
const isDev = mode === 'development';
+const PUBLIC_PATH = process.env.PUBLIC_PATH ?? '/public/';
+if (!PUBLIC_PATH.endsWith('/')) {
+ PUBLIC_PATH += '/';
+}
const typeScriptLoader = process.env.TYPESCRIPT_LOADER === "esbuild-loader" ? {
test: /\.tsx?$/,
@@ -34,7 +38,7 @@ var config = [
output: {
path: __dirname + '/public/',
filename: 'bundle.js',
- publicPath: '/public/'
+ publicPath: PUBLIC_PATH
},
module: {
rules: [{ oneOf: [typeScriptLoader] }]