Repository navigation
feat(categories): nest product and catalog categories up to three levels - #156
Merged
Merged
Conversation
…els (server) Product categories and catalog (menu) categories nest: Drinks › Coffee › Cold brew. A parent is in the same store or catalog and of the same kind, and a tree is at most three levels deep; CategoryTreeObserver refuses anything else with a 422 and moves a removed category's subcategories up a level. - Public categories carry parent (public id) and depth; with_subcategories lists the categories under each one; with_products&rollup=1 brings every product under a category. - Products filtered by a category (public category=, console category and category_slug) include its subcategories' products; category_direct=1 keeps an exact match. Public products carry their category's public id. - A catalog saves its categories as a tree (parent_uuid, or parent_key for a category created in the same save), validated whole and attached top-down; the public catalog payload gives each category's parent.
…n a modal The catalog editor's pencil button only renamed a category inline, so a menu category could not get an icon. It now opens the product category modal on the catalog category (name, description, icon upload). Changes stay on the page until the catalog is saved, like every other editor change; cancel restores them. A set icon shows in the category row, and Duplicate copies each category's description and icon. Catalog::setCategories() now writes description, icon, icon_color and icon_file_uuid when the payload carries them (left alone when it does not), and the catalog category resource returns icon and icon_color, plus icon_file_uuid on internal requests, so the editor's save round trip keeps them.
- Product categories: the category form has a parent picker (the store's tree, minus the category itself, its subcategories and anything past three levels); the sidebar's rows offer New subcategory up to the second level; the category page's header shows its path and rolled-up product count; the product form names each category option by its path. - Bulk move to category now shows the store's categories in tree order (the modal ignored the categories it was given and showed the network picker). - Catalog editor: categories show as a tree with indent, outdent, add subcategory and move within siblings; removing one moves its subcategories up; new categories carry a key so a subcategory can sit under one before it is saved; a duplicated catalog keeps its tree. - A refused parent (the server's 422) is shown and the form stays open.
The console builds the category tree and the parent picker from parent_uuid, which core's internal Category resource sends from 1.6.71 (core-api#316). Without it a nested category would read as top-level and be saved as one.
This was referenced Oct 15, 2026
Merged
The catalog editor's category edit modal (#155) replaces the inline rename; a new subcategory now opens in it to be named, and duplicating a catalog keeps both the tree and each category's description and icon.
6 of 16 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Product categories and catalog (menu) categories nest up to three levels, for example Drinks › Coffee › Cold brew. Opening a parent shows its own products plus those of every category under it. The customer app change is fleetbase/storefront-app#82.
Requires fleetbase/core-api#316 (core-api 1.6.71): the internal Category resource sends
parent_uuid, which the console builds its tree from.composer.jsonnow requires^1.6.71.Server
Support/CategoryTree(descendants, depth, height, whole-tree validation, top-down ordering).CategoryTreeObserveron the coreCategoryand onCatalogCategory: it refuses a bad parent with a 422 and moves a removed category's subcategories up a level.v1/categories):parent(public id) anddepth, from one query per store;with_subcategoriesnow really lists the categories under each one (it wrappedtoArray()rows before);with_products&rollup=1brings every product under a category.products?category=, plus the console'scategoryandcategory_slugfilters, include subcategories' products.category_direct=1keeps an exact match. Product's API cache now depends oncategory, so moving a category invalidates the rolled-up lists.category: the category's public id, so the app can group a parent's products by subcategory.setCategories()takes each category's parent byparent_uuid, or byparent_keyfor a category created in the same save;parent.Console
keyuntil saved;Tests
server/tests/Unit/Support/NestedCategoriesTest.phpcovers the tree rules, the observer, public categories (parent, depth, subcategories, rollup) and nested catalog saves;CustomerControllerContractsTest, which needs core-api 1.6.70 for the phone fix. My local vendor copy is 1.6.69; CI installs the current version.tests/unit/utils/category-tree-test.js;eslint,ember-template-lint,stylelint,fleetbase-intl-lintandphp-cs-fixer: clean.Not checked in the browser: the console dev server wasn't running locally.
API and docs
Categories:parent,depth,with_subcategories,rollup;Products:category=includes subcategories,category_direct, and the product'scategory;Catalogs: each category'sparent.storefront/catalog/categories.mdx(nesting, the three-level limit, rollup) and the food-truck menu docs.Labelled
needs-api-specandneeds-docs.Merge order
This branch includes #155 (the catalog-category edit modal), merged in with the conflicts resolved: a new subcategory opens in #155's modal to be named, and a duplicated catalog keeps both its tree and each category's description and icon. Merge #155 first, then this PR; its diff then shrinks to the nesting changes.