fix: workspace resolution via ArcGIS listLayer + seed UATs from uat.json

- resolveWorkspace: use listLayer() instead of listLayerByWhere() with
  hardcoded field names. Auto-discovers admin field (ADMIN_UNIT_ID/SIRUTA)
  from ArcGIS layer metadata via buildWhere().
- resolveWorkspace: persist WORKSPACE_ID to DB on first resolution for
  fast subsequent lookups.
- UATs POST: seed from uat.json (correct SIRUTA codes) instead of eTerra
  nomenclature API (nomenPk != SIRUTA, county nomenPk != WORKSPACE_ID).
- Remove eTerra nomenclature dependency from UATs endpoint.
- Fix activeJobs Set iteration error on container restart.
- Remove unused enrichedUatsFetched ref.
This commit is contained in:
AI Assistant
2026-03-06 21:24:51 +02:00
parent 1b72d641cd
commit 6b8feb9075
4 changed files with 107 additions and 210 deletions
@@ -284,7 +284,6 @@ export function ParcelSyncModule() {
const [siruta, setSiruta] = useState("");
const [workspacePk, setWorkspacePk] = useState<number | null>(null);
const uatRef = useRef<HTMLDivElement>(null);
const enrichedUatsFetched = useRef(false);
/* ── Export state ────────────────────────────────────────────── */
const [exportJobId, setExportJobId] = useState<string | null>(null);
@@ -328,11 +327,12 @@ export function ParcelSyncModule() {
// Load UATs from local DB (fast — no eTerra needed)
fetch("/api/eterra/uats")
.then((res) => res.json())
.then((data: { uats?: UatEntry[] }) => {
.then((data: { uats?: UatEntry[]; total?: number }) => {
if (data.uats && data.uats.length > 0) {
setUatData(data.uats);
} else {
// DB empty — fall back to static uat.json (no county/workspace)
// DB empty — seed from uat.json via POST, then load from uat.json
fetch("/api/eterra/uats", { method: "POST" }).catch(() => {});
fetch("/uat.json")
.then((res) => res.json())
.then((fallback: UatEntry[]) => setUatData(fallback))
@@ -358,32 +358,10 @@ export function ParcelSyncModule() {
}, [fetchSession]);
/* ════════════════════════════════════════════════════════════ */
/* Sync UATs from eTerra → DB on connect (lightweight check) */
/* (Sync effect removed — POST seeds from uat.json, no */
/* eTerra nomenclature needed. Workspace resolved lazily.) */
/* ════════════════════════════════════════════════════════════ */
useEffect(() => {
if (!session.connected || enrichedUatsFetched.current) return;
enrichedUatsFetched.current = true;
// POST triggers sync check — only does full fetch if data changed
fetch("/api/eterra/uats", { method: "POST" })
.then((res) => res.json())
.then((data: { synced?: boolean }) => {
if (data.synced) {
// Data changed — reload from DB
fetch("/api/eterra/uats")
.then((res) => res.json())
.then((fresh: { uats?: UatEntry[] }) => {
if (fresh.uats && fresh.uats.length > 0) {
setUatData(fresh.uats);
}
})
.catch(() => {});
}
})
.catch(() => {});
}, [session.connected]);
/* ════════════════════════════════════════════════════════════ */
/* UAT autocomplete filter */
/* ════════════════════════════════════════════════════════════ */