Skip to content

Split the product edit tabs out of BaseProductController - #974

Merged
KrzysztofPajak merged 16 commits into
developfrom
refactor/split-base-product-controller
Oct 22, 2026
Merged

KrzysztofPajak merged 16 commits into
developfrom
refactor/split-base-product-controller

Conversation

@KrzysztofPajak

Copy link
Copy Markdown
Member

Part of the architecture backlog (item S5: god classes, BaseProductController)
Type: feature

Issue

Grand.Web.AdminShared/Controllers/BaseProductController.cs was 3396 lines with 140 actions and 11 constructor dependencies. Every tab of the product edit screen lived in it, so each panel's ProductController (Admin, Store, Vendor) carried the dependencies of every tab, the 5755-line test file shared one fixture, and any two changes to different tabs collided in the same file.

Solution

  • Twelve tab controllers, each a BaseProduct<Tab>Controller in AdminShared plus an Admin, Store and Vendor subclass with the same class attributes as that panel's ProductController:
    • ProductCategory, ProductCollection
    • ProductRelated (related, similar, cross-sell, recommended), ProductBundle, ProductAssociated
    • ProductPicture, ProductSpecification
    • ProductPrice (currency prices, tier prices)
    • ProductAttributeMapping (attributes, conditions, attribute values), ProductAttributeCombination (combinations and their tier prices)
    • ProductReservation, ProductBid
  • Each base controller carries [PermissionAuthorize(PermissionSystemName.Products)] and [AutoValidateAntiforgeryToken] and takes only the services its actions use. Action bodies moved unchanged.
  • ProductController keeps list, create, edit, delete, copy, required products, purchased with orders, reviews, export/import and bulk edit. BaseProductController is down to 685 lines and 7 dependencies.
  • The Vendor-only hooks moved with their actions: Invalid*AddPopupResult to Vendor's ProductRelatedController and ProductBundleController, AssociatedProductVendorId (and the IContextAccessor it needs) to Vendor's ProductAssociatedController.
  • Views: popups returned by a moved action live in that controller's view folder, Views/AdminShared/<Controller>/ (AttributeCombinationPopup in each panel's Areas/<Panel>/Views/ProductAttributeCombination/). The partials only those popups use moved with them: CreateOrUpdateTierPrice, TierPrice.StoreScope (including Vendor's override), WidgetZone.TierPrice.*, CreateOrUpdateProductAttributeValue, WidgetZone.AttributeValueButtons, ProductAttributes. The edit tabs point their Url.Action / asp-controller at the new controllers.
  • Tests: the fixture of BaseProductControllerTests became ProductControllerTestsBase<TController>, and each tab's tests moved to BaseProduct<Tab>ControllerTests unchanged. The panel attribute tests now run over all 13 product controllers, and a Vendor test checks that each Vendor hook is overridden where the action now lives (a lost override would compile and silently fall back to the Admin/Store behavior).

Breaking changes

  • Admin, Store and Vendor URLs of the product tab actions change their controller segment. Action names are unchanged: /Admin/Product/ProductPictureList is now /Admin/ProductPicture/ProductPictureList, and so on for every action listed above. A theme or plugin that links to one of these actions through "Product", or calls the URL directly, gets a 404 until it uses the new controller name.
  • A view override of one of the moved popups or partials under Views/Product/ is no longer picked up; it has to move to the new controller's folder.
  • BaseProductController's constructor lost IInventoryManageService, IProductReservationService, IAuctionService and IEnumTranslationService, and its tab actions and protected hooks moved to the new base controllers. Code outside this repository that subclasses it must follow.
  • Permissions, menu entries, localization keys and settings are unchanged.

Testing

  1. dotnet build GrandNode.slnx: no errors, no warnings in the files this PR changes.
  2. dotnet test for Grand.Web.Admin.Tests (1592), Grand.Web.Store.Tests (181) and Grand.Web.Vendor.Tests (53) pass. Before the change: 1580 / 169 / 35; the difference is only the new attribute and Vendor hook tests. No assertion was removed or weakened.
  3. Checked on a fresh install with sample data, as admin, as a store manager and as a vendor, on a product owned by that vendor and limited to the store: open the product edit page and click every tab. No request fails, no console error, no empty link. Every grid loads and every popup opens: required, related, similar, cross-sell, recommended, bundle and associated product popups, picture edit, specification attribute, tier price create/edit, attribute mapping, validation rules, condition, attribute value create/edit, associate product to attribute value, attribute combination. Generating and clearing attribute combinations works.

Copilot AI balanced review requested due to automatic review settings October 22, 2026 06:03

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

Comment thread src/Web/Grand.Web.AdminShared/Controllers/BaseProductReservationController.cs Dismissed
Comment thread src/Tests/Grand.Web.Admin.Tests/Controllers/BaseProductAssociatedControllerTests.cs Dismissed
Comment thread src/Tests/Grand.Web.Admin.Tests/Controllers/BaseProductAssociatedControllerTests.cs Dismissed
Comment thread src/Tests/Grand.Web.Admin.Tests/Controllers/BaseProductAssociatedControllerTests.cs Dismissed
Comment thread src/Tests/Grand.Web.Admin.Tests/Controllers/BaseProductAssociatedControllerTests.cs Dismissed
InsertAsync stamps CreatedOnUtc with the current time, so the dates the test gave were dropped and posts inserted in the same millisecond came back in any order.
Comment thread src/Tests/Grand.Web.Admin.Tests/Controllers/BaseProductPriceControllerTests.cs Dismissed
Comment thread src/Tests/Grand.Web.Admin.Tests/Controllers/BaseProductPriceControllerTests.cs Dismissed
Comment thread src/Tests/Grand.Web.Admin.Tests/Controllers/BaseProductAssociatedControllerTests.cs Dismissed
Comment thread src/Tests/Grand.Web.Admin.Tests/Controllers/BaseProductAssociatedControllerTests.cs Dismissed
@KrzysztofPajak
KrzysztofPajak merged commit d1ee724 into develop Oct 22, 2026
9 checks passed
@KrzysztofPajak
KrzysztofPajak deleted the refactor/split-base-product-controller branch October 22, 2026 17:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants