feat: extract Variables as first config tab in create and detail views
Environment Variables moved from Resources into a dedicated "Variables" tab, placed first in the tab order since it's the most commonly needed config when creating new apps. Tab order: - Create page: Variables | Monitoring | Resources - Detail page: Variables | Monitoring | Traces & Taps | Route Recording | Resources Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -175,7 +175,7 @@ function CreateAppView({ environments, selectedEnv }: { environments: Environmen
|
|||||||
const [newPort, setNewPort] = useState('');
|
const [newPort, setNewPort] = useState('');
|
||||||
const [envVars, setEnvVars] = useState<{ key: string; value: string }[]>([]);
|
const [envVars, setEnvVars] = useState<{ key: string; value: string }[]>([]);
|
||||||
|
|
||||||
const [configTab, setConfigTab] = useState<'monitoring' | 'resources'>('monitoring');
|
const [configTab, setConfigTab] = useState<'variables' | 'monitoring' | 'resources'>('variables');
|
||||||
const [busy, setBusy] = useState(false);
|
const [busy, setBusy] = useState(false);
|
||||||
const [step, setStep] = useState('');
|
const [step, setStep] = useState('');
|
||||||
|
|
||||||
@@ -309,10 +309,29 @@ function CreateAppView({ environments, selectedEnv }: { environments: Environmen
|
|||||||
|
|
||||||
{/* Config Tabs */}
|
{/* Config Tabs */}
|
||||||
<div className={styles.subTabs}>
|
<div className={styles.subTabs}>
|
||||||
|
<button className={`${styles.subTab} ${configTab === 'variables' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('variables')}>Variables</button>
|
||||||
<button className={`${styles.subTab} ${configTab === 'monitoring' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('monitoring')}>Monitoring</button>
|
<button className={`${styles.subTab} ${configTab === 'monitoring' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('monitoring')}>Monitoring</button>
|
||||||
<button className={`${styles.subTab} ${configTab === 'resources' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('resources')}>Resources</button>
|
<button className={`${styles.subTab} ${configTab === 'resources' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('resources')}>Resources</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{configTab === 'variables' && (
|
||||||
|
<>
|
||||||
|
{envVars.map((v, i) => (
|
||||||
|
<div key={i} className={styles.envVarRow}>
|
||||||
|
<Input disabled={busy} value={v.key} onChange={(e) => {
|
||||||
|
const next = [...envVars]; next[i] = { ...v, key: e.target.value }; setEnvVars(next);
|
||||||
|
}} className={styles.envVarKey} placeholder="KEY" />
|
||||||
|
<Input disabled={busy} value={v.value} onChange={(e) => {
|
||||||
|
const next = [...envVars]; next[i] = { ...v, value: e.target.value }; setEnvVars(next);
|
||||||
|
}} className={styles.envVarValue} placeholder="value" />
|
||||||
|
<button className={styles.envVarDelete} disabled={busy}
|
||||||
|
onClick={() => !busy && setEnvVars(envVars.filter((_, j) => j !== i))}>×</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
<Button size="sm" variant="secondary" disabled={busy} onClick={() => setEnvVars([...envVars, { key: '', value: '' }])}>+ Add Variable</Button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{configTab === 'monitoring' && (
|
{configTab === 'monitoring' && (
|
||||||
<div className={styles.configGrid}>
|
<div className={styles.configGrid}>
|
||||||
<span className={styles.configLabel}>Engine Level</span>
|
<span className={styles.configLabel}>Engine Level</span>
|
||||||
@@ -412,21 +431,6 @@ function CreateAppView({ environments, selectedEnv }: { environments: Environmen
|
|||||||
onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addPort(); } }} />
|
onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addPort(); } }} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SectionHeader>Environment Variables</SectionHeader>
|
|
||||||
{envVars.map((v, i) => (
|
|
||||||
<div key={i} className={styles.envVarRow}>
|
|
||||||
<Input disabled={busy} value={v.key} onChange={(e) => {
|
|
||||||
const next = [...envVars]; next[i] = { ...v, key: e.target.value }; setEnvVars(next);
|
|
||||||
}} className={styles.envVarKey} placeholder="KEY" />
|
|
||||||
<Input disabled={busy} value={v.value} onChange={(e) => {
|
|
||||||
const next = [...envVars]; next[i] = { ...v, value: e.target.value }; setEnvVars(next);
|
|
||||||
}} className={styles.envVarValue} placeholder="value" />
|
|
||||||
<button className={styles.envVarDelete} disabled={busy}
|
|
||||||
onClick={() => !busy && setEnvVars(envVars.filter((_, j) => j !== i))}>×</button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<Button size="sm" variant="secondary" disabled={busy} onClick={() => setEnvVars([...envVars, { key: '', value: '' }])}>+ Add Variable</Button>
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -647,7 +651,7 @@ function ConfigSubTab({ app, environment }: { app: App; environment?: Environmen
|
|||||||
const { data: processorToRoute = {} } = useProcessorRouteMapping(app.slug);
|
const { data: processorToRoute = {} } = useProcessorRouteMapping(app.slug);
|
||||||
const isProd = environment?.production ?? false;
|
const isProd = environment?.production ?? false;
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
const [configTab, setConfigTab] = useState<'monitoring' | 'traces' | 'recording' | 'resources'>('monitoring');
|
const [configTab, setConfigTab] = useState<'variables' | 'monitoring' | 'traces' | 'recording' | 'resources'>('variables');
|
||||||
|
|
||||||
const appRoutes: RouteSummary[] = useMemo(() => {
|
const appRoutes: RouteSummary[] = useMemo(() => {
|
||||||
if (!catalog) return [];
|
if (!catalog) return [];
|
||||||
@@ -840,12 +844,34 @@ function ConfigSubTab({ app, environment }: { app: App; environment?: Environmen
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className={styles.subTabs}>
|
<div className={styles.subTabs}>
|
||||||
|
<button className={`${styles.subTab} ${configTab === 'variables' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('variables')}>Variables</button>
|
||||||
<button className={`${styles.subTab} ${configTab === 'monitoring' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('monitoring')}>Monitoring</button>
|
<button className={`${styles.subTab} ${configTab === 'monitoring' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('monitoring')}>Monitoring</button>
|
||||||
<button className={`${styles.subTab} ${configTab === 'traces' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('traces')}>Traces & Taps</button>
|
<button className={`${styles.subTab} ${configTab === 'traces' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('traces')}>Traces & Taps</button>
|
||||||
<button className={`${styles.subTab} ${configTab === 'recording' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('recording')}>Route Recording</button>
|
<button className={`${styles.subTab} ${configTab === 'recording' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('recording')}>Route Recording</button>
|
||||||
<button className={`${styles.subTab} ${configTab === 'resources' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('resources')}>Resources</button>
|
<button className={`${styles.subTab} ${configTab === 'resources' ? styles.subTabActive : ''}`} onClick={() => setConfigTab('resources')}>Resources</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{configTab === 'variables' && (
|
||||||
|
<>
|
||||||
|
{envVars.map((v, i) => (
|
||||||
|
<div key={i} className={styles.envVarRow}>
|
||||||
|
<Input disabled={!editing} value={v.key} onChange={(e) => {
|
||||||
|
const next = [...envVars]; next[i] = { ...v, key: e.target.value }; setEnvVars(next);
|
||||||
|
}} className={styles.envVarKey} placeholder="KEY" />
|
||||||
|
<Input disabled={!editing} value={v.value} onChange={(e) => {
|
||||||
|
const next = [...envVars]; next[i] = { ...v, value: e.target.value }; setEnvVars(next);
|
||||||
|
}} className={styles.envVarValue} placeholder="value" />
|
||||||
|
<button className={styles.envVarDelete} disabled={!editing}
|
||||||
|
onClick={() => editing && setEnvVars(envVars.filter((_, j) => j !== i))}>×</button>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
{editing && (
|
||||||
|
<Button size="sm" variant="secondary" onClick={() => setEnvVars([...envVars, { key: '', value: '' }])}>+ Add Variable</Button>
|
||||||
|
)}
|
||||||
|
{envVars.length === 0 && !editing && <p className={styles.emptyNote}>No environment variables configured.</p>}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{configTab === 'monitoring' && (
|
{configTab === 'monitoring' && (
|
||||||
<div className={styles.configGrid}>
|
<div className={styles.configGrid}>
|
||||||
<span className={styles.configLabel}>Engine Level</span>
|
<span className={styles.configLabel}>Engine Level</span>
|
||||||
@@ -964,24 +990,6 @@ function ConfigSubTab({ app, environment }: { app: App; environment?: Environmen
|
|||||||
onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addPort(); } }} />
|
onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addPort(); } }} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Environment Variables */}
|
|
||||||
<SectionHeader>Environment Variables</SectionHeader>
|
|
||||||
{envVars.map((v, i) => (
|
|
||||||
<div key={i} className={styles.envVarRow}>
|
|
||||||
<Input disabled={!editing} value={v.key} onChange={(e) => {
|
|
||||||
const next = [...envVars]; next[i] = { ...v, key: e.target.value }; setEnvVars(next);
|
|
||||||
}} className={styles.envVarKey} />
|
|
||||||
<Input disabled={!editing} value={v.value} onChange={(e) => {
|
|
||||||
const next = [...envVars]; next[i] = { ...v, value: e.target.value }; setEnvVars(next);
|
|
||||||
}} className={styles.envVarValue} />
|
|
||||||
<button className={styles.envVarDelete} disabled={!editing}
|
|
||||||
onClick={() => editing && setEnvVars(envVars.filter((_, j) => j !== i))}>×</button>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
{editing && (
|
|
||||||
<Button size="sm" variant="secondary" onClick={() => setEnvVars([...envVars, { key: '', value: '' }])}>+ Add Variable</Button>
|
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|||||||
Reference in New Issue
Block a user