


























@@ -118,6 +118,13 @@ extension SettingsProTab {
118118119119var settingsListSection: some View {
120120VStack(spacing: 10) {
121+self.settingsListRow(
122+ icon: "checkmark.shield.fill",
123+ title: "Approvals",
124+ detail: self.approvalsDetail,
125+ route: .approvals,
126+ color: self.pendingApproval == nil ? .secondary : OpenClawBrand.warn,
127+ badgeValue: self.pendingApproval == nil ? nil : "1")
121128self.settingsListRow(
122129 icon: "person.2",
123130 title: "Permissions",
@@ -156,11 +163,13 @@ extension SettingsProTab {
156163 icon: String,
157164 title: String,
158165 detail: String,
159- route: SettingsRoute) -> some View
166+ route: SettingsRoute,
167+ color: Color = .secondary,
168+ badgeValue: String? = nil) -> some View
160169{
161170NavigationLink(value: route) {
162171HStack(spacing: 12) {
163-ProIconBadge(systemName: icon, color: .secondary)
172+ProIconBadge(systemName: icon, color: color)
164173VStack(alignment: .leading, spacing: 2) {
165174Text(title)
166175.font(.subheadline.weight(.semibold))
@@ -170,6 +179,9 @@ extension SettingsProTab {
170179.lineLimit(1)
171180}
172181Spacer(minLength: 8)
182+if let badgeValue {
183+ProValuePill(value: badgeValue, color: color)
184+}
173185Image(systemName: "chevron.right")
174186.font(.caption.weight(.semibold))
175187.foregroundStyle(.secondary)
@@ -189,6 +201,8 @@ extension SettingsProTab {
189201switch route {
190202case .gateway:
191203self.gatewayDestination
204+case .approvals:
205+self.approvalsDestination
192206case .permissions:
193207self.permissionsDestination
194208case .voice:
@@ -250,6 +264,90 @@ extension SettingsProTab {
250264}
251265}
252266267+var approvalsDestination: some View {
268+VStack(alignment: .leading, spacing: 14) {
269+self.detailStatusCard(
270+ icon: "checkmark.shield.fill",
271+ title: "Approvals",
272+ detail: self.pendingApproval == nil ? "No gateway actions are waiting for review." :
273+"Review the pending gateway action.",
274+ value: self.pendingApproval == nil ? "clear" : "1 waiting",
275+ color: self.pendingApproval == nil ? OpenClawBrand.ok : OpenClawBrand.warn)
276+277+self.approvalsReviewCard
278+}
279+}
280+281+var approvalsReviewCard: some View {
282+ProCard(radius: SettingsLayout.cardRadius) {
283+VStack(alignment: .leading, spacing: 12) {
284+if let pendingApproval {
285+VStack(spacing: 0) {
286+ForEach(Array(self.approvalItems.enumerated()), id: \.element.id) { index, item in
287+SettingsApprovalRow(item: item)
288+if index < self.approvalItems.count - 1 {
289+Divider().padding(.leading, 46)
290+}
291+}
292+}
293+294+if let errorText = self.appModel.pendingExecApprovalPromptErrorText {
295+Text(errorText)
296+.font(.caption2.weight(.medium))
297+.foregroundStyle(OpenClawBrand.danger)
298+}
299+300+HStack(spacing: 8) {
301+Button {
302+Task { await self.appModel.resolvePendingExecApprovalPrompt(decision: "allow-once") }
303+} label: {
304+Label("Allow", systemImage: "checkmark")
305+}
306+.buttonStyle(.borderedProminent)
307+.disabled(self.appModel.pendingExecApprovalPromptResolving)
308+309+if pendingApproval.allowsAllowAlways {
310+Button {
311+Task {
312+await self.appModel.resolvePendingExecApprovalPrompt(decision: "allow-always")
313+}
314+} label: {
315+Label("Always", systemImage: "checkmark.shield")
316+}
317+.buttonStyle(.bordered)
318+.disabled(self.appModel.pendingExecApprovalPromptResolving)
319+}
320+321+Button(role: .destructive) {
322+Task { await self.appModel.resolvePendingExecApprovalPrompt(decision: "deny") }
323+} label: {
324+Label("Deny", systemImage: "xmark")
325+}
326+.buttonStyle(.bordered)
327+.disabled(self.appModel.pendingExecApprovalPromptResolving)
328+329+Spacer(minLength: 0)
330+}
331+.controlSize(.small)
332+} else {
333+HStack(spacing: 12) {
334+ProIconBadge(systemName: "checkmark.shield.fill", color: OpenClawBrand.ok)
335+VStack(alignment: .leading, spacing: 3) {
336+Text("No approvals waiting")
337+.font(.subheadline.weight(.semibold))
338+Text(self
339+.gatewayConnected ? "Gateway requests will appear here." : "Connect to the gateway.")
340+.font(.caption)
341+.foregroundStyle(.secondary)
342+.lineLimit(2)
343+}
344+}
345+}
346+}
347+}
348+.padding(.horizontal, OpenClawProMetric.pagePadding)
349+}
350+253351var permissionsDestination: some View {
254352VStack(alignment: .leading, spacing: 14) {
255353self.toggleCard(
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。