Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
a3af88b
Wire local search strategy to factory and UI
joshheald Nov 19, 2025
3e82715
[Local catalog] Add explicit local catalog flag to factory
joshheald Nov 19, 2025
9afae0b
[Local catalog] Add analytics tracking for local search
joshheald Nov 19, 2025
9d13321
Add SearchDebounceStrategy enum for configurable search debouncing
joshheald Nov 20, 2025
3637ba0
Add debounceStrategy property to fetch strategy protocols
joshheald Nov 19, 2025
6acb890
Implement strategy-based debouncing in search UI
joshheald Nov 19, 2025
5dae392
Apply simple debouncing strategy to local product search
joshheald Nov 19, 2025
753ca24
Add tests for SearchDebounceStrategy
joshheald Nov 19, 2025
a81e1c7
Fix line length lint violations in SearchDebounceStrategyTests
joshheald Nov 20, 2025
b78f674
Fix SearchDebounceStrategyTests to use existing mocks
joshheald Nov 20, 2025
5548479
Merge PR2: includes SQL LIKE escaping fix
joshheald Nov 20, 2025
fe4b43c
Merge PR3: includes SQL LIKE escaping fix
joshheald Nov 20, 2025
ebe7eaa
Merge PR4: includes SQL LIKE escaping fix
joshheald Nov 20, 2025
b528346
Fix GRDBManager access when feature flag is disabled
joshheald Nov 20, 2025
976fff5
Merge PR3: GRDBManager access fix
joshheald Nov 20, 2025
f112338
Merge PR4: GRDBManager access fix
joshheald Nov 20, 2025
60f51e1
Add currentDebounceStrategy to mock controllers
joshheald Nov 20, 2025
d37005d
Fix lint
joshheald Nov 20, 2025
300cd55
Revert marketing version from 23.8 to 23.7
joshheald Nov 20, 2025
adf6e1f
Merge factory-integration branch with version fix
joshheald Nov 20, 2025
3aa198b
Merge analytics branch with version fix
joshheald Nov 20, 2025
0a668f1
Add loadingDelayThreshold to smart debounce strategy
joshheald Nov 20, 2025
9656089
Fix loading indicators not showing on first remote search
joshheald Nov 20, 2025
de5a625
Remove unnecessary comment
joshheald Nov 20, 2025
42335af
Fix test build
joshheald Nov 20, 2025
5e4e396
Fix periphery issues
joshheald Nov 20, 2025
2dc3ff6
Rename debounceStrategy to currentDebounceStrategy for clarity
joshheald Nov 20, 2025
5e690fb
Revert "Revert marketing version from 23.8 to 23.7"
joshheald Nov 21, 2025
9045166
Revert changes to marketing version
joshheald Nov 21, 2025
bc2a8ca
Merge branch 'woomob-1112-woo-poslocal-catalog-local-search-strategy'…
joshheald Nov 21, 2025
61837ab
Merge branch 'woomob-1112-woo-poslocal-catalog-factory-integration' i…
joshheald Nov 21, 2025
59f976f
Merge branch 'woomob-1112-woo-poslocal-catalog-analytics' into woomob…
joshheald Nov 21, 2025
3945526
Merge branch 'woomob-1112-woo-poslocal-catalog-local-search-strategy'…
joshheald Nov 21, 2025
d1bf02e
Merge branch 'woomob-1112-woo-poslocal-catalog-factory-integration' i…
joshheald Nov 21, 2025
bf2d785
Merge branch 'woomob-1112-woo-poslocal-catalog-analytics' into woomob…
joshheald Nov 21, 2025
992afaf
Escape the escape!
joshheald Nov 21, 2025
37b4e98
Don’t show intermittent cancellation errors in search
joshheald Nov 21, 2025
6d45ae6
Remove unnecessary `await` call
joshheald Nov 24, 2025
094c919
Use a default duration for smart debounce
joshheald Nov 24, 2025
6efe96f
Split up debounce logic
joshheald Nov 24, 2025
851119c
[Local catalog] Add configurable search debounce strategies (#16377)
joshheald Nov 24, 2025
5b71a8e
[Local catalog] Add analytics tracking for local search (#16376)
joshheald Nov 24, 2025
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 @@ -43,4 +43,13 @@ struct POSItemFetchAnalytics: POSItemFetchAnalyticsTracking {
)
)
}

/// Tracks when a local search results fetch completes
/// - Parameters:
/// - milliseconds: The time taken to fetch results in milliseconds
/// - totalItems: The total number of items found in the search
func trackSearchLocalResultsFetchComplete(millisecondsSinceRequestSent: Int, totalItems: Int) {
// TODO: Implement analytics event for local search results
// This will be implemented in the final PR
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import class Networking.ProductVariationsRemote
import class Networking.AlamofireNetwork
import struct Combine.AnyPublisher
import struct NetworkingCore.JetpackSite
import protocol Storage.GRDBManagerProtocol

public protocol PointOfSaleItemFetchStrategyFactoryProtocol {
func defaultStrategy(analytics: POSItemFetchAnalyticsTracking) -> PointOfSalePurchasableItemFetchStrategy
Expand All @@ -16,17 +17,23 @@ public final class PointOfSaleItemFetchStrategyFactory: PointOfSaleItemFetchStra
private let siteID: Int64
private let productsRemote: ProductsRemote
private let variationsRemote: ProductVariationsRemote
private let grdbManager: GRDBManagerProtocol?
private let isLocalCatalogEnabled: Bool

public init(siteID: Int64,
credentials: Credentials?,
selectedSite: AnyPublisher<JetpackSite?, Never>? = nil,
appPasswordSupportState: AnyPublisher<Bool, Never>? = nil) {
appPasswordSupportState: AnyPublisher<Bool, Never>? = nil,
grdbManager: GRDBManagerProtocol? = nil,
isLocalCatalogEnabled: Bool = false) {
self.siteID = siteID
let network = AlamofireNetwork(credentials: credentials,
selectedSite: selectedSite,
appPasswordSupportState: appPasswordSupportState)
self.productsRemote = ProductsRemote(network: network)
self.variationsRemote = ProductVariationsRemote(network: network)
self.grdbManager = grdbManager
self.isLocalCatalogEnabled = isLocalCatalogEnabled
}

public func defaultStrategy(analytics: POSItemFetchAnalyticsTracking) -> PointOfSalePurchasableItemFetchStrategy {
Expand All @@ -37,11 +44,19 @@ public final class PointOfSaleItemFetchStrategyFactory: PointOfSaleItemFetchStra
}
public func searchStrategy(searchTerm: String,
analytics: POSItemFetchAnalyticsTracking) -> PointOfSalePurchasableItemFetchStrategy {
PointOfSaleSearchPurchasableItemFetchStrategy(siteID: siteID,
searchTerm: searchTerm,
productsRemote: productsRemote,
variationsRemote: variationsRemote,
analytics: analytics)
// Use local search if explicitly enabled and GRDB manager is available
if isLocalCatalogEnabled, let grdbManager = grdbManager {
return PointOfSaleLocalSearchPurchasableItemFetchStrategy(siteID: siteID,
searchTerm: searchTerm,
grdbManager: grdbManager,
variationsRemote: variationsRemote,
analytics: analytics)
}
return PointOfSaleSearchPurchasableItemFetchStrategy(siteID: siteID,
searchTerm: searchTerm,
productsRemote: productsRemote,
variationsRemote: variationsRemote,
analytics: analytics)
}

public func popularStrategy(pageSize: Int = 10) -> PointOfSalePurchasableItemFetchStrategy {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,10 @@ public protocol POSItemFetchAnalyticsTracking {
/// - millisecondsSinceRequestSent: The time taken to fetch results in milliseconds
/// - totalItems: The total number of items found in the search
func trackSearchRemoteResultsFetchComplete(millisecondsSinceRequestSent: Int, totalItems: Int)

/// Tracks when a local search results fetch completes
/// - Parameters:
/// - millisecondsSinceRequestSent: The time taken to fetch results in milliseconds
/// - totalItems: The total number of items found in the search
func trackSearchLocalResultsFetchComplete(millisecondsSinceRequestSent: Int, totalItems: Int)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ final class MockPOSItemFetchAnalyticsTracking: POSItemFetchAnalyticsTracking {
private(set) var spyTotalItems: Int?
private(set) var spyMillisecondsSinceRequestSent: Int?
private(set) var spySearchTotalItems: Int?
private(set) var spyLocalSearchMilliseconds: Int?
private(set) var spyLocalSearchTotalItems: Int?

func trackItemsFetchComplete(totalItems: Int) {
spyTotalItems = totalItems
Expand All @@ -14,4 +16,9 @@ final class MockPOSItemFetchAnalyticsTracking: POSItemFetchAnalyticsTracking {
spyMillisecondsSinceRequestSent = millisecondsSinceRequestSent
spySearchTotalItems = totalItems
}

func trackSearchLocalResultsFetchComplete(millisecondsSinceRequestSent: Int, totalItems: Int) {
spyLocalSearchMilliseconds = millisecondsSinceRequestSent
spyLocalSearchTotalItems = totalItems
}
}
21 changes: 13 additions & 8 deletions WooCommerce/Classes/POS/TabBar/POSTabCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,16 +47,21 @@ final class POSTabCoordinator {
/// Local catalog eligibility service - created asynchronously during init
private(set) var localCatalogEligibilityService: POSLocalCatalogEligibilityServiceProtocol?

private lazy var posItemFetchStrategyFactory: PointOfSaleItemFetchStrategyFactory = {
/// Creates item fetch strategy factory with current local catalog eligibility
private func createItemFetchStrategyFactory(isLocalCatalogEnabled: Bool) -> PointOfSaleItemFetchStrategyFactory {
PointOfSaleItemFetchStrategyFactory(siteID: siteID,
credentials: credentials,
selectedSite: defaultSitePublisher,
appPasswordSupportState: isAppPasswordSupported)
}()
appPasswordSupportState: isAppPasswordSupported,
grdbManager: isLocalCatalogEnabled ? ServiceLocator.grdbManager : nil,
isLocalCatalogEnabled: isLocalCatalogEnabled)
}

private lazy var posPopularItemFetchStrategyFactory: PointOfSaleFixedItemFetchStrategyFactory = {
PointOfSaleFixedItemFetchStrategyFactory(fixedStrategy: posItemFetchStrategyFactory.popularStrategy())
}()
/// Creates popular item fetch strategy factory with current local catalog eligibility
private func createPopularItemFetchStrategyFactory(isLocalCatalogEnabled: Bool) -> PointOfSaleFixedItemFetchStrategyFactory {
let itemFactory = createItemFetchStrategyFactory(isLocalCatalogEnabled: isLocalCatalogEnabled)
return PointOfSaleFixedItemFetchStrategyFactory(fixedStrategy: itemFactory.popularStrategy())
}

private lazy var posCouponFetchStrategyFactory: PointOfSaleCouponFetchStrategyFactory = {
PointOfSaleCouponFetchStrategyFactory(siteID: siteID,
Expand Down Expand Up @@ -229,8 +234,8 @@ private extension POSTabCoordinator {
appPasswordSupportState: isAppPasswordSupported) {
let posView = PointOfSaleEntryPointView(
siteID: siteID,
itemFetchStrategyFactory: posItemFetchStrategyFactory,
popularItemFetchStrategyFactory: posPopularItemFetchStrategyFactory,
itemFetchStrategyFactory: createItemFetchStrategyFactory(isLocalCatalogEnabled: isLocalCatalogEligible),
popularItemFetchStrategyFactory: createPopularItemFetchStrategyFactory(isLocalCatalogEnabled: isLocalCatalogEligible),
couponProvider: posCouponProvider,
couponFetchStrategyFactory: posCouponFetchStrategyFactory,
orderListFetchStrategyFactory: POSOrderListFetchStrategyFactory(
Expand Down
15 changes: 9 additions & 6 deletions WooCommerce/WooCommerce.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16594,6 +16594,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 23.7;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we revert this change? Should be overwritten by code freeze through build_code_code_freeze(version_short: new_version), but I'm not positive will also override the lines newly added.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh I thought I caught this! I'll make sure it's dealt with in the merge, and if not, I'll fix it before it hits trunk. Thanks for pointing it out.

OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.alpha.woocommerce;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -16980,7 +16981,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 23.7;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
Expand Down Expand Up @@ -17025,7 +17026,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 23.7;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_FAST_MATH = YES;
Expand Down Expand Up @@ -17068,7 +17069,7 @@
"@loader_path/Frameworks",
);
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 23.7;
MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
MTL_FAST_MATH = YES;
Expand Down Expand Up @@ -17097,7 +17098,7 @@
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 23.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressAuthenticatorTests;
Expand All @@ -17120,7 +17121,7 @@
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 23.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressAuthenticatorTests;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand All @@ -17141,7 +17142,7 @@
GCC_C_LANGUAGE_STANDARD = gnu17;
GENERATE_INFOPLIST_FILE = YES;
LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
MARKETING_VERSION = 1.0;
MARKETING_VERSION = 23.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.WordPressAuthenticatorTests;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -17399,6 +17400,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 23.7;
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.woocommerce;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down Expand Up @@ -17428,6 +17430,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 23.7;
OTHER_SWIFT_FLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = com.automattic.woocommerce;
PRODUCT_NAME = "$(TARGET_NAME)";
Expand Down