mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-21 21:33:02 +01:00
Added easy label creation to multiselect (#425)
* feat: added easy label creation to multiselect, also fixed webhooks in dev mode * fix: add missing translation
This commit is contained in:
@@ -5,8 +5,8 @@
|
|||||||
</label>
|
</label>
|
||||||
<div class="dropdown dropdown-top sm:dropdown-end">
|
<div class="dropdown dropdown-top sm:dropdown-end">
|
||||||
<div tabindex="0" class="flex min-h-[48px] w-full flex-wrap gap-2 rounded-lg border border-gray-400 p-4">
|
<div tabindex="0" class="flex min-h-[48px] w-full flex-wrap gap-2 rounded-lg border border-gray-400 p-4">
|
||||||
<span v-for="itm in value" :key="name != '' ? itm[name] : itm" class="badge">
|
<span v-for="itm in value" :key="itm.id" class="badge">
|
||||||
{{ name != "" ? itm[name] : itm }}
|
{{ itm.name }}
|
||||||
</span>
|
</span>
|
||||||
<button
|
<button
|
||||||
v-if="value.length > 0"
|
v-if="value.length > 0"
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
<div
|
<div
|
||||||
tabindex="0"
|
tabindex="0"
|
||||||
style="display: inline"
|
style="display: inline"
|
||||||
class="dropdown-content menu z-[9999] mb-1 w-full rounded border border-gray-400 bg-base-100 shadow"
|
class="dropdown-content menu bg-base-100 z-[9999] mb-1 w-full rounded border border-gray-400 shadow"
|
||||||
>
|
>
|
||||||
<div class="m-2">
|
<div class="m-2">
|
||||||
<input v-model="search" placeholder="Search…" class="input input-bordered input-sm w-full" />
|
<input v-model="search" placeholder="Search…" class="input input-bordered input-sm w-full" />
|
||||||
@@ -30,13 +30,16 @@
|
|||||||
v-for="(obj, idx) in filteredItems"
|
v-for="(obj, idx) in filteredItems"
|
||||||
:key="idx"
|
:key="idx"
|
||||||
:class="{
|
:class="{
|
||||||
bordered: selected.includes(obj[props.uniqueField]),
|
bordered: selected.includes(obj.id),
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<button type="button" @click="toggle(obj[props.uniqueField])">
|
<button type="button" @click="toggle(obj.id)">
|
||||||
{{ name != "" ? obj[name] : obj }}
|
{{ obj.name }}
|
||||||
</button>
|
</button>
|
||||||
</li>
|
</li>
|
||||||
|
<li v-if="!filteredItems.some(itm => itm.name === search) && search.length > 0">
|
||||||
|
<button type="button" @click="createAndAdd(search)">{{ $t("global.create") }} {{ search }}</button>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -60,14 +63,6 @@
|
|||||||
type: Array as () => any[],
|
type: Array as () => any[],
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
name: {
|
|
||||||
type: String,
|
|
||||||
default: "name",
|
|
||||||
},
|
|
||||||
uniqueField: {
|
|
||||||
type: String,
|
|
||||||
default: "id",
|
|
||||||
},
|
|
||||||
selectFirst: {
|
selectFirst: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
@@ -84,7 +79,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
return props.items.filter(item => {
|
return props.items.filter(item => {
|
||||||
return item[props.name].toLowerCase().includes(search.value.toLowerCase());
|
return item.name.toLowerCase().includes(search.value.toLowerCase());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -93,15 +88,33 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const selected = computed<string[]>(() => {
|
const selected = computed<string[]>(() => {
|
||||||
return value.value.map(itm => itm[props.uniqueField]);
|
return value.value.map(itm => itm.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
function toggle(uniqueField: string) {
|
function toggle(uniqueField: string) {
|
||||||
const item = props.items.find(itm => itm[props.uniqueField] === uniqueField);
|
const item = props.items.find(itm => itm.id === uniqueField);
|
||||||
if (selected.value.includes(item[props.uniqueField])) {
|
if (selected.value.includes(item.id)) {
|
||||||
value.value = value.value.filter(itm => itm[props.uniqueField] !== item[props.uniqueField]);
|
value.value = value.value.filter(itm => itm.id !== item.id);
|
||||||
} else {
|
} else {
|
||||||
value.value = [...value.value, item];
|
value.value = [...value.value, item];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const api = useUserApi();
|
||||||
|
const toast = useNotifier();
|
||||||
|
|
||||||
|
async function createAndAdd(name: string) {
|
||||||
|
const { error, data } = await api.labels.create({
|
||||||
|
name,
|
||||||
|
color: "", // Future!
|
||||||
|
description: "",
|
||||||
|
});
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
console.error(error);
|
||||||
|
toast.error(`Failed to create label: ${name}`);
|
||||||
|
} else {
|
||||||
|
value.value = [...value.value, data];
|
||||||
|
}
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
@@ -18,7 +18,11 @@ function connect(onmessage: (m: EventMessage) => void) {
|
|||||||
protocol = "wss";
|
protocol = "wss";
|
||||||
}
|
}
|
||||||
|
|
||||||
const ws = new WebSocket(`${protocol}://${window.location.host}/api/v1/ws/events`);
|
const dev = import.meta.dev;
|
||||||
|
|
||||||
|
const host = dev ? window.location.host.replace("3000", "7745") : window.location.host;
|
||||||
|
|
||||||
|
const ws = new WebSocket(`${protocol}://${host}/api/v1/ws/events`);
|
||||||
|
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
console.debug("connected to server");
|
console.debug("connected to server");
|
||||||
|
|||||||
Reference in New Issue
Block a user