update
This commit is contained in:
@@ -4,6 +4,7 @@ $appBaseUrl = $GLOBALS['app_base_url'] ?? '';
|
|||||||
$defaultNavLinks = [
|
$defaultNavLinks = [
|
||||||
['id' => 'dashboard', 'label' => 'Dashboard', 'href' => $appBaseUrl . '/admin/dashboard.php'],
|
['id' => 'dashboard', 'label' => 'Dashboard', 'href' => $appBaseUrl . '/admin/dashboard.php'],
|
||||||
['id' => 'settings', 'label' => 'API & Tabellen', 'href' => $appBaseUrl . '/admin/settings.php'],
|
['id' => 'settings', 'label' => 'API & Tabellen', 'href' => $appBaseUrl . '/admin/settings.php'],
|
||||||
|
['id' => 'users', 'label' => 'Userverwaltung', 'href' => $appBaseUrl . '/admin/users.php'],
|
||||||
['id' => 'profile', 'label' => 'Mein Konto', 'href' => $appBaseUrl . '/admin/profile.php'],
|
['id' => 'profile', 'label' => 'Mein Konto', 'href' => $appBaseUrl . '/admin/profile.php'],
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@@ -6,48 +6,6 @@ require __DIR__ . '/accountsetup_config.php';
|
|||||||
require dirname(__DIR__) . '/../structure/layout_start.php';
|
require dirname(__DIR__) . '/../structure/layout_start.php';
|
||||||
?>
|
?>
|
||||||
<main class="max-w-5xl mx-auto p-4 md:p-6 flex-1 w-full space-y-6">
|
<main class="max-w-5xl mx-auto p-4 md:p-6 flex-1 w-full space-y-6">
|
||||||
<section class="section-card" data-role="owner">
|
|
||||||
<div class="flex items-center justify-between mb-3">
|
|
||||||
<h4>Team</h4>
|
|
||||||
<button type="button" id="btn-user-add" class="btn">+ Nutzer</button>
|
|
||||||
</div>
|
|
||||||
<div class="overflow-auto">
|
|
||||||
<table class="team-table" id="teamTable">
|
|
||||||
<thead>
|
|
||||||
<tr><th>Name</th><th>E-Mail</th><th>Rolle</th><th>Status</th><th class="text-right">Aktionen</th></tr>
|
|
||||||
</thead>
|
|
||||||
<tbody></tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
<form id="userForm" class="space-y-3 mt-4 hidden">
|
|
||||||
<input type="hidden" name="user_id">
|
|
||||||
<label class="block text-sm text-slate-600">Name
|
|
||||||
<input type="text" name="name" class="input mt-1" required>
|
|
||||||
</label>
|
|
||||||
<label class="block text-sm text-slate-600">E-Mail
|
|
||||||
<input type="email" name="email" class="input mt-1" required>
|
|
||||||
</label>
|
|
||||||
<label class="block text-sm text-slate-600">Rolle
|
|
||||||
<select name="role" class="input mt-1">
|
|
||||||
<option value="owner">Owner</option>
|
|
||||||
<option value="admin">Admin</option>
|
|
||||||
<option value="editor">Editor</option>
|
|
||||||
<option value="viewer">Viewer</option>
|
|
||||||
</select>
|
|
||||||
</label>
|
|
||||||
<label class="inline-flex items-center gap-2 text-sm text-slate-600">
|
|
||||||
<input type="checkbox" name="is_active" checked> Aktiv
|
|
||||||
</label>
|
|
||||||
<label class="inline-flex items-center gap-2 text-sm text-slate-600 reset-only hidden">
|
|
||||||
<input type="checkbox" name="reset_password"> Passwort zurücksetzen
|
|
||||||
</label>
|
|
||||||
<div class="flex justify-end gap-2">
|
|
||||||
<button type="button" id="userFormCancel" class="btn">Abbrechen</button>
|
|
||||||
<button type="submit" class="btn">Speichern</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="section-card" data-role="admin">
|
<section class="section-card" data-role="admin">
|
||||||
<div class="flex items-center justify-between mb-3">
|
<div class="flex items-center justify-between mb-3">
|
||||||
<h4>Absender für Testmails</h4>
|
<h4>Absender für Testmails</h4>
|
||||||
@@ -152,7 +110,7 @@ require dirname(__DIR__) . '/../structure/layout_start.php';
|
|||||||
|
|
||||||
<div id="toast-root"></div>
|
<div id="toast-root"></div>
|
||||||
|
|
||||||
<dialog id="bridgeSetupDialog" class="rounded-xl max-w-4xl w-[92vw]">
|
<dialog id="bridgeSetupDialog" class="rounded-xl max-w-4xl w-[92vw] p-5">
|
||||||
<div class="flex items-center justify-between gap-3 border-b border-slate-200 pb-3 mb-4">
|
<div class="flex items-center justify-between gap-3 border-b border-slate-200 pb-3 mb-4">
|
||||||
<h3 class="text-lg font-semibold">Bridge-Setup</h3>
|
<h3 class="text-lg font-semibold">Bridge-Setup</h3>
|
||||||
<button type="button" id="btn-close-bridge-setup" class="btn">Schliessen</button>
|
<button type="button" id="btn-close-bridge-setup" class="btn">Schliessen</button>
|
||||||
|
|||||||
56
partials/landingpage/accountsetup/users.php
Normal file
56
partials/landingpage/accountsetup/users.php
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<?php
|
||||||
|
$pageTitle = 'Email Template System – Userverwaltung';
|
||||||
|
$pageId = 'admin';
|
||||||
|
$navActive = 'users';
|
||||||
|
require __DIR__ . '/accountsetup_config.php';
|
||||||
|
require dirname(__DIR__) . '/../structure/layout_start.php';
|
||||||
|
?>
|
||||||
|
<main class="max-w-5xl mx-auto p-4 md:p-6 flex-1 w-full space-y-6">
|
||||||
|
<section class="section-card" data-role="owner">
|
||||||
|
<div class="flex items-center justify-between mb-3">
|
||||||
|
<h4>Team</h4>
|
||||||
|
<button type="button" id="btn-user-add" class="btn">+ Nutzer</button>
|
||||||
|
</div>
|
||||||
|
<div class="overflow-auto">
|
||||||
|
<table class="team-table" id="teamTable">
|
||||||
|
<thead>
|
||||||
|
<tr><th>Name</th><th>E-Mail</th><th>Rolle</th><th>Status</th><th class="text-right">Aktionen</th></tr>
|
||||||
|
</thead>
|
||||||
|
<tbody></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<form id="userForm" class="space-y-3 mt-4 hidden">
|
||||||
|
<input type="hidden" name="user_id">
|
||||||
|
<label class="block text-sm text-slate-600">Name
|
||||||
|
<input type="text" name="name" class="input mt-1" required>
|
||||||
|
</label>
|
||||||
|
<label class="block text-sm text-slate-600">E-Mail
|
||||||
|
<input type="email" name="email" class="input mt-1" required>
|
||||||
|
</label>
|
||||||
|
<label class="block text-sm text-slate-600">Rolle
|
||||||
|
<select name="role" class="input mt-1">
|
||||||
|
<option value="owner">Owner</option>
|
||||||
|
<option value="admin">Admin</option>
|
||||||
|
<option value="editor">Editor</option>
|
||||||
|
<option value="viewer">Viewer</option>
|
||||||
|
</select>
|
||||||
|
</label>
|
||||||
|
<label class="inline-flex items-center gap-2 text-sm text-slate-600">
|
||||||
|
<input type="checkbox" name="is_active" checked> Aktiv
|
||||||
|
</label>
|
||||||
|
<label class="inline-flex items-center gap-2 text-sm text-slate-600 reset-only hidden">
|
||||||
|
<input type="checkbox" name="reset_password"> Passwort zurücksetzen
|
||||||
|
</label>
|
||||||
|
<div class="flex justify-end gap-2">
|
||||||
|
<button type="button" id="userFormCancel" class="btn">Abbrechen</button>
|
||||||
|
<button type="submit" class="btn">Speichern</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
</main>
|
||||||
|
|
||||||
|
<div id="toast-root"></div>
|
||||||
|
<?php
|
||||||
|
tpl_add_script(app_asset_url('/assets/js/toast.js'));
|
||||||
|
tpl_add_script(app_asset_url('/assets/js/account.js'), 'footer', false, false, '', null, true);
|
||||||
|
require dirname(__DIR__) . '/../structure/layout_end.php';
|
||||||
@@ -5,6 +5,7 @@ $appBaseUrl = $layoutContext['app_base_url'] ?? '';
|
|||||||
$navLinks = $navLinks ?? [
|
$navLinks = $navLinks ?? [
|
||||||
['id' => 'dashboard', 'label' => 'Dashboard', 'href' => $appBaseUrl . '/admin/dashboard.php'],
|
['id' => 'dashboard', 'label' => 'Dashboard', 'href' => $appBaseUrl . '/admin/dashboard.php'],
|
||||||
['id' => 'settings', 'label' => 'API & Tabellen', 'href' => $appBaseUrl . '/admin/settings.php'],
|
['id' => 'settings', 'label' => 'API & Tabellen', 'href' => $appBaseUrl . '/admin/settings.php'],
|
||||||
|
['id' => 'users', 'label' => 'Userverwaltung', 'href' => $appBaseUrl . '/admin/users.php'],
|
||||||
['id' => 'profile', 'label' => 'Mein Konto', 'href' => $appBaseUrl . '/admin/profile.php'],
|
['id' => 'profile', 'label' => 'Mein Konto', 'href' => $appBaseUrl . '/admin/profile.php'],
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -48,6 +49,7 @@ $showNavLinks = !$hasHeaderTabs && !empty($navLinks);
|
|||||||
<a href="<?= htmlspecialchars($appBaseUrl . '/admin/profile.php') ?>" class="user-menu-item" data-menu="profile">Profil</a>
|
<a href="<?= htmlspecialchars($appBaseUrl . '/admin/profile.php') ?>" class="user-menu-item" data-menu="profile">Profil</a>
|
||||||
<a href="<?= htmlspecialchars($appBaseUrl . '/admin/dashboard.php') ?>" class="user-menu-item" data-role="admin">Dashboard</a>
|
<a href="<?= htmlspecialchars($appBaseUrl . '/admin/dashboard.php') ?>" class="user-menu-item" data-role="admin">Dashboard</a>
|
||||||
<a href="<?= htmlspecialchars($appBaseUrl . '/admin/settings.php') ?>" class="user-menu-item" data-role="admin">API & Tabellen</a>
|
<a href="<?= htmlspecialchars($appBaseUrl . '/admin/settings.php') ?>" class="user-menu-item" data-role="admin">API & Tabellen</a>
|
||||||
|
<a href="<?= htmlspecialchars($appBaseUrl . '/admin/users.php') ?>" class="user-menu-item" data-role="owner">Userverwaltung</a>
|
||||||
<button id="btn-logout" type="button" class="user-menu-item text-red-600">Logout</button>
|
<button id="btn-logout" type="button" class="user-menu-item text-red-600">Logout</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
3
public/admin/users.php
Normal file
3
public/admin/users.php
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
<?php
|
||||||
|
require_once __DIR__ . '/../../config/fileload.php';
|
||||||
|
require_once __DIR__ . '/../../partials/landingpage/accountsetup/users.php';
|
||||||
@@ -21,7 +21,6 @@ let configExampleBtn;
|
|||||||
let configExampleDialog;
|
let configExampleDialog;
|
||||||
let bridgeSetupDialog;
|
let bridgeSetupDialog;
|
||||||
let openBridgeSetupBtn;
|
let openBridgeSetupBtn;
|
||||||
let adminLoadBridgeBtn;
|
|
||||||
let closeBridgeSetupBtn;
|
let closeBridgeSetupBtn;
|
||||||
|
|
||||||
export function initBridgeSetupPage() {
|
export function initBridgeSetupPage() {
|
||||||
@@ -40,7 +39,6 @@ export function initBridgeSetupPage() {
|
|||||||
modeInputs = Array.from(form.querySelectorAll('input[name="db_mode"]'));
|
modeInputs = Array.from(form.querySelectorAll('input[name="db_mode"]'));
|
||||||
bridgeSetupDialog = document.getElementById('bridgeSetupDialog');
|
bridgeSetupDialog = document.getElementById('bridgeSetupDialog');
|
||||||
openBridgeSetupBtn = document.getElementById('btn-open-bridge-setup');
|
openBridgeSetupBtn = document.getElementById('btn-open-bridge-setup');
|
||||||
adminLoadBridgeBtn = document.getElementById('btn-admin-load-bridge');
|
|
||||||
closeBridgeSetupBtn = document.getElementById('btn-close-bridge-setup');
|
closeBridgeSetupBtn = document.getElementById('btn-close-bridge-setup');
|
||||||
|
|
||||||
form.addEventListener('submit', submitBridgeSetup);
|
form.addEventListener('submit', submitBridgeSetup);
|
||||||
@@ -59,12 +57,6 @@ export function initBridgeSetupPage() {
|
|||||||
closeBridgeSetupBtn?.addEventListener('click', () => {
|
closeBridgeSetupBtn?.addEventListener('click', () => {
|
||||||
if (bridgeSetupDialog?.open) bridgeSetupDialog.close();
|
if (bridgeSetupDialog?.open) bridgeSetupDialog.close();
|
||||||
});
|
});
|
||||||
adminLoadBridgeBtn?.addEventListener('click', (ev) => {
|
|
||||||
if (bridgeSetupDialog?.showModal && !bridgeSetupDialog.open) {
|
|
||||||
bridgeSetupDialog.showModal();
|
|
||||||
}
|
|
||||||
loadTablesFromBridge(ev, { preserveSelection: state.selectedTables.length > 0 });
|
|
||||||
});
|
|
||||||
modeInputs.forEach(input => {
|
modeInputs.forEach(input => {
|
||||||
input.addEventListener('change', () => applyModeVisibility(input.value));
|
input.addEventListener('change', () => applyModeVisibility(input.value));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ let adminTablesAllSelect;
|
|||||||
let adminTablesSelectedSelect;
|
let adminTablesSelectedSelect;
|
||||||
let adminTablesAddBtn;
|
let adminTablesAddBtn;
|
||||||
let adminTablesRemoveBtn;
|
let adminTablesRemoveBtn;
|
||||||
|
let adminLoadBridgeBtn;
|
||||||
|
|
||||||
ensureConsoleCapture();
|
ensureConsoleCapture();
|
||||||
|
|
||||||
@@ -69,6 +70,7 @@ export function initAccountPage() {
|
|||||||
adminTablesSelectedSelect = document.getElementById('adminBridgeTablesSelected');
|
adminTablesSelectedSelect = document.getElementById('adminBridgeTablesSelected');
|
||||||
adminTablesAddBtn = document.getElementById('adminBridgeTablesAdd');
|
adminTablesAddBtn = document.getElementById('adminBridgeTablesAdd');
|
||||||
adminTablesRemoveBtn = document.getElementById('adminBridgeTablesRemove');
|
adminTablesRemoveBtn = document.getElementById('adminBridgeTablesRemove');
|
||||||
|
adminLoadBridgeBtn = document.getElementById('btn-admin-load-bridge');
|
||||||
|
|
||||||
document.getElementById('btn-user-add')?.addEventListener('click', () => openUserForm());
|
document.getElementById('btn-user-add')?.addEventListener('click', () => openUserForm());
|
||||||
document.getElementById('userFormCancel')?.addEventListener('click', () => closeUserForm());
|
document.getElementById('userFormCancel')?.addEventListener('click', () => closeUserForm());
|
||||||
@@ -112,6 +114,9 @@ export function initAccountPage() {
|
|||||||
adminTablesRemoveBtn?.addEventListener('click', () => {
|
adminTablesRemoveBtn?.addEventListener('click', () => {
|
||||||
removeAdminTables(getSelectedOptions(adminTablesSelectedSelect));
|
removeAdminTables(getSelectedOptions(adminTablesSelectedSelect));
|
||||||
});
|
});
|
||||||
|
adminLoadBridgeBtn?.addEventListener('click', () => {
|
||||||
|
refreshBridgeTablesFromEndpoint();
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener('bridge-setup-updated', (ev) => {
|
window.addEventListener('bridge-setup-updated', (ev) => {
|
||||||
const setup = ev?.detail || {};
|
const setup = ev?.detail || {};
|
||||||
@@ -413,6 +418,32 @@ function addAdminTables(list) {
|
|||||||
updateAdminTableSelects(whitelist, merged);
|
updateAdminTableSelects(whitelist, merged);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function refreshBridgeTablesFromEndpoint() {
|
||||||
|
if (state.loading) return;
|
||||||
|
state.loading = true;
|
||||||
|
try {
|
||||||
|
const res = await apiAction('account.bridge.test', { method: 'POST', data: {} });
|
||||||
|
if (!res?.ok) throw new Error(res?.error || 'Bridge konnte nicht abgefragt werden');
|
||||||
|
const fetched = normalizeTableList(res.tables || []);
|
||||||
|
if (!fetched.length) {
|
||||||
|
toast('Keine Tabellen vom Bridge-Endpunkt erhalten', false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const selected = normalizeTableList(state.settings.bridge_tables || []);
|
||||||
|
const selectedSet = new Set(selected);
|
||||||
|
const nextSelected = fetched.filter(name => selectedSet.has(name));
|
||||||
|
state.settings.bridge_setup = state.settings.bridge_setup || {};
|
||||||
|
state.settings.bridge_setup.tables = fetched;
|
||||||
|
state.settings.bridge_tables = nextSelected;
|
||||||
|
updateAdminTableSelects(fetched, nextSelected);
|
||||||
|
toast('Tabellen aktualisiert', true);
|
||||||
|
} catch (err) {
|
||||||
|
toast(err.message || 'Bridge konnte nicht geprüft werden', false);
|
||||||
|
} finally {
|
||||||
|
state.loading = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function removeAdminTables(list) {
|
function removeAdminTables(list) {
|
||||||
const whitelist = normalizeTableList(state.settings.bridge_setup?.tables || []);
|
const whitelist = normalizeTableList(state.settings.bridge_setup?.tables || []);
|
||||||
if (!whitelist.length) return;
|
if (!whitelist.length) return;
|
||||||
|
|||||||
Reference in New Issue
Block a user