This commit is contained in:
j3d1 2026-08-26 20:40:23 +02:00
parent 35be834799
commit 8de6ae8d8b
11 changed files with 168 additions and 150 deletions

View file

@ -148,33 +148,14 @@ export default {
error: null,
insecureContext: window.isSecureContext,
insecureOrigin: `${window.location.protocol}//${window.location.hostname}`,
// One-shot: cleared by maybeVisitFirstMatch as soon as it navigates, so it doesn't
// keep firing router.push for every later scan/decode while left switched on.
// Defaults on when the page itself was opened with ?navigate=immediate (e.g. a link
// shared for a "scan and go" workflow), so the toggle doesn't need a manual flip first.
visitFirstMatch: this.$route.query.navigate === "immediate",
cameraLog: [],
};
},
methods: {
...mapActions(["fetchItemByHandle", "fetchGroup", "fetchStorageLocations", "fetchIdMap"]),
...mapActions(["fetchItemByHandle", "fetchStorageLocations", "fetchIdMap"]),
// Resolves entry.link into entry.description ("[#7] Cordless drill") for the non-URL
// formats classifyScanText recognizes - mutates the already-rendered entry in place once
// the lookup lands, rather than delaying the log/result list from showing the raw scanned
// text and link immediately. Left as `undefined` (template shows "resolving...") while in
// flight, and settles to a string or `null` (nothing else known to show, e.g. a workflow
// short id, or the owner/item genuinely couldn't be resolved).
//
// descriptionCache (keyed by the raw scanned text) memoizes the outcome - a still-in-frame
// code gets re-decoded and re-logged several times a second (see logDecode), and
// re-scanning the same printed label later is common too, so without this every repeat
// would re-fire the same fetchItemByHandle/fetchGroup/fetchStorageLocations/fetchIdMap
// round trip. Caching the in-flight promise itself (not just its settled value) also
// dedupes concurrent lookups for the same still-in-frame code, rather than firing one
// request per decode.
resolveDescription(entry) {
const {link, text} = entry;
if (!link || link.href) {
@ -185,10 +166,6 @@ export default {
return;
}
if (!this.descriptionCache.has(text)) {
// Wrapped as {error} rather than swallowed to null: a lookup can fail for very
// different reasons (not logged in, item not shared with this viewer, a genuine
// network error) and collapsing them all to "no description" made every one of
// them look identical to "nothing to show" - undiagnosable from the UI.
this.descriptionCache.set(text, this.describeLink(link).catch(e => ({error: e.message ?? String(e)})));
}
this.descriptionCache.get(text).then(result => {
@ -198,19 +175,12 @@ export default {
return;
}
entry.description = result;
// Only a truthy description confirms the target actually exists - a null/empty
// one (unresolvable, or a kind with no title lookup wired up) shouldn't count as
// a "match" to auto-visit.
if (result) {
this.maybeVisitFirstMatch(link);
}
});
},
// Sends the viewer straight to the first scan this session that's confirmed to resolve
// (immediately for a plain URL, or once resolveDescription confirms a real target for a
// token/handle) while the "Visit first match" toggle is on. One-shot: switches the toggle
// back off so it doesn't fire again for every later scan of the same or another code.
maybeVisitFirstMatch(link) {
if (!this.visitFirstMatch || !link?.to) {
return;
@ -242,8 +212,12 @@ export default {
return handle === undefined ? null : this.describeItem(handle, decoded.item_local_id);
}
if (decoded.kind === "group") {
const group = await this.fetchGroup({id: decoded.group_id});
return group ? group.handle : null;
let handle = this.$store.getters.groupHandleById[decoded.group_id];
if (handle === undefined) {
await this.fetchIdMap();
handle = this.$store.getters.groupHandleById[decoded.group_id];
}
return handle === undefined ? null : handle;
}
if (decoded.kind === "storage_location") {
if (!this.$store.state.storage_locations.length) {