diff --git a/frontend/src/components/service-detail/SettingsTab.jsx b/frontend/src/components/service-detail/SettingsTab.jsx
index f43a43c8..dab55d0b 100644
--- a/frontend/src/components/service-detail/SettingsTab.jsx
+++ b/frontend/src/components/service-detail/SettingsTab.jsx
@@ -1,14 +1,26 @@
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
+import { SlidersHorizontal, GitBranch, AlertTriangle } from 'lucide-react';
import api from '../../services/api';
import { useToast } from '../../contexts/ToastContext';
import { DangerZone } from '../DangerZone';
import { Button } from '@/components/ui/button';
import { Select, SelectTrigger, SelectContent, SelectItem, SelectValue } from '@/components/ui/select';
+// Grouped left sub-nav for the service Settings tab — mirrors the WordPress
+// detail page's settings layout: an uppercase mono group label per section with
+// the existing setting panels on the right. Groups give it structure (and room
+// to grow) instead of one long flat stack.
+const SVC_SETTINGS_GROUPS = [
+ { label: 'General', items: [{ id: 'environment', label: 'Environment', icon: SlidersHorizontal }] },
+ { label: 'Connections', items: [{ id: 'repository', label: 'Repository', icon: GitBranch }] },
+ { label: 'Advanced', items: [{ id: 'danger', label: 'Danger Zone', icon: AlertTriangle }] },
+];
+
const SettingsTab = ({ app, deployConfig, onUpdate, onOpenGitModal }) => {
const navigate = useNavigate();
const toast = useToast();
+ const [section, setSection] = useState('environment');
const [deleting, setDeleting] = useState(false);
const [environmentType, setEnvironmentType] = useState(app.environment_type || 'standalone');
const [savingEnvironment, setSavingEnvironment] = useState(false);
@@ -67,100 +79,127 @@ const SettingsTab = ({ app, deployConfig, onUpdate, onOpenGitModal }) => {
return (
- {/* Repository Configuration */}
-
-
Repository
-
-
-
- Connected Repository
-
- {deployConfig
- ? `${deployConfig.repo_url} (${deployConfig.branch || 'main'})`
- : 'No repository connected'}
-
-
-
-
- {deployConfig ? 'Edit' : 'Connect'}
-
-
+
+ {SVC_SETTINGS_GROUPS.map(g => (
+
+
{g.label}
+ {g.items.map(s => (
+
setSection(s.id)}
+ >
+
+ {s.label}
+
+ ))}
-
-
+ ))}
+
- {/* Environment Configuration */}
-
-
Environment
-
-
-
- Environment Type
-
- {app.has_linked_app
- ? 'This app is linked. Unlink to change environment type.'
- : 'Set how this application is used in your workflow.'}
-
-
-
- {app.has_linked_app ? (
-
- {envLabels[app.environment_type] || app.environment_type}
-
- ) : (
-
-
-
-
-
- Standalone
- Development
- Staging
- Production
-
-
+
+ {/* Environment Configuration */}
+ {section === 'environment' && (
+
+
Environment
+
+
+
+ Environment Type
+
+ {app.has_linked_app
+ ? 'This app is linked. Unlink to change environment type.'
+ : 'Set how this application is used in your workflow.'}
+
+
+
+ {app.has_linked_app ? (
+
+ {envLabels[app.environment_type] || app.environment_type}
+
+ ) : (
+
+
+
+
+
+ Standalone
+ Development
+ Staging
+ Production
+
+
+ )}
+ {savingEnvironment && Saving... }
+
+
+
+ {app.has_linked_app && (
+
+
+ Linked Application
+
+ Unlinking will reset both apps to standalone mode.
+
+
+
+
+ {unlinking ? 'Unlinking...' : 'Unlink'}
+
+
+
)}
- {savingEnvironment &&
Saving... }
+ )}
- {app.has_linked_app && (
-
-
- Linked Application
-
- Unlinking will reset both apps to standalone mode.
-
-
-
-
- {unlinking ? 'Unlinking...' : 'Unlink'}
-
+ {/* Repository Configuration */}
+ {section === 'repository' && (
+
+
Repository
+
+
+
+ Connected Repository
+
+ {deployConfig
+ ? `${deployConfig.repo_url} (${deployConfig.branch || 'main'})`
+ : 'No repository connected'}
+
+
+
+
+ {deployConfig ? 'Edit' : 'Connect'}
+
+
- )}
-
-
+
+ )}
- {/* Danger Zone */}
-
-
Danger Zone
-
- {deleting ? 'Deleting...' : 'Delete Service'}
-
- }
- />
+ {/* Danger Zone */}
+ {section === 'danger' && (
+
+
Danger Zone
+
+ {deleting ? 'Deleting...' : 'Delete Service'}
+
+ }
+ />
+
+ )}
);
diff --git a/frontend/src/styles/pages/_service-detail.scss b/frontend/src/styles/pages/_service-detail.scss
index 9b19a388..412d9ab4 100644
--- a/frontend/src/styles/pages/_service-detail.scss
+++ b/frontend/src/styles/pages/_service-detail.scss
@@ -719,12 +719,81 @@ h3.svc-eyebrow {
}
}
-// Settings tab within service detail
+// Settings tab within service detail — grouped left sub-nav + content pane,
+// mirroring the WordPress detail page's settings layout (.wp-settings).
.svc-settings {
- max-width: 820px;
+ display: grid;
+ grid-template-columns: 200px 1fr;
+ gap: $space-4;
+ align-items: start;
+
+ @media (max-width: $breakpoint-md) {
+ grid-template-columns: 1fr;
+ }
+
+ &__nav {
+ display: flex;
+ flex-direction: column;
+ gap: 2px;
+ position: sticky;
+ top: $space-4;
+
+ @media (max-width: $breakpoint-md) {
+ position: static;
+ flex-direction: row;
+ flex-wrap: wrap;
+ }
+ }
+
+ // Grouped left nav — an uppercase mono label per group.
+ &__group + &__group {
+ margin-top: $space-4;
+ }
+
+ &__grouplabel {
+ padding: 0 12px;
+ margin-bottom: 6px;
+ font-family: var(--mono);
+ font-size: 10px;
+ font-weight: $font-weight-semibold;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ color: var(--text-faint);
+ }
+
+ &__navitem {
+ display: flex;
+ align-items: center;
+ gap: 9px;
+ padding: 9px 12px;
+ border: none;
+ border-radius: 8px;
+ background: none;
+ color: var(--text-dim);
+ font-size: 13.5px;
+ font-weight: $font-weight-medium;
+ text-align: left;
+ cursor: pointer;
+ transition: background 0.14s, color 0.14s;
+
+ svg { color: var(--text-faint); flex-shrink: 0; }
+
+ &:hover { background: var(--surface-hover); color: var(--text); }
+ &.is-active {
+ background: var(--accent-bg);
+ color: var(--accent-bright);
+ svg { color: var(--accent-bright); }
+ }
+ }
+
+ &__content {
+ min-width: 0;
+ }
&__section {
margin-bottom: $space-6;
+
+ &:last-child { margin-bottom: 0; }
}
&__section-title {