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'} - -
-
- -
+
-
+ ))} + - {/* 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} - - ) : ( - +
+ {/* 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} + + ) : ( + + )} + {savingEnvironment && Saving...} +
+
+ + {app.has_linked_app && ( +
+
+ Linked Application + + Unlinking will reset both apps to standalone mode. + +
+
+ +
+
)} - {savingEnvironment && Saving...}
+ )} - {app.has_linked_app && ( -
-
- Linked Application - - Unlinking will reset both apps to standalone mode. - -
-
- + {/* Repository Configuration */} + {section === 'repository' && ( +
+

Repository

+
+
+
+ Connected Repository + + {deployConfig + ? `${deployConfig.repo_url} (${deployConfig.branch || 'main'})` + : 'No repository connected'} + +
+
+ +
- )} -
-
+
+ )} - {/* 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 {