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
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
objects = {

/* Begin PBXBuildFile section */
4F5945B82ED51C00003C5BDE /* InfoSectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F5945B72ED51C00003C5BDE /* InfoSectionView.swift */; };
4F95A89C2EA806E700C98D18 /* SalesforceAnalytics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F95A8962EA801DC00C98D18 /* SalesforceAnalytics.framework */; };
4F95A89D2EA806E700C98D18 /* SalesforceAnalytics.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4F95A8962EA801DC00C98D18 /* SalesforceAnalytics.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4F95A89F2EA806E900C98D18 /* SalesforceSDKCommon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4F95A8982EA801DC00C98D18 /* SalesforceSDKCommon.framework */; };
Expand Down Expand Up @@ -44,6 +45,7 @@
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */
4F5945B72ED51C00003C5BDE /* InfoSectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InfoSectionView.swift; sourceTree = "<group>"; };
4F95A8962EA801DC00C98D18 /* SalesforceAnalytics.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SalesforceAnalytics.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4F95A8982EA801DC00C98D18 /* SalesforceSDKCommon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SalesforceSDKCommon.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4F95A89A2EA801DC00C98D18 /* SalesforceSDKCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = SalesforceSDKCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
Expand Down Expand Up @@ -149,6 +151,7 @@
AUTH039 /* Views */ = {
isa = PBXGroup;
children = (
4F5945B72ED51C00003C5BDE /* InfoSectionView.swift */,
4FEBAF282EA9B91500D4880A /* RevokeView.swift */,
AUTH038 /* UserCredentialsView.swift */,
AUTH041 /* RestApiTestView.swift */,
Expand Down Expand Up @@ -246,6 +249,7 @@
4FEBAF292EA9B91500D4880A /* RevokeView.swift in Sources */,
AUTH049 /* JwtAccessView.swift in Sources */,
AUTH051 /* InfoRowView.swift in Sources */,
4F5945B82ED51C00003C5BDE /* InfoSectionView.swift in Sources */,
);
};
/* End PBXSourcesBuildPhase section */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@
})

// User Credentials Section
UserCredentialsView(isExpanded: $isUserCredentialsExpanded)
.id(refreshTrigger)
UserCredentialsView(isExpanded: $isUserCredentialsExpanded, refreshTrigger: refreshTrigger)

// JWT Access Token Details Section (if applicable)
if let credentials = UserAccountManager.shared.currentUserAccount?.credentials,
Expand Down Expand Up @@ -253,7 +252,7 @@

// Update the rootView with actual closures after init
self.rootView = SessionDetailView(
onChangeConsumerKey: { [weak self] in

Check warning on line 255 in native/SampleApps/AuthFlowTester/AuthFlowTester/ViewControllers/SessionDetailViewController.swift

View workflow job for this annotation

GitHub Actions / native-samples-pr (AuthFlowTester, ^18) / test-ios

variable 'self' was written to, but never read
// Alert is handled in SwiftUI
},
onSwitchUser: { [weak self] in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ struct InfoRowView: View {
.font(.caption)
.foregroundColor(.secondary)

if isSensitive && !isRevealed {
if isSensitive && !isRevealed && !value.isEmpty {
HStack {
Text(maskedValue)
.font(.system(.caption, design: .monospaced))
Expand All @@ -54,9 +54,8 @@ struct InfoRowView: View {
HStack {
Text(value.isEmpty ? "(empty)" : value)
.font(.system(.caption, design: .monospaced))
.foregroundColor(value.isEmpty ? .secondary : .primary)
Spacer()
if isSensitive {
if isSensitive && !value.isEmpty {
Button(action: { isRevealed.toggle() }) {
Image(systemName: "eye.slash")
.foregroundColor(.blue)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/*
InfoSectionView.swift
AuthFlowTester

Copyright (c) 2025-present, salesforce.com, inc. All rights reserved.

Redistribution and use of this software in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this list of conditions
and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice, this list of
conditions and the following disclaimer in the documentation and/or other materials provided
with the distribution.
* Neither the name of salesforce.com, inc. nor the names of its contributors may be used to
endorse or promote products derived from this software without specific prior written
permission of salesforce.com, inc.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

import SwiftUI

struct InfoSectionView<Content: View>: View {
let title: String
@Binding var isExpanded: Bool
let content: Content

init(title: String, isExpanded: Binding<Bool>, @ViewBuilder content: () -> Content) {
self.title = title
self._isExpanded = isExpanded
self.content = content()
}

var body: some View {
VStack(alignment: .leading, spacing: 8) {
Button(action: {
withAnimation {
isExpanded.toggle()
}
}) {
HStack {
Text(title)
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.primary)
Spacer()
Image(systemName: isExpanded ? "chevron.up" : "chevron.down")
.font(.caption2)
.foregroundColor(.secondary)
}
}
.padding(.horizontal, 8)
.padding(.vertical, 6)
.background(Color(.tertiarySystemBackground))
.cornerRadius(6)

if isExpanded {
content
.padding(.leading, 8)
}
}
}
}

Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,15 @@ import SwiftUI
import SalesforceSDKCore

struct RestApiTestView: View {
enum AlertType {
case success
case error(String)
}

@State private var isLoading = false
@State private var lastRequestResult: String = ""
@State private var isResultExpanded = false
@State private var alertType: AlertType?

let onRequestCompleted: () -> Void

Expand Down Expand Up @@ -59,57 +65,73 @@ struct RestApiTestView: View {
}
.disabled(isLoading)

// Result section - always visible
VStack(alignment: .leading, spacing: 8) {
Button(action: {
if !lastRequestResult.isEmpty {
// Response details section - collapsible
if !lastRequestResult.isEmpty {
VStack(alignment: .leading, spacing: 8) {
Button(action: {
withAnimation {
isResultExpanded.toggle()
}
}
}) {
HStack {
Text("Last Request Result:")
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.primary)
Spacer()
if !lastRequestResult.isEmpty {
}) {
HStack {
Text("Response Details")
.font(.subheadline)
.fontWeight(.semibold)
.foregroundColor(.primary)
Spacer()
Image(systemName: isResultExpanded ? "chevron.up" : "chevron.down")
.font(.caption)
.foregroundColor(.secondary)
}
}
}
.disabled(lastRequestResult.isEmpty)

if lastRequestResult.isEmpty {
Text("No request made yet")
.font(.system(.caption, design: .monospaced))
.foregroundColor(.secondary)
.padding(8)
.frame(maxWidth: .infinity, alignment: .leading)
.background(Color(.tertiarySystemBackground))
.cornerRadius(6)
}

if isResultExpanded {
ScrollView([.vertical, .horizontal], showsIndicators: true) {
Text(lastRequestResult)
.font(.system(.caption, design: .monospaced))
.foregroundColor(.primary)
.padding(8)
.frame(maxWidth: .infinity, alignment: .leading)
.textSelection(.enabled)
}
.frame(minHeight: 200, maxHeight: 400)
.background(Color(.systemGray6))
.cornerRadius(4)
} else if isResultExpanded {
ScrollView([.vertical, .horizontal], showsIndicators: true) {
Text(lastRequestResult)
.font(.system(.caption, design: .monospaced))
.foregroundColor(lastRequestResult.hasPrefix("✓") ? .green : .red)
.padding(8)
.frame(maxWidth: .infinity, alignment: .leading)
.textSelection(.enabled)
}
.frame(minHeight: 200, maxHeight: 400)
.background(Color(.systemGray6))
.cornerRadius(4)
}
.padding(.vertical, 4)
}
.padding(.vertical, 4)
}
.padding()
.background(Color(.secondarySystemBackground))
.cornerRadius(8)
.alert(item: Binding(
get: { alertType.map { AlertItem(type: $0) } },
set: { alertType = $0?.type }
)) { alertItem in
switch alertItem.type {
case .success:
return Alert(
title: Text("Request Successful"),
message: Text("The REST API request completed successfully. Expand 'Response Details' below to see the full response."),
dismissButton: .default(Text("OK"))
)
case .error(let message):
return Alert(
title: Text("Request Failed"),
message: Text(message),
dismissButton: .default(Text("OK"))
)
}
}
}

struct AlertItem: Identifiable {
let id = UUID()
let type: AlertType
}

// MARK: - REST API Request
Expand All @@ -118,22 +140,25 @@ struct RestApiTestView: View {
private func makeRestRequest() async {
isLoading = true
lastRequestResult = ""
isResultExpanded = false // Start collapsed

do {
let request = RestClient.shared.cheapRequest("v63.0")
let response = try await RestClient.shared.send(request: request)

// Request succeeded - pretty print the JSON
let prettyJSON = prettyPrintJSON(response.asString())
lastRequestResult = "✓ Success:\n\n\(prettyJSON)"
isResultExpanded = true // Auto-expand on new result
lastRequestResult = prettyJSON
alertType = .success
// Response starts collapsed - user can expand to see details

// Notify parent to refresh fields
onRequestCompleted()
} catch {
// Request failed
lastRequestResult = "✗ Error: \(error.localizedDescription)"
isResultExpanded = true // Auto-expand on error
lastRequestResult = error.localizedDescription
alertType = .error(error.localizedDescription)
// Error details start collapsed - user can expand to see details
}

isLoading = false
Expand Down
Loading
Loading