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.
54 lines
1.5 KiB
Go
54 lines
1.5 KiB
Go
package web
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/base64"
|
|
"image/png"
|
|
"net/http"
|
|
|
|
"github.com/boombuler/barcode"
|
|
"github.com/boombuler/barcode/code128"
|
|
qrcode "github.com/skip2/go-qrcode"
|
|
)
|
|
|
|
// qrDataURI renders content as a QR code PNG and returns it as a data: URI
|
|
// suitable for an <img src>, so labels need no separate image requests.
|
|
func qrDataURI(content string, size int) (string, error) {
|
|
png, err := qrcode.Encode(content, qrcode.Medium, size)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
return "data:image/png;base64," + base64.StdEncoding.EncodeToString(png), nil
|
|
}
|
|
|
|
// barcodeDataURI renders content as a Code128 linear barcode PNG, scaled to
|
|
// widthPx x heightPx, and returns it as a data: URI.
|
|
func barcodeDataURI(content string, widthPx, heightPx int) (string, error) {
|
|
bc, err := code128.Encode(content)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
scaled, err := barcode.Scale(bc, widthPx, heightPx)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
var buf bytes.Buffer
|
|
if err := png.Encode(&buf, scaled); err != nil {
|
|
return "", err
|
|
}
|
|
return "data:image/png;base64," + base64.StdEncoding.EncodeToString(buf.Bytes()), nil
|
|
}
|
|
|
|
// requestOrigin reconstructs the scheme+host the request arrived on, for
|
|
// building absolute URLs (e.g. QR codes need a full URL, not a path).
|
|
func requestOrigin(r *http.Request) string {
|
|
scheme := "http"
|
|
if r.TLS != nil {
|
|
scheme = "https"
|
|
}
|
|
if proto := r.Header.Get("X-Forwarded-Proto"); proto != "" {
|
|
scheme = proto
|
|
}
|
|
return scheme + "://" + r.Host
|
|
}
|