Files
openclaw/apps/ios/Sources/Design/AgentProTab+Destinations.swift
Colin Johnson f6e51ff99a feat(ios): refresh pro UI and gateway flows (#87367)
Summary:
- Replace the legacy iOS shell with Pro Command, Chat, Agents, and Settings tabs.
- Wire iOS chat/session/settings/diagnostics and realtime Talk flows through gateway-backed APIs.
- Add gateway/session and shared chat coverage for the new iOS flow.

Verification:
- git diff --check
- node scripts/run-vitest.mjs src/gateway/server.sessions.create.test.ts src/gateway/talk-realtime-relay.test.ts
- swift test --filter ChatViewModelTests (apps/shared/OpenClawKit)
- xcodebuild build for Nimrod's iPhone succeeded; install succeeded; launch was blocked because the phone was locked

Known follow-up:
- Preserve traceLevel in sessions.create parent runtime inheritance and keep the changelog credit in the follow-up patch.
2026-05-28 17:23:26 +03:00

149 lines
4.9 KiB
Swift

import OpenClawKit
import OpenClawProtocol
import SwiftUI
extension AgentProTab {
@ViewBuilder
func destination(for route: AgentRoute) -> some View {
switch route {
case .skills:
self.skillsDestination
case .nodes:
self.nodesDestination
case .cron:
self.cronDestination
case .usage:
self.usageDestination
case .dreaming:
self.dreamingDestination
}
}
var skillsDestination: some View {
ZStack {
OpenClawProBackground()
ScrollView {
VStack(alignment: .leading, spacing: 16) {
self.detailSummaryCard(
icon: "sparkles",
title: "Skills",
value: self.skillsValue,
detail: self.skillsDetail,
color: self.gatewayConnected ? OpenClawBrand.accent : .secondary)
self.skillsPolicyControls
self.skillsFilterField
self.clawHubSearchCard
self.skillsList
}
.padding(.vertical, 18)
}
.refreshable {
await self.refreshOverview(force: true)
}
.safeAreaPadding(.bottom, OpenClawProMetric.bottomScrollInset)
}
.navigationTitle("Skills")
.navigationBarTitleDisplayMode(.inline)
}
var nodesDestination: some View {
AgentProNodesDestination(
overview: self.overview,
gatewayConnected: self.gatewayConnected,
agentCount: self.appModel.gatewayAgents.count,
instancesValue: self.instancesValue,
instancesDetail: self.instancesDetail,
instancesColor: self.instancesColor,
refresh: {
await self.refreshOverview(force: true)
})
}
var cronDestination: some View {
ZStack {
OpenClawProBackground()
ScrollView {
VStack(alignment: .leading, spacing: 16) {
self.detailSummaryCard(
icon: "clock.arrow.circlepath",
title: "Cron Jobs",
value: self.cronValue,
detail: self.cronDetail,
color: self.cronColor)
self.cronStatusCard
self.cronJobsList(limit: nil)
}
.padding(.vertical, 18)
}
.refreshable {
await self.refreshOverview(force: true)
}
.safeAreaPadding(.bottom, OpenClawProMetric.bottomScrollInset)
}
.navigationTitle("Cron Jobs")
.navigationBarTitleDisplayMode(.inline)
}
var usageDestination: some View {
ZStack {
OpenClawProBackground()
ScrollView {
VStack(alignment: .leading, spacing: 16) {
self.detailSummaryCard(
icon: "chart.line.uptrend.xyaxis",
title: "Usage",
value: self.usageValue,
detail: self.usageDetail,
color: self.gatewayConnected ? OpenClawBrand.accent : .secondary)
self.usageTotalsCard
self.usageDailyList
}
.padding(.vertical, 18)
}
.refreshable {
await self.refreshOverview(force: true)
}
.safeAreaPadding(.bottom, OpenClawProMetric.bottomScrollInset)
}
.navigationTitle("Usage")
.navigationBarTitleDisplayMode(.inline)
}
var dreamingDestination: some View {
AgentProDreamingDestination(
overview: self.overview,
gatewayConnected: self.gatewayConnected,
overviewLoading: self.overviewLoading,
dreamingValue: self.dreamingValue,
dreamingDetail: self.dreamingDetail,
dreamingColor: self.dreamingColor,
refresh: {
await self.refreshOverview(force: true)
})
}
func detailSummaryCard(
icon: String,
title: String,
value: String,
detail: String,
color: Color) -> some View
{
ProCard(radius: AgentLayout.cardRadius) {
HStack(spacing: 12) {
ProIconBadge(systemName: icon, color: color)
VStack(alignment: .leading, spacing: 3) {
Text(title)
.font(.headline)
Text(detail)
.font(.caption)
.foregroundStyle(.secondary)
}
Spacer(minLength: 8)
ProValuePill(value: value, color: color)
}
}
.padding(.horizontal, OpenClawProMetric.pagePadding)
}
}