diff --git a/zddc/internal/apps/availability.go b/zddc/internal/apps/availability.go index 0feba33..f2c3174 100644 --- a/zddc/internal/apps/availability.go +++ b/zddc/internal/apps/availability.go @@ -3,6 +3,8 @@ package apps import ( "path/filepath" "strings" + + "codeberg.org/VARASYS/ZDDC/zddc/internal/zddc" ) // AppAvailableAt reports whether app's virtual HTML can be served at @@ -95,6 +97,16 @@ func inAncestorWithName(root, requestDir string, names ...string) bool { // // requestDir and root are absolute filesystem paths; requestDir must // be under root (otherwise "" is returned). +// +// Phase 3b: delegates to zddc.DefaultToolAt, which resolves the +// answer from the .zddc cascade (operator on-disk + embedded +// defaults). The convention previously hardcoded in the switch +// statement below now lives in zddc/internal/zddc/defaults.zddc.yaml +// and is overridable per-directory by operators. +// +// Project root itself (depth-1) still returns "" — the cascade +// doesn't declare a default tool for it (landing is handled by the +// dispatcher's own depth-1 check). func DefaultAppAt(root, requestDir string) string { root = filepath.Clean(root) requestDir = filepath.Clean(requestDir) @@ -107,25 +119,9 @@ func DefaultAppAt(root, requestDir string) string { } parts := strings.Split(rel, string(filepath.Separator)) if len(parts) < 2 { - // Project root itself — no default tool. + // Project root itself — no default tool from the cascade. + // (Landing is handled separately by the dispatcher.) return "" } - // The project segment is parts[0]; canonical folder is parts[1]. - canonical := strings.ToLower(parts[1]) - switch canonical { - case "archive": - // Inside archive/. Check for the mdl sub-case at depth 4 - // (parts: project, archive, party, mdl). - if len(parts) >= 4 && strings.EqualFold(parts[3], "mdl") { - return "tables" - } - return "archive" - case "staging": - return "transmittal" - case "working": - return "mdedit" - case "reviewing": - return "mdedit" - } - return "" + return zddc.DefaultToolAt(root, requestDir) } diff --git a/zddc/internal/apps/availability_test.go b/zddc/internal/apps/availability_test.go index 9b71294..19788bb 100644 --- a/zddc/internal/apps/availability_test.go +++ b/zddc/internal/apps/availability_test.go @@ -86,11 +86,13 @@ func TestDefaultAppAt(t *testing.T) { {root + "/Project-A/working/2026-06-15_x (DFT) - y", "mdedit"}, {root + "/Project-A/staging", "transmittal"}, {root + "/Project-A/staging/2026-06-15_x (DFT) - y", "transmittal"}, - // archive: at the archive root, party folders, and per-party - // subfolders (incoming/received/issued). + // archive: at the archive root, party folders default to archive. + // Per-party subfolders override per their function: + // incoming → classifier (the bulk-rename workflow) + // received / issued → archive (WORM record browser) {root + "/Project-A/archive", "archive"}, {root + "/Project-A/archive/Acme", "archive"}, - {root + "/Project-A/archive/Acme/incoming", "archive"}, + {root + "/Project-A/archive/Acme/incoming", "classifier"}, {root + "/Project-A/archive/Acme/issued", "archive"}, {root + "/Project-A/archive/Acme/received", "archive"}, // mdl wins over the broader archive rule. diff --git a/zddc/internal/handler/tables.html b/zddc/internal/handler/tables.html index 01a5479..c021d09 100644 --- a/zddc/internal/handler/tables.html +++ b/zddc/internal/handler/tables.html @@ -1300,7 +1300,7 @@ body.help-open .app-header {