This commit is contained in:
j3d1 2026-08-27 02:51:30 +02:00
parent 6ee5ae38b1
commit 9685b4020e
11 changed files with 331 additions and 268 deletions

View file

@ -27,7 +27,10 @@ import Scan from "@/views/Scan.vue";
import Workflows from '@/views/Workflows.vue';
import WorkflowDetail from '@/views/WorkflowDetail.vue';
import ShortId from '@/views/ShortId.vue';
import {encodeShortId, serializeShortId,decodeShortId, deserializeShortId} from '@/short-id';
import {
encodeShortId, serializeShortId, decodeShortId, deserializeShortId,
isDomainQualifiedShortId, decodeDomainQualifiedShortId
} from '@/short-id';
import Account from '@/views/settings/Account.vue';
import Password from '@/views/settings/Password.vue';
@ -46,33 +49,31 @@ export function decodeHandleFromUrl(segment) {
return segment.replace(/\+/g, "#");
}
// item/group_item share this /inventory/:handle/:id shape; only owner-handle resolution (identity vs. group, see store.js) differs.
function itemDetailRoute(handle, item_local_id) {
return handle ? `/inventory/${encodeHandleForUrl(handle)}/${item_local_id}` : null;
}
// storage_location/group_storage_location share this /storage-locations/:handle/:id shape, same idea as itemDetailRoute above.
function storageLocationDetailRoute(handle, storage_location_id) {
return handle ? `/storage-locations/${encodeHandleForUrl(handle)}/${storage_location_id}` : null;
}
export function ownerOverviewRoute(item) {
return item.owner_group ? `/groups/${encodeHandleForUrl(item.owner_group)}` : '/inventory';
}
const EXPANDED_ROUTE_BUILDERS = {
item: ({owner_identity_id, item_local_id}) =>
itemDetailRoute(store.getters.identityHandleById[owner_identity_id], item_local_id),
group_item: ({owner_group_id, item_local_id}) =>
itemDetailRoute(store.getters.groupHandleById[owner_group_id], item_local_id),
item: ({owner_identity_id, item_local_id}) => {
const handle = store.getters.identityHandleById[owner_identity_id];
return handle ? `/inventory/${encodeHandleForUrl(handle)}/${item_local_id}` : null;
},
group_item: ({owner_group_id, item_local_id}) => {
const handle = store.getters.groupHandleById[owner_group_id];
return handle ? `/inventory/${encodeHandleForUrl(handle)}/${item_local_id}` : null;
},
group: ({group_id}) => {
const handle = store.getters.groupHandleById[group_id];
return handle ? `/groups/${encodeHandleForUrl(handle)}` : null;
},
storage_location: ({owner_identity_id, storage_location_id}) =>
storageLocationDetailRoute(store.getters.identityHandleById[owner_identity_id], storage_location_id),
group_storage_location: ({owner_group_id, storage_location_id}) =>
storageLocationDetailRoute(store.getters.groupHandleById[owner_group_id], storage_location_id),
storage_location: ({owner_identity_id, storage_location_id}) => {
const handle = store.getters.identityHandleById[owner_identity_id];
return handle ? `/storage-locations/${encodeHandleForUrl(handle)}/${storage_location_id}` : null;
},
group_storage_location: ({owner_group_id, storage_location_id}) => {
const handle = store.getters.groupHandleById[owner_group_id];
return handle ? `/storage-locations/${encodeHandleForUrl(handle)}/${storage_location_id}` : null;
},
workflow: ({workflow_id}) => `/workflows/${workflow_id}`,
};
@ -88,6 +89,37 @@ export function shortenedRoute(named) {
return '/' + encodeShortId(serializeShortId(named));
}
// Owned kinds only - matches handles-and-shortids.md's User-Qualified ID split (group/category/file have no owner id to hand a foreign backend).
export const OWNED_KIND_FIELDS = {
item: {ownerField: 'owner_identity_id', localField: 'item_local_id', isLocation: false},
group_item: {ownerField: 'owner_group_id', localField: 'item_local_id', isLocation: false},
storage_location: {ownerField: 'owner_identity_id', localField: 'storage_location_id', isLocation: true},
group_storage_location: {ownerField: 'owner_group_id', localField: 'storage_location_id', isLocation: true},
};
// Resolves a Domain-Qualified Short ID to a route, locally or via a network round-trip. See docs/implementation.md#domain-qualified-short-id-resolution.
export async function domainQualifiedRoute(domain, ints) {
const homeDomain = store.getters.isLoggedIn && store.state.user ? store.state.user.split('@')[1] : null;
const deserialized = deserializeShortId(ints);
if (domain === homeDomain) {
return expandedRoute(deserialized) || undefined;
}
const owned = OWNED_KIND_FIELDS[deserialized.kind];
if (!owned) {
return undefined; // no owner id to resolve a foreign backend against yet (group/category/file/workflow)
}
const resolved = await store.dispatch('resolveShortId', {
domain, kind: deserialized.kind,
ownerId: deserialized[owned.ownerField], localId: deserialized[owned.localField],
});
if (!resolved || !resolved.handle) {
return undefined;
}
return owned.isLocation
? `/storage-locations/${encodeHandleForUrl(resolved.handle)}/${resolved.id}`
: `/inventory/${encodeHandleForUrl(resolved.handle)}/${resolved.id}`;
}
const routes = [{path: '/', component: Dashboard, meta: {requiresAuth: true}}, {
path: '/inventory',
component: Inventory,
@ -111,13 +143,12 @@ const routes = [{path: '/', component: Dashboard, meta: {requiresAuth: true}}, {
path: '/:short_id',
component: ShortId,
props: true,
beforeEnter: to => {
console.log(to);
const p = deserializeShortId(decodeShortId(to.params.short_id))
console.log(p)
const url = expandedRoute(p);
console.log(url);
return url;
beforeEnter: async to => {
if (isDomainQualifiedShortId(to.params.short_id)) {
const {domain, ints} = decodeDomainQualifiedShortId(to.params.short_id);
return await domainQualifiedRoute(domain, ints);
}
return expandedRoute(deserializeShortId(decodeShortId(to.params.short_id)));
}
}, {path: '/inventory/new', component: InventoryNew, meta: {requiresAuth: true}}, {
path: '/friends',
@ -209,10 +240,6 @@ const routes = [{path: '/', component: Dashboard, meta: {requiresAuth: true}}, {
path: '/storage-locations/new',
component: StorageLocationNew,
meta: {requiresAuth: true}
}, {
path: '/debug/:short_id',
component: ShortId,
props: true
}, {path: '/:pathMatch(.*)*', redirect: '/'}]
const router = createRouter({