Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
207 changes: 1 addition & 206 deletions apps/decodex-app/Sources/DecodexApp/AccountPanelView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -283,10 +283,7 @@ struct AccountPanelView: View {
AccountTelemetryMatrixView(
aggregate: accountProfileAggregate,
usageEstimate: store.accountList?.usageEstimate,
accounts: store.accounts,
snapshot: displayableOperatorSnapshot,
updatedAt: store.operatorSnapshotUpdatedAt,
currentTime: currentTime
accounts: store.accounts
)
}

Expand Down Expand Up @@ -651,18 +648,9 @@ struct AccountPanelView: View {
AccountProfileAggregate.make(accounts: store.accounts)
}

private var displayableOperatorSnapshot: OperatorSnapshotResponse? {
guard let snapshot = store.operatorSnapshot, snapshot.shouldDisplayInPanel else {
return nil
}

return snapshot
}

private var telemetryMatrixIsVisible: Bool {
accountProfileAggregate != nil
|| store.accountList?.usageEstimate != nil
|| displayableOperatorSnapshot != nil
}

private var telemetryMatrixHeight: CGFloat {
Expand All @@ -677,10 +665,6 @@ struct AccountPanelView: View {
: AccountPanelLayout.telemetryPoolHeight
)
}
if let snapshot = displayableOperatorSnapshot {
rows.append(operatorTelemetryHeight(for: snapshot))
}

guard rows.isEmpty == false else {
return 0
}
Expand All @@ -690,19 +674,6 @@ struct AccountPanelView: View {
+ CGFloat(rows.count - 1) * AccountPanelLayout.telemetryRowSpacing
}

private func operatorTelemetryHeight(for snapshot: OperatorSnapshotResponse) -> CGFloat {
var rows: [CGFloat] = [AccountPanelLayout.telemetryOperatorMetricHeight]
if snapshot.activeRuns.isEmpty == false {
rows.append(AccountRunChipLayout.height)
}
if snapshot.warningSummary != nil {
rows.append(AccountPanelLayout.telemetryOperatorWarningHeight)
}

return rows.reduce(0, +)
+ CGFloat(rows.count - 1) * AccountPanelLayout.telemetryOperatorRowSpacing
}

private func displayName(for account: CodexAccount) -> String {
if emailsHidden {
return AccountDisplay.aliases(for: store.accounts)[account.id]
Expand Down Expand Up @@ -1471,9 +1442,6 @@ private enum AccountPanelLayout {
static let telemetryProfileHeight: CGFloat = 50
static let telemetryPoolHeight: CGFloat = 16
static let telemetryPoolMeasuredHeight: CGFloat = 29
static let telemetryOperatorMetricHeight: CGFloat = 16
static let telemetryOperatorWarningHeight: CGFloat = 16
static let telemetryOperatorRowSpacing: CGFloat = 4
static let noticeHeight: CGFloat = 44
static let minimumScrollableListHeight: CGFloat = 312

Expand Down Expand Up @@ -1669,9 +1637,6 @@ private struct AccountTelemetryMatrixView: View {
let aggregate: AccountProfileAggregate?
let usageEstimate: AccountUsageEstimate?
let accounts: [CodexAccount]
let snapshot: OperatorSnapshotResponse?
let updatedAt: Date?
let currentTime: Date
@Environment(\.colorScheme) private var colorScheme

var body: some View {
Expand All @@ -1683,14 +1648,6 @@ private struct AccountTelemetryMatrixView: View {
if let usageEstimate {
AccountPoolUsageEstimateView(estimate: usageEstimate, accounts: accounts)
}

if let snapshot {
OperatorStatusStripView(
snapshot: snapshot,
updatedAt: updatedAt,
currentTime: currentTime
)
}
}
.padding(.horizontal, AccountPanelLayout.telemetryHorizontalPadding)
.padding(.top, AccountPanelLayout.telemetryTopPadding)
Expand Down Expand Up @@ -2503,104 +2460,6 @@ struct NoticeView: View {
}
}

struct OperatorStatusStripView: View {
let snapshot: OperatorSnapshotResponse
let updatedAt: Date?
let currentTime: Date
private let liveFreshnessWindow: TimeInterval = 5
@Environment(\.colorScheme) private var colorScheme

var body: some View {
VStack(alignment: .leading, spacing: AccountPanelLayout.telemetryOperatorRowSpacing) {
HStack(spacing: 5) {
ForEach(Array(metrics.enumerated()), id: \.element.id) { index, metric in
OperatorFlowMetricView(metric: metric)

if index < metrics.count - 1 {
Spacer(minLength: 3)
}
}
}
.frame(height: 16)

if snapshot.activeRuns.isEmpty == false {
AccountRunSummaryView(runs: snapshot.activeRuns)
}

if let warning = snapshot.warningSummary {
HStack(alignment: .firstTextBaseline, spacing: 5) {
PanelMetricIconView(
symbol: "exclamationmark.circle",
tint: PanelPalette.warning(colorScheme).opacity(0.82)
)

Text(warning)
.font(PanelFont.metricLabel)
.foregroundStyle(PanelPalette.secondaryText(colorScheme))
.lineLimit(1)
.truncationMode(.tail)

Spacer(minLength: 4)

Text(refreshMeta)
.font(PanelFont.tertiary)
.foregroundStyle(PanelPalette.secondaryText(colorScheme).opacity(0.68))
.monospacedDigit()
.frame(minWidth: 38, alignment: .trailing)
}
.frame(height: 16)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}

private var metrics: [OperatorFlowMetric] {
[
OperatorFlowMetric(
title: "Intake",
value: snapshot.queuedCount,
unitSingular: "issue",
unitPlural: "issues",
tint: PanelPalette.secondaryText(colorScheme)
),
OperatorFlowMetric(
title: "Running",
value: snapshot.activeRunCount,
unitSingular: "lane",
unitPlural: "lanes",
tint: PanelPalette.routeAccent(colorScheme)
),
OperatorFlowMetric(
title: "Review",
value: snapshot.reviewCount,
unitSingular: "PR",
unitPlural: "PRs",
tint: PanelPalette.codexAccent(colorScheme)
),
OperatorFlowMetric(
title: "Landing",
value: snapshot.landingCount,
unitSingular: "PR",
unitPlural: "PRs",
tint: PanelPalette.landingAccent(colorScheme)
),
]
}

private var refreshMeta: String {
guard let updatedAt else {
return "WS live"
}

let age = max(0, Int(currentTime.timeIntervalSince(updatedAt).rounded()))
if TimeInterval(age) < liveFreshnessWindow {
return "live"
}

return "\(age)s ago"
}
}

struct OperatorLanePopoverView: View {
let run: OperatorRunStatus

Expand Down Expand Up @@ -3314,70 +3173,6 @@ struct OperatorLaneReadoutDivider: View {
}
}

struct OperatorFlowMetric: Identifiable {
let title: String
let value: Int
let unitSingular: String
let unitPlural: String
let tint: Color

init(
title: String,
value: Int,
unitSingular: String,
unitPlural: String,
tint: Color
) {
self.title = title
self.value = value
self.unitSingular = unitSingular
self.unitPlural = unitPlural
self.tint = tint
}

var id: String {
title
}

var unit: String {
value == 1 ? unitSingular : unitPlural
}

var fullText: String {
"\(title) \(value) \(unit)"
}
}

struct OperatorFlowMetricView: View {
let metric: OperatorFlowMetric
@Environment(\.colorScheme) private var colorScheme

var body: some View {
HStack(alignment: .firstTextBaseline, spacing: 3) {
Text(metric.title)
.font(PanelFont.usageLabel)
.foregroundStyle(PanelPalette.secondaryText(colorScheme).opacity(0.82))
.lineLimit(1)

Text("\(metric.value)")
.font(PanelFont.usageValue)
.foregroundStyle(valueTint)
.monospacedDigit()
.lineLimit(1)
.minimumScaleFactor(0.72)
}
.lineLimit(1)
.help(metric.fullText)
.accessibilityLabel(metric.fullText)
}

private var valueTint: Color {
metric.value > 0
? metric.tint
: PanelPalette.primaryText(colorScheme).opacity(colorScheme == .dark ? 0.76 : 0.66)
}
}

private struct PanelMetricIconView: View {
let symbol: String
let tint: Color
Expand Down
42 changes: 37 additions & 5 deletions apps/decodex/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -884,11 +884,25 @@ fn validate_env_var_name(field_name: &str, value: &str) -> Result<()> {
fn resolve_secret_env_var(field_name: &str, env_var: &str) -> Result<String> {
validate_env_var_name(field_name, env_var)?;

let value = env::var(env_var).map_err(|error| {
eyre::eyre!(
"Failed to read environment variable `{env_var}` referenced by `{field_name}`: {error}"
)
})?;
let value = match env::var(env_var) {
Ok(value) if !value.trim().is_empty() => value,
Ok(_) =>
if let Some(value) = resolve_secret_launchd_env_var(env_var) {
value
} else {
eyre::bail!(
"Environment variable `{env_var}` referenced by `{field_name}` must not be blank."
);
},
Err(error) =>
if let Some(value) = resolve_secret_launchd_env_var(env_var) {
value
} else {
return Err(eyre::eyre!(
"Failed to read environment variable `{env_var}` referenced by `{field_name}`: {error}"
));
},
};

if value.trim().is_empty() {
eyre::bail!(
Expand All @@ -899,6 +913,24 @@ fn resolve_secret_env_var(field_name: &str, env_var: &str) -> Result<String> {
Ok(value)
}

#[cfg(target_os = "macos")]
fn resolve_secret_launchd_env_var(env_var: &str) -> Option<String> {
let output = Command::new("/bin/launchctl").args(["getenv", env_var]).output().ok()?;

if !output.status.success() {
return None;
}

let value = String::from_utf8(output.stdout).ok()?.trim().to_owned();

if value.is_empty() { None } else { Some(value) }
}

#[cfg(not(target_os = "macos"))]
fn resolve_secret_launchd_env_var(_env_var: &str) -> Option<String> {
None
}

#[cfg(test)]
mod tests {
use std::{
Expand Down
Loading