Skip to content

Commit ff60011

Browse files
authored
Merge pull request #5301 from woocommerce/ea/add-telemetry-action
WC Tracker: Add telemetry action
2 parents 1ae6a14 + 152ca51 commit ff60011

File tree

22 files changed

+692
-2
lines changed

22 files changed

+692
-2
lines changed

Networking/Networking.xcodeproj/project.pbxproj

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,11 @@
343343
93D8BBFF226BC1DA00AD2EB3 /* me-settings.json in Resources */ = {isa = PBXBuildFile; fileRef = 93D8BBFE226BC1DA00AD2EB3 /* me-settings.json */; };
344344
93D8BC01226BC20600AD2EB3 /* AccountSettingsRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D8BC00226BC20600AD2EB3 /* AccountSettingsRemoteTests.swift */; };
345345
A69FE19D2588D70E0059A96B /* order-with-deleted-refunds.json in Resources */ = {isa = PBXBuildFile; fileRef = A69FE19C2588D70E0059A96B /* order-with-deleted-refunds.json */; };
346+
AE2D6623272A8F6E004A2C3A /* TelemetryRemoteTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE2D6622272A8F6E004A2C3A /* TelemetryRemoteTests.swift */; };
347+
AED8AEBA272A97B400663FCC /* null-data.json in Resources */ = {isa = PBXBuildFile; fileRef = AE2D6624272A941C004A2C3A /* null-data.json */; };
348+
AED8AEBC272A997500663FCC /* IgnoringResponseMapperTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AED8AEBB272A997500663FCC /* IgnoringResponseMapperTests.swift */; };
349+
AEF94585272974F2001DCCFB /* TelemetryRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF94584272974F2001DCCFB /* TelemetryRemote.swift */; };
350+
AEF9458B27297FF6001DCCFB /* IgnoringResponseMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AEF9458A27297FF6001DCCFB /* IgnoringResponseMapper.swift */; };
346351
B505F6CD20BEE37E00BB1B69 /* AccountMapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = B505F6CC20BEE37E00BB1B69 /* AccountMapper.swift */; };
347352
B505F6CF20BEE38B00BB1B69 /* Account.swift in Sources */ = {isa = PBXBuildFile; fileRef = B505F6CE20BEE38B00BB1B69 /* Account.swift */; };
348353
B505F6D120BEE39600BB1B69 /* AccountRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = B505F6D020BEE39600BB1B69 /* AccountRemote.swift */; };
@@ -911,6 +916,11 @@
911916
93D8BC00226BC20600AD2EB3 /* AccountSettingsRemoteTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountSettingsRemoteTests.swift; sourceTree = "<group>"; };
912917
9BD9C6C44CAC220B3C3B90B7 /* Pods-Networking.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Networking.release-alpha.xcconfig"; path = "../Pods/Target Support Files/Pods-Networking/Pods-Networking.release-alpha.xcconfig"; sourceTree = "<group>"; };
913918
A69FE19C2588D70E0059A96B /* order-with-deleted-refunds.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "order-with-deleted-refunds.json"; sourceTree = "<group>"; };
919+
AE2D6622272A8F6E004A2C3A /* TelemetryRemoteTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryRemoteTests.swift; sourceTree = "<group>"; };
920+
AE2D6624272A941C004A2C3A /* null-data.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "null-data.json"; sourceTree = "<group>"; };
921+
AED8AEBB272A997500663FCC /* IgnoringResponseMapperTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IgnoringResponseMapperTests.swift; sourceTree = "<group>"; };
922+
AEF94584272974F2001DCCFB /* TelemetryRemote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryRemote.swift; sourceTree = "<group>"; };
923+
AEF9458A27297FF6001DCCFB /* IgnoringResponseMapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IgnoringResponseMapper.swift; sourceTree = "<group>"; };
914924
B505F6CC20BEE37E00BB1B69 /* AccountMapper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountMapper.swift; sourceTree = "<group>"; };
915925
B505F6CE20BEE38B00BB1B69 /* Account.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Account.swift; sourceTree = "<group>"; };
916926
B505F6D020BEE39600BB1B69 /* AccountRemote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountRemote.swift; sourceTree = "<group>"; };
@@ -1345,6 +1355,7 @@
13451355
74002D6B2118B88200A63C19 /* SiteVisitStatsRemoteTests.swift */,
13461356
45ED4F13239E8F2E004F1BE3 /* TaxClassRemoteTests.swift */,
13471357
74CF5E8321402C04000CED0A /* TopEarnerStatsRemoteTests.swift */,
1358+
AE2D6622272A8F6E004A2C3A /* TelemetryRemoteTests.swift */,
13481359
026CF621237D7E61009563D4 /* ProductVariationsRemoteTests.swift */,
13491360
025CA2C5238F4F3500B05C81 /* ProductShippingClassRemoteTests.swift */,
13501361
02E7FFCA256218F600C53030 /* ShippingLabelRemoteTests.swift */,
@@ -1475,7 +1486,9 @@
14751486
029BA4EF255D7282006171FD /* ShippingLabelRemote.swift */,
14761487
D8EDFE1D25EE87F1003D2213 /* WCPayRemote.swift */,
14771488
FE28F6E5268429B6004465C7 /* UserRemote.swift */,
1489+
077F39D526A58E4500ABEADC /* SystemPluginsRemote.swift */,
14781490
077F39D526A58E4500ABEADC /* SystemStatusRemote.swift */,
1491+
AEF94584272974F2001DCCFB /* TelemetryRemote.swift */,
14791492
);
14801493
path = Remote;
14811494
sourceTree = "<group>";
@@ -1607,6 +1620,7 @@
16071620
022902D322E2436400059692 /* no_stats_permission_error.json */,
16081621
B5A24178217F98F600595DEF /* notifications-load-all.json */,
16091622
B554FA8C2180B59700C54DFF /* notifications-load-hashes.json */,
1623+
AE2D6624272A941C004A2C3A /* null-data.json */,
16101624
B5C6FCD520A3768900A4F8E4 /* order.json */,
16111625
02C254D62563999200A04423 /* order-shipping-labels.json */,
16121626
B559EBA920A0B5CD00836CD4 /* orders-load-all.json */,
@@ -1755,6 +1769,7 @@
17551769
45150A9D26836A57006922EA /* CountryListMapper.swift */,
17561770
B524193E21AC5FE400D6FC0A /* DotcomDeviceMapper.swift */,
17571771
24F98C572502EA8800F49B68 /* FeatureFlagMapper.swift */,
1772+
AEF9458A27297FF6001DCCFB /* IgnoringResponseMapper.swift */,
17581773
26B2F74424C5573F0065CCC8 /* LeaderboardListMapper.swift */,
17591774
020D07BD23D8570800FD9580 /* MediaListMapper.swift */,
17601775
D823D904223746CE00C90817 /* NewShipmentTrackingMapper.swift */,
@@ -1883,6 +1898,7 @@
18831898
74AB0AC921948CE4008220CD /* CommentResultMapperTests.swift */,
18841899
45150A9F26837357006922EA /* CountryListMapperTests.swift */,
18851900
B524194221AC622500D6FC0A /* DotcomDeviceMapperTests.swift */,
1901+
AED8AEBB272A997500663FCC /* IgnoringResponseMapperTests.swift */,
18861902
B554FA922180C17200C54DFF /* NoteHashListMapperTests.swift */,
18871903
B5C151BF217EE3FB00C7BDC1 /* NoteListMapperTests.swift */,
18881904
B5C6FCCC20A34B8300A4F8E4 /* OrderListMapperTests.swift */,
@@ -2193,6 +2209,7 @@
21932209
B53EF53621813681003E146F /* generic_success.json in Resources */,
21942210
31054718262E2F5E00C5C02B /* wcpay-payment-intent-requires-confirmation.json in Resources */,
21952211
D8FBFF2922D52AFB006E3336 /* order-stats-v4-year.json in Resources */,
2212+
AED8AEBA272A97B400663FCC /* null-data.json in Resources */,
21962213
02BA23CA22EEF62C009539E7 /* order-stats-v4-wcadmin-activated.json in Resources */,
21972214
45152819257A84A60076B03C /* product-attributes-all.json in Resources */,
21982215
45AB8B1324AA34CB00B5B36E /* product-tags-deleted.json in Resources */,
@@ -2550,6 +2567,7 @@
25502567
451A97C92609FF050059D135 /* ShippingLabelPackagesResponse.swift in Sources */,
25512568
029BA4F0255D7282006171FD /* ShippingLabelRemote.swift in Sources */,
25522569
B557DA0F20975E07005962F4 /* DotcomRequest.swift in Sources */,
2570+
AEF94585272974F2001DCCFB /* TelemetryRemote.swift in Sources */,
25532571
740211E321939C84002248DA /* CommentResultMapper.swift in Sources */,
25542572
CC9A24F42642CF37005DE56E /* ShippingLabelCreationEligibilityMapper.swift in Sources */,
25552573
45E3EEBB237009CF00A826AC /* ShippingLine.swift in Sources */,
@@ -2572,6 +2590,7 @@
25722590
26B2F74324C545D50065CCC8 /* Leaderboard.swift in Sources */,
25732591
458C6DE425AC72A1009B300D /* StoredProductSettings.swift in Sources */,
25742592
45150A9C2683417A006922EA /* StateOfACountry.swift in Sources */,
2593+
AEF9458B27297FF6001DCCFB /* IgnoringResponseMapper.swift in Sources */,
25752594
B59325C7217E22FC000B0E8E /* Note.swift in Sources */,
25762595
CE0A0F13223942D90075ED8D /* ProductImage.swift in Sources */,
25772596
D8FBFF0B22D3ADB1006E3336 /* OrderStatsRemoteV4.swift in Sources */,
@@ -2623,6 +2642,7 @@
26232642
74AB5B4D21AF354E00859C12 /* SiteAPIMapperTests.swift in Sources */,
26242643
93D8BC01226BC20600AD2EB3 /* AccountSettingsRemoteTests.swift in Sources */,
26252644
262E5AD5255ACD6F000B2416 /* PaymentGatewayListMapperTests.swift in Sources */,
2645+
AE2D6623272A8F6E004A2C3A /* TelemetryRemoteTests.swift in Sources */,
26262646
B5C151C0217EE3FB00C7BDC1 /* NoteListMapperTests.swift in Sources */,
26272647
026CF622237D7E61009563D4 /* ProductVariationsRemoteTests.swift in Sources */,
26282648
CCF48B802628BBC10034EA83 /* ShippingLabelAccountSettingsMapperTests.swift in Sources */,
@@ -2633,6 +2653,7 @@
26332653
B567AF3120A0FB8F00AB6C62 /* JetpackRequestTests.swift in Sources */,
26342654
7412A8F221B6E47A005D182A /* ReportRemoteTests.swift in Sources */,
26352655
7412A8EE21B6E335005D182A /* ReportOrderMapperTests.swift in Sources */,
2656+
AED8AEBC272A997500663FCC /* IgnoringResponseMapperTests.swift in Sources */,
26362657
74CF0A8C22414D7800DB993F /* ProductMapperTests.swift in Sources */,
26372658
45152815257A83DD0076B03C /* ProductAttributesRemoteTests.swift in Sources */,
26382659
B505F6D720BEE58800BB1B69 /* AccountRemoteTests.swift in Sources */,
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import Foundation
2+
3+
4+
/// Mapper: Ignore responses
5+
///
6+
struct IgnoringResponseMapper: Mapper {
7+
8+
func map(response: Data) throws -> Void {
9+
// Do nothing, accept any type of response, including null
10+
}
11+
}

Networking/Networking/Model/SiteAPI.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ public struct SiteAPI: Decodable, Equatable, GeneratedFakeable {
2727
return .none
2828
}
2929

30+
/// Check if telemetry reporting namespace is available
31+
///
32+
public var telemetryIsAvailable: Bool {
33+
return namespaces.contains(WooAPIVersion.wcTelemetry.rawValue)
34+
}
35+
3036
/// Decodable Conformance.
3137
///
3238
public init(from decoder: Decoder) throws {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import Foundation
2+
3+
4+
/// Site API: Remote Endpoints
5+
///
6+
public class TelemetryRemote: Remote {
7+
8+
/// Sends data to the telemetry endpoint via the Jetpack tunnel for the provided siteID.
9+
/// Response is expected to be null.
10+
///
11+
/// - Parameters:
12+
/// - siteID: Site for which we'll fetch the API settings.
13+
/// - versionString: App version to report.
14+
/// - completion: Closure to be executed upon completion.
15+
///
16+
public func sendTelemetry(for siteID: Int64, versionString: String, completion: @escaping (Result<Void, Error>) -> Void) {
17+
let path = "tracker"
18+
let parameters = ["platform": "ios", "version": versionString]
19+
let request = JetpackRequest(wooApiVersion: .wcTelemetry, method: .post, siteID: siteID, path: path, parameters: parameters)
20+
let mapper = IgnoringResponseMapper()
21+
22+
enqueue(request, mapper: mapper, completion: completion)
23+
}
24+
}

Networking/Networking/Settings/WooAPIVersion.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,11 @@ public enum WooAPIVersion: String {
3838
///
3939
case addOnsV1 = "wc-product-add-ons/v1"
4040

41+
/// WooCommerce Telemetry.
42+
/// Only works on WC 5.9.0 and up.
43+
///
44+
case wcTelemetry = "wc-telemetry"
45+
4146
/// Returns the path for the current API Version
4247
///
4348
var path: String {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import XCTest
2+
@testable import Networking
3+
4+
5+
/// IgnoringResponseMapper Unit Tests
6+
///
7+
class IgnoringResponseMapperTests: XCTestCase {
8+
9+
func test_null_data_does_not_error() throws {
10+
try mapData(from: "null-data")
11+
}
12+
13+
func test_non_null_data_does_not_error() throws {
14+
try mapData(from: "generic_success_data")
15+
}
16+
17+
func test_missing_data_envelope_does_not_error() throws {
18+
try mapData(from: "generic_success")
19+
}
20+
}
21+
22+
private extension IgnoringResponseMapperTests {
23+
24+
/// Runs EmptyResponseMapper on encoded data in `filename`
25+
///
26+
func mapData(from filename: String) throws {
27+
guard let response = Loader.contentsOf(filename) else {
28+
throw IgnoringResponseMapperTestsError.noFileFound
29+
}
30+
31+
try IgnoringResponseMapper().map(response: response)
32+
}
33+
34+
enum IgnoringResponseMapperTestsError: Error {
35+
case noFileFound
36+
}
37+
}
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import XCTest
2+
@testable import Networking
3+
4+
5+
/// TelemetryRemote Unit Tests
6+
///
7+
class TelemetryRemoteTests: XCTestCase {
8+
9+
/// Dummy Network Wrapper
10+
///
11+
let network = MockNetwork()
12+
13+
/// Dummy Site ID
14+
///
15+
let sampleSiteID: Int64 = 1234
16+
17+
/// Repeat always!
18+
///
19+
override func setUp() {
20+
network.removeAllSimulatedResponses()
21+
}
22+
23+
/// Verifies that sendTelemetry properly accepts null response.
24+
///
25+
func test_sendTelemetry_properly_accepts_null_response() throws {
26+
// Given
27+
let remote = TelemetryRemote(network: network)
28+
network.simulateResponse(requestUrlSuffix: "tracker", filename: "null-data")
29+
30+
// When
31+
let result: Result<Void, Error> = waitFor { promise in
32+
remote.sendTelemetry(for: self.sampleSiteID, versionString: "1.2") { result in
33+
promise(result)
34+
}
35+
}
36+
37+
// Then
38+
XCTAssertTrue(result.isSuccess)
39+
}
40+
41+
/// Verifies that sendTelemetry properly accepts non-null response.
42+
///
43+
func test_sendTelemetry_properly_accepts_non_null_response() throws {
44+
// Given
45+
let remote = TelemetryRemote(network: network)
46+
network.simulateResponse(requestUrlSuffix: "tracker", filename: "generic_success_data")
47+
48+
// When
49+
let result: Result<Void, Error> = waitFor { promise in
50+
remote.sendTelemetry(for: self.sampleSiteID, versionString: "1.2") { result in
51+
promise(result)
52+
}
53+
}
54+
55+
// Then
56+
XCTAssertTrue(result.isSuccess)
57+
}
58+
59+
/// Verifies that sendTelemetry properly relays Networking Layer errors.
60+
///
61+
func test_sendTelemetry_properly_relays_networking_errors() {
62+
// Given
63+
let remote = TelemetryRemote(network: network)
64+
65+
// When
66+
let result: Result<Void, Error> = waitFor { promise in
67+
remote.sendTelemetry(for: self.sampleSiteID, versionString: "1.2") { result in
68+
promise(result)
69+
}
70+
}
71+
72+
// Then
73+
XCTAssertTrue(result.isFailure)
74+
}
75+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"data": null
3+
}

Storage/Storage.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@
131131
9302E3A6220DC3AE00DA5018 /* CoreDataIterativeMigrator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9302E3A5220DC3AE00DA5018 /* CoreDataIterativeMigrator.swift */; };
132132
9302E3AC220E1CE900DA5018 /* CoreDataIterativeMigratorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9302E3AB220E1CE900DA5018 /* CoreDataIterativeMigratorTests.swift */; };
133133
933A27302222344D00C2143A /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = 933A272F2222344D00C2143A /* Logging.swift */; };
134+
AE93BE90272C0E9F001B55EA /* GeneralStoreSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE93BE8F272C0E9F001B55EA /* GeneralStoreSettings.swift */; };
134135
B505255420EE6914008090F5 /* StorageType+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B505255320EE6914008090F5 /* StorageType+Extensions.swift */; };
135136
B505F6DA20BEEA3200BB1B69 /* Account+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = B505F6D820BEEA3100BB1B69 /* Account+CoreDataProperties.swift */; };
136137
B505F6DB20BEEA3200BB1B69 /* Account+CoreDataClass.swift in Sources */ = {isa = PBXBuildFile; fileRef = B505F6D920BEEA3200BB1B69 /* Account+CoreDataClass.swift */; };
@@ -391,6 +392,7 @@
391392
933A272F2222344D00C2143A /* Logging.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Logging.swift; sourceTree = "<group>"; };
392393
93D8BBF9226A6B3200AD2EB3 /* Model 14.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Model 14.xcdatamodel"; sourceTree = "<group>"; };
393394
A3821B262583F14863740A37 /* Pods-Storage.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Storage.debug.xcconfig"; path = "../Pods/Target Support Files/Pods-Storage/Pods-Storage.debug.xcconfig"; sourceTree = "<group>"; };
395+
AE93BE8F272C0E9F001B55EA /* GeneralStoreSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralStoreSettings.swift; sourceTree = "<group>"; };
394396
AEBAAFAE2657C5AC00404651 /* Model 51.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Model 51.xcdatamodel"; sourceTree = "<group>"; };
395397
B505255320EE6914008090F5 /* StorageType+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "StorageType+Extensions.swift"; sourceTree = "<group>"; };
396398
B505F6D820BEEA3100BB1B69 /* Account+CoreDataProperties.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Account+CoreDataProperties.swift"; sourceTree = "<group>"; };
@@ -779,6 +781,7 @@
779781
028296EF237D404F00E84012 /* ProductVariation+CoreDataProperties.swift */,
780782
028296F0237D404F00E84012 /* GenericAttribute+CoreDataClass.swift */,
781783
028296F1237D404F00E84012 /* GenericAttribute+CoreDataProperties.swift */,
784+
AE93BE8F272C0E9F001B55EA /* GeneralStoreSettings.swift */,
782785
9302E3A8220DC7DF00DA5018 /* Mapping Models */,
783786
746A9D12214071EB0013F6FF /* MIGRATIONS.md */,
784787
B59E11D820A9D00C004121A4 /* WooCommerce.xcdatamodeld */,
@@ -1125,6 +1128,7 @@
11251128
D4466F5626D524FC003E931B /* Feature.swift in Sources */,
11261129
268BF6DB2642CBA6003948D8 /* Models+Copiable.generated.swift in Sources */,
11271130
D4ABCACF26D6E7E400CD18F4 /* Announcement.swift in Sources */,
1131+
AE93BE90272C0E9F001B55EA /* GeneralStoreSettings.swift in Sources */,
11281132
D87F61552265AA900031A13B /* PListFileStorage.swift in Sources */,
11291133
B5B914C620EFF03500F2F832 /* Site+CoreDataProperties.swift in Sources */,
11301134
45E462072684BCEE00011BF2 /* StateOfACountry+CoreDataClass.swift in Sources */,

Storage/Storage/Model/Copiable/Models+Copiable.generated.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,3 +30,18 @@ extension GeneralAppSettings {
3030
)
3131
}
3232
}
33+
34+
extension GeneralStoreSettings {
35+
public func copy(
36+
isTelemetryAvailable: CopiableProp<Bool> = .copy,
37+
telemetryLastReportedTime: NullableCopiableProp<Date> = .copy
38+
) -> GeneralStoreSettings {
39+
let isTelemetryAvailable = isTelemetryAvailable ?? self.isTelemetryAvailable
40+
let telemetryLastReportedTime = telemetryLastReportedTime ?? self.telemetryLastReportedTime
41+
42+
return GeneralStoreSettings(
43+
isTelemetryAvailable: isTelemetryAvailable,
44+
telemetryLastReportedTime: telemetryLastReportedTime
45+
)
46+
}
47+
}

0 commit comments

Comments
 (0)