ZDDC/zddc/internal/apps/availability.go
ZDDC e7f6334daa chore: retire mdedit tool — markdown editor lives in browse now
mdedit/ is gone. Its functionality moved into browse's preview plugin
(browse/js/preview-markdown.js) — YAML front matter editing, outline,
and on-demand DOCX/HTML/PDF download all happen there. Browse is the
default_tool for working/ + reviewing/ as of the previous commit, so
existing URLs of the form /<project>/working land on browse without
operator action.

Removed:

  • mdedit/ source tree (Toast UI app, CSS, JS, template, build.sh)
  • zddc/internal/apps/embedded/mdedit.html (//go:embed blob)
  • tests/mdedit.spec.js + the "mdedit" project in playwright.config.js
  • mdedit entries in zddc/internal/apps/embed.go (//go:embed, var,
    switch case in EmbeddedBytes)
  • "mdedit" in zddc/internal/zddc/validate.go AppNames + the matching
    error-message app list
  • "mdedit.html" branch in zddc/internal/apps/handler.go MatchAppHTML
  • mdedit case in tests (handler_test.go, validate_test.go,
    zddchandler_test.go) — test fixtures now use browse/classifier
  • mdedit from build (per-tool build.sh loop, tool-list literals,
    composer cards) and shared/build-lib.sh ZDDC_RELEASE_TOOLS
  • mdedit from freshen-channel's tool list and usage banner
  • mdedit-specific paragraphs in AGENTS.md and ARCHITECTURE.md;
    Markdown Editor section in ARCHITECTURE.md rewritten to point at
    browse/js/preview-markdown.js
  • mdedit from CLAUDE.md, README.md, zddc/README.md tool lists

Historical mdedit_v*.html / mdedit_v*.html.sig files in
/srv/zddc/releases/ on the deploy host are immutable history — they
stay where they are. The next ./build release cut will simply not
produce new mdedit_v* artifacts.
2026-05-13 10:34:31 -05:00

87 lines
3.5 KiB
Go

package apps
import (
"path/filepath"
"strings"
"codeberg.org/VARASYS/ZDDC/zddc/internal/zddc"
)
// AppAvailableAt reports whether app's virtual HTML can be served at
// requestDir. Delegates to the .zddc cascade's available_tools union
// (zddc.IsToolAvailableAt). The convention previously hardcoded here
// now lives in defaults.zddc.yaml and is overridable per-directory
// by operators.
//
// Operators can always drop a real <name>.html file at any path to
// override — that path is served by the static handler regardless of
// this function's result. AppAvailableAt is consulted only when no
// real file exists.
//
// Landing is a special case: the cascade declares it available
// universally (since available_tools concat-merges from the root
// baseline), but the dispatcher only auto-serves landing at the
// deployment root. We enforce that here too so callers don't trip
// over project-deep landing requests.
func AppAvailableAt(root, requestDir, app string) bool {
root = filepath.Clean(root)
requestDir = filepath.Clean(requestDir)
if app == "landing" {
return requestDir == root
}
return zddc.IsToolAvailableAt(root, requestDir, app)
}
// DefaultAppAt returns the canonical default tool name for requestDir,
// or "" if no specific tool fits. Used by the dispatcher to decide
// which app to serve at a directory URL with no trailing slash —
// trailing-slash URLs serve the browse app for any directory.
//
// Rules (case-insensitive on canonical folder names):
//
// - <project>/archive/<party>/mdl/... → "tables"
// - <project>/archive/ → "archive"
// - <project>/archive/<party>/... → "archive"
// - <project>/staging/... → "transmittal"
// - <project>/working/... → "browse" (hosts the
// markdown editor plugin)
// - <project>/reviewing/... → "browse" (operates on the
// virtual aggregator listing)
// - any other directory → "" (no default)
//
// The mdl rule wins over the broader archive rule because the table
// editor is a more specific surface for browsing planned deliverables
// than the archive index. Note: the dir at archive/<party>/mdl/
// itself IS the table — its table.yaml + form.yaml + row YAMLs all
// live there together (self-contained directory).
//
// 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)
if requestDir == root {
return ""
}
rel, err := filepath.Rel(root, requestDir)
if err != nil || strings.HasPrefix(rel, "..") {
return ""
}
parts := strings.Split(rel, string(filepath.Separator))
if len(parts) < 2 {
// Project root itself — no default tool from the cascade.
// (Landing is handled separately by the dispatcher.)
return ""
}
return zddc.DefaultToolAt(root, requestDir)
}