satdetect-dev / templates /library_dda.html
coderuday21's picture
Cursor
Deploy latest uday app code to Hugging Face (skip research binaries).
c682b53
Raw History Blame Contribute Delete
22.2 kB
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Image Library — Vedangsoft Change Detection</title>
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css" integrity="sha256-p4NxAoJBhIIN+hmNHrzRCf9tD/miZyoHS5obTRR9BMY=" crossorigin="" />
<link rel="stylesheet" href="/static/css/style.css?v=35" />
<link rel="stylesheet" href="/static/css/dda.css?v=66" />
<link rel="stylesheet" href="/static/css/dda-modernist-sidebar.css?v=1" />
<link rel="stylesheet" href="/static/css/dda-modernist-library.css?v=2" />
</head>
<body>
<div class="app dda-app">
{% include "partials/navbar_dda.html" %}
<div class="dda-main-col">
{% include "partials/alerts_dda.html" %}
<section id="tab-library" class="dda-panel active" role="tabpanel">
<div class="dda-layout">
<aside class="dda-sidebar card">
<div class="card-header">
<h3>Image Library</h3>
<div class="dda-sidebar-actions">
<button type="button" class="btn btn-secondary btn-sm hidden" id="btn-manage-library" data-requires-permission="library:edit">Folders master</button>
<button type="button" class="btn btn-secondary btn-sm" id="btn-refresh-lib" data-requires-permission="library:view">Refresh</button>
</div>
</div>
<div id="lib-folder-path" class="dda-folder-path dim"></div>
<input type="search" id="lib-tree-search" class="dda-search" placeholder="Filter folders…" />
<div class="dda-tree-toolbar">
<button type="button" class="dda-tree-toolbar-btn" id="lib-tree-expand-all">Expand all</button>
<button type="button" class="dda-tree-toolbar-btn" id="lib-tree-collapse-all">Collapse all</button>
</div>
<p class="dim dda-tree-hint">Right-click a folder to add, rename, or remove. Drop files onto a folder to upload.</p>
<div id="lib-tree" class="dda-tree"><p class="dim">Loading…</p></div>
</aside>
<main class="dda-main">
<div class="card" id="upload-card">
<div class="card-header">
<h3>Upload images</h3>
<div class="dda-sidebar-actions">
<button type="button" class="btn btn-secondary btn-sm" id="btn-open-bulk-upload" data-requires-permission="library:create">Bulk upload (Excel)</button>
<button type="submit" form="form-tree-upload" class="btn btn-primary" id="btn-tree-upload" data-requires-permission="library:create" data-permission-mode="disable" data-permission-denied-title="Your role doesn't have permission to upload images.">Upload</button>
</div>
</div>
<p class="sub" id="upload-limit-hint">Select a folder and image type, then drop files here or browse. Only extensions allowed for the selected type are accepted.</p>
<form id="form-tree-upload" class="dda-upload-form">
<div class="location-row dda-upload-row">
<div class="form-group">
<label for="upload-node">Destination folder</label>
<select id="upload-node" required><option value="">— Select folder —</option></select>
</div>
<div class="form-group">
<label for="upload-image-type">Image type</label>
<select id="upload-image-type">
<option>GeoTIFF</option>
<option>PNG</option>
<option>JPEG</option>
</select>
</div>
<div class="form-group">
<label for="upload-year">Year</label>
<select id="upload-year">
<option value="">— Select year —</option>
</select>
</div>
<div class="form-group">
<label for="upload-source">Source</label>
<select id="upload-source">
<option value="">— Select source —</option>
<option value="satellite">Satellite</option>
<option value="drone">Drone</option>
</select>
</div>
<div class="form-group">
<label for="upload-zone">Zone / District <span class="dda-required-mark" title="Required">*</span></label>
<select id="upload-zone" aria-label="Select zone or district" required>
<option value="">— Select zone —</option>
</select>
</div>
<div class="form-group">
<label for="upload-village">Village / Location <span class="dda-required-mark" title="Required">*</span></label>
<select id="upload-village" aria-label="Select village or location" required>
<option value="">— Select village —</option>
</select>
</div>
<div class="form-group">
<label for="upload-capture-date">Capture date</label>
<input type="date" id="upload-capture-date" class="dda-date-input" />
</div>
<div class="form-group">
<label for="upload-manual-bounds">Geo bounds (W,S,E,N)</label>
<input type="text" id="upload-manual-bounds" placeholder="optional, e.g. 77.5,12.9,77.6,13.0" />
</div>
</div>
<p class="sub dim">A <strong>zone</strong> and <strong>village</strong> are required for every upload — images without a location are no longer accepted, so nothing shows up as "Unassigned."</p>
<div id="dda-upload-dropzone" class="dda-dropzone" tabindex="0">
<p class="dda-dropzone-title">Drag &amp; drop files or a folder</p>
<p class="dim" id="upload-accept-hint">GeoTIFF, PNG, or JPEG. Multiple files and nested folders are supported.</p>
<div class="dda-dropzone-actions">
<label class="btn btn-secondary btn-sm dda-file-btn">Choose images
<input type="file" id="upload-file" accept=".tif,.tiff,.png,.jpg,.jpeg" multiple />
</label>
<label class="btn btn-secondary btn-sm dda-file-btn">Choose folder
<input type="file" id="upload-folder" webkitdirectory multiple />
</label>
</div>
<p id="upload-file-summary" class="dim dda-upload-summary">No files selected.</p>
<p id="upload-type-error" class="dda-upload-type-error hidden" role="alert"></p>
</div>
<div id="upload-file-list-wrap" class="dda-upload-file-list-wrap hidden">
<table class="dda-upload-file-table" id="upload-file-table">
<thead>
<tr>
<th></th>
<th>Original name</th>
<th>Server filename</th>
<th>Type</th>
<th>Size</th>
</tr>
</thead>
<tbody id="upload-file-tbody"></tbody>
</table>
</div>
<div id="upload-progress" class="dda-upload-progress hidden">
<div class="dda-progress-bar"><div id="upload-progress-fill" class="dda-progress-fill"></div></div>
<span id="upload-progress-label" class="dim">Uploading…</span>
</div>
</form>
<details class="dda-storage-info">
<summary>Storage layout</summary>
<p class="sub" id="lib-instructions">Organize images in a configurable zone → area → year → type hierarchy.</p>
<pre id="lib-path-display" class="dda-path-code"></pre>
</details>
</div>
<div class="card" id="dda-area-pairs-card">
<div class="card-header">
<h3>Same-area pairs</h3>
<div class="dda-lib-grid-actions">
<span class="dim" id="dda-area-pairs-hint"></span>
<button type="button" class="btn btn-secondary btn-sm" id="btn-load-area-pairs">Load pairs</button>
</div>
</div>
<p class="sub">Each pair is exactly <strong>two images</strong>, never reused. Matching uses location, folder, capture date, filename, and geographic overlap. Oldest is <strong>Before</strong>, newest is <strong>After</strong>.</p>
<div id="dda-area-pairs" class="dda-area-pairs"><p class="dim">Click <strong>Load pairs</strong> to find same-area pairs for the current folder (kept off the initial page load so large libraries stay fast).</p></div>
<div class="pagination" id="dda-area-pairs-pagination"></div>
</div>
<div class="card">
<div class="card-header">
<h3 id="lib-grid-title">Images</h3>
<div class="dda-lib-grid-actions">
<button type="button" class="btn btn-secondary btn-sm" id="btn-lib-select-all">Select all</button>
<button type="button" class="btn btn-danger btn-sm" id="btn-lib-delete-selected" data-requires-permission="library:delete" disabled>Delete selected</button>
<button type="button" class="btn btn-secondary btn-sm" id="btn-lib-export-csv" data-requires-permission="library:view">Export CSV</button>
<button type="button" class="btn btn-secondary btn-sm" id="btn-lib-export-xlsx" data-requires-permission="library:view">Export Excel</button>
<input type="search" id="lib-filter" class="dda-search" placeholder="Search filenames…" />
</div>
</div>
<div class="dda-filter-bar" id="lib-filter-bar">
<label class="dda-filter-field">Year
<select id="lib-filter-year"><option value="">All</option></select>
</label>
<label class="dda-filter-field">Type
<select id="lib-filter-type">
<option value="">All</option>
<option>GeoTIFF</option>
<option>PNG</option>
<option>JPEG</option>
</select>
</label>
<label class="dda-filter-field">Zone
<select id="lib-filter-zone"><option value="">All</option></select>
</label>
<label class="dda-filter-field">Village
<select id="lib-filter-village"><option value="">All</option></select>
</label>
<label class="dda-filter-field">From
<input type="date" id="lib-filter-from" class="dda-date-input" />
</label>
<label class="dda-filter-field">To
<input type="date" id="lib-filter-to" class="dda-date-input" />
</label>
<button type="button" class="btn btn-ghost btn-sm" id="btn-lib-filter-clear">Clear</button>
</div>
<div id="lib-grid" class="dda-grid"><p class="dim">Select a node in the tree.</p></div>
<div class="pagination" id="lib-grid-pagination"></div>
<p class="sub dim">Click an image to view · use the delete button to remove from library</p>
</div>
</main>
</div>
</section>
</div>
</div>
<div id="dda-image-viewer-modal" class="dda-modal hidden" role="dialog" aria-modal="true">
<div class="dda-modal-panel card dda-image-viewer-panel">
<div class="card-header">
<h3 id="dda-image-viewer-title">Image</h3>
<div class="dda-image-viewer-actions">
<button type="button" class="btn btn-danger btn-sm" id="dda-image-delete-btn" data-requires-permission="library:delete">Delete</button>
<button type="button" class="btn btn-secondary btn-sm" id="dda-image-viewer-close">Close</button>
</div>
</div>
<div class="dda-image-viewer-body">
<div id="dda-image-viewer-meta" class="dim dda-image-viewer-meta"></div>
<p id="dda-image-viewer-status" class="dim dda-image-viewer-status"></p>
<div class="dda-viewer-mode-bar" role="tablist">
<button type="button" class="dda-view-btn active" id="dda-viewer-mode-preview" data-viewer-mode="preview">Preview</button>
<button type="button" class="dda-view-btn" id="dda-viewer-mode-map" data-viewer-mode="map">Map</button>
</div>
<div id="dda-image-viewer-preview-pane">
<div class="dda-image-viewer-wrap">
<img id="dda-image-viewer-img" alt="" />
</div>
</div>
<div id="dda-image-viewer-map-pane" class="dda-map-pane hidden">
<div class="dda-map-toolbar">
<label class="dda-map-field">
<span>Basemap</span>
<select id="dda-lib-basemap" aria-label="Basemap"></select>
</label>
<input type="url" id="dda-lib-xyz" class="dda-map-xyz hidden" placeholder="https://…/{z}/{x}/{y}.png" aria-label="Custom XYZ URL" />
<label class="dda-check"><input type="checkbox" id="dda-lib-overlay" checked /> TIF overlay</label>
<label class="dda-map-field dda-map-opacity">
<span>Opacity <em id="dda-lib-opacity-val">75%</em></span>
<input type="range" id="dda-lib-opacity" min="10" max="100" value="75" />
</label>
<button type="button" class="btn btn-secondary btn-sm" id="dda-lib-fit">Fit extent</button>
</div>
<p id="dda-library-map-status" class="dim dda-map-status"></p>
<div id="dda-library-map" class="dda-map-canvas"></div>
</div>
</div>
</div>
</div>
<div id="dda-manage-modal" class="dda-modal hidden" role="dialog" aria-labelledby="dda-manage-title">
<div class="dda-modal-panel card dda-manage-panel">
<div class="card-header">
<h3 id="dda-manage-title">Folders master</h3>
<button type="button" class="btn btn-secondary btn-sm" id="dda-manage-close">Close</button>
</div>
<p class="sub dim">Create, rename, move, or remove folders in the masters library. Images stay in the destination folder you pick on upload.</p>
<div class="dda-manage-section">
<h4>Add folder</h4>
<div class="location-row">
<select id="add-child-parent" aria-label="Parent folder"><option value="">— Root —</option></select>
<input type="text" id="add-node-name" placeholder="Folder name" />
<select id="add-node-type" aria-label="Folder type">
<option>Folder</option>
<option>Zone</option><option>Area</option><option>Year</option>
<option>Satellite Images</option><option>Drone Survey</option><option>Change Detection</option>
</select>
<button type="button" class="btn btn-primary btn-sm" id="btn-add-node" data-requires-permission="library:create">Add</button>
</div>
</div>
<div class="dda-manage-section">
<h4>Edit / move / remove</h4>
<select id="manage-node-select" aria-label="Folder to edit"></select>
<div class="location-row">
<input type="text" id="rename-node-name" placeholder="Rename to…" />
<button type="button" class="btn btn-secondary btn-sm" id="btn-rename-node" data-requires-permission="library:edit">Rename</button>
</div>
<div class="location-row">
<select id="move-parent" aria-label="Move under"><option value="">— Move to root —</option></select>
<button type="button" class="btn btn-secondary btn-sm" id="btn-move-node" data-requires-permission="library:edit">Move</button>
</div>
<label class="dda-check"><input type="checkbox" id="delete-files-check" /> Also delete files on disk</label>
<button type="button" class="btn btn-danger btn-sm" id="btn-delete-node" data-requires-permission="library:delete">Remove folder</button>
</div>
</div>
</div>
<div id="dda-bulk-upload-modal" class="dda-modal hidden" role="dialog" aria-labelledby="dda-bulk-upload-title">
<div class="dda-modal-panel card dda-manage-panel">
<div class="card-header">
<h3 id="dda-bulk-upload-title">Bulk upload (Excel)</h3>
<button type="button" class="btn btn-secondary btn-sm" id="dda-bulk-upload-close">Close</button>
</div>
<p class="sub dim">Paths in the Excel sheet are <strong>relative to this server’s Main folder</strong>. Fill General Folder / Zone / Village / Image Type in the sheet (or use the defaults below for blank cells). Each file can have its own server filename.</p>
<div class="dda-manage-section">
<h4>Main folder (this server)</h4>
<pre id="bulk-main-folder" class="dda-path-code">Loading…</pre>
</div>
<div class="dda-manage-section">
<h4>1. Get the template</h4>
<a class="btn btn-secondary btn-sm" id="btn-bulk-upload-template" href="/api/dda/tree/bulk-upload/template" download>Download Excel template</a>
</div>
<div class="dda-manage-section">
<h4>2. Defaults for blank Excel cells</h4>
<div class="location-row dda-upload-row">
<div class="form-group">
<label for="bulk-image-type">Image type</label>
<select id="bulk-image-type">
<option value="">— From Excel —</option>
<option>GeoTIFF</option>
<option>PNG</option>
<option>JPEG</option>
</select>
</div>
<div class="form-group">
<label for="bulk-year">Year</label>
<select id="bulk-year">
<option value="">— From Excel —</option>
</select>
</div>
<div class="form-group">
<label for="bulk-source">Source</label>
<select id="bulk-source">
<option value="">— From Excel —</option>
<option value="satellite">Satellite</option>
<option value="drone">Drone</option>
</select>
</div>
<div class="form-group">
<label for="bulk-zone">Zone / District</label>
<select id="bulk-zone">
<option value="">— From Excel —</option>
</select>
</div>
<div class="form-group">
<label for="bulk-village">Village / Location</label>
<select id="bulk-village">
<option value="">— From Excel —</option>
</select>
</div>
</div>
</div>
<div class="dda-manage-section">
<h4>3. Excel sheet + image files</h4>
<div class="location-row">
<label class="btn btn-secondary btn-sm dda-file-btn">Choose Excel file
<input type="file" id="bulk-upload-excel" accept=".xlsx" />
</label>
<span id="bulk-upload-excel-name" class="dim">No file selected.</span>
</div>
<div class="location-row">
<label class="btn btn-secondary btn-sm dda-file-btn">Choose image files
<input type="file" id="bulk-upload-files" accept=".tif,.tiff,.png,.jpg,.jpeg" multiple />
</label>
<span id="bulk-upload-files-name" class="dim">No files selected.</span>
</div>
<p id="bulk-upload-type-error" class="dda-upload-type-error hidden" role="alert"></p>
<div id="bulk-upload-file-list-wrap" class="dda-upload-file-list-wrap hidden">
<table class="dda-upload-file-table" id="bulk-upload-file-table">
<thead>
<tr>
<th>Original name</th>
<th>Server filename</th>
<th>Size</th>
</tr>
</thead>
<tbody id="bulk-upload-file-tbody"></tbody>
</table>
</div>
</div>
<div id="bulk-upload-progress" class="dda-upload-progress hidden">
<div class="dda-progress-bar"><div id="bulk-upload-progress-fill" class="dda-progress-fill"></div></div>
<span id="bulk-upload-progress-label" class="dim">Uploading…</span>
</div>
<div id="bulk-upload-result" class="dda-manage-section hidden">
<h4>Result</h4>
<div id="bulk-upload-summary"></div>
<div id="bulk-upload-errors"></div>
</div>
<div class="location-row">
<button type="button" class="btn btn-primary" id="btn-bulk-upload-submit" data-requires-permission="library:create">Upload</button>
</div>
</div>
</div>
<div id="dda-tree-menu" class="dda-tree-menu hidden" role="menu">
<button type="button" role="menuitem" data-tree-act="upload" data-requires-permission="library:create">Upload images here</button>
<button type="button" role="menuitem" data-tree-act="add" data-requires-permission="library:create">Add subfolder</button>
<button type="button" role="menuitem" data-tree-act="rename" data-requires-permission="library:edit">Rename</button>
<button type="button" role="menuitem" data-tree-act="delete" data-requires-permission="library:delete">Remove</button>
<button type="button" role="menuitem" data-tree-act="manage" data-requires-permission="library:edit">Open Folders master</button>
</div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js" integrity="sha256-20nQCchB9co0qIjJZRGuk2/Z9VM+kNiyxNV1lvTlZBo=" crossorigin=""></script>
<script src="/static/js/dda/shared.js?v=14"></script>
<script src="/static/js/dda/app.js?v=32"></script>
<script src="/static/js/dda/tree.js?v=8"></script>
<script src="/static/js/dda/map.js?v=4"></script>
<script src="/static/js/dda/library.js?v=24"></script>
<script src="/static/js/dda/pairs.js?v=14"></script>
<script src="/static/js/dda/notifications.js?v=6"></script>
</body>
</html>