fix: all service pages use live domain; cell_name/domain propagate to DNS; /api/status reads stored identity

Changes:
- ConfigContext.jsx: React context that loads /api/config once; exposes domain,
  cell_name, refresh() — wraps entire app in App.jsx
- Email/Calendar/Files pages: replace hardcoded 'mail.cell', 'calendar.cell',
  'files.cell', 'webdav.cell' with domain from ConfigContext; hostname updates
  immediately after Settings save (refreshConfig() called on save)
- /api/status: cell_name and domain now read from stored _identity in config_manager,
  not hardcoded 'personal-internet-cell' / 'cell.local'
- network_manager.apply_cell_name(old, new): updates hostname A-record in primary
  zone file and reloads CoreDNS; called from PUT /api/config when cell_name changes
- Old identity captured before save so apply_cell_name gets the correct old value
- Settings EmailForm: smtp/imap ports are read-only with note (docker-compose.yml level)
- Settings FilesForm: port is read-only with note (Caddy proxies on 80 externally)
- Settings CalendarForm: port labeled "Internal port; clients use 80 via Caddy"

Tests added:
- test_apply_cell_name_renames_host_record
- test_apply_cell_name_noop_when_same

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-21 05:05:51 -04:00
parent ac9b26303f
commit 1f3386d43b
9 changed files with 157 additions and 29 deletions
+10 -8
View File
@@ -1,10 +1,9 @@
import { useState, useEffect } from 'react';
import { FolderOpen, Users, HardDrive, Wifi, Copy, CheckCheck } from 'lucide-react';
import { fileAPI } from '../services/api';
import { useConfig } from '../contexts/ConfigContext';
const FILES_HOST = 'files.cell';
const FILES_IP = '172.20.0.22';
const WEBDAV_HOST = 'webdav.cell';
const WEBDAV_IP = '172.20.0.24';
function CopyButton({ text }) {
@@ -34,6 +33,9 @@ function InfoRow({ label, value }) {
}
function Files() {
const { domain = 'cell' } = useConfig();
const filesHost = `files.${domain}`;
const webdavHost = `webdav.${domain}`;
const [users, setUsers] = useState([]);
const [status, setStatus] = useState(null);
const [isLoading, setIsLoading] = useState(true);
@@ -80,7 +82,7 @@ function Files() {
<h3 className="text-lg font-medium text-gray-900">Web file manager</h3>
</div>
<div className="bg-gray-50 rounded-lg px-4 py-2">
<InfoRow label="URL" value={`http://${FILES_HOST}`} />
<InfoRow label="URL" value={`http://${filesHost}`} />
<InfoRow label="Direct IP" value={`http://${FILES_IP}`} />
<InfoRow label="Port" value="80" />
</div>
@@ -96,7 +98,7 @@ function Files() {
<h3 className="text-lg font-medium text-gray-900">WebDAV (mount as drive)</h3>
</div>
<div className="bg-gray-50 rounded-lg px-4 py-2">
<InfoRow label="URL" value={`http://${WEBDAV_HOST}`} />
<InfoRow label="URL" value={`http://${webdavHost}`} />
<InfoRow label="Direct IP" value={`http://${WEBDAV_IP}`} />
<InfoRow label="Port" value="80" />
<InfoRow label="Auth" value="Basic (user / password)" />
@@ -115,19 +117,19 @@ function Files() {
<div className="space-y-3 text-sm">
<div>
<p className="font-medium text-gray-900 mb-1">macOS (Finder)</p>
<p className="text-xs text-gray-600">Go Connect to Server <span className="font-mono">http://webdav.cell</span></p>
<p className="text-xs text-gray-600">Go Connect to Server <span className="font-mono">http://{webdavHost}</span></p>
</div>
<div>
<p className="font-medium text-gray-900 mb-1">Windows</p>
<p className="text-xs text-gray-600">Map Network Drive <span className="font-mono">\\webdav.cell\DavWWWRoot</span> or use <span className="font-mono">http://webdav.cell</span> in "Connect to a Web Site"</p>
<p className="text-xs text-gray-600">Map Network Drive <span className="font-mono">\\{webdavHost}\DavWWWRoot</span> or use <span className="font-mono">http://{webdavHost}</span> in "Connect to a Web Site"</p>
</div>
<div>
<p className="font-medium text-gray-900 mb-1">iOS (Files app)</p>
<p className="text-xs text-gray-600">Files ... Connect to Server <span className="font-mono">http://webdav.cell</span></p>
<p className="text-xs text-gray-600">Files ... Connect to Server <span className="font-mono">http://{webdavHost}</span></p>
</div>
<div>
<p className="font-medium text-gray-900 mb-1">Android</p>
<p className="text-xs text-gray-600">Use <strong>Solid Explorer</strong> or <strong>FX File Explorer</strong> Add cloud WebDAV</p>
<p className="text-xs text-gray-600">Use <strong>Solid Explorer</strong> or <strong>FX File Explorer</strong> Add cloud WebDAV <span className="font-mono">http://{webdavHost}</span></p>
</div>
</div>
</div>