diff --git a/wwwroot/js/api.js b/wwwroot/js/api.js
index 7f7da7e..ebf2dd1 100644
--- a/wwwroot/js/api.js
+++ b/wwwroot/js/api.js
@@ -211,6 +211,9 @@ function apiShareMessage(id, includeContext) { return _post('/api/messages/' + i
function apiGetShared(token) { return _get('/api/shared/' + token); }
function apiDeleteShare(token) { return fetch('/api/shared/' + token, { method: 'DELETE' }); }
+// Minimales User-Verzeichnis (jeder eingeloggte User) – z. B. um eine Session zuzuweisen.
+function apiGetUsers() { return _get('/api/users'); }
+
// ── Admin User API ──
function apiAdminGetUsers() { return _get('/api/admin/users'); }
diff --git a/wwwroot/js/cards.js b/wwwroot/js/cards.js
index 029f002..3e7e07f 100644
--- a/wwwroot/js/cards.js
+++ b/wwwroot/js/cards.js
@@ -87,6 +87,35 @@ function buildTelegramBotCard(bot) {
}
+// ── User Card Helper ──
+// Erzeugt ein kompaktes .card-Element für einen Benutzer (für den Zuweisungs-Picker).
+function buildUserCard(user) {
+ const card = document.createElement('div');
+ card.className = 'card card-compact';
+
+ const badges = [];
+ if (user.isAdmin) {
+ badges.push('
Admin');
+ }
+
+ const metaParts = [];
+ metaParts.push(`
${esc(user.username)}`);
+
+ const title = user.displayName || user.username;
+ card.innerHTML = `
+
+
+ ${esc(title)}
+ ${badges.join('')}
+
+ ${metaParts.length ? `
${metaParts.join('')}
` : ''}
+
+ `;
+
+ return card;
+}
+
+
// ── Agent Card Helper ──
// Erzeugt ein .card-Element für einen Agent (wiederverwendbar für Dashboard + Picker).
diff --git a/wwwroot/js/pages/session-page.js b/wwwroot/js/pages/session-page.js
index 76bab02..0930ee5 100644
--- a/wwwroot/js/pages/session-page.js
+++ b/wwwroot/js/pages/session-page.js
@@ -37,6 +37,9 @@ registerPage('session', {
const addCommandBtn = document.getElementById('addCommandBtn');
const unityMcpUrlEl = document.getElementById('sessionUnityMcpUrl');
const unityMcpTokenEl = document.getElementById('sessionUnityMcpToken');
+ const ownerRow = document.getElementById('sessionOwnerRow');
+ const userSelectCard = document.getElementById('sessionUserSelectCard');
+ const userSelect = document.getElementById('sessionUserSelect');
const more = document.querySelector('.more');
// Avatar Editor initialisieren
@@ -123,6 +126,11 @@ registerPage('session', {
updateReviewVisibility();
setupAgentPicker(finalizerAgentSelectCard, finalizerAgentSelect, session && session.finalizerAgentId, 'fa-flag-checkered', 'Kein Finalizer-Agent');
+ // User-Zuweisung (jeder Besitzer, nur für bestehende Sessions)
+ if (!isNew) {
+ initSessionUserPicker(ownerRow, userSelectCard, userSelect, session && session.userId);
+ }
+
initMoreButton(more);
// Workspace Browse
@@ -179,6 +187,16 @@ registerPage('session', {
unityMcpToken: unityMcpTokenEl.value.trim() || null
};
+ // Session einem anderen Benutzer zuweisen. Wechselt der Besitzer tatsächlich,
+ // erst rückfragen – die Session verschwindet danach aus der eigenen Übersicht.
+ if (!isNew && userSelect.value && userSelect.value !== (session && session.userId)) {
+ var targetLabel = userSelect.dataset.userLabel || 'einem anderen Benutzer';
+ if (!confirm('Diese Session an "' + targetLabel + '" zuweisen? Sie verschwindet danach aus deiner Übersicht.')) {
+ return;
+ }
+ data.userId = userSelect.value;
+ }
+
if (isNew) {
await apiCreateSession(data);
} else {
@@ -284,4 +302,53 @@ async function initTelegramBotPicker(cardEl, selectEl, currentBotId) {
});
}
+// Session einem anderen Benutzer zuweisen (jeder Besitzer seiner eigenen Session).
+async function initSessionUserPicker(rowEl, cardEl, selectEl, currentOwnerId) {
+ var users = [];
+ try {
+ var result = await apiGetUsers();
+ if (Array.isArray(result)) users = result;
+ } catch (e) {
+ // Fehler beim Laden → Zuweisung bleibt versteckt
+ return;
+ }
+ var userMap = {};
+ for (var i = 0; i < users.length; i++) userMap[users[i].userId] = users[i];
+
+ function userLabel(user) {
+ return user ? (user.displayName || user.username || '') : '';
+ }
+
+ function renderUserInCard(user) {
+ var inner = user ? buildUserCard(user) : null;
+ _renderCardPreview(cardEl, inner, 'fa-user', 'Kein Benutzer', 'agent-select-change');
+ selectEl.dataset.userLabel = userLabel(user);
+ }
+
+ selectEl.value = currentOwnerId || '';
+ renderUserInCard(userMap[currentOwnerId] || null);
+ rowEl.hidden = false;
+
+ cardEl.addEventListener('click', function() {
+ openUserPickerModal(users, selectEl.value, function(selectedUserId) {
+ // "Keine Änderung" (null) ignorieren – eine Session muss immer einen Besitzer haben.
+ if (!selectedUserId) return;
+ selectEl.value = selectedUserId;
+ renderUserInCard(userMap[selectedUserId] || null);
+ });
+ });
+}
+
+function openUserPickerModal(users, currentId, onSelect) {
+ var items = users.map(function(u) {
+ u._pickerId = u.userId;
+ return u;
+ });
+ _openPickerModal('Benutzer auswählen', items, currentId, onSelect, {
+ noneLabel: 'Keine Änderung',
+ noneIcon: 'fa-user',
+ buildCard: function(u) { return buildUserCard(u); }
+ });
+}
+