Multi-select (Ctrl/Cmd+click toggle, Shift+click range, right-click the
active selection for bulk actions - same conventions as a native file
manager):
- Print Labels (N) / Export CSV (N) for any mix of individually-picked
assets and whole folders. Labels/export now take asset_ids/folder_ids
instead of a single asset_id/folder_id.
- Edit Status..., Check Out..., Duplicate, Move to..., and Delete, bulk
versions of the existing single-asset actions. Checkout/Move modals
were generalized to accept an array of ids instead of just one; status
editing got its own lightweight POST /app/assets/{id}/status endpoint
(assets.SetStatus) so a bulk status change doesn't need to resend every
other field the way a full PATCH would.
Labels:
- Choose QR (a /scan/<tag> URL, for a phone camera) or Code128 barcode
(the bare Asset ID, for a USB scanner typing into the search box) via a
format selector on the print page. New barcodeDataURI using
github.com/boombuler/barcode alongside the existing QR generator.
- "Start at #" lets printing resume partway into an already-used sheet
instead of wasting it on a fresh one.
- Added the Avery 5260 label template (same grid as 5160, rounded
corners, so it isn't flagged approximate).
Also: the configured Site Name now shows on the login page too, not just
the authenticated navbar.
208 lines
9.2 KiB
HTML
208 lines
9.2 KiB
HTML
{{define "modals"}}
|
|
{{if .User.IsAdmin}}
|
|
<!-- Create / rename folder -->
|
|
<div class="modal fade" id="folderModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form id="folderForm">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="folderModalTitle">New Folder</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<input type="hidden" name="folder_id" id="folderFormId">
|
|
<input type="hidden" name="parent_id" id="folderFormParentId">
|
|
<div class="mb-3">
|
|
<label class="form-label">Name</label>
|
|
<input type="text" class="form-control" name="name" id="folderFormName" required autofocus>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label class="form-label">Description</label>
|
|
<textarea class="form-control" name="description" id="folderFormDescription" rows="2"></textarea>
|
|
</div>
|
|
<div class="row g-2">
|
|
<div class="col">
|
|
<label class="form-label">Icon <span class="text-body-secondary">(optional)</span></label>
|
|
<div class="icon-picker" data-icon-picker>
|
|
<input type="hidden" name="icon" id="folderFormIcon" value="">
|
|
<button type="button" class="btn btn-outline-secondary icon-picker-toggle w-100">
|
|
<i class="bi icon-picker-preview"></i>
|
|
<span class="icon-picker-label text-body-secondary">Choose icon…</span>
|
|
<i class="bi bi-chevron-down icon-picker-caret"></i>
|
|
</button>
|
|
<div class="icon-picker-menu">
|
|
<input type="search" class="form-control form-control-sm icon-picker-search" placeholder="Search icons…">
|
|
<div class="icon-picker-grid"></div>
|
|
<button type="button" class="btn btn-sm btn-link p-0 mt-2 icon-picker-clear">Clear</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="col-4">
|
|
<label class="form-label">Sort Order</label>
|
|
<input type="number" class="form-control" name="sort_order" id="folderFormSortOrder" value="0">
|
|
</div>
|
|
</div>
|
|
<div class="invalid-feedback d-block d-none" id="folderFormError"></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="submit" class="btn btn-primary">Save Folder</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Delete folder confirmation -->
|
|
<div class="modal fade" id="deleteFolderModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title"><i class="bi bi-exclamation-triangle-fill text-danger"></i> Delete Folder</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p>Delete <strong id="deleteFolderName"></strong>?</p>
|
|
<div id="deleteFolderEmptyNotice" class="d-none">
|
|
<p class="text-body-secondary">This folder is empty and can be deleted safely.</p>
|
|
</div>
|
|
<div id="deleteFolderNotEmptyNotice" class="d-none">
|
|
<div class="alert alert-warning py-2">
|
|
This folder contains <span id="deleteFolderCounts"></span>. Choose what to do with its contents.
|
|
</div>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="delete_mode" id="modeRelocate" value="relocate" checked>
|
|
<label class="form-check-label" for="modeRelocate">Move contents to…</label>
|
|
</div>
|
|
<select class="form-select mt-1 mb-2" id="deleteFolderDestination"></select>
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="radio" name="delete_mode" id="modeCascade" value="cascade">
|
|
<label class="form-check-label text-danger" for="modeCascade">Permanently delete everything inside</label>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-danger" id="confirmDeleteFolderBtn">Delete Folder</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Add / edit asset -->
|
|
<div class="modal fade" id="assetModal" tabindex="-1">
|
|
<div class="modal-dialog modal-lg">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="assetModalTitle">New Asset</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body" id="assetModalBody"></div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="submit" form="assetForm" class="btn btn-primary" id="assetModalSubmit">Create Asset</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Move asset -->
|
|
<div class="modal fade" id="moveAssetModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="moveAssetModalTitle">Move Asset</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<label class="form-label">Destination Folder</label>
|
|
<select class="form-select" id="moveAssetDestination">
|
|
<option value="">Inventory (top level)</option>
|
|
</select>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" id="confirmMoveAssetBtn">Move</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Check out / check in asset -->
|
|
<div class="modal fade" id="checkoutModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="checkoutModalTitle">Check Out Asset</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<p class="text-body-secondary small mb-3" id="checkoutCurrent"></p>
|
|
<label class="form-label">Assigned User</label>
|
|
<select class="form-select" id="checkoutUserSelect">
|
|
<option value="">Unassigned (check in)</option>
|
|
</select>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" id="confirmCheckoutBtn">Save</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Bulk status change (multi-select > Edit Status...) -->
|
|
<div class="modal fade" id="bulkStatusModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="bulkStatusModalTitle">Edit Status</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<label class="form-label">New Status</label>
|
|
<select class="form-select" id="bulkStatusSelect">
|
|
{{range .Statuses}}<option value="{{.ID}}">{{.Name}}</option>{{end}}
|
|
</select>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
<button type="button" class="btn btn-primary" id="confirmBulkStatusBtn">Save</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Import CSV into a specific folder (right-click a folder > Import CSV...) -->
|
|
<div class="modal fade" id="importModal" tabindex="-1">
|
|
<div class="modal-dialog">
|
|
<div class="modal-content">
|
|
<form id="importForm">
|
|
<div class="modal-header">
|
|
<h5 class="modal-title" id="importModalTitle">Import CSV</h5>
|
|
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
|
|
</div>
|
|
<div class="modal-body">
|
|
<input type="hidden" name="folder_id" id="importFolderId">
|
|
<div class="mb-3">
|
|
<label class="form-label">CSV File</label>
|
|
<input type="file" class="form-control" name="file" id="importFile" accept=".csv" required>
|
|
</div>
|
|
<p class="text-body-secondary small mb-0">
|
|
Every row imports into this folder. Columns: <code>Name</code>, <code>Item Type</code>,
|
|
<code>Status</code>. Optional: <code>Asset ID</code>, <code>Assigned User</code>, <code>Notes</code>,
|
|
plus <code>cf_<field_key></code> for custom fields. No Folder column needed.
|
|
</p>
|
|
<div id="importResult" class="mt-3"></div>
|
|
</div>
|
|
<div class="modal-footer">
|
|
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Close</button>
|
|
<button type="submit" class="btn btn-primary" id="importSubmitBtn">Import</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
{{end}}
|
|
{{end}}
|