cognitivesystems 0.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cognitivesystems-0.0.2/.gitignore +49 -0
- cognitivesystems-0.0.2/PKG-INFO +229 -0
- cognitivesystems-0.0.2/README.md +199 -0
- cognitivesystems-0.0.2/frontend/.gitignore +11 -0
- cognitivesystems-0.0.2/frontend/e2e/auth.setup.ts +15 -0
- cognitivesystems-0.0.2/frontend/e2e/dashboard.spec.ts +47 -0
- cognitivesystems-0.0.2/frontend/e2e/docker.spec.ts +41 -0
- cognitivesystems-0.0.2/frontend/e2e/fixtures.ts +7 -0
- cognitivesystems-0.0.2/frontend/e2e/services.spec.ts +14 -0
- cognitivesystems-0.0.2/frontend/eslint.config.js +19 -0
- cognitivesystems-0.0.2/frontend/index.html +12 -0
- cognitivesystems-0.0.2/frontend/package-lock.json +5377 -0
- cognitivesystems-0.0.2/frontend/package.json +42 -0
- cognitivesystems-0.0.2/frontend/playwright.config.ts +37 -0
- cognitivesystems-0.0.2/frontend/src/App.test.tsx +125 -0
- cognitivesystems-0.0.2/frontend/src/App.tsx +45 -0
- cognitivesystems-0.0.2/frontend/src/api/client.ts +57 -0
- cognitivesystems-0.0.2/frontend/src/api/hooks.ts +50 -0
- cognitivesystems-0.0.2/frontend/src/app.css +203 -0
- cognitivesystems-0.0.2/frontend/src/components/JobLog.tsx +27 -0
- cognitivesystems-0.0.2/frontend/src/context/auth.tsx +72 -0
- cognitivesystems-0.0.2/frontend/src/context/notify.tsx +68 -0
- cognitivesystems-0.0.2/frontend/src/context/theme.tsx +29 -0
- cognitivesystems-0.0.2/frontend/src/layout/Shell.tsx +52 -0
- cognitivesystems-0.0.2/frontend/src/main.tsx +24 -0
- cognitivesystems-0.0.2/frontend/src/pages/Config.tsx +171 -0
- cognitivesystems-0.0.2/frontend/src/pages/Custom.tsx +102 -0
- cognitivesystems-0.0.2/frontend/src/pages/Docker.tsx +335 -0
- cognitivesystems-0.0.2/frontend/src/pages/Jobs.tsx +62 -0
- cognitivesystems-0.0.2/frontend/src/pages/Login.tsx +109 -0
- cognitivesystems-0.0.2/frontend/src/pages/Networks.tsx +99 -0
- cognitivesystems-0.0.2/frontend/src/pages/Overview.tsx +41 -0
- cognitivesystems-0.0.2/frontend/src/pages/Services.tsx +253 -0
- cognitivesystems-0.0.2/frontend/src/pages/System.tsx +85 -0
- cognitivesystems-0.0.2/frontend/src/pages.test.tsx +113 -0
- cognitivesystems-0.0.2/frontend/src/test/setup.ts +1 -0
- cognitivesystems-0.0.2/frontend/src/types.ts +155 -0
- cognitivesystems-0.0.2/frontend/src/ui.tsx +89 -0
- cognitivesystems-0.0.2/frontend/tsconfig.json +23 -0
- cognitivesystems-0.0.2/frontend/vite.config.ts +24 -0
- cognitivesystems-0.0.2/hatch_build.py +65 -0
- cognitivesystems-0.0.2/profiles/README.md +72 -0
- cognitivesystems-0.0.2/profiles/homeserver.yml +46 -0
- cognitivesystems-0.0.2/profiles/localdev.yml +41 -0
- cognitivesystems-0.0.2/pyproject.toml +96 -0
- cognitivesystems-0.0.2/services/adguard/service.yml +19 -0
- cognitivesystems-0.0.2/services/autobrr/service.yml +18 -0
- cognitivesystems-0.0.2/services/bazarr/service.yml +21 -0
- cognitivesystems-0.0.2/services/betterdesk/service.yml +106 -0
- cognitivesystems-0.0.2/services/byparr/service.yml +25 -0
- cognitivesystems-0.0.2/services/chrome/service.yml +29 -0
- cognitivesystems-0.0.2/services/code-server/service.yml +23 -0
- cognitivesystems-0.0.2/services/crontabui/service.yml +22 -0
- cognitivesystems-0.0.2/services/crossseed/service.yml +26 -0
- cognitivesystems-0.0.2/services/firefox/service.yml +29 -0
- cognitivesystems-0.0.2/services/flaresolverr/service.yml +23 -0
- cognitivesystems-0.0.2/services/heimdall/service.yml +21 -0
- cognitivesystems-0.0.2/services/install_order.yml +8 -0
- cognitivesystems-0.0.2/services/jackett/service.yml +20 -0
- cognitivesystems-0.0.2/services/maintainerr/service.yml +19 -0
- cognitivesystems-0.0.2/services/mariadb/service.yml +26 -0
- cognitivesystems-0.0.2/services/mongodb/service.yml +19 -0
- cognitivesystems-0.0.2/services/mqtt-broker/service.yml +22 -0
- cognitivesystems-0.0.2/services/mysql/service.yml +19 -0
- cognitivesystems-0.0.2/services/ollama/service.yml +19 -0
- cognitivesystems-0.0.2/services/openwebui/service.yml +24 -0
- cognitivesystems-0.0.2/services/paperless/service.yml +74 -0
- cognitivesystems-0.0.2/services/plex/service.yml +28 -0
- cognitivesystems-0.0.2/services/portainer/service.yml +25 -0
- cognitivesystems-0.0.2/services/profilarr/service.yml +18 -0
- cognitivesystems-0.0.2/services/prowlarr/service.yml +20 -0
- cognitivesystems-0.0.2/services/qbittorrent/service.yml +28 -0
- cognitivesystems-0.0.2/services/qbittorrent/sidecars/ext_webhooks.sh +59 -0
- cognitivesystems-0.0.2/services/radarr/service.yml +21 -0
- cognitivesystems-0.0.2/services/rarrnomore/service.yml +22 -0
- cognitivesystems-0.0.2/services/seerr/service.yml +18 -0
- cognitivesystems-0.0.2/services/sftpgo/service.yml +33 -0
- cognitivesystems-0.0.2/services/snappymail/service.yml +18 -0
- cognitivesystems-0.0.2/services/sonarr/service.yml +21 -0
- cognitivesystems-0.0.2/services/stalwart/service.yml +50 -0
- cognitivesystems-0.0.2/services/stash/service.yml +28 -0
- cognitivesystems-0.0.2/services/tautulli/service.yml +21 -0
- cognitivesystems-0.0.2/services/threadfin/service.yml +20 -0
- cognitivesystems-0.0.2/services/traefik/service.yml +116 -0
- cognitivesystems-0.0.2/services/traefik/sidecars/dynamic_config/tls.yml +6 -0
- cognitivesystems-0.0.2/services/uploadarr/service.yml +22 -0
- cognitivesystems-0.0.2/services/vaultwarden/service.yml +24 -0
- cognitivesystems-0.0.2/services/watchtower/service.yml +23 -0
- cognitivesystems-0.0.2/services/wg-easy/service.yml +31 -0
- cognitivesystems-0.0.2/services/whisparr/service.yml +21 -0
- cognitivesystems-0.0.2/services/wizarr/service.yml +18 -0
- cognitivesystems-0.0.2/src/cognitivesystems/__init__.py +8 -0
- cognitivesystems-0.0.2/src/cognitivesystems/__main__.py +7 -0
- cognitivesystems-0.0.2/src/cognitivesystems/bootstrap.py +10 -0
- cognitivesystems-0.0.2/src/cognitivesystems/catalog.py +65 -0
- cognitivesystems-0.0.2/src/cognitivesystems/cli.py +540 -0
- cognitivesystems-0.0.2/src/cognitivesystems/config.py +104 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/__init__.py +8 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/capabilities.py +149 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/dockerctl.py +627 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/__init__.py +14 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/config.py +350 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/custom.py +279 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/docker.py +356 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/jobs.py +60 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/network.py +257 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/overview.py +48 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/services.py +475 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/ops/system.py +149 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/registry.py +42 -0
- cognitivesystems-0.0.2/src/cognitivesystems/core/runner.py +364 -0
- cognitivesystems-0.0.2/src/cognitivesystems/credentials.py +502 -0
- cognitivesystems-0.0.2/src/cognitivesystems/deploy.py +453 -0
- cognitivesystems-0.0.2/src/cognitivesystems/hooks.py +335 -0
- cognitivesystems-0.0.2/src/cognitivesystems/hydrate.py +64 -0
- cognitivesystems-0.0.2/src/cognitivesystems/render.py +1058 -0
- cognitivesystems-0.0.2/src/cognitivesystems/state.py +393 -0
- cognitivesystems-0.0.2/src/cognitivesystems/system.py +351 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/__init__.py +13 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/app.py +405 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/__init__.py +13 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/config.py +97 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/custom.py +102 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/docker.py +154 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/jobs.py +72 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/network.py +130 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/overview.py +76 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/registries.py +107 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/secrets.py +123 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/services.py +228 -0
- cognitivesystems-0.0.2/src/cognitivesystems/tui/screens/system.py +135 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/__init__.py +7 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/app.py +128 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/auth.py +167 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/deps.py +187 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/__init__.py +12 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/config.py +319 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/custom.py +263 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/docker.py +501 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/jobs.py +100 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/networks.py +236 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/overview.py +31 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/services.py +342 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/settings.py +70 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/routers/system.py +202 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/schemas.py +54 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/security.py +235 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/server.py +72 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/settings.py +60 -0
- cognitivesystems-0.0.2/src/cognitivesystems/web/static/index.html +32 -0
- cognitivesystems-0.0.2/tests/README.md +45 -0
- cognitivesystems-0.0.2/tools/bootstrap-opencode.cmd +23 -0
- cognitivesystems-0.0.2/tools/bootstrap-opencode.ps1 +81 -0
- cognitivesystems-0.0.2/tools/check-operator-env-gates.sh +28 -0
- cognitivesystems-0.0.2/tools/e2e_server.py +87 -0
- cognitivesystems-0.0.2/tools/fix_tests_zero_env.py +28 -0
- cognitivesystems-0.0.2/tools/install-githooks.cmd +8 -0
- cognitivesystems-0.0.2/tools/rename_catalog_roots.py +31 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Root credentials file — copy from .env.example, never commit real values
|
|
2
|
+
.env
|
|
3
|
+
|
|
4
|
+
# Test render artefacts — tests render under $CS_TMP (defaults to /tmp/cs-*,
|
|
5
|
+
# outside the repo). Nothing test-related is written into the tree.
|
|
6
|
+
|
|
7
|
+
# Python build / packaging artefacts (byte-compile, ruff cache, wheel builds)
|
|
8
|
+
__pycache__/
|
|
9
|
+
*.pyc
|
|
10
|
+
.ruff_cache/
|
|
11
|
+
.pytest_cache/
|
|
12
|
+
.coverage
|
|
13
|
+
build/
|
|
14
|
+
dist/
|
|
15
|
+
*.egg-info/
|
|
16
|
+
.venv/
|
|
17
|
+
venv/
|
|
18
|
+
# CLI render output (cognitivesystems render --out default)
|
|
19
|
+
render-out/
|
|
20
|
+
|
|
21
|
+
# Built dashboard SPA copied into the package at publish time (the committed
|
|
22
|
+
# placeholder web/static/index.html is replaced by the real Vite build in CI).
|
|
23
|
+
src/cognitivesystems/web/static/assets/
|
|
24
|
+
|
|
25
|
+
# Dev-only files (DEVELOPMENT.md, docs/development/, CLAUDE.md, .mcp.json,
|
|
26
|
+
# .claude/, tasks/, ...) are tracked on dev and stripped from main by the
|
|
27
|
+
# Release workflow — see .github/dev-only-paths. Only machine-local AI state
|
|
28
|
+
# stays untracked:
|
|
29
|
+
AGENT-HANDOFF.md
|
|
30
|
+
AGENTS.md
|
|
31
|
+
CLAUDE.md
|
|
32
|
+
.cursor/
|
|
33
|
+
.claude/
|
|
34
|
+
.mcp.json
|
|
35
|
+
.cursorrules
|
|
36
|
+
.aider*
|
|
37
|
+
.windsurf/
|
|
38
|
+
.copilot/
|
|
39
|
+
.continuedev/
|
|
40
|
+
.codeium/
|
|
41
|
+
opencode.json
|
|
42
|
+
.opencode/
|
|
43
|
+
.claude/settings.local.json
|
|
44
|
+
|
|
45
|
+
# Editor
|
|
46
|
+
*.swp
|
|
47
|
+
*.log
|
|
48
|
+
.vscode/
|
|
49
|
+
.idea/
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: cognitivesystems
|
|
3
|
+
Version: 0.0.2
|
|
4
|
+
Summary: Catalog-driven Docker homeserver deployer: per-service compose renderer + terminal UI.
|
|
5
|
+
Project-URL: Homepage, https://github.com/automationnexus/CognitiveSystems
|
|
6
|
+
Project-URL: Source, https://github.com/automationnexus/CognitiveSystems
|
|
7
|
+
Author: Tahasanul Abraham
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
Keywords: compose,deploy,docker,homeserver,self-hosted
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Topic :: System :: Installation/Setup
|
|
14
|
+
Requires-Python: >=3.9
|
|
15
|
+
Requires-Dist: pyyaml>=6
|
|
16
|
+
Requires-Dist: textual>=0.60
|
|
17
|
+
Provides-Extra: dev
|
|
18
|
+
Requires-Dist: httpx>=0.26; extra == 'dev'
|
|
19
|
+
Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
20
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
21
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
22
|
+
Provides-Extra: web
|
|
23
|
+
Requires-Dist: docker<8,>=7; extra == 'web'
|
|
24
|
+
Requires-Dist: fastapi>=0.115; extra == 'web'
|
|
25
|
+
Requires-Dist: itsdangerous>=2.2; extra == 'web'
|
|
26
|
+
Requires-Dist: pydantic>=2; extra == 'web'
|
|
27
|
+
Requires-Dist: python-multipart>=0.0.9; extra == 'web'
|
|
28
|
+
Requires-Dist: uvicorn[standard]>=0.30; extra == 'web'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# CognitiveSystems Deployment
|
|
32
|
+
|
|
33
|
+
A pip-installable deployment app for the CognitiveSystems Docker stack.
|
|
34
|
+
One package, 42 services — no per-service `git clone` at deploy time.
|
|
35
|
+
|
|
36
|
+
`cognitivesystems` renders a `docker-compose.yml` + `.env` for each service from
|
|
37
|
+
per-service definitions (`services/<name>/service.yml`) plus an **install profile**
|
|
38
|
+
that supplies the values specific to your machine (paths, network, ports, timezone),
|
|
39
|
+
then drives `docker compose`. Drive it from the **web dashboard**, the **terminal UI**,
|
|
40
|
+
or the CLI. Rendering works on any OS; **deploying needs Linux + Docker** (run it on the
|
|
41
|
+
server, or in WSL).
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Install
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install cognitivesystems # from PyPI
|
|
49
|
+
# or, from a clone (for development):
|
|
50
|
+
git clone https://github.com/automationnexus/CognitiveSystems.git
|
|
51
|
+
cd CognitiveSystems && pip install -e .
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
Requires **Python 3.9+**; deploying additionally needs **Docker + compose v2** on a
|
|
55
|
+
Linux host (the app checks and tells you what's missing).
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Quick start
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
pip install "cognitivesystems[web]" # include the web dashboard (optional extra)
|
|
63
|
+
sudo cognitivesystems # launch the dashboard (or the TUI); deploy actions need root
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
With the `[web]` extra, `cognitivesystems` opens the **web dashboard** on `127.0.0.1:8800` — a
|
|
67
|
+
browser GUI that does everything the TUI does. Disable the dashboard with `dashboard.enabled: false` in
|
|
68
|
+
`state.json` to get the **terminal UI** instead (or run `cognitivesystems tui`). See [docs/dashboard.md](docs/dashboard.md).
|
|
69
|
+
|
|
70
|
+
The TUI lists every service (`✓` = installed) with a live deploy-log pane. Keys:
|
|
71
|
+
**`i`** install · **`u`** update · **`x`** uninstall · **`c`** configure · **`s`** service ·
|
|
72
|
+
**`g`** config · **`k`** secrets · **`d`** docker · **`n`** network · **`a`** apps · **`h`** host ·
|
|
73
|
+
**`r`** refresh · **`q`** quit (arrows/mouse to select). Great over SSH on the server.
|
|
74
|
+
|
|
75
|
+
Or use the CLI:
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
# 1. pick an install profile (system-specific paths/network/ports/timezone)
|
|
79
|
+
cognitivesystems init --profile homeserver # NFS-backed homeserver (default)
|
|
80
|
+
cognitivesystems init --profile localdev # laptop / VM
|
|
81
|
+
|
|
82
|
+
# 2. set credentials (prompt; Enter = auto-generate a strong value). No defaults ship.
|
|
83
|
+
cognitivesystems configure # mode/domain + admin password, LE email,
|
|
84
|
+
# Cloudflare DNS token, per-service overrides
|
|
85
|
+
|
|
86
|
+
# 3. install services (Linux + Docker; needs root for docker/chown)
|
|
87
|
+
sudo cognitivesystems install traefik portainer plex uploadarr \
|
|
88
|
+
--mode public --domain example.com --auto-update --wildcard
|
|
89
|
+
|
|
90
|
+
# 4. update / list / uninstall
|
|
91
|
+
sudo cognitivesystems update # all installed
|
|
92
|
+
sudo cognitivesystems update traefik plex # specific services
|
|
93
|
+
cognitivesystems list # catalog (* = installed)
|
|
94
|
+
sudo cognitivesystems uninstall plex # remove service + working dir
|
|
95
|
+
sudo cognitivesystems uninstall plex --purge # also delete the data dir
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
`homeserver` expects two NFS mounts to exist first — `/home/data` and
|
|
99
|
+
`/mnt/homeserver`. See [docs/services.md](docs/services.md#install-profiles) for the
|
|
100
|
+
mount layout and `localdev` caveats. Re-run `init --profile <name>` to switch profiles.
|
|
101
|
+
|
|
102
|
+
### Reinstall an existing service
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
sudo cognitivesystems install plex --force # uninstall then install (keeps data dir)
|
|
106
|
+
sudo cognitivesystems install plex --force --purge # same, but also drops the data dir
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Without `--force`, installing an already-installed service is a no-op.
|
|
110
|
+
|
|
111
|
+
### Render only (any OS)
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
cognitivesystems render plex --out ./out # write docker-compose.yml + .env, no deploy
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### OS administration (Linux)
|
|
118
|
+
|
|
119
|
+
```bash
|
|
120
|
+
sudo cognitivesystems system ssh-keygen --bits=8192 --install-to=admin,operator
|
|
121
|
+
sudo cognitivesystems system change-password --target=root --password='…' --enable-root-ssh
|
|
122
|
+
sudo cognitivesystems system media-user create
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
See [docs/system-admin.md](docs/system-admin.md).
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## Repository layout
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
.
|
|
133
|
+
├── pyproject.toml # package metadata (hatchling); entry point `cognitivesystems`
|
|
134
|
+
├── frontend/ # React + Vite dashboard SPA (built into the wheel at package time)
|
|
135
|
+
├── src/cognitivesystems/ # the app
|
|
136
|
+
│ ├── cli.py # CLI: list / render / init / install / update / uninstall / system / tui / web
|
|
137
|
+
│ ├── render.py # renderer: catalog + state -> docker-compose.yml + .env
|
|
138
|
+
│ ├── catalog.py state.py config.py deploy.py hooks.py system.py
|
|
139
|
+
│ ├── core/ # shared capability registry, job runner, Docker client, per-area ops
|
|
140
|
+
│ ├── tui/ # Textual terminal UI (app + per-area screens)
|
|
141
|
+
│ ├── web/ # FastAPI dashboard backend (serves the built SPA + JSON/WS API)
|
|
142
|
+
│ └── data/ # catalog bundled into the wheel (services + profiles)
|
|
143
|
+
├── services/
|
|
144
|
+
│ ├── install_order.yml # infra precedence (db/proxy come up first)
|
|
145
|
+
│ └── <name>/
|
|
146
|
+
│ ├── service.yml # one service definition per folder
|
|
147
|
+
│ └── sidecars/ # optional static files (e.g. the qbittorrent webhook script)
|
|
148
|
+
├── profiles/ # install profiles: homeserver.yml, localdev.yml
|
|
149
|
+
├── tests/ # pytest (render parity, GUI⇄TUI parity, variants, profiles, …)
|
|
150
|
+
└── docs/ # install-guide, migration-guide, dashboard, services, networking, configuration, system-admin
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Deployment modes
|
|
156
|
+
|
|
157
|
+
| Mode | Flag | TLS | Use case |
|
|
158
|
+
|---|---|---|---|
|
|
159
|
+
| Public | `--mode public` | Let's Encrypt TLS-ALPN-01, one cert per subdomain | Internet-facing server |
|
|
160
|
+
| Public + Wildcard | `--mode public --wildcard` | Cloudflare DNS-01, single `*.<domain>` cert | Internet-facing, one cert for all |
|
|
161
|
+
| Private | `--mode private` | None | LAN access via IP or hostname |
|
|
162
|
+
| Local | `--mode local` | None | Single machine, `localhost` only |
|
|
163
|
+
|
|
164
|
+
`--wildcard` needs `--cf-token` (a scoped Cloudflare DNS-edit API token). Healthchecks
|
|
165
|
+
are not configured by the installer; use each image's built-in `HEALTHCHECK` if needed.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Automatic install ordering
|
|
170
|
+
|
|
171
|
+
You never order services manually — infra installs first, in a fixed order:
|
|
172
|
+
`traefik → mariadb → mysql → mongodb → mqtt-broker`. Everything else follows.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## State & profile
|
|
177
|
+
|
|
178
|
+
Persisted under `/home/installation_cognitivesystems/state.json` (override with
|
|
179
|
+
`CS_STATE_DIR`):
|
|
180
|
+
|
|
181
|
+
- **Runtime config** — mode, domain, passwords, installed services. Saved as you install.
|
|
182
|
+
- **`.site`** — the system-specific values from your chosen install profile.
|
|
183
|
+
|
|
184
|
+
Re-running `update` re-renders every installed service from saved state. To change
|
|
185
|
+
domain / passwords / TLS mode: edit `state.json`, then `update`. To change profile
|
|
186
|
+
values (paths, ports, network): edit `profiles/<name>.yml` and re-run `init`.
|
|
187
|
+
See [docs/configuration.md](docs/configuration.md) for the schema.
|
|
188
|
+
|
|
189
|
+
### Host file layout after install (homeserver defaults)
|
|
190
|
+
|
|
191
|
+
```
|
|
192
|
+
~/cognitivesystems/state/state.json # default state file (--state to override)
|
|
193
|
+
/home/<service>/{docker-compose.yml,.env} # per-service working dir (install_root)
|
|
194
|
+
/home/data/<ServiceDisplayName>/ # persistent app data (config_root)
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Data directories are never removed by `uninstall`; pass `--purge` to delete them too.
|
|
198
|
+
Paths resolve from `state.json` `.site.paths` after `init --profile <name>`.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Services
|
|
203
|
+
|
|
204
|
+
42 services. Full details: [docs/services.md](docs/services.md) · Port model: [docs/networking-and-ports.md](docs/networking-and-ports.md)
|
|
205
|
+
|
|
206
|
+
| Category | Services |
|
|
207
|
+
|---|---|
|
|
208
|
+
| Core infra | Traefik, Portainer, WatchTower, WG-Easy, CrontabUI |
|
|
209
|
+
| Databases | MariaDB, MySQL, MongoDB, MQTT-Broker |
|
|
210
|
+
| Media | Plex, Radarr, Sonarr, Prowlarr, Jackett, Bazarr, Tautulli, Stash, Whisparr, Threadfin, Seerr |
|
|
211
|
+
| Download | Qbittorrent, CrossSeed, Autobrr, Rarrnomore, FlareSolverr, Byparr |
|
|
212
|
+
| Files / Comms | SFTPGo, SnappyMail, Stalwart, Vaultwarden, Paperless |
|
|
213
|
+
| Dev / Tools | Code-Server, OpenWebUI, Profilarr, Maintainerr, Heimdall, Wizarr, AdGuard, BetterDesk, Firefox, Chrome |
|
|
214
|
+
| Custom | Uploadarr |
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
## Contributing
|
|
219
|
+
|
|
220
|
+
Development happens on the `dev` branch, which carries the developer documentation
|
|
221
|
+
(architecture, catalog reference, how to add a service, the test framework):
|
|
222
|
+
|
|
223
|
+
→ [DEVELOPMENT.md on the `dev` branch](https://github.com/automationnexus/CognitiveSystems/blob/dev/DEVELOPMENT.md)
|
|
224
|
+
|
|
225
|
+
<!-- dev-ci-verify -->
|
|
226
|
+
|
|
227
|
+
<!-- nightly-e2e-verify -->
|
|
228
|
+
|
|
229
|
+
<!-- final-nightly-verify -->
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# CognitiveSystems Deployment
|
|
2
|
+
|
|
3
|
+
A pip-installable deployment app for the CognitiveSystems Docker stack.
|
|
4
|
+
One package, 42 services — no per-service `git clone` at deploy time.
|
|
5
|
+
|
|
6
|
+
`cognitivesystems` renders a `docker-compose.yml` + `.env` for each service from
|
|
7
|
+
per-service definitions (`services/<name>/service.yml`) plus an **install profile**
|
|
8
|
+
that supplies the values specific to your machine (paths, network, ports, timezone),
|
|
9
|
+
then drives `docker compose`. Drive it from the **web dashboard**, the **terminal UI**,
|
|
10
|
+
or the CLI. Rendering works on any OS; **deploying needs Linux + Docker** (run it on the
|
|
11
|
+
server, or in WSL).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pip install cognitivesystems # from PyPI
|
|
19
|
+
# or, from a clone (for development):
|
|
20
|
+
git clone https://github.com/automationnexus/CognitiveSystems.git
|
|
21
|
+
cd CognitiveSystems && pip install -e .
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Requires **Python 3.9+**; deploying additionally needs **Docker + compose v2** on a
|
|
25
|
+
Linux host (the app checks and tells you what's missing).
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Quick start
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install "cognitivesystems[web]" # include the web dashboard (optional extra)
|
|
33
|
+
sudo cognitivesystems # launch the dashboard (or the TUI); deploy actions need root
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
With the `[web]` extra, `cognitivesystems` opens the **web dashboard** on `127.0.0.1:8800` — a
|
|
37
|
+
browser GUI that does everything the TUI does. Disable the dashboard with `dashboard.enabled: false` in
|
|
38
|
+
`state.json` to get the **terminal UI** instead (or run `cognitivesystems tui`). See [docs/dashboard.md](docs/dashboard.md).
|
|
39
|
+
|
|
40
|
+
The TUI lists every service (`✓` = installed) with a live deploy-log pane. Keys:
|
|
41
|
+
**`i`** install · **`u`** update · **`x`** uninstall · **`c`** configure · **`s`** service ·
|
|
42
|
+
**`g`** config · **`k`** secrets · **`d`** docker · **`n`** network · **`a`** apps · **`h`** host ·
|
|
43
|
+
**`r`** refresh · **`q`** quit (arrows/mouse to select). Great over SSH on the server.
|
|
44
|
+
|
|
45
|
+
Or use the CLI:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
# 1. pick an install profile (system-specific paths/network/ports/timezone)
|
|
49
|
+
cognitivesystems init --profile homeserver # NFS-backed homeserver (default)
|
|
50
|
+
cognitivesystems init --profile localdev # laptop / VM
|
|
51
|
+
|
|
52
|
+
# 2. set credentials (prompt; Enter = auto-generate a strong value). No defaults ship.
|
|
53
|
+
cognitivesystems configure # mode/domain + admin password, LE email,
|
|
54
|
+
# Cloudflare DNS token, per-service overrides
|
|
55
|
+
|
|
56
|
+
# 3. install services (Linux + Docker; needs root for docker/chown)
|
|
57
|
+
sudo cognitivesystems install traefik portainer plex uploadarr \
|
|
58
|
+
--mode public --domain example.com --auto-update --wildcard
|
|
59
|
+
|
|
60
|
+
# 4. update / list / uninstall
|
|
61
|
+
sudo cognitivesystems update # all installed
|
|
62
|
+
sudo cognitivesystems update traefik plex # specific services
|
|
63
|
+
cognitivesystems list # catalog (* = installed)
|
|
64
|
+
sudo cognitivesystems uninstall plex # remove service + working dir
|
|
65
|
+
sudo cognitivesystems uninstall plex --purge # also delete the data dir
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`homeserver` expects two NFS mounts to exist first — `/home/data` and
|
|
69
|
+
`/mnt/homeserver`. See [docs/services.md](docs/services.md#install-profiles) for the
|
|
70
|
+
mount layout and `localdev` caveats. Re-run `init --profile <name>` to switch profiles.
|
|
71
|
+
|
|
72
|
+
### Reinstall an existing service
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
sudo cognitivesystems install plex --force # uninstall then install (keeps data dir)
|
|
76
|
+
sudo cognitivesystems install plex --force --purge # same, but also drops the data dir
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Without `--force`, installing an already-installed service is a no-op.
|
|
80
|
+
|
|
81
|
+
### Render only (any OS)
|
|
82
|
+
|
|
83
|
+
```bash
|
|
84
|
+
cognitivesystems render plex --out ./out # write docker-compose.yml + .env, no deploy
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### OS administration (Linux)
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
sudo cognitivesystems system ssh-keygen --bits=8192 --install-to=admin,operator
|
|
91
|
+
sudo cognitivesystems system change-password --target=root --password='…' --enable-root-ssh
|
|
92
|
+
sudo cognitivesystems system media-user create
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
See [docs/system-admin.md](docs/system-admin.md).
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Repository layout
|
|
100
|
+
|
|
101
|
+
```
|
|
102
|
+
.
|
|
103
|
+
├── pyproject.toml # package metadata (hatchling); entry point `cognitivesystems`
|
|
104
|
+
├── frontend/ # React + Vite dashboard SPA (built into the wheel at package time)
|
|
105
|
+
├── src/cognitivesystems/ # the app
|
|
106
|
+
│ ├── cli.py # CLI: list / render / init / install / update / uninstall / system / tui / web
|
|
107
|
+
│ ├── render.py # renderer: catalog + state -> docker-compose.yml + .env
|
|
108
|
+
│ ├── catalog.py state.py config.py deploy.py hooks.py system.py
|
|
109
|
+
│ ├── core/ # shared capability registry, job runner, Docker client, per-area ops
|
|
110
|
+
│ ├── tui/ # Textual terminal UI (app + per-area screens)
|
|
111
|
+
│ ├── web/ # FastAPI dashboard backend (serves the built SPA + JSON/WS API)
|
|
112
|
+
│ └── data/ # catalog bundled into the wheel (services + profiles)
|
|
113
|
+
├── services/
|
|
114
|
+
│ ├── install_order.yml # infra precedence (db/proxy come up first)
|
|
115
|
+
│ └── <name>/
|
|
116
|
+
│ ├── service.yml # one service definition per folder
|
|
117
|
+
│ └── sidecars/ # optional static files (e.g. the qbittorrent webhook script)
|
|
118
|
+
├── profiles/ # install profiles: homeserver.yml, localdev.yml
|
|
119
|
+
├── tests/ # pytest (render parity, GUI⇄TUI parity, variants, profiles, …)
|
|
120
|
+
└── docs/ # install-guide, migration-guide, dashboard, services, networking, configuration, system-admin
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Deployment modes
|
|
126
|
+
|
|
127
|
+
| Mode | Flag | TLS | Use case |
|
|
128
|
+
|---|---|---|---|
|
|
129
|
+
| Public | `--mode public` | Let's Encrypt TLS-ALPN-01, one cert per subdomain | Internet-facing server |
|
|
130
|
+
| Public + Wildcard | `--mode public --wildcard` | Cloudflare DNS-01, single `*.<domain>` cert | Internet-facing, one cert for all |
|
|
131
|
+
| Private | `--mode private` | None | LAN access via IP or hostname |
|
|
132
|
+
| Local | `--mode local` | None | Single machine, `localhost` only |
|
|
133
|
+
|
|
134
|
+
`--wildcard` needs `--cf-token` (a scoped Cloudflare DNS-edit API token). Healthchecks
|
|
135
|
+
are not configured by the installer; use each image's built-in `HEALTHCHECK` if needed.
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## Automatic install ordering
|
|
140
|
+
|
|
141
|
+
You never order services manually — infra installs first, in a fixed order:
|
|
142
|
+
`traefik → mariadb → mysql → mongodb → mqtt-broker`. Everything else follows.
|
|
143
|
+
|
|
144
|
+
---
|
|
145
|
+
|
|
146
|
+
## State & profile
|
|
147
|
+
|
|
148
|
+
Persisted under `/home/installation_cognitivesystems/state.json` (override with
|
|
149
|
+
`CS_STATE_DIR`):
|
|
150
|
+
|
|
151
|
+
- **Runtime config** — mode, domain, passwords, installed services. Saved as you install.
|
|
152
|
+
- **`.site`** — the system-specific values from your chosen install profile.
|
|
153
|
+
|
|
154
|
+
Re-running `update` re-renders every installed service from saved state. To change
|
|
155
|
+
domain / passwords / TLS mode: edit `state.json`, then `update`. To change profile
|
|
156
|
+
values (paths, ports, network): edit `profiles/<name>.yml` and re-run `init`.
|
|
157
|
+
See [docs/configuration.md](docs/configuration.md) for the schema.
|
|
158
|
+
|
|
159
|
+
### Host file layout after install (homeserver defaults)
|
|
160
|
+
|
|
161
|
+
```
|
|
162
|
+
~/cognitivesystems/state/state.json # default state file (--state to override)
|
|
163
|
+
/home/<service>/{docker-compose.yml,.env} # per-service working dir (install_root)
|
|
164
|
+
/home/data/<ServiceDisplayName>/ # persistent app data (config_root)
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Data directories are never removed by `uninstall`; pass `--purge` to delete them too.
|
|
168
|
+
Paths resolve from `state.json` `.site.paths` after `init --profile <name>`.
|
|
169
|
+
|
|
170
|
+
---
|
|
171
|
+
|
|
172
|
+
## Services
|
|
173
|
+
|
|
174
|
+
42 services. Full details: [docs/services.md](docs/services.md) · Port model: [docs/networking-and-ports.md](docs/networking-and-ports.md)
|
|
175
|
+
|
|
176
|
+
| Category | Services |
|
|
177
|
+
|---|---|
|
|
178
|
+
| Core infra | Traefik, Portainer, WatchTower, WG-Easy, CrontabUI |
|
|
179
|
+
| Databases | MariaDB, MySQL, MongoDB, MQTT-Broker |
|
|
180
|
+
| Media | Plex, Radarr, Sonarr, Prowlarr, Jackett, Bazarr, Tautulli, Stash, Whisparr, Threadfin, Seerr |
|
|
181
|
+
| Download | Qbittorrent, CrossSeed, Autobrr, Rarrnomore, FlareSolverr, Byparr |
|
|
182
|
+
| Files / Comms | SFTPGo, SnappyMail, Stalwart, Vaultwarden, Paperless |
|
|
183
|
+
| Dev / Tools | Code-Server, OpenWebUI, Profilarr, Maintainerr, Heimdall, Wizarr, AdGuard, BetterDesk, Firefox, Chrome |
|
|
184
|
+
| Custom | Uploadarr |
|
|
185
|
+
|
|
186
|
+
---
|
|
187
|
+
|
|
188
|
+
## Contributing
|
|
189
|
+
|
|
190
|
+
Development happens on the `dev` branch, which carries the developer documentation
|
|
191
|
+
(architecture, catalog reference, how to add a service, the test framework):
|
|
192
|
+
|
|
193
|
+
→ [DEVELOPMENT.md on the `dev` branch](https://github.com/automationnexus/CognitiveSystems/blob/dev/DEVELOPMENT.md)
|
|
194
|
+
|
|
195
|
+
<!-- dev-ci-verify -->
|
|
196
|
+
|
|
197
|
+
<!-- nightly-e2e-verify -->
|
|
198
|
+
|
|
199
|
+
<!-- final-nightly-verify -->
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { expect, test as setup } from '@playwright/test'
|
|
2
|
+
import { ADMIN, AUTH_FILE } from './fixtures'
|
|
3
|
+
|
|
4
|
+
// First-run against a fresh state (no admin password): the sign-in screen shows the one-time
|
|
5
|
+
// "create admin password" form. Setting it must land on the dashboard. This also primes the
|
|
6
|
+
// password for every other spec (it persists in the server's state).
|
|
7
|
+
setup('first-run creates the admin password', async ({ page }) => {
|
|
8
|
+
await page.goto('/')
|
|
9
|
+
await expect(page.getByRole('heading', { name: 'Welcome' })).toBeVisible()
|
|
10
|
+
await page.getByLabel('New password').fill(ADMIN.pass)
|
|
11
|
+
await page.getByLabel('Confirm password').fill(ADMIN.pass)
|
|
12
|
+
await page.getByRole('button', { name: /create & sign in/i }).click()
|
|
13
|
+
await expect(page.getByRole('heading', { name: 'Overview' })).toBeVisible()
|
|
14
|
+
await page.context().storageState({ path: AUTH_FILE }) // reused by every other spec
|
|
15
|
+
})
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
const PAGES: ReadonlyArray<readonly [string, string]> = [
|
|
4
|
+
['Services', 'Services'],
|
|
5
|
+
['Config', 'Configuration'],
|
|
6
|
+
['Docker', 'Docker'],
|
|
7
|
+
['Networks', 'Managed networks'],
|
|
8
|
+
['Apps', 'Custom apps'],
|
|
9
|
+
['Host', 'Host administration'],
|
|
10
|
+
['Jobs', 'Jobs'],
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
test('navigates every page without a runtime error', async ({ page }) => {
|
|
14
|
+
const errors: string[] = []
|
|
15
|
+
page.on('pageerror', (e) => errors.push(String(e)))
|
|
16
|
+
await page.goto('/')
|
|
17
|
+
await expect(page.getByRole('heading', { name: 'Overview' })).toBeVisible()
|
|
18
|
+
for (const [nav, heading] of PAGES) {
|
|
19
|
+
await page.getByRole('link', { name: nav, exact: true }).click()
|
|
20
|
+
await expect(page.getByRole('heading', { level: 1, name: heading })).toBeVisible()
|
|
21
|
+
}
|
|
22
|
+
await page.getByRole('link', { name: 'Overview', exact: true }).click()
|
|
23
|
+
await expect(page.getByRole('heading', { name: 'Overview' })).toBeVisible()
|
|
24
|
+
expect(errors, errors.join('\n')).toEqual([])
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
test('theme toggle flips data-theme', async ({ page }) => {
|
|
28
|
+
await page.goto('/')
|
|
29
|
+
await expect(page.getByRole('heading', { name: 'Overview' })).toBeVisible()
|
|
30
|
+
const before = await page.evaluate(() => document.documentElement.dataset.theme)
|
|
31
|
+
await page.getByRole('button', { name: /light|dark/i }).click()
|
|
32
|
+
const after = await page.evaluate(() => document.documentElement.dataset.theme)
|
|
33
|
+
expect(after).not.toBe(before)
|
|
34
|
+
})
|
|
35
|
+
|
|
36
|
+
test('logout returns to the sign-in screen', async ({ page }) => {
|
|
37
|
+
await page.goto('/')
|
|
38
|
+
await page.getByRole('button', { name: /logout/i }).click()
|
|
39
|
+
await expect(page.getByRole('heading', { name: 'Sign in' })).toBeVisible()
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
test('responsive: the nav still works at mobile width', async ({ page }) => {
|
|
43
|
+
await page.setViewportSize({ width: 390, height: 800 })
|
|
44
|
+
await page.goto('/')
|
|
45
|
+
await page.getByRole('link', { name: 'Docker', exact: true }).click()
|
|
46
|
+
await expect(page.getByRole('heading', { name: 'Docker' })).toBeVisible()
|
|
47
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
async function gotoDocker(page: import('@playwright/test').Page) {
|
|
4
|
+
await page.goto('/')
|
|
5
|
+
await page.getByRole('link', { name: 'Docker', exact: true }).click()
|
|
6
|
+
await expect(page.getByRole('heading', { name: 'Docker' })).toBeVisible()
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
test('containers tab streams logs and exec over websockets', async ({ page }) => {
|
|
10
|
+
await gotoDocker(page)
|
|
11
|
+
await expect(page.getByText('nginx-demo')).toBeVisible()
|
|
12
|
+
|
|
13
|
+
// logs websocket → "fake log line"
|
|
14
|
+
await page.getByRole('button', { name: 'logs' }).click()
|
|
15
|
+
await expect(page.getByText('fake log line')).toBeVisible({ timeout: 10000 })
|
|
16
|
+
await page.getByRole('button', { name: '✕' }).click()
|
|
17
|
+
|
|
18
|
+
// exec websocket (CSRF-gated) echoes the command output
|
|
19
|
+
await page.getByRole('button', { name: 'exec' }).click()
|
|
20
|
+
await page.getByPlaceholder(/command/).fill('ls -la')
|
|
21
|
+
await page.getByRole('button', { name: 'Run' }).click()
|
|
22
|
+
await expect(page.getByText(/ran:/)).toBeVisible({ timeout: 10000 })
|
|
23
|
+
await page.getByRole('button', { name: '✕' }).click()
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
test('images and volumes tabs show seeded data', async ({ page }) => {
|
|
27
|
+
await gotoDocker(page)
|
|
28
|
+
await page.getByRole('button', { name: 'images' }).click()
|
|
29
|
+
await expect(page.getByText('nginx:alpine')).toBeVisible()
|
|
30
|
+
await page.getByRole('button', { name: 'volumes' }).click()
|
|
31
|
+
await expect(page.getByText('demo-vol')).toBeVisible()
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('confirm modal cancels a destructive action (no window.confirm)', async ({ page }) => {
|
|
35
|
+
await gotoDocker(page)
|
|
36
|
+
// "remove" opens the glass confirm dialog; cancelling keeps the container
|
|
37
|
+
await page.getByRole('button', { name: 'remove', exact: true }).first().click()
|
|
38
|
+
await expect(page.getByRole('dialog')).toContainText(/Remove container/)
|
|
39
|
+
await page.getByRole('button', { name: 'Cancel' }).click()
|
|
40
|
+
await expect(page.getByText('nginx-demo')).toBeVisible()
|
|
41
|
+
})
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// >= 8 chars to satisfy the first-run min-length check.
|
|
2
|
+
export const ADMIN = { user: 'admin', pass: 'e2e-password-123' }
|
|
3
|
+
|
|
4
|
+
// auth.setup.ts signs in once and saves the session here; the chromium project reuses it
|
|
5
|
+
// (storageState), so specs start authenticated — one login total, which also keeps the backend
|
|
6
|
+
// login rate-limiter (5/60s per IP) from tripping across parallel specs.
|
|
7
|
+
export const AUTH_FILE = 'e2e/.auth/state.json'
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { expect, test } from '@playwright/test'
|
|
2
|
+
|
|
3
|
+
test('install streams a job log to completion', async ({ page }) => {
|
|
4
|
+
await page.goto('/')
|
|
5
|
+
await page.getByRole('link', { name: 'Services', exact: true }).click()
|
|
6
|
+
await expect(page.getByRole('heading', { name: 'Services' })).toBeVisible()
|
|
7
|
+
|
|
8
|
+
// open a service's Manage modal and kick off an install — the fake runner emits two lines
|
|
9
|
+
// and exits 0, so the JobLog websocket streams to a "done (rc=0)" end frame.
|
|
10
|
+
await page.getByRole('button', { name: 'Manage' }).first().click()
|
|
11
|
+
await expect(page.getByRole('dialog')).toBeVisible()
|
|
12
|
+
await page.getByRole('button', { name: 'Install', exact: true }).click()
|
|
13
|
+
await expect(page.getByText(/rc=0/)).toBeVisible({ timeout: 15000 })
|
|
14
|
+
})
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
3
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
4
|
+
import globals from 'globals'
|
|
5
|
+
import tseslint from 'typescript-eslint'
|
|
6
|
+
|
|
7
|
+
export default tseslint.config(
|
|
8
|
+
{ ignores: ['dist', 'coverage', 'node_modules'] },
|
|
9
|
+
{
|
|
10
|
+
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
|
11
|
+
files: ['**/*.{ts,tsx}'],
|
|
12
|
+
languageOptions: { ecmaVersion: 2022, globals: globals.browser },
|
|
13
|
+
plugins: { 'react-hooks': reactHooks, 'react-refresh': reactRefresh },
|
|
14
|
+
rules: {
|
|
15
|
+
...reactHooks.configs.recommended.rules,
|
|
16
|
+
'react-refresh/only-export-components': ['warn', { allowConstantExport: true }],
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en" data-theme="dark">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>CognitiveSystems Dashboard</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.tsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|