feat(podcasts): the rules page retires — the collection builder IS the filter builder (item 3.4)
The smart-collection editor at /collections/:id/rules now hosts the SAME builder island as All-Books (FilterBuilderRows — the rows markup extracted into one shared templ both mounts render; the shared filterBuilderExtra component). One vocabulary, one engine, one row UI; the collection differences are exactly three: the payload is the collection's scope (episode trees get the episode fields — books trees hide them), Apply writes the tree to the collection (PUT filter_tree through the validated write path), and a legacy rules array preloads as its CONVERTED tree (RulesToFilterTree rendered server-side) so the upgrade lands at the first Apply — read-compat never mutates data silently. Retired with the page: the per-rule CRUD endpoints and test-rules (their handler bodies, routes, api-docs rows, and the dead collections.ts island functions — the file's LIVE halves, the collection modal/navigate/ grid-refresh, stay; the dead rules half went). match-mode endpoint and preview survive (legacy channel + the dashboard custom-section-builder, flagged for its own migration). Contract-pin changelog documents the deletions per the asymmetry rule. The builder component gains collection mounts: scopeKey (the row universe for counts/apply), data-tree prefill, treeJSON (the apply wire with scope riding the top level), and an apply hook (the page owns the write; All-Books never sets one). ensureReadyRule defaults to the scope's first field instead of hardcoding author. Tests migrated onto trees: TestSmartCollections' live-membership / reject-mutations / include-auto / system-collection subtests now drive TREE collections; the deleted-endpoint subtests die with them.
This commit is contained in:
1 parent
eb68672390
commit
4f71eda6be
16 files changed
+518
-1422
No files matched your search
@@ -701,6 +701,29 @@ func registerFrontendRoutes(cfg *Config) {
|
||||
return renderErrorPage(c, "System collections cannot have rules", "not_allowed")
|
||||
}
|
||||
|
||||
// The editor's vocabulary + prefill (item 3.4): the unified
|
||||
// builder in the collection's scope. A stored tree renders as-is;
|
||||
// a legacy rules array preloads as its CONVERTED tree
|
||||
// (RulesToFilterTree) — the upgrade lands at the first Apply.
|
||||
scope := "books"
|
||||
treeJSON := "{}"
|
||||
if len(collection.FilterTree) > 0 {
|
||||
if t, perr := services.ParseFilterTree(string(collection.FilterTree)); perr == nil {
|
||||
scope = t.FilterScope()
|
||||
if b, merr := json.Marshal(t); merr == nil {
|
||||
treeJSON = string(b)
|
||||
}
|
||||
}
|
||||
} else if rules := cfg.CollectionHandler.CollectionService().ParseRules(collection.AutoAssignRules); len(rules) > 0 {
|
||||
if t, cerr := services.RulesToFilterTree(rules, collection.RuleMatchMode); cerr == nil {
|
||||
scope = t.FilterScope()
|
||||
if b, merr := json.Marshal(t); merr == nil {
|
||||
treeJSON = string(b)
|
||||
}
|
||||
}
|
||||
}
|
||||
fieldsJSON := templates.JSONArg(services.FilterFieldsPayload(scope))
|
||||
|
||||
colData := templates.CollectionData{
|
||||
ID: collectionID,
|
||||
Name: collection.Name,
|
||||
@@ -708,11 +731,11 @@ func registerFrontendRoutes(cfg *Config) {
|
||||
Color: utils.PgTextString(collection.Color),
|
||||
Icon: utils.PgTextString(collection.Icon),
|
||||
IsSystem: collection.IsSystemCollection.Bool,
|
||||
IsSmart: cfg.CollectionHandler.CollectionService().IsSmartCollection(collection.AutoAssignRules),
|
||||
IsSmart: services.IsCollectionSmart(collection),
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = templates.CollectionRules(user, colData).Render(c.Request().Context(), &buf)
|
||||
err = templates.CollectionRules(user, colData, fieldsJSON, treeJSON, scope).Render(c.Request().Context(), &buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user