docs: add Antora site sources under docs/ with CI smoke build

Move the docs.olivetin.app AsciiDoc component into this repository, add
local Antora playbooks for contributors and CI, and document the split
between this repo and the docs build repository.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
jamesread 2026-05-10 21:58:48 +01:00
parent 841ef770f3
commit c132eacc00
286 changed files with 9225 additions and 1 deletions

34
.github/workflows/docs-antora.yml vendored Normal file
View File

@ -0,0 +1,34 @@
name: Antora docs
on:
push:
paths:
- 'docs/**'
- 'local-antora-playbook.yml'
- 'local-antora-playbook-ci.yml'
- '.github/workflows/docs-antora.yml'
pull_request:
paths:
- 'docs/**'
- 'local-antora-playbook.yml'
- 'local-antora-playbook-ci.yml'
- '.github/workflows/docs-antora.yml'
jobs:
antora:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install Antora toolchain
run: npm i antora@3.1.14 asciidoctor-kroki@0.18.1 @asciidoctor/tabs@1.0.0-beta.6
- name: Generate docs site (smoke)
run: npx antora local-antora-playbook-ci.yml --log-level info

2
.gitignore vendored
View File

@ -20,3 +20,5 @@ integration-tests/configs/authRequireGuestsToLogin/sessions.yaml
webui
webui.dev
sessions.yaml
docs/build/
build/

View File

@ -58,6 +58,7 @@ make
The project layout is reasonably straightforward;
* See the `Makefile` for common targets. This project was originally created on top of Fedora, but it should be usable on Debian/your faveourite distro with minor changes (if any).
* End-user documentation (AsciiDoc for link:https://docs.olivetin.app[docs.olivetin.app]) lives in `docs/` as an Antora component; the published site is built from the separate link:https://github.com/OliveTin/docs.olivetin.app[docs.olivetin.app] repository.
* The API is defined in protobuf+Connect RPC - you will need to `make proto`.
* The Go daemon is built from the `cmd` and `internal` directories mostly.
* The webui is just a single page application with a bit of Javascript in the `webui` directory. This can happily be hosted on another webserver.

View File

@ -20,6 +20,8 @@
All documentation can be found at [docs.olivetin.app](https://docs.olivetin.app). This includes installation and usage guide, etc.
The AsciiDoc sources for that site live in this repository under [`docs/`](docs/) (Antora component). The [docs.olivetin.app](https://github.com/OliveTin/docs.olivetin.app) repository contains the Antora playbook, theme supplemental files, and the workflow that publishes GitHub Pages.
## Use cases
**Safely** give access to commands, for less technical people;

15
docs/antora.yml Normal file
View File

@ -0,0 +1,15 @@
---
name: ROOT
title: OliveTin
version: ''
display_version: 'Version 3k'
start_page: index.adoc
asciidoc:
attributes:
source-language: asciidoc@
table-caption: false
toclevels: 2
nav:
- modules/ROOT/nav.adoc

View File

@ -0,0 +1,40 @@
#!/usr/bin/env python3
import glob
import re
nav_file = open('nav.adoc', 'r')
nav_string = nav_file.read()
adoc_files = glob.glob('pages/**/*.adoc', recursive=True)
filelist = dict()
for file in adoc_files:
with open(file, 'r') as handle:
content = handle.read()
matches = re.findall(r'<<(.*?),?([\w\- ]+)>>', content)
for match in matches:
m = match
if match[0] == "":
m = match[1]
else:
m = match[0]
if content.count("#" + m) != 1:
if file not in filelist:
filelist[file] = list()
filelist[file].append(m)
print("Files:", len(filelist))
for file in filelist.keys():
print(file)
for match in filelist[file]:
print("\t", match)

View File

@ -0,0 +1,24 @@
#!/usr/bin/env python3
import glob
import re
adoc_files = glob.glob('pages/**/*.adoc', recursive=True)
filelist = list()
for file in adoc_files:
with open(file, 'r') as handle:
content = handle.read()
matches = re.findall('^= ', content, re.MULTILINE)
if len(matches) == 0:
filelist.append(file)
print("Files:", len(filelist))
for file in filelist:
print(file)

View File

@ -0,0 +1,25 @@
#!/usr/bin/env python3
# find .adoc files that are not navigable from the nav.adoc file
import glob
nav_file = open('nav.adoc', 'r')
nav_string = nav_file.read()
adoc_files = glob.glob('pages/**/*.adoc', recursive=True)
unnavigable_files = []
for file in adoc_files:
filename = file.replace("pages/", "")
if filename not in nav_string:
unnavigable_files.append(filename)
unnavigable_files = sorted(unnavigable_files)
print("Unnavigable files:", len(unnavigable_files))
for file in unnavigable_files:
print(file)

View File

@ -0,0 +1,15 @@
actions:
- title: Unicode (emoji) alias icon
shell: echo "Hello!"
icon: smile
- title: Unicode (emoji) icon
shell: echo "Hello!"
icon: "&#128526;"
- title: Iconify Icon
icon: <iconify-icon icon="ant-design:bug-filled"></iconify-icon>
- title: HTML Image (jpg/png/gif/etc) icon
shell: echo "Hello!"
icon: '<img src = "custom-webui/icons/mrgreen.gif" style = "width: 1em;" />'

View File

@ -0,0 +1,9 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: olivetin-config
data:
config.yaml: |
actions:
- title: "Hello world!"
shell: echo 'Hello World!'

View File

@ -0,0 +1,37 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: olivetin
spec:
replicas: 1
selector:
matchLabels:
app: olivetin
template:
metadata:
labels:
app: olivetin
spec:
containers:
- name: olivetin
image: docker.io/jamesread/olivetin:latest
ports:
- containerPort: 1337
volumeMounts:
- name: olivetin-config
mountPath: "/config"
readOnly: true
livenessProbe:
exec:
command:
- curl
- localhost:1337
initialDelaySeconds: 5
periodSeconds: 30
volumes:
- name: olivetin-config
configMap:
name: olivetin-config

View File

@ -0,0 +1,21 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: olivetin-ingress
spec:
defaultBackend:
service:
name: olivetin
port:
number: 1337
rules:
- host: olivetin.apps.ocp.teratan.net
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: olivetin
port:
number: 1337

View File

@ -0,0 +1,19 @@
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
olivetin:
container_name: olivetin
image: jamesread/olivetin
volumes:
- ./OliveTin:/config # replace host path or volume as needed
ports:
- "1337:1337"
restart: unless-stopped

View File

@ -0,0 +1,25 @@
server {
listen 443 ssl;
ssl_certificate "/etc/nginx/conf.d/server.crt";
ssl_certificate_key "/etc/nginx/conf.d/server.key";
access_log /var/log/nginx/ot.access.log main;
error_log /var/log/nginx/ot.error.log notice;
server_name olivetin.example.com;
location / {
proxy_pass http://localhost:1337/;
proxy_redirect http://localhost:1337/ http://localhost/OliveTin/;
}
location /websocket {
proxy_set_header Upgrade "websocket";
proxy_set_header Connection "upgrade";
proxy_pass http://localhost:1337/websocket;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
}
}

View File

@ -0,0 +1,48 @@
# This config has two actions which are applied to all "container" entities
# found in the entity file.
#
# Docs: http://localhost/docs.olivetin.app/docs/entities.html
actions:
- title: Start {{ container.Names }}
icon: box
shell: docker start {{ container.Names }}
entity: container
triggers:
- Update container entity file
- title: Stop {{ container.Names }}
icon: box
shell: docker stop {{ container.Names }}
entity: container
triggers:
- Update container entity file
# This is a hidden action, that is run on startup, and every 5 minutes, and
# when the above start/stop commands are run (see the `triggers` property).
- title: Update container entity file
shell: 'docker ps -a --format json > /etc/OliveTin/entities/containers.json'
hidden: true
execOnStartup: true
execOnCron: '*/5 * * * *'
# Docs: http://docs.olivetin.app/entities.html
entities:
- file: /etc/OliveTin/entities/containers.json
name: container
# The only way to properly use entities, are to use them with a `fieldset` on
# a dashboard.
dashboards:
# This is the second dashboard.
- title: My Containers
contents:
- title: 'Container {{ container.Names }} ({{ container.Image }})'
entity: container
type: fieldset
contents:
- type: display
title: |
{{ container.RunningFor }} <br /><br /><strong>{{ container.State }}</strong>
- title: 'Start {{ container.Names }}'
- title: 'Stop {{ container.Names }}'

View File

@ -0,0 +1,2 @@
{"Command":"\"/bin/bash\"","CreatedAt":"2024-02-28 22:33:35 +0000 GMT","ID":"fcf468e18a0e","Image":"fedora","Labels":"maintainer=Clement Verna \u003ccverna@fedoraproject.org\u003e","LocalVolumes":"0","Mounts":"","Names":"minecraft","Networks":"bridge","Ports":"","RunningFor":"3 minutes ago","Size":"0B","State":"created","Status":"Created"}
{"Command":"\"/bin/bash\"","CreatedAt":"2024-02-23 23:18:57 +0000 GMT","ID":"442dd6fe316a","Image":"fedora","Labels":"maintainer=Clement Verna \u003ccverna@fedoraproject.org\u003e","LocalVolumes":"0","Mounts":"","Names":"brave_shirley","Networks":"bridge","Ports":"","RunningFor":"4 days ago","Size":"0B","State":"created","Status":"Created"}

View File

@ -0,0 +1,32 @@
actions:
- title: check log directory
hidden: true
shell: |
function addDirectory {
COUNT=$(ls -l $1 | wc -l)
echo "- directory: $1" >> /etc/OliveTin/entities/directories.yaml
echo " count: $COUNT" >> /etc/OliveTin/entities/directories.yaml
}
truncate -s 0 /etc/OliveTin/entities/directories.yaml
addDirectory /var/log/
addDirectory /home/xconspirisist/logs
execOnStartup: true
execOnCron: "* * * * *"
- title: clean {{ log_directory.directory }} ({{log_directory.count }} files)
shell: |
echo "Removing all files in {{ log_directory.directory }}"
entity: log_directory
entities:
- name: log_directory
file: /etc/OliveTin/entities/directories.yaml
dashboards:
- title: Log Actions
contents:
- entity: log_directory
type: fieldset
contents:
- title: clean {{ log_directory.directory }} ({{log_directory.count }} files)

View File

@ -0,0 +1,28 @@
logLevel: "INFO"
actions:
- title: Turn heating up
icon: '&#128316;'
shell: /opt/heating.sh up
- title: Turn heating down
icon: '&#128317;'
shell: /opt/heating.sh down
entities:
- file: /etc/OliveTin/entities/heating.yaml
name: heating
dashboards:
- title: Heating Control Panel
contents:
- title: "{{ heater.title }}"
entity: heating
type: fieldset
contents:
- type: display
title: |
<span class = "icon">&#127777;</span> <br />{{ heating.temperature }}
- title: Turn heating up
- title: Turn heating down

View File

@ -0,0 +1,2 @@
- title: Main heater
temperature: 20 degrees

View File

@ -0,0 +1,35 @@
const myPassword = 'sekrit'
const domMain = document.getElementsByTagName('main')[0]
domMain.style.display = 'none'
const domPassword = document.createElement('input')
const domLogin = document.createElement('button')
function checkPassword () {
if (domPassword.value === myPassword) {
domMain.style.display = 'block'
domPassword.remove()
domLogin.remove()
} else {
window.alert('Incorrect password. Please try again.')
}
}
function setupPasswordForm () {
domPassword.setAttribute('type', 'password')
domPassword.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
checkPassword()
}
})
domLogin.innerText = 'Login'
domLogin.onclick = checkPassword
const domHeader = document.querySelector('header')
domHeader.appendChild(domPassword)
domHeader.appendChild(domLogin)
}
document.addEventListener('DOMContentLoaded', setupPasswordForm)

View File

@ -0,0 +1,36 @@
actions:
- title: Stop {{ systemd_unit.unit }}
shell: systemctl stop {{ systemd_unit.unit }}
icon: <iconify-icon icon="zondicons:hand-stop"></iconify-icon>
entity: systemd_unit
triggers:
- Update services file
- title: Start {{ systemd_unit.unit }}
shell: systemctl start {{ systemd_unit.unit }}
icon: <iconify-icon icon="ic:round-directions-run"></iconify-icon>
entity: systemd_unit
triggers:
- Update services file
- title: Update services file
shell: systemctl list-units -a -o json --no-pager | jq -c 'map(select (.unit | contains ("upsilon", "podman", "boot.mount"))) | .[]' > /etc/OliveTin/entities/systemd_units.json
hidden: true
execOnStartup: true
entities:
- file: /etc/OliveTin/entities/systemd_units.json
name: systemd_unit
dashboards:
- title: My Services
contents:
- title: '{{ systemd_unit.description }}'
type: fieldset
entity: systemd_unit
contents:
- title: 'Status: {{ systemd_unit.sub }}'
type: display
- title: Start {{ systemd_unit.unit }}
- title: Stop {{ systemd_unit.unit }}

View File

@ -0,0 +1,4 @@
{"unit":"boot.mount","load":"loaded","active":"active","sub":"mounted","description":"/boot"}
{"unit":"podman.service","load":"loaded","active":"inactive","sub":"dead","description":"Podman API Service"}
{"unit":"upsilon-drone.service","load":"loaded","active":"active","sub":"running","description":"upsilon-drone"}
{"unit":"podman.socket","load":"loaded","active":"active","sub":"listening","description":"Podman API Socket"}

View File

@ -0,0 +1,10 @@
actions:
- title: WakeOnLan Server1
shell: ether-wake A8:5E:45:E4:FF:2A
icon: ping
- title: Install ether-wake on startup
shell: microdnf install -y net-tools
hidden: true
execOnStartup: true
timeout: 120

View File

@ -0,0 +1,6 @@
- title: WakeOnLan Server1
# The r0gger/docker-wake-on-lan is a minimal container for WOL
# that can be run on the host network.
# It is not required to run the OliveTin container on the host network.
shell: |
docker run --rm --name wake-on-lan --net=host -e MAC='A8:5E:45:E4:FF:2A' r0gger/docker-wake-on-lan

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 128 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 91 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Some files were not shown because too many files have changed in this diff Show More