setName(e.target.value)} placeholder="e.g. Payment Gateway" disabled={busy} />
+
+
Identity & Artifact
+
+
Application Name
+
setName(e.target.value)} placeholder="e.g. Payment Gateway" disabled={busy} />
-
External URL
-
/{env?.slug ?? '...'}/{slug || '...'}/
+
External URL
+
/{env?.slug ?? '...'}/{slug || '...'}/
-
Environment
-
@@ -334,7 +338,8 @@ function CreateAppView({ environments, selectedEnv }: { environments: Environmen
/>
{configTab === 'variables' && (
- <>
+
+
Variables
{envVars.map((v, i) => (
{
@@ -348,68 +353,71 @@ function CreateAppView({ environments, selectedEnv }: { environments: Environmen
))}
- >
+
)}
{configTab === 'monitoring' && (
-
-
Engine Level
-
setEngineLevel(e.target.value)}
- options={[{ value: 'NONE', label: 'NONE' }, { value: 'MINIMAL', label: 'MINIMAL' }, { value: 'REGULAR', label: 'REGULAR' }, { value: 'COMPLETE', label: 'COMPLETE' }]} />
+
+
Monitoring
+
+
Engine Level
+
setEngineLevel(e.target.value)}
+ options={[{ value: 'NONE', label: 'NONE' }, { value: 'MINIMAL', label: 'MINIMAL' }, { value: 'REGULAR', label: 'REGULAR' }, { value: 'COMPLETE', label: 'COMPLETE' }]} />
- Payload Capture
- setPayloadCapture(e.target.value)}
- options={[{ value: 'NONE', label: 'NONE' }, { value: 'INPUT', label: 'INPUT' }, { value: 'OUTPUT', label: 'OUTPUT' }, { value: 'BOTH', label: 'BOTH' }]} />
+ Payload Capture
+ setPayloadCapture(e.target.value)}
+ options={[{ value: 'NONE', label: 'NONE' }, { value: 'INPUT', label: 'INPUT' }, { value: 'OUTPUT', label: 'OUTPUT' }, { value: 'BOTH', label: 'BOTH' }]} />
- Max Payload Size
-
- setPayloadSize(e.target.value)} className={styles.inputMd} />
- setPayloadUnit(e.target.value)} className={styles.inputXl}
- options={[{ value: 'bytes', label: 'bytes' }, { value: 'KB', label: 'KB' }, { value: 'MB', label: 'MB' }]} />
-
+ Max Payload Size
+
+ setPayloadSize(e.target.value)} className={styles.inputMd} />
+ setPayloadUnit(e.target.value)} className={styles.inputXl}
+ options={[{ value: 'bytes', label: 'bytes' }, { value: 'KB', label: 'KB' }, { value: 'MB', label: 'MB' }]} />
+
- App Log Level
- setAppLogLevel(e.target.value)}
- options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
+ App Log Level
+ setAppLogLevel(e.target.value)}
+ options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
- Agent Log Level
- setAgentLogLevel(e.target.value)}
- options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
+ Agent Log Level
+ setAgentLogLevel(e.target.value)}
+ options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
- Metrics
-
- !busy && setMetricsEnabled(!metricsEnabled)} disabled={busy} />
- {metricsEnabled ? 'Enabled' : 'Disabled'}
- Interval
- setMetricsInterval(e.target.value)} className={styles.inputXs} />
- s
-
+ Metrics
+
+ !busy && setMetricsEnabled(!metricsEnabled)} disabled={busy} />
+ {metricsEnabled ? 'Enabled' : 'Disabled'}
+ Interval
+ setMetricsInterval(e.target.value)} className={styles.inputXs} />
+ s
+
- Sampling Rate
- setSamplingRate(e.target.value)} className={styles.inputLg} />
+ Sampling Rate
+ setSamplingRate(e.target.value)} className={styles.inputLg} />
- Compress Success
-
- !busy && setCompressSuccess(!compressSuccess)} disabled={busy} />
- {compressSuccess ? 'Enabled' : 'Disabled'}
-
+ Compress Success
+
+ !busy && setCompressSuccess(!compressSuccess)} disabled={busy} />
+ {compressSuccess ? 'Enabled' : 'Disabled'}
+
- Replay
-
- !busy && setReplayEnabled(!replayEnabled)} disabled={busy} />
- {replayEnabled ? 'Enabled' : 'Disabled'}
-
+ Replay
+
+ !busy && setReplayEnabled(!replayEnabled)} disabled={busy} />
+ {replayEnabled ? 'Enabled' : 'Disabled'}
+
- Route Control
-
-
!busy && setRouteControlEnabled(!routeControlEnabled)} disabled={busy} />
- {routeControlEnabled ? 'Enabled' : 'Disabled'}
+ Route Control
+
+ !busy && setRouteControlEnabled(!routeControlEnabled)} disabled={busy} />
+ {routeControlEnabled ? 'Enabled' : 'Disabled'}
+
)}
{configTab === 'resources' && (
- <>
+
Container Resources
Memory Limit
@@ -472,7 +480,7 @@ function CreateAppView({ environments, selectedEnv }: { environments: Environmen
{sslOffloading ? 'Enabled' : 'Disabled'}
- >
+
)}
);
@@ -615,70 +623,84 @@ function OverviewSubTab({ app, deployments, versions, environments, envMap, sele
[environments, selectedEnv],
);
+ type DeploymentRow = Deployment & {
+ dEnv: Environment | undefined;
+ version: AppVersion | undefined;
+ isSelectedEnv: boolean;
+ canAct: boolean;
+ canStart: boolean;
+ configChanged: boolean;
+ url: string;
+ };
+
+ const deploymentRows: DeploymentRow[] = useMemo(() => deployments.map((d) => {
+ const dEnv = envMap.get(d.environmentId);
+ const version = versions.find((v) => v.id === d.appVersionId);
+ const isSelectedEnv = !selectedEnvId || d.environmentId === selectedEnvId;
+ const canAct = isSelectedEnv && (d.status === 'RUNNING' || d.status === 'STARTING');
+ const canStart = isSelectedEnv && d.status === 'STOPPED';
+ const configChanged = canAct && !!d.deployedAt && new Date(app.updatedAt) > new Date(d.deployedAt);
+ const url = dEnv ? `/${dEnv.slug}/${app.slug}/` : '';
+ return { ...d, dEnv, version, isSelectedEnv, canAct, canStart, configChanged, url };
+ }), [deployments, envMap, versions, selectedEnvId, app]);
+
+ const deploymentColumns: Column
[] = useMemo(() => [
+ { key: 'environmentId', header: 'Environment', render: (_v, row) => (
+
+
+
+ )},
+ { key: 'appVersionId', header: 'Version', render: (_v, row) => (
+
+
+
+ )},
+ { key: 'status', header: 'Status', render: (_v, row) => (
+
+
+
+
+ )},
+ { key: 'replicaStates', header: 'Replicas', render: (_v, row) => (
+
+ {row.replicaStates && row.replicaStates.length > 0
+ ? {row.replicaStates.filter((r) => r.status === 'RUNNING').length}/{row.replicaStates.length}
+ : <>{'—'}>}
+
+ )},
+ { key: 'url' as any, header: 'URL', render: (_v, row) => (
+
+ {row.status === 'RUNNING'
+ ? {row.url}
+ : {row.url}}
+
+ )},
+ { key: 'deployedAt', header: 'Deployed', render: (_v, row) => (
+
+ {row.deployedAt ? timeAgo(row.deployedAt) : '—'}
+
+ )},
+ { key: 'actions' as any, header: '', render: (_v, row) => (
+
+ {row.configChanged && }
+ {row.canAct && }
+ {row.canStart && }
+ {!row.isSelectedEnv && switch env to manage}
+
+ )},
+ ], [onDeploy, onStop]);
+
return (
<>
- Deployments
- {deployments.length === 0 && No deployments yet.
}
- {deployments.length > 0 && (
-
-
-
- | Environment |
- Version |
- Status |
- Replicas |
- URL |
- Deployed |
- Actions |
-
-
-
- {deployments.map((d) => {
- const dEnv = envMap.get(d.environmentId);
- const version = versions.find((v) => v.id === d.appVersionId);
- const isSelectedEnv = !selectedEnvId || d.environmentId === selectedEnvId;
- const canAct = isSelectedEnv && (d.status === 'RUNNING' || d.status === 'STARTING');
- const canStart = isSelectedEnv && d.status === 'STOPPED';
- const configChanged = canAct && d.deployedAt && new Date(app.updatedAt) > new Date(d.deployedAt);
- const url = dEnv ? `/${dEnv.slug}/${app.slug}/` : '';
-
- return (
-
- |
-
- |
- |
-
-
-
- |
-
- {d.replicaStates && d.replicaStates.length > 0 ? (
-
- {d.replicaStates.filter((r) => r.status === 'RUNNING').length}/{d.replicaStates.length}
-
- ) : '—'}
- |
-
- {d.status === 'RUNNING' ? (
- {url}
- ) : (
- {url}
- )}
- |
- {d.deployedAt ? timeAgo(d.deployedAt) : '—'} |
-
- {configChanged && }
- {canAct && }
- {canStart && }
- {!isSelectedEnv && switch env to manage}
- |
-
- );
- })}
-
-
- )}
+
+
+ Deployments
+
+ {deploymentRows.length === 0
+ ?
No deployments yet.
+ :
columns={deploymentColumns} data={deploymentRows} flush />
+ }
+
{deployments.filter((d) => d.deployStage).map((d) => (
{d.containerName}
@@ -949,7 +971,8 @@ function ConfigSubTab({ app, environment }: { app: App; environment?: Environmen
/>
{configTab === 'variables' && (
- <>
+
+
Variables
{envVars.map((v, i) => (
{
@@ -966,87 +989,91 @@ function ConfigSubTab({ app, environment }: { app: App; environment?: Environmen
)}
{envVars.length === 0 && !editing &&
No environment variables configured.
}
- >
+
)}
{configTab === 'monitoring' && (
-
-
Engine Level
-
setEngineLevel(e.target.value)}
- options={[{ value: 'NONE', label: 'NONE' }, { value: 'MINIMAL', label: 'MINIMAL' }, { value: 'REGULAR', label: 'REGULAR' }, { value: 'COMPLETE', label: 'COMPLETE' }]} />
+
+
Monitoring
+
+
Engine Level
+
setEngineLevel(e.target.value)}
+ options={[{ value: 'NONE', label: 'NONE' }, { value: 'MINIMAL', label: 'MINIMAL' }, { value: 'REGULAR', label: 'REGULAR' }, { value: 'COMPLETE', label: 'COMPLETE' }]} />
- Payload Capture
- setPayloadCapture(e.target.value)}
- options={[{ value: 'NONE', label: 'NONE' }, { value: 'INPUT', label: 'INPUT' }, { value: 'OUTPUT', label: 'OUTPUT' }, { value: 'BOTH', label: 'BOTH' }]} />
+ Payload Capture
+ setPayloadCapture(e.target.value)}
+ options={[{ value: 'NONE', label: 'NONE' }, { value: 'INPUT', label: 'INPUT' }, { value: 'OUTPUT', label: 'OUTPUT' }, { value: 'BOTH', label: 'BOTH' }]} />
- Max Payload Size
-
- setPayloadSize(e.target.value)} className={styles.inputMd} />
- setPayloadUnit(e.target.value)} className={styles.inputXl}
- options={[{ value: 'bytes', label: 'bytes' }, { value: 'KB', label: 'KB' }, { value: 'MB', label: 'MB' }]} />
-
+ Max Payload Size
+
+ setPayloadSize(e.target.value)} className={styles.inputMd} />
+ setPayloadUnit(e.target.value)} className={styles.inputXl}
+ options={[{ value: 'bytes', label: 'bytes' }, { value: 'KB', label: 'KB' }, { value: 'MB', label: 'MB' }]} />
+
- App Log Level
- setAppLogLevel(e.target.value)}
- options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
+ App Log Level
+ setAppLogLevel(e.target.value)}
+ options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
- Agent Log Level
- setAgentLogLevel(e.target.value)}
- options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
+ Agent Log Level
+ setAgentLogLevel(e.target.value)}
+ options={['TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR'].map((l) => ({ value: l, label: l }))} />
- Metrics
-
- editing && setMetricsEnabled(!metricsEnabled)} disabled={!editing} />
- {metricsEnabled ? 'Enabled' : 'Disabled'}
- Interval
- setMetricsInterval(e.target.value)} className={styles.inputXs} />
- s
-
+ Metrics
+
+ editing && setMetricsEnabled(!metricsEnabled)} disabled={!editing} />
+ {metricsEnabled ? 'Enabled' : 'Disabled'}
+ Interval
+ setMetricsInterval(e.target.value)} className={styles.inputXs} />
+ s
+
- Sampling Rate
- setSamplingRate(e.target.value)} className={styles.inputLg} />
+ Sampling Rate
+ setSamplingRate(e.target.value)} className={styles.inputLg} />
- Compress Success
-
- editing && setCompressSuccess(!compressSuccess)} disabled={!editing} />
- {compressSuccess ? 'Enabled' : 'Disabled'}
-
+ Compress Success
+
+ editing && setCompressSuccess(!compressSuccess)} disabled={!editing} />
+ {compressSuccess ? 'Enabled' : 'Disabled'}
+
- Replay
-
- editing && setReplayEnabled(!replayEnabled)} disabled={!editing} />
- {replayEnabled ? 'Enabled' : 'Disabled'}
-
+ Replay
+
+ editing && setReplayEnabled(!replayEnabled)} disabled={!editing} />
+ {replayEnabled ? 'Enabled' : 'Disabled'}
+
- Route Control
-
-
editing && setRouteControlEnabled(!routeControlEnabled)} disabled={!editing} />
- {routeControlEnabled ? 'Enabled' : 'Disabled'}
+ Route Control
+
+ editing && setRouteControlEnabled(!routeControlEnabled)} disabled={!editing} />
+ {routeControlEnabled ? 'Enabled' : 'Disabled'}
+
)}
{configTab === 'traces' && (
- <>
+
+
Traces & Taps
{tracedCount} traced · {tapCount} taps
{tracedTapRows.length > 0
?
columns={tracedTapColumns} data={tracedTapRows} pageSize={20} flush />
: No processor traces or taps configured.
}
- >
+
)}
{configTab === 'recording' && (
- <>
+
+
Route Recording
{recordingCount} of {routeRecordingRows.length} routes recording
{routeRecordingRows.length > 0
?
columns={routeRecordingColumns} data={routeRecordingRows} pageSize={20} flush />
: No routes found for this application.
}
- >
+
)}
{configTab === 'resources' && (
- <>
- {/* Container Resources */}
+
Container Resources
Memory Limit
@@ -1109,7 +1136,7 @@ function ConfigSubTab({ app, environment }: { app: App; environment?: Environmen
{sslOffloading ? 'Enabled' : 'Disabled'}
- >
+
)}
>
);