feat: v0.4.0 — Apache service stack, shell access, log viewer, changelog

Service stack (backend):
- webserver.ts rewritten: apache2/php-fpm routes replacing nginx; per-account
  Apache log endpoint; PHP-FPM reload per version; apache2ctl configtest/reload
- accounts.ts: added PUT /:id/shell to toggle /bin/bash vs /usr/sbin/nologin,
  runs usermod -s and writes audit log

New UI features (nixserver):
- ShellAccess page: grant/revoke SSH access per account via AccountPicker
- ApacheLogs page: live log viewer (access/error) per account; replaces stub
- NginxLogs: re-exports ApacheLogs (NixPanel uses Apache, not NGINX)
- WebServer page: shows apache2, php8.2-fpm, php8.3-fpm status with reload
  buttons; config test; Apache log viewer

Bug fixes:
- Accounts.tsx: Lucide icon size prop type widened (string|number); removed
  unused Users import; dropped duplicate NGINX log card
- Removed soon badge from ShellAccess and ApacheLogs entries

Project:
- CHANGELOG.md created with full history from 0.2.x through 0.4.0
- All packages bumped from 0.3.2 to 0.4.0
This commit is contained in:
NixReaper
2026-04-11 05:17:49 -05:00
parent 10e31482b0
commit 8ff00c544c
65 changed files with 11223 additions and 1259 deletions
+116
View File
@@ -22,6 +22,34 @@ const System = React.lazy(() => import('./pages/System'))
const WebServer = React.lazy(() => import('./pages/WebServer'))
const Settings = React.lazy(() => import('./pages/Settings'))
// Accounts sub-pages
const AccountList = React.lazy(() => import('./pages/accounts/List'))
const AccountParkedDomains = React.lazy(() => import('./pages/accounts/ParkedDomains'))
const AccountSubdomains = React.lazy(() => import('./pages/accounts/Subdomains'))
const AccountSuspended = React.lazy(() => import('./pages/accounts/Suspended'))
const AccountOverQuota = React.lazy(() => import('./pages/accounts/OverQuota'))
const AccountBandwidth = React.lazy(() => import('./pages/accounts/Bandwidth'))
const AccountChangeIP = React.lazy(() => import('./pages/accounts/ChangeIP'))
const AccountEmailUsers = React.lazy(() => import('./pages/accounts/EmailUsers'))
const AccountForcePassword = React.lazy(() => import('./pages/accounts/ForcePassword'))
const AccountLimitBandwidth = React.lazy(() => import('./pages/accounts/LimitBandwidth'))
const AccountSuspension = React.lazy(() => import('./pages/accounts/Suspension'))
const AccountDemoMode = React.lazy(() => import('./pages/accounts/DemoMode'))
const AccountShellAccess = React.lazy(() => import('./pages/accounts/ShellAccess'))
const AccountModify = React.lazy(() => import('./pages/accounts/Modify'))
const AccountPasswordMod = React.lazy(() => import('./pages/accounts/PasswordMod'))
const AccountQuotaMod = React.lazy(() => import('./pages/accounts/QuotaMod'))
const AccountApacheLogs = React.lazy(() => import('./pages/accounts/ApacheLogs'))
const AccountNginxLogs = React.lazy(() => import('./pages/accounts/NginxLogs'))
const AccountRearrange = React.lazy(() => import('./pages/accounts/Rearrange'))
const AccountResetBandwidth = React.lazy(() => import('./pages/accounts/ResetBandwidth'))
const AccountTerminate = React.lazy(() => import('./pages/accounts/Terminate'))
const AccountUnsuspendBW = React.lazy(() => import('./pages/accounts/UnsuspendBandwidth'))
const AccountUpgrade = React.lazy(() => import('./pages/accounts/Upgrade'))
const AccountWebTemplate = React.lazy(() => import('./pages/accounts/WebTemplate'))
const AccountBulkIP = React.lazy(() => import('./pages/accounts/BulkIP'))
const AccountBulkModify = React.lazy(() => import('./pages/accounts/BulkModify'))
function ProtectedRoute({ children }: { children: React.ReactNode }) {
const { user, loading, setupComplete } = useAuth()
@@ -63,8 +91,96 @@ function AppRoutes() {
</ProtectedRoute>
}>
<Route index element={<Dashboard />} />
{/* Accounts hub */}
<Route path="accounts" element={<Accounts />} />
<Route path="accounts/create" element={<CreateAccount />} />
{/* Account Information */}
<Route path="accounts/list" element={
<React.Suspense fallback={<PageLoader />}><AccountList /></React.Suspense>
} />
<Route path="accounts/parked-domains" element={
<React.Suspense fallback={<PageLoader />}><AccountParkedDomains /></React.Suspense>
} />
<Route path="accounts/subdomains" element={
<React.Suspense fallback={<PageLoader />}><AccountSubdomains /></React.Suspense>
} />
<Route path="accounts/suspended" element={
<React.Suspense fallback={<PageLoader />}><AccountSuspended /></React.Suspense>
} />
<Route path="accounts/over-quota" element={
<React.Suspense fallback={<PageLoader />}><AccountOverQuota /></React.Suspense>
} />
<Route path="accounts/bandwidth" element={
<React.Suspense fallback={<PageLoader />}><AccountBandwidth /></React.Suspense>
} />
{/* Account Functions */}
<Route path="accounts/change-ip" element={
<React.Suspense fallback={<PageLoader />}><AccountChangeIP /></React.Suspense>
} />
<Route path="accounts/email-users" element={
<React.Suspense fallback={<PageLoader />}><AccountEmailUsers /></React.Suspense>
} />
<Route path="accounts/force-password" element={
<React.Suspense fallback={<PageLoader />}><AccountForcePassword /></React.Suspense>
} />
<Route path="accounts/limit-bandwidth" element={
<React.Suspense fallback={<PageLoader />}><AccountLimitBandwidth /></React.Suspense>
} />
<Route path="accounts/suspension" element={
<React.Suspense fallback={<PageLoader />}><AccountSuspension /></React.Suspense>
} />
<Route path="accounts/demo-mode" element={
<React.Suspense fallback={<PageLoader />}><AccountDemoMode /></React.Suspense>
} />
<Route path="accounts/shell-access" element={
<React.Suspense fallback={<PageLoader />}><AccountShellAccess /></React.Suspense>
} />
<Route path="accounts/modify" element={
<React.Suspense fallback={<PageLoader />}><AccountModify /></React.Suspense>
} />
<Route path="accounts/password" element={
<React.Suspense fallback={<PageLoader />}><AccountPasswordMod /></React.Suspense>
} />
<Route path="accounts/quota" element={
<React.Suspense fallback={<PageLoader />}><AccountQuotaMod /></React.Suspense>
} />
<Route path="accounts/apache-logs" element={
<React.Suspense fallback={<PageLoader />}><AccountApacheLogs /></React.Suspense>
} />
<Route path="accounts/nginx-logs" element={
<React.Suspense fallback={<PageLoader />}><AccountNginxLogs /></React.Suspense>
} />
<Route path="accounts/rearrange" element={
<React.Suspense fallback={<PageLoader />}><AccountRearrange /></React.Suspense>
} />
<Route path="accounts/reset-bandwidth" element={
<React.Suspense fallback={<PageLoader />}><AccountResetBandwidth /></React.Suspense>
} />
<Route path="accounts/terminate" element={
<React.Suspense fallback={<PageLoader />}><AccountTerminate /></React.Suspense>
} />
<Route path="accounts/unsuspend-bandwidth" element={
<React.Suspense fallback={<PageLoader />}><AccountUnsuspendBW /></React.Suspense>
} />
<Route path="accounts/upgrade" element={
<React.Suspense fallback={<PageLoader />}><AccountUpgrade /></React.Suspense>
} />
<Route path="accounts/web-template" element={
<React.Suspense fallback={<PageLoader />}><AccountWebTemplate /></React.Suspense>
} />
{/* Multi Account Functions */}
<Route path="accounts/bulk-ip" element={
<React.Suspense fallback={<PageLoader />}><AccountBulkIP /></React.Suspense>
} />
<Route path="accounts/bulk-modify" element={
<React.Suspense fallback={<PageLoader />}><AccountBulkModify /></React.Suspense>
} />
{/* Other sections */}
<Route path="packages" element={<Packages />} />
<Route path="resellers" element={
<React.Suspense fallback={<PageLoader />}><Resellers /></React.Suspense>