KI-AGENT: Projekträume und Direktnachrichten integrieren
This commit is contained in:
@@ -7,6 +7,8 @@ const { $api } = useNuxtApp()
|
||||
const status = ref(null)
|
||||
const identity = ref(null)
|
||||
const matrixRooms = ref([])
|
||||
const matrixProjectRooms = ref([])
|
||||
const matrixDirectRooms = ref([])
|
||||
const activeRoomKey = ref("allgemein")
|
||||
const matrixMessages = ref([])
|
||||
const matrixMembers = ref([])
|
||||
@@ -35,6 +37,7 @@ const roomCreateForm = ref({
|
||||
})
|
||||
const loading = ref(false)
|
||||
const roomProvisioning = ref(false)
|
||||
const roomProvisioningKey = ref("")
|
||||
const roomCreating = ref(false)
|
||||
const roomMembersSyncing = ref(false)
|
||||
const matrixMessagesLoading = ref(false)
|
||||
@@ -54,7 +57,7 @@ const canUseMatrixChat = computed(() =>
|
||||
)
|
||||
|
||||
const activeRoom = computed(() =>
|
||||
matrixRooms.value.find((room) => room.key === activeRoomKey.value) || {
|
||||
rooms.value.find((room) => room.key === activeRoomKey.value) || {
|
||||
key: activeRoomKey.value,
|
||||
name: activeRoomKey.value,
|
||||
description: "Mandantenweiter Austausch",
|
||||
@@ -109,26 +112,34 @@ const roomCreateKeyPreview = computed(() =>
|
||||
normalizeRoomKey(roomCreateForm.value.key || roomCreateForm.value.name)
|
||||
)
|
||||
|
||||
const rooms = computed(() => [
|
||||
...matrixRooms.value.map((room) => ({
|
||||
const rooms = computed(() => {
|
||||
const baseRooms = matrixRooms.value
|
||||
.filter((room) => !["project", "direct"].includes(room.type))
|
||||
.map((room) => ({
|
||||
...room,
|
||||
group: "Räume",
|
||||
icon: "i-heroicons-chat-bubble-left-right",
|
||||
description: room.alias || room.roomId || "Mandantenweiter Austausch"
|
||||
}))
|
||||
|
||||
const projectRooms = matrixProjectRooms.value.map((room) => ({
|
||||
...room,
|
||||
description: room.alias || room.roomId || "Mandantenweiter Austausch"
|
||||
})),
|
||||
{
|
||||
key: "projects",
|
||||
name: "Projekt-Chats",
|
||||
description: "Nächste Ausbaustufe",
|
||||
exists: false,
|
||||
disabled: true
|
||||
},
|
||||
{
|
||||
key: "direct",
|
||||
name: "Direktnachrichten",
|
||||
description: "Nächste Ausbaustufe",
|
||||
exists: false,
|
||||
disabled: true
|
||||
}
|
||||
])
|
||||
group: "Projekte",
|
||||
icon: "i-heroicons-briefcase",
|
||||
description: room.projectNumber || room.topic || "Projektkommunikation",
|
||||
provisionEndpoint: `/api/communication/matrix/project-rooms/${encodeURIComponent(room.projectId)}/provision`
|
||||
}))
|
||||
|
||||
const directRooms = matrixDirectRooms.value.map((room) => ({
|
||||
...room,
|
||||
group: "Direkt",
|
||||
icon: "i-heroicons-user-circle",
|
||||
description: room.email || room.topic || "Direktnachricht",
|
||||
provisionEndpoint: `/api/communication/matrix/direct-rooms/${encodeURIComponent(room.userId)}/provision`
|
||||
}))
|
||||
|
||||
return [...baseRooms, ...projectRooms, ...directRooms]
|
||||
})
|
||||
|
||||
const normalizeRoomKey = (value) => {
|
||||
const normalized = String(value || "")
|
||||
@@ -149,12 +160,61 @@ const normalizeRoomKey = (value) => {
|
||||
const setActiveRoom = async (room) => {
|
||||
if (room.disabled || room.key === activeRoomKey.value) return
|
||||
|
||||
if (!room.exists && room.provisionEndpoint) {
|
||||
await provisionRoomFromList(room)
|
||||
return
|
||||
}
|
||||
|
||||
activeRoomKey.value = room.key
|
||||
matrixMessages.value = []
|
||||
matrixMembers.value = []
|
||||
await loadRoomChat({ includeMembers: true })
|
||||
}
|
||||
|
||||
const mergeRoomIntoLists = (room) => {
|
||||
upsertRoom({ ...room, exists: true })
|
||||
|
||||
if (room.type === "project") {
|
||||
matrixProjectRooms.value = matrixProjectRooms.value.map((item) =>
|
||||
item.key === room.key ? { ...item, ...room, exists: true } : item
|
||||
)
|
||||
}
|
||||
|
||||
if (room.type === "direct") {
|
||||
matrixDirectRooms.value = matrixDirectRooms.value.map((item) =>
|
||||
item.key === room.key ? { ...item, ...room, exists: true } : item
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const provisionRoomFromList = async (room) => {
|
||||
roomProvisioningKey.value = room.key
|
||||
try {
|
||||
const createdRoom = await $api(room.provisionEndpoint, {
|
||||
method: "POST"
|
||||
})
|
||||
|
||||
mergeRoomIntoLists(createdRoom)
|
||||
activeRoomKey.value = createdRoom.key
|
||||
matrixMessages.value = []
|
||||
matrixMembers.value = []
|
||||
|
||||
toast.add({
|
||||
title: "Chatraum ist bereit",
|
||||
color: "success"
|
||||
})
|
||||
|
||||
await loadRoomChat({ includeMembers: true })
|
||||
} catch (error) {
|
||||
toast.add({
|
||||
title: "Chatraum konnte nicht erstellt werden",
|
||||
color: "error"
|
||||
})
|
||||
} finally {
|
||||
roomProvisioningKey.value = ""
|
||||
}
|
||||
}
|
||||
|
||||
const upsertRoom = (room) => {
|
||||
const roomWasKnown = matrixRooms.value.some((item) => item.key === room.key)
|
||||
matrixRooms.value = roomWasKnown
|
||||
@@ -192,15 +252,19 @@ const scrollMessagesToBottom = async () => {
|
||||
const loadChatInfo = async () => {
|
||||
loading.value = true
|
||||
try {
|
||||
const [statusRes, identityRes, roomsRes] = await Promise.all([
|
||||
const [statusRes, identityRes, roomsRes, projectRoomsRes, directRoomsRes] = await Promise.all([
|
||||
$api("/api/communication/matrix/status"),
|
||||
$api("/api/communication/matrix/me"),
|
||||
$api("/api/communication/matrix/rooms")
|
||||
$api("/api/communication/matrix/rooms"),
|
||||
$api("/api/communication/matrix/project-rooms"),
|
||||
$api("/api/communication/matrix/direct-rooms")
|
||||
])
|
||||
|
||||
status.value = statusRes
|
||||
identity.value = identityRes
|
||||
matrixRooms.value = roomsRes.rooms || []
|
||||
matrixProjectRooms.value = projectRoomsRes.rooms || []
|
||||
matrixDirectRooms.value = directRoomsRes.rooms || []
|
||||
lastUpdated.value = new Date()
|
||||
|
||||
if (activeRoom.value?.exists && canUseMatrixChat.value) {
|
||||
@@ -869,14 +933,22 @@ onBeforeUnmount(() => {
|
||||
@click="setActiveRoom(room)"
|
||||
>
|
||||
<span class="flex size-9 shrink-0 items-center justify-center rounded-md bg-primary/10 text-primary">
|
||||
<UIcon name="i-heroicons-chat-bubble-left-right" class="size-5" />
|
||||
<UIcon :name="room.icon || 'i-heroicons-chat-bubble-left-right'" class="size-5" />
|
||||
</span>
|
||||
<span class="min-w-0 flex-1">
|
||||
<span class="block truncate text-sm font-medium">{{ room.name }}</span>
|
||||
<span class="block truncate text-xs text-muted">{{ room.description }}</span>
|
||||
</span>
|
||||
<UBadge
|
||||
v-if="room.exists"
|
||||
v-if="roomProvisioningKey === room.key"
|
||||
color="primary"
|
||||
variant="soft"
|
||||
size="xs"
|
||||
>
|
||||
lädt
|
||||
</UBadge>
|
||||
<UBadge
|
||||
v-else-if="room.exists"
|
||||
color="success"
|
||||
variant="soft"
|
||||
size="xs"
|
||||
@@ -978,7 +1050,7 @@ onBeforeUnmount(() => {
|
||||
|
||||
<div class="border-b border-default bg-default p-3 lg:hidden">
|
||||
<div class="flex gap-2 overflow-x-auto pb-1">
|
||||
<button
|
||||
<button
|
||||
v-for="room in rooms"
|
||||
:key="room.key"
|
||||
type="button"
|
||||
|
||||
Reference in New Issue
Block a user