feat(phase 3d auto-tag): backfill area tags, bulk-edit UI, soft-delete cleanup
- migration 0012: one-shot populate empty tags from each item's area-roots (so chips on /?tag=work etc. actually filter the 40+ mai-backfilled rows) - migration 0013: cleanup 12 orphan item_links + BEFORE-UPDATE trigger that cascades soft-delete to item_links going forward — closes the data drift that made TestItemsUnifiedSurfacesMaiPointer fail since 3c - /admin/bulk page: flat filter+checkbox list with one-tx Apply for add/ remove tag, set management, set status. Per-row inline chip add/remove via /admin/bulk/chip. Reuses tree_filter URL params 1:1. - design.md §3.2 + §4.1 updated; tag+management section notes 0012 - bulk + tag-backfill + soft-delete-cascade tests cover the new surface
This commit is contained in:
@@ -133,6 +133,34 @@ func New(s *store.Store, logger *slog.Logger) (*Server, error) {
|
||||
return nil, fmt.Errorf("parse login: %w", err)
|
||||
}
|
||||
pages["login"] = loginTmpl
|
||||
|
||||
// Bulk-edit page + its fragment + per-row chip cells. The chip cells share
|
||||
// definitions with bulk_section so we parse them together every time.
|
||||
bulkTmpl, err := template.New("bulk").Funcs(funcs).ParseFS(templatesFS,
|
||||
"templates/layout.tmpl",
|
||||
"templates/bulk.tmpl",
|
||||
"templates/bulk_section.tmpl",
|
||||
)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse bulk: %w", err)
|
||||
}
|
||||
pages["bulk"] = bulkTmpl
|
||||
bulkSection, err := template.New("bulk_section").Funcs(funcs).ParseFS(templatesFS, "templates/bulk_section.tmpl")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse bulk_section: %w", err)
|
||||
}
|
||||
pages["bulk_section"] = bulkSection
|
||||
bulkChipTags, err := template.New("bulk_chip_tags").Funcs(funcs).ParseFS(templatesFS, "templates/bulk_section.tmpl")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse bulk_chip_tags: %w", err)
|
||||
}
|
||||
pages["bulk_chip_tags"] = bulkChipTags
|
||||
bulkChipMgmt, err := template.New("bulk_chip_mgmt").Funcs(funcs).ParseFS(templatesFS, "templates/bulk_section.tmpl")
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse bulk_chip_mgmt: %w", err)
|
||||
}
|
||||
pages["bulk_chip_mgmt"] = bulkChipMgmt
|
||||
|
||||
return &Server{Store: s, pages: pages, Logger: logger}, nil
|
||||
}
|
||||
|
||||
@@ -146,6 +174,9 @@ func (s *Server) Routes() http.Handler {
|
||||
mux.HandleFunc("GET /new", s.handleNewForm)
|
||||
mux.HandleFunc("POST /new", s.handleNewSubmit)
|
||||
mux.HandleFunc("GET /admin/classify", s.handleClassify)
|
||||
mux.HandleFunc("GET /admin/bulk", s.handleBulk)
|
||||
mux.HandleFunc("POST /admin/bulk/apply", s.handleBulkApply)
|
||||
mux.HandleFunc("POST /admin/bulk/chip", s.handleBulkChip)
|
||||
mux.HandleFunc("GET /admin/caldav", s.handleCalDAVAdmin)
|
||||
mux.HandleFunc("POST /admin/caldav/link", s.handleCalDAVLink)
|
||||
mux.HandleFunc("POST /admin/caldav/unlink", s.handleCalDAVUnlink)
|
||||
@@ -569,6 +600,8 @@ func (s *Server) render(w http.ResponseWriter, name string, data map[string]any)
|
||||
entry = "tree-section"
|
||||
case "documents_section":
|
||||
entry = "documents-section"
|
||||
case "bulk_section":
|
||||
entry = "bulk-section"
|
||||
}
|
||||
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
if err := t.ExecuteTemplate(w, entry, data); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user