Add: Ticket Benutzer-Filter, Dropdown-Styling, User Model Felder fix
This commit is contained in:
@@ -8,6 +8,8 @@ class User {
|
|||||||
u.id, u.username, u.email, u.first_name, u.last_name,
|
u.id, u.username, u.email, u.first_name, u.last_name,
|
||||||
u.is_active, u.must_change_password, u.email_notifications, u.last_login,
|
u.is_active, u.must_change_password, u.email_notifications, u.last_login,
|
||||||
u.created_at, u.updated_at, u.role_id, u.azure_id,
|
u.created_at, u.updated_at, u.role_id, u.azure_id,
|
||||||
|
u.department, u.position, u.phone, u.location, u.manager_id,
|
||||||
|
u.cost_center, u.employment_type, u.work_hours, u.joined_date, u.avatar_url,
|
||||||
r.name as role_name, r.description as role_description
|
r.name as role_name, r.description as role_description
|
||||||
FROM users u
|
FROM users u
|
||||||
LEFT JOIN roles r ON u.role_id = r.id
|
LEFT JOIN roles r ON u.role_id = r.id
|
||||||
@@ -23,6 +25,8 @@ class User {
|
|||||||
u.id, u.username, u.email, u.first_name, u.last_name,
|
u.id, u.username, u.email, u.first_name, u.last_name,
|
||||||
u.is_active, u.must_change_password, u.email_notifications, u.last_login,
|
u.is_active, u.must_change_password, u.email_notifications, u.last_login,
|
||||||
u.created_at, u.updated_at, u.role_id, u.azure_id,
|
u.created_at, u.updated_at, u.role_id, u.azure_id,
|
||||||
|
u.department, u.position, u.phone, u.location, u.manager_id,
|
||||||
|
u.cost_center, u.employment_type, u.work_hours, u.joined_date, u.avatar_url,
|
||||||
r.name as role_name, r.description as role_description
|
r.name as role_name, r.description as role_description
|
||||||
FROM users u
|
FROM users u
|
||||||
LEFT JOIN roles r ON u.role_id = r.id
|
LEFT JOIN roles r ON u.role_id = r.id
|
||||||
|
|||||||
@@ -1250,4 +1250,4 @@ async function invalidateUserSessions(azureId) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { pollMailbox, pollMonitoringMailbox, pollMdoAlerts, getTeamsAllChannels, getIntuneManagedDevices, getAzureGroups, getAzureGroupMembers, getEntraSubscribedSkus, getEntraLicenseUsers, getDepartmentManager, searchEntraUserByName, syncItTopicsToPlanner, getPlannerBuckets, getSecureScore, getRiskyUsers, getDefenderAlerts, getNonCompliantDevices, getUsersWithoutMfa, getEntraUsers, getAllMfaRegistrationDetails, getEntraUserGroups, getDirectoryRolesWithMembers, addGroupMember, removeGroupMember, getUserEntraProfile, getUserLicenseDetails, getUserSignInActivity, getUserSignInRisk, getConditionalAccessPolicies, invalidateUserSessions };
|
module.exports = { getClientToken, pollMailbox, pollMonitoringMailbox, pollMdoAlerts, getTeamsAllChannels, getIntuneManagedDevices, getAzureGroups, getAzureGroupMembers, getEntraSubscribedSkus, getEntraLicenseUsers, getDepartmentManager, searchEntraUserByName, syncItTopicsToPlanner, getPlannerBuckets, getSecureScore, getRiskyUsers, getDefenderAlerts, getNonCompliantDevices, getUsersWithoutMfa, getEntraUsers, getAllMfaRegistrationDetails, getEntraUserGroups, getDirectoryRolesWithMembers, addGroupMember, removeGroupMember, getUserEntraProfile, getUserLicenseDetails, getUserSignInActivity, getUserSignInRisk, getConditionalAccessPolicies, invalidateUserSessions };
|
||||||
|
|||||||
@@ -172,6 +172,8 @@ const TicketsPage = () => {
|
|||||||
const [statusFilter, setStatusFilter] = useState('');
|
const [statusFilter, setStatusFilter] = useState('');
|
||||||
const [priorityFilter, setPriorityFilter] = useState('');
|
const [priorityFilter, setPriorityFilter] = useState('');
|
||||||
const [categoryFilter, setCategoryFilter] = useState('');
|
const [categoryFilter, setCategoryFilter] = useState('');
|
||||||
|
const [userFilter, setUserFilter] = useState('');
|
||||||
|
const [allUsers, setAllUsers] = useState([]);
|
||||||
const [viewMode, setViewMode] = useState(() => localStorage.getItem('ticketsViewMode') || 'table');
|
const [viewMode, setViewMode] = useState(() => localStorage.getItem('ticketsViewMode') || 'table');
|
||||||
|
|
||||||
// Drag & Drop
|
// Drag & Drop
|
||||||
@@ -195,7 +197,10 @@ const TicketsPage = () => {
|
|||||||
});
|
});
|
||||||
const [formLoading, setFormLoading] = useState(false);
|
const [formLoading, setFormLoading] = useState(false);
|
||||||
|
|
||||||
useEffect(() => { loadAll(); }, [statusFilter, priorityFilter, categoryFilter, searchTerm]);
|
useEffect(() => { loadAll(); }, [statusFilter, priorityFilter, categoryFilter, searchTerm, userFilter]);
|
||||||
|
useEffect(() => {
|
||||||
|
userService.getAll().then(setAllUsers).catch(() => {});
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Auto-refresh alle 30 Sekunden
|
// Auto-refresh alle 30 Sekunden
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -233,6 +238,7 @@ const TicketsPage = () => {
|
|||||||
priority: priorityFilter || undefined,
|
priority: priorityFilter || undefined,
|
||||||
category: categoryFilter || undefined,
|
category: categoryFilter || undefined,
|
||||||
search: searchTerm || undefined,
|
search: searchTerm || undefined,
|
||||||
|
assigned_to: userFilter || undefined,
|
||||||
}),
|
}),
|
||||||
ticketService.getStats(),
|
ticketService.getStats(),
|
||||||
]);
|
]);
|
||||||
@@ -417,6 +423,14 @@ const TicketsPage = () => {
|
|||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
<select className="form-select" value={userFilter} onChange={(e) => setUserFilter(e.target.value)} style={{ width: 'auto', minWidth: '160px' }}>
|
||||||
|
<option value="">👤 Alle Mitarbeiter</option>
|
||||||
|
{allUsers.map(u => (
|
||||||
|
<option key={u.id} value={u.id}>
|
||||||
|
{u.first_name || u.last_name ? `${u.first_name || ''} ${u.last_name || ''}`.trim() : u.username}
|
||||||
|
</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
<select className="form-select" value={priorityFilter} onChange={(e) => setPriorityFilter(e.target.value)} style={{ width: 'auto', minWidth: '130px' }}>
|
<select className="form-select" value={priorityFilter} onChange={(e) => setPriorityFilter(e.target.value)} style={{ width: 'auto', minWidth: '130px' }}>
|
||||||
<option value="">Priorität (alle)</option>
|
<option value="">Priorität (alle)</option>
|
||||||
<option value="kritisch">🔴 Kritisch</option>
|
<option value="kritisch">🔴 Kritisch</option>
|
||||||
|
|||||||
@@ -971,7 +971,7 @@ const EditModal = ({ user, allUsers, onClose, onSaved }) => {
|
|||||||
))}
|
))}
|
||||||
<div className="bv-form-row">
|
<div className="bv-form-row">
|
||||||
<label className="bv-form-label">Beschäftigungsart</label>
|
<label className="bv-form-label">Beschäftigungsart</label>
|
||||||
<select className="form-input" value={form.employment_type} onChange={e => setForm(p => ({...p, employment_type: e.target.value}))}>
|
<select className="bv-modal-select" value={form.employment_type} onChange={e => setForm(p => ({...p, employment_type: e.target.value}))}>
|
||||||
<option>Vollzeit</option><option>Teilzeit</option><option>Minijob</option><option>Werkstudent</option>
|
<option>Vollzeit</option><option>Teilzeit</option><option>Minijob</option><option>Werkstudent</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
@@ -985,7 +985,7 @@ const EditModal = ({ user, allUsers, onClose, onSaved }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="bv-form-row">
|
<div className="bv-form-row">
|
||||||
<label className="bv-form-label">Vorgesetzter</label>
|
<label className="bv-form-label">Vorgesetzter</label>
|
||||||
<select className="form-input" value={form.manager_id} onChange={e => setForm(p => ({...p, manager_id: e.target.value}))}>
|
<select className="bv-modal-select" value={form.manager_id} onChange={e => setForm(p => ({...p, manager_id: e.target.value}))}>
|
||||||
<option value="">— kein Vorgesetzter —</option>
|
<option value="">— kein Vorgesetzter —</option>
|
||||||
{allUsers.filter(u => u.id !== user.id).map(u => (
|
{allUsers.filter(u => u.id !== user.id).map(u => (
|
||||||
<option key={u.id} value={u.id}>{u.first_name} {u.last_name} ({u.username})</option>
|
<option key={u.id} value={u.id}>{u.first_name} {u.last_name} ({u.username})</option>
|
||||||
|
|||||||
@@ -4056,3 +4056,80 @@ html[data-theme="light"] .ap-pill:hover { color: #1d1d1f; border-color: #94a3b8;
|
|||||||
.ap-left-panel { display: none; }
|
.ap-left-panel { display: none; }
|
||||||
.ap-right-panel { padding: 16px; }
|
.ap-right-panel { padding: 16px; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── Global Select Styling ── */
|
||||||
|
select, .form-select, select.form-control {
|
||||||
|
background-color: #1e293b !important;
|
||||||
|
color: #f1f5f9 !important;
|
||||||
|
border: 1px solid rgba(255,255,255,0.1) !important;
|
||||||
|
border-radius: 8px !important;
|
||||||
|
padding: 8px 12px !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
outline: none !important;
|
||||||
|
cursor: pointer !important;
|
||||||
|
appearance: none !important;
|
||||||
|
-webkit-appearance: none !important;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") !important;
|
||||||
|
background-repeat: no-repeat !important;
|
||||||
|
background-position: right 12px center !important;
|
||||||
|
padding-right: 36px !important;
|
||||||
|
transition: border-color 0.2s !important;
|
||||||
|
}
|
||||||
|
select:focus, .form-select:focus, select.form-control:focus {
|
||||||
|
border-color: #0d9488 !important;
|
||||||
|
box-shadow: 0 0 0 2px rgba(13,148,136,0.15) !important;
|
||||||
|
}
|
||||||
|
select option {
|
||||||
|
background-color: #1e293b !important;
|
||||||
|
color: #f1f5f9 !important;
|
||||||
|
}
|
||||||
|
select:hover {
|
||||||
|
border-color: rgba(255,255,255,0.2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── AP Form Select (AssetsPage) ── */
|
||||||
|
.ap-form-input[type="text"], .ap-form-input, select.ap-form-input {
|
||||||
|
background-color: #1e293b !important;
|
||||||
|
color: #f1f5f9 !important;
|
||||||
|
border: 1px solid rgba(255,255,255,0.1) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ── BV Modal Select (Benutzerverwaltung) ── */
|
||||||
|
.bv-modal-select, .bv-form-select {
|
||||||
|
background-color: #1e293b;
|
||||||
|
color: #f1f5f9;
|
||||||
|
border: 1px solid rgba(255,255,255,0.1);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 36px 8px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
appearance: none;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: right 12px center;
|
||||||
|
}
|
||||||
|
.bv-modal-select:focus {
|
||||||
|
border-color: #0d9488;
|
||||||
|
box-shadow: 0 0 0 2px rgba(13,148,136,0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Light Theme Overrides für Global Selects */
|
||||||
|
html[data-theme="light"] select,
|
||||||
|
html[data-theme="light"] .form-select,
|
||||||
|
html[data-theme="light"] select.form-control {
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
color: #0f172a !important;
|
||||||
|
border-color: #e2e8f0 !important;
|
||||||
|
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%2364748b' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E") !important;
|
||||||
|
}
|
||||||
|
html[data-theme="light"] select option {
|
||||||
|
background-color: #ffffff !important;
|
||||||
|
color: #0f172a !important;
|
||||||
|
}
|
||||||
|
html[data-theme="light"] .bv-modal-select {
|
||||||
|
background-color: #ffffff;
|
||||||
|
color: #0f172a;
|
||||||
|
border-color: #e2e8f0;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user