143 lines
6.5 KiB
Vue
143 lines
6.5 KiB
Vue
<template>
|
|
<BaseLayout>
|
|
<main class="content">
|
|
<div class="row">
|
|
<div class="col">
|
|
<div class="card">
|
|
<div class="card-header">Create New Storage Location</div>
|
|
<div class="card-body">
|
|
<div class="mb-3">
|
|
<label for="name" class="form-label">Name</label>
|
|
<input type="text" class="form-control" id="name" name="name"
|
|
placeholder="Enter storage location name" v-model="location.name">
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="description" class="form-label">Description</label>
|
|
<textarea class="form-control" id="description" name="description"
|
|
placeholder="Enter description" v-model="location.description"></textarea>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="category" class="form-label">Category</label>
|
|
<select class="form-select" id="category" name="category"
|
|
v-model="location.category">
|
|
<option value="">No Category</option>
|
|
<option v-for="category in categories" :value="category">
|
|
{{ category }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="owner" class="form-label">Owner</label>
|
|
<select class="form-select" id="owner" name="owner" v-model="location.owner_group">
|
|
<option :value="null">Myself</option>
|
|
<option v-for="group in ownerGroups" :value="group.handle" :key="group.handle">
|
|
{{ group.handle }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<label for="parent" class="form-label">Parent Location</label>
|
|
<select class="form-select" id="parent" name="parent"
|
|
v-model="location.parent">
|
|
<option value="">No Parent</option>
|
|
<option v-for="parent in availableParents" :value="parent.id">
|
|
{{ parent.path }}
|
|
</option>
|
|
</select>
|
|
</div>
|
|
<div class="mb-3">
|
|
<button type="submit" class="btn btn-primary" style="width: 100%"
|
|
@click="submitForm()">Add
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</main>
|
|
</BaseLayout>
|
|
</template>
|
|
|
|
<script>
|
|
import * as BIcons from "bootstrap-icons-vue";
|
|
import {mapActions, mapState} from "vuex";
|
|
import BaseLayout from "@/components/BaseLayout.vue";
|
|
import {decodeHandleFromUrl, ownerOverviewRoute} from "@/router";
|
|
|
|
export default {
|
|
name: "StorageLocationNew",
|
|
components: {
|
|
BaseLayout,
|
|
...BIcons
|
|
},
|
|
data() {
|
|
return {
|
|
location: {
|
|
name: "",
|
|
description: "",
|
|
category: null,
|
|
parent: null,
|
|
// The group's own "#name@domain" handle once picked, or null for a personal
|
|
// location - createStorageLocation resolves the target domain from it directly.
|
|
owner_group: null
|
|
},
|
|
// The selected owner's own location list, for the parent dropdown - own personal
|
|
// locations, or the chosen group's own (see loadParentOptionsForOwner).
|
|
groupLocations: []
|
|
}
|
|
},
|
|
methods: {
|
|
ownerOverviewRoute,
|
|
...mapActions(['createStorageLocation', 'fetchInfo', 'fetchStorageLocations', 'fetchGroups',
|
|
'fetchGroupMemberships', 'fetchGroupStorageLocations']),
|
|
async loadParentOptionsForOwner() {
|
|
if (!this.location.owner_group) {
|
|
this.groupLocations = []
|
|
return
|
|
}
|
|
this.groupLocations = await this.fetchGroupStorageLocations({groupHandle: this.location.owner_group})
|
|
},
|
|
submitForm() {
|
|
// Convert empty strings to null for ForeignKey fields
|
|
const locationData = {
|
|
...this.location,
|
|
category: this.location.category === "" ? null : this.location.category,
|
|
parent: this.location.parent === "" ? null : this.location.parent
|
|
};
|
|
this.createStorageLocation(locationData).then(created => this.$router.push(ownerOverviewRoute(created)));
|
|
}
|
|
},
|
|
computed: {
|
|
...mapState(["categories", "storage_locations", "groups", "groupMemberships"]),
|
|
// Groups hosted here plus groups only known via a GroupMembership pointer (see
|
|
// Groups.vue's allGroups for the same merge/dedupe).
|
|
ownerGroups() {
|
|
const hostedHandles = new Set(this.groups.map(group => group.handle))
|
|
const foreign = this.groupMemberships.filter(m => !hostedHandles.has(m.handle))
|
|
return [...this.groups, ...foreign].sort((a, b) => a.handle.localeCompare(b.handle))
|
|
},
|
|
availableParents() {
|
|
return this.location.owner_group ? this.groupLocations : this.storage_locations
|
|
}
|
|
},
|
|
watch: {
|
|
'location.owner_group'() {
|
|
// Previously-selected parent likely doesn't belong to the newly-chosen owner.
|
|
this.location.parent = null
|
|
this.loadParentOptionsForOwner()
|
|
}
|
|
},
|
|
async mounted() {
|
|
await this.fetchInfo();
|
|
await this.fetchStorageLocations();
|
|
await this.fetchGroups();
|
|
await this.fetchGroupMemberships();
|
|
if (this.$route.query.group) {
|
|
this.location.owner_group = decodeHandleFromUrl(this.$route.query.group)
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style scoped>
|
|
</style>
|