This commit is contained in:
j3d1 2026-08-26 18:37:06 +02:00
parent 9ce700c388
commit 35be834799
8 changed files with 92 additions and 15 deletions

View file

@ -56,13 +56,16 @@ const EXPANDED_ROUTE_BUILDERS = {
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),
group: ({group_id}) => `/groups/${group_id}`,
group: ({group_id}) => {
const handle = store.getters.groupHandleById[group_id];
return handle ? `/groups/${encodeHandleForUrl(handle)}` : null;
},
storage_location: ({storage_location_id}) => `/storage-locations/${storage_location_id}`,
workflow: ({workflow_id}) => `/workflows/${workflow_id}`,
};
// Kinds whose route needs identityHandleById/groupHandleById (from state.idmap); ShortId.vue only waits on an idmap fetch for these.
export const NEEDS_IDMAP = new Set(['item', 'group_item']);
export const NEEDS_IDMAP = new Set(['item', 'group_item', 'group']);
export function expandedRoute({kind, ...fields}) {
const buildRoute = EXPANDED_ROUTE_BUILDERS[kind];
@ -117,7 +120,7 @@ const routes = [{path: '/', component: Dashboard, meta: {requiresAuth: true}}, {
component: GroupNew,
meta: {requiresAuth: true}
}, {
path: '/groups/:id',
path: '/groups/:handle',
component: GroupDetail,
meta: {requiresAuth: true},
props: true

View file

@ -134,7 +134,7 @@ import {mapActions, mapGetters, mapState} from "vuex";
import * as BIcons from "bootstrap-icons-vue";
import BaseLayout from "@/components/BaseLayout.vue";
import UserNameTag from "@/components/UserNameTag.vue";
import {encodeHandleForUrl} from "@/router";
import {decodeHandleFromUrl, encodeHandleForUrl} from "@/router";
export default {
name: 'GroupDetail',
@ -144,8 +144,8 @@ export default {
...BIcons
},
props: {
id: {
type: [String, Number],
handle: {
type: String,
required: true
}
},
@ -159,14 +159,17 @@ export default {
},
computed: {
...mapState(['user']),
id() {
return this.groupIdByHandle[decodeHandleFromUrl(this.handle)]
},
items() {
return this.groupInventoryItems(this.id)
},
...mapGetters(['groupInventoryItems'])
...mapGetters(['groupInventoryItems', 'groupIdByHandle'])
},
methods: {
...mapActions(['fetchGroup', 'removeGroupMember', 'inviteToGroup', 'fetchGroupInventoryItems',
'deleteInventoryItem']),
'deleteInventoryItem', 'fetchIdMap']),
refresh() {
this.fetchGroup({id: this.id}).then((group) => {
this.group = group
@ -201,8 +204,15 @@ export default {
}
},
mounted() {
this.refresh()
this.fetchItems()
if (this.id === undefined) {
this.fetchIdMap().then(() => {
this.refresh()
this.fetchItems()
})
} else {
this.refresh()
this.fetchItems()
}
}
}
</script>

View file

@ -25,6 +25,7 @@
<script>
import {mapActions} from "vuex";
import BaseLayout from "@/components/BaseLayout.vue";
import {encodeHandleForUrl} from "@/router";
export default {
name: 'GroupNew',
@ -40,7 +41,7 @@ export default {
...mapActions(['createGroup']),
tryCreateGroup() {
this.createGroup({name: this.name}).then((group) => {
this.$router.push(`/groups/${group.id}`)
this.$router.push(`/groups/${encodeHandleForUrl(group.handle)}`)
}).catch(() => {
})
}

View file

@ -29,7 +29,7 @@
<tbody>
<tr v-for="group in groups" :key="group.id">
<td>
<router-link :to="`/groups/${group.id}`">{{ group.handle }}</router-link>
<router-link :to="`/groups/${encodeHandleForUrl(group.handle)}`">{{ group.handle }}</router-link>
</td>
<td class="d-none d-md-table-cell">{{ group.members.length }}</td>
<td class="table-action"></td>
@ -38,6 +38,32 @@
</table>
</div>
</div>
<div class="col-12 col-xl-6">
<div class="card">
<div class="card-header">
<h5 class="card-title">Other groups you're a member of</h5>
</div>
<table class="table table-striped">
<thead>
<tr>
<th>Group</th>
<th style="width: 16em">
<a @click="fetchGroupMemberships" class="align-middle">
<b-icon-arrow-clockwise></b-icon-arrow-clockwise>
Refresh
</a>
</th>
</tr>
</thead>
<tbody>
<tr v-for="membership in foreignGroupMemberships" :key="membership.id">
<td>{{ membership.handle }}</td>
<td class="table-action"></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="col-12 col-xl-6">
<div class="card">
<div class="card-header">
@ -85,6 +111,7 @@
import {mapActions, mapState} from "vuex";
import * as BIcons from "bootstrap-icons-vue";
import BaseLayout from "@/components/BaseLayout.vue";
import {encodeHandleForUrl} from "@/router";
export default {
name: 'Groups',
@ -93,14 +120,21 @@ export default {
...BIcons
},
computed: {
...mapState(['groups', 'groupInvites']),
...mapState(['groups', 'groupInvites', 'groupMemberships']),
foreignGroupMemberships() {
const hostedHandles = new Set(this.groups.map(group => group.handle))
return this.groupMemberships.filter(membership => !hostedHandles.has(membership.handle))
},
},
methods: {
...mapActions(['fetchGroups', 'fetchGroupInvites', 'acceptGroupInvite', 'declineGroupInvite']),
encodeHandleForUrl,
...mapActions(['fetchGroups', 'fetchGroupInvites', 'fetchGroupMemberships', 'acceptGroupInvite',
'declineGroupInvite']),
tryAcceptInvite(invite) {
this.acceptGroupInvite(invite).then(() => {
this.fetchGroupInvites()
this.fetchGroups()
this.fetchGroupMemberships()
}).catch(() => {
})
},
@ -114,6 +148,7 @@ export default {
mounted() {
this.fetchGroups()
this.fetchGroupInvites()
this.fetchGroupMemberships()
}
}
</script>