Implement RBAC roles system
This commit is contained in:
@@ -10,82 +10,94 @@
|
||||
<h3 class="card-title">Active connections</h3>
|
||||
</div>
|
||||
<div class="card-body table-responsive p-0">
|
||||
<table id="dashboard-clients-table" class="table table-striped w-100 mb-0">
|
||||
<thead><tr><th>Client</th><th>Current Screen</th><th>Current Slide</th><th>IP</th><th>Viewport</th><th>Connected/Updated</th><th>Actions</th></tr></thead>
|
||||
<tbody id="dashboard-clients-table-body">
|
||||
{{#if clients.length}}
|
||||
{{#each clients}}
|
||||
<tr data-client-key="{{id}}" data-client-id="{{clientId}}" data-client-device-id="{{deviceId}}" data-client-screen-slug="{{screen_slug}}">
|
||||
<td data-label="Client" class="client-rename-cell" title="Double-click to rename">
|
||||
<div>{{#if client_name}}{{client_name}}{{else}}Unknown{{/if}}</div>
|
||||
</td>
|
||||
<td data-label="Current Screen">
|
||||
<div>{{#if screen_name}}{{screen_name}}{{else}}Unknown{{/if}}</div>
|
||||
</td>
|
||||
<td data-label="Current Slide">
|
||||
{{#if currentSlideTitle}}
|
||||
<div>{{currentSlideTitle}}</div>
|
||||
{{else}}
|
||||
<span class="empty">No slide currently showing</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td data-label="IP">{{#if clientIp}}{{clientIp}}{{else}}<span class="empty">Unknown</span>{{/if}}</td>
|
||||
<td data-label="Viewport">
|
||||
{{#if viewport}}
|
||||
{{viewport.width}}x{{viewport.height}}
|
||||
{{else}}
|
||||
<span class="empty">Unknown</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td data-label="Connected/Updated">
|
||||
{{#if connectedAt}}
|
||||
<div>{{connectedAtLabel}}</div>
|
||||
{{#if lastSeenAt}}
|
||||
<div class="subtle"><i>{{lastSeenAtLabel}}</i></div>
|
||||
<table id="dashboard-clients-table" class="table table-striped w-100 mb-0" data-has-actions-column="{{#if (hasPermission currentUser 'clients.allow')}}true{{else}}false{{/if}}">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Client</th>
|
||||
<th>Current Screen</th>
|
||||
<th>Current Slide</th>
|
||||
<th>IP</th>
|
||||
<th>Viewport</th>
|
||||
<th>Connected/Updated</th>
|
||||
{{#if (hasPermission currentUser 'clients.allow')}}<th>Actions</th>{{/if}}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="dashboard-clients-table-body">
|
||||
{{#if clients.length}}
|
||||
{{#each clients}}
|
||||
<tr data-client-key="{{id}}" data-client-id="{{clientId}}" data-client-device-id="{{deviceId}}" data-client-screen-slug="{{screen_slug}}">
|
||||
<td data-label="Client" class="client-rename-cell" title="Double-click to rename">
|
||||
<div>{{#if client_name}}{{client_name}}{{else}}Unknown{{/if}}</div>
|
||||
</td>
|
||||
<td data-label="Current Screen">
|
||||
<div>{{#if screen_name}}{{screen_name}}{{else}}Unknown{{/if}}</div>
|
||||
</td>
|
||||
<td data-label="Current Slide">
|
||||
{{#if currentSlideTitle}}
|
||||
<div>{{currentSlideTitle}}</div>
|
||||
{{else}}
|
||||
<span class="empty">No slide currently showing</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="empty">Unknown</span>
|
||||
</td>
|
||||
<td data-label="IP">{{#if clientIp}}{{clientIp}}{{else}}<span class="empty">Unknown</span>{{/if}}</td>
|
||||
<td data-label="Viewport">
|
||||
{{#if viewport}}
|
||||
{{viewport.width}}x{{viewport.height}}
|
||||
{{else}}
|
||||
<span class="empty">Unknown</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td data-label="Connected/Updated">
|
||||
{{#if connectedAt}}
|
||||
<div>{{connectedAtLabel}}</div>
|
||||
{{#if lastSeenAt}}
|
||||
<div class="subtle"><i>{{lastSeenAtLabel}}</i></div>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="empty">Unknown</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
{{#if (hasPermission currentUser 'clients.allow')}}
|
||||
<td data-label="Actions" class="text-end">
|
||||
<div class="actions justify-content-end">
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-confirm-message="Reloading will restart the player page. Continue?" data-async-command>
|
||||
<input type="hidden" name="command" value="reload" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm btn-danger">Reload</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-async-command>
|
||||
<input type="hidden" name="command" value="previous" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm btn-warning" aria-label="Previous slide">◀</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-async-command>
|
||||
<input type="hidden" name="command" value="next" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm btn-warning" aria-label="Next slide">▶</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-async-command>
|
||||
<input type="hidden" name="command" value="pause" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm btn-info">
|
||||
<i class="bi bi-pause-fill me-1" aria-hidden="false"></i>Pause
|
||||
</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-async-command>
|
||||
<input type="hidden" name="command" value="blackout" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm {{#if blackout}}btn-success{{else}}btn-secondary{{/if}}">
|
||||
<i class="bi bi-eye-slash me-1" aria-hidden="false"></i>Blackout
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td data-label="Actions" class="text-end">
|
||||
<div class="actions justify-content-end">
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-confirm-message="Reloading will restart the player page. Continue?" data-async-command>
|
||||
<input type="hidden" name="command" value="reload" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm btn-danger">Reload</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-async-command>
|
||||
<input type="hidden" name="command" value="previous" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm btn-warning" aria-label="Previous slide">◀</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-async-command>
|
||||
<input type="hidden" name="command" value="next" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm btn-warning" aria-label="Next slide">▶</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-async-command>
|
||||
<input type="hidden" name="command" value="pause" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm btn-info">
|
||||
<i class="bi bi-pause-fill me-1" aria-hidden="false"></i>Pause
|
||||
</button>
|
||||
</form>
|
||||
<form method="post" action="/admin/screens/{{screen_slug}}/commands" class="inline-form" data-async-command>
|
||||
<input type="hidden" name="command" value="blackout" />
|
||||
<input type="hidden" name="connectionId" value="{{id}}" />
|
||||
<button type="submit" class="btn btn-sm {{#if blackout}}btn-success{{else}}btn-secondary{{/if}}">
|
||||
<i class="bi bi-eye-slash me-1" aria-hidden="false"></i>Blackout
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<tr><td colspan="7" class="empty">No connected clients yet.</td></tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<tr><td colspan="{{#if (hasPermission currentUser 'clients.allow')}}7{{else}}6{{/if}}" class="empty">No connected clients yet.</td></tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -13,104 +13,126 @@
|
||||
<p class="dashboard-hero-copy">Use the cards below for the current totals, then jump to the screens table when you need a deeper look at playback and connection state.</p>
|
||||
</div>
|
||||
<div class="dashboard-hero-stats">
|
||||
{{#if (hasPermission currentUser "playlists.read")}}
|
||||
<div class="dashboard-hero-stat">
|
||||
<span class="dashboard-hero-stat-value">{{playlists.length}}</span>
|
||||
<span class="dashboard-hero-stat-label">playlists</span>
|
||||
</div>
|
||||
<div class="dashboard-hero-stat">
|
||||
<span class="dashboard-hero-stat-value">{{screens.length}}</span>
|
||||
<span class="dashboard-hero-stat-label">screens</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser "screens.read")}}
|
||||
<div class="dashboard-hero-stat">
|
||||
<span class="dashboard-hero-stat-value">{{screens.length}}</span>
|
||||
<span class="dashboard-hero-stat-label">screens</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser "clients.read")}}
|
||||
<div class="dashboard-hero-stat">
|
||||
<span class="dashboard-hero-stat-value">{{connectedClientsCount}}</span>
|
||||
<span class="dashboard-hero-stat-label">clients</span>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card mb-4 card-outline card-primary dashboard-actions-card">
|
||||
<div class="card-header">
|
||||
<div class="dashboard-card-heading">
|
||||
<h3 class="card-title">Quick actions</h3>
|
||||
<p class="dashboard-card-subtitle">Send global commands without leaving the overview.</p>
|
||||
{{#if (hasPermission currentUser "dashboard.allow")}}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card mb-4 card-outline card-primary dashboard-actions-card">
|
||||
<div class="card-header">
|
||||
<div class="dashboard-card-heading">
|
||||
<h3 class="card-title">Quick actions</h3>
|
||||
<p class="dashboard-card-subtitle">Send global commands without
|
||||
leaving the overview.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="dashboard-action-grid">
|
||||
<form
|
||||
method="post"
|
||||
action="/admin/commands"
|
||||
class="dashboard-action-form"
|
||||
data-confirm-message="Reload all connected clients?"
|
||||
data-async-command
|
||||
>
|
||||
<input type="hidden" name="command" value="reload" />
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-danger dashboard-action-button"
|
||||
id="dashboard-reload-all-button"
|
||||
><i class="bi bi-arrow-repeat me-1" aria-hidden="true"></i>Reload all clients</button>
|
||||
<span class="dashboard-action-help">Restart every connected player page.</span>
|
||||
</form>
|
||||
<form
|
||||
method="post"
|
||||
action="/admin/commands"
|
||||
class="dashboard-action-form"
|
||||
data-confirm-message="Blackout all connected clients?"
|
||||
data-async-command
|
||||
>
|
||||
<input type="hidden" name="command" value="blackout" />
|
||||
<input type="hidden" name="blackout" value="true" />
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-secondary dashboard-action-button"
|
||||
id="dashboard-blackout-all-button"
|
||||
><i class="bi bi-eye-slash me-1" aria-hidden="false"></i>Blackout all clients</button>
|
||||
<span class="dashboard-action-help">Blank active players immediately.</span>
|
||||
</form>
|
||||
<div class="card-body">
|
||||
<div class="dashboard-action-grid">
|
||||
<form
|
||||
method="post"
|
||||
action="/admin/commands"
|
||||
class="dashboard-action-form"
|
||||
data-confirm-message="Reload all connected clients?"
|
||||
data-async-command
|
||||
>
|
||||
<input type="hidden" name="command" value="reload" />
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-danger dashboard-action-button"
|
||||
id="dashboard-reload-all-button"
|
||||
><i class="bi bi-arrow-repeat me-1" aria-hidden="true"></i>Reload all clients</button>
|
||||
<span class="dashboard-action-help">Restart every connected player page.</span>
|
||||
</form>
|
||||
<form
|
||||
method="post"
|
||||
action="/admin/commands"
|
||||
class="dashboard-action-form"
|
||||
data-confirm-message="Blackout all connected clients?"
|
||||
data-async-command
|
||||
>
|
||||
<input type="hidden" name="command" value="blackout" />
|
||||
<input type="hidden" name="blackout" value="true" />
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-secondary dashboard-action-button"
|
||||
id="dashboard-blackout-all-button"
|
||||
><i class="bi bi-eye-slash me-1" aria-hidden="false"></i>Blackout
|
||||
all clients</button>
|
||||
<span class="dashboard-action-help">Blank active players
|
||||
immediately.</span>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card card-outline card-secondary dashboard-table-card">
|
||||
<div class="card-header">
|
||||
<div class="dashboard-card-heading">
|
||||
<h3 class="card-title">Current screens</h3>
|
||||
<p class="dashboard-card-subtitle">Player URL, playlist assignment, and live connection count.</p>
|
||||
{{#if (hasPermission currentUser "screens.read")}}
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="card card-outline card-secondary dashboard-table-card">
|
||||
<div class="card-header">
|
||||
<div class="dashboard-card-heading">
|
||||
<h3 class="card-title">Current screens</h3>
|
||||
<p class="dashboard-card-subtitle">Player URL, playlist assignment,
|
||||
and live connection count.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body table-responsive p-0">
|
||||
<table
|
||||
id="dashboard-screens-table"
|
||||
class="table table-striped w-100 mb-0"
|
||||
>
|
||||
<thead><tr><th>Name</th><th>Player URL</th><th>Playlist</th><th
|
||||
>Connected clients</th></tr></thead>
|
||||
<tbody>
|
||||
{{#if screens.length}}
|
||||
{{#each screens}}
|
||||
<tr data-client-key="{{id}}">
|
||||
<td data-label="Name">{{name}}</td>
|
||||
<td data-label="Player URL"><a
|
||||
href="{{playerUrl slug}}"
|
||||
target="_blank"
|
||||
>{{playerUrl slug}}</a></td>
|
||||
<td data-label="Playlist">{{playlist_name}}</td>
|
||||
<td data-label="Connected clients">
|
||||
{{#if player_connection_count}}
|
||||
<div class="connection-count">{{player_connection_count}}
|
||||
connected</div>
|
||||
{{else}}
|
||||
<span class="empty">No clients connected.</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<tr><td colspan="4" class="empty">No screens yet.</td></tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body table-responsive p-0">
|
||||
<table id="dashboard-screens-table" class="table table-striped w-100 mb-0">
|
||||
<thead><tr><th>Name</th><th>Player URL</th><th>Playlist</th><th>Connected clients</th></tr></thead>
|
||||
<tbody>
|
||||
{{#if screens.length}}
|
||||
{{#each screens}}
|
||||
<tr data-client-key="{{id}}">
|
||||
<td data-label="Name">{{name}}</td>
|
||||
<td data-label="Player URL"><a href="{{playerUrl slug}}" target="_blank">{{playerUrl slug}}</a></td>
|
||||
<td data-label="Playlist">{{playlist_name}}</td>
|
||||
<td data-label="Connected clients">
|
||||
{{#if player_connection_count}}
|
||||
<div class="connection-count">{{player_connection_count}} connected</div>
|
||||
{{else}}
|
||||
<span class="empty">No clients connected.</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<tr><td colspan="4" class="empty">No screens yet.</td></tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
@@ -0,0 +1,15 @@
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="text-center">
|
||||
<div class="display-1 fw-bold text-primary lh-1 mb-3">{{statusCode}}</div>
|
||||
<h1 class="h3 mb-3">{{errorTitle}}</h1>
|
||||
<p class="text-secondary mb-4">
|
||||
{{errorMessage}}
|
||||
</p>
|
||||
<a href="{{backUrl}}" class="btn btn-outline-secondary">
|
||||
<i class="bi bi-arrow-left me-1" aria-hidden="true"></i>
|
||||
{{backLabel}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+83
-51
@@ -18,7 +18,13 @@
|
||||
{{/if}}
|
||||
</head>
|
||||
<body class="hold-transition layout-fixed sidebar-expand-lg bg-body-tertiary {{#if authShell}}login-page{{/if}} {{bodyClass}}">
|
||||
{{#if authShell}}
|
||||
{{#if errorShell}}
|
||||
<main class="d-flex align-items-center justify-content-center min-vh-100 p-3 {{bodyClass}}">
|
||||
{{{body}}}
|
||||
</main>
|
||||
<script src="/assets/js/admin-page.js"></script>
|
||||
<script src="/assets/js/system-status.js"></script>
|
||||
{{else if authShell}}
|
||||
<main class="login-page d-flex align-items-center justify-content-center min-vh-100 p-3">
|
||||
<div class="login-box">
|
||||
{{{body}}}
|
||||
@@ -29,7 +35,7 @@
|
||||
{{else}}
|
||||
<div id="app-toast-container" class="toast-container position-fixed top-0 end-0 p-3">
|
||||
{{#if message}}
|
||||
<div class="toast align-items-center text-bg-primary border-0" id="app-toast" role="status" aria-live="polite" aria-atomic="true" data-bs-autohide="true" data-bs-delay="4000">
|
||||
<div class="toast align-items-center text-bg-{{#if messageVariant}}{{messageVariant}}{{else}}primary{{/if}} border-0" id="app-toast" role="status" aria-live="polite" aria-atomic="true" data-bs-autohide="true" data-bs-delay="4000" data-toast-variant="{{#if messageVariant}}{{messageVariant}}{{else}}primary{{/if}}">
|
||||
<div class="d-flex">
|
||||
<div class="toast-body">{{message}}</div>
|
||||
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Dismiss notification"></button>
|
||||
@@ -138,55 +144,81 @@
|
||||
<nav class="mt-2 flex-grow-1" aria-label="Main navigation">
|
||||
<ul class="nav sidebar-menu flex-column" data-lte-toggle="treeview" data-accordion="false" role="menu" id="navigation">
|
||||
<li class="nav-header">MAIN NAVIGATION</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'dashboard')}}active{{/if}}" href="/admin">
|
||||
<i class="nav-icon bi bi-speedometer2"></i>
|
||||
<p>Dashboard</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'clients')}}active{{/if}}" href="/admin/clients">
|
||||
<i class="nav-icon bi bi-broadcast"></i>
|
||||
<p>Connected clients</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'screens')}}active{{/if}}" href="/admin/screens">
|
||||
<i class="nav-icon bi bi-display"></i>
|
||||
<p>Screens</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'playlists')}}active{{/if}}" href="/admin/playlists">
|
||||
<i class="nav-icon bi bi-collection-play"></i>
|
||||
<p>Playlists</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'slides')}}active{{/if}}" href="/admin/slides">
|
||||
<i class="nav-icon bi bi-file-earmark-richtext"></i>
|
||||
<p>Slides</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'templates')}}active{{/if}}" href="/admin/templates">
|
||||
<i class="nav-icon bi bi-layout-text-window-reverse"></i>
|
||||
<p>Slide templates</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'canvas-sizes')}}active{{/if}}" href="/admin/canvas-sizes">
|
||||
<i class="nav-icon bi bi-aspect-ratio"></i>
|
||||
<p>Canvas sizes</p>
|
||||
</a>
|
||||
</li>
|
||||
<li class="nav-header">SETTINGS</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'users')}}active{{/if}}" href="/admin/users">
|
||||
<i class="nav-icon bi bi-people"></i>
|
||||
<p>Users</p>
|
||||
</a>
|
||||
</li>
|
||||
{{#if (hasPermission currentUser 'dashboard.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'dashboard')}}active{{/if}}" href="/admin">
|
||||
<i class="nav-icon bi bi-speedometer2"></i>
|
||||
<p>Dashboard</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser 'clients.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'clients')}}active{{/if}}" href="/admin/clients">
|
||||
<i class="nav-icon bi bi-broadcast"></i>
|
||||
<p>Connected clients</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser 'screens.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'screens')}}active{{/if}}" href="/admin/screens">
|
||||
<i class="nav-icon bi bi-display"></i>
|
||||
<p>Screens</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser 'playlists.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'playlists')}}active{{/if}}" href="/admin/playlists">
|
||||
<i class="nav-icon bi bi-collection-play"></i>
|
||||
<p>Playlists</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser 'slides.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'slides')}}active{{/if}}" href="/admin/slides">
|
||||
<i class="nav-icon bi bi-file-earmark-richtext"></i>
|
||||
<p>Slides</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser 'templates.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'templates')}}active{{/if}}" href="/admin/templates">
|
||||
<i class="nav-icon bi bi-layout-text-window-reverse"></i>
|
||||
<p>Slide templates</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser 'canvas-sizes.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'canvas-sizes')}}active{{/if}}" href="/admin/canvas-sizes">
|
||||
<i class="nav-icon bi bi-aspect-ratio"></i>
|
||||
<p>Canvas sizes</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (anyPermission currentUser 'users.read' 'rbac.read')}}
|
||||
<li class="nav-header">SETTINGS</li>
|
||||
{{#if (hasPermission currentUser 'users.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'users')}}active{{/if}}" href="/admin/users">
|
||||
<i class="nav-icon bi bi-people"></i>
|
||||
<p>Users</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{#if (hasPermission currentUser 'rbac.read')}}
|
||||
<li class="nav-item">
|
||||
<a class="nav-link {{#if (eq active 'rbac')}}active{{/if}}" href="/admin/rbac">
|
||||
<i class="nav-icon bi bi-shield-lock"></i>
|
||||
<p>Roles and permissions</p>
|
||||
</a>
|
||||
</li>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="sidebar-version mt-auto pt-2 text-secondary small">
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h2>Create role</h2>
|
||||
<p>Define a new role and choose its permissions before saving.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="post" action="/admin/rbac" id="role-create-form" data-async-save data-async-save-close-url="/admin/rbac">
|
||||
<div class="row g-4">
|
||||
<div class="col-12 col-xl-4 d-flex flex-column gap-4">
|
||||
<div class="card card-outline card-primary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Role details</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="role-name" class="form-label">Role name</label>
|
||||
<input id="role-name" name="name" class="form-control" value="{{formValues.name}}" required />
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label for="role-description" class="form-label">Description</label>
|
||||
<textarea id="role-description" name="description" class="form-control" rows="5">{{formValues.description}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-xl-8 d-flex flex-column gap-4">
|
||||
<div class="card card-outline card-secondary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Permissions</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<p class="text-body-secondary mb-3">Pick the permissions this role should have now.</p>
|
||||
{{#if permissionGroups.length}}
|
||||
<div class="accordion" id="role-create-permissions-accordion">
|
||||
{{#each permissionGroups}}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="create-heading-{{id}}">
|
||||
<button class="accordion-button {{#unless @first}}collapsed{{/unless}}" type="button" data-bs-toggle="collapse" data-bs-target="#create-collapse-{{id}}" aria-expanded="{{#if @first}}true{{else}}false{{/if}}" aria-controls="create-collapse-{{id}}">
|
||||
<span>{{title}}</span>
|
||||
{{#if categoryName}}
|
||||
<span class="badge text-bg-secondary ms-2">{{categoryName}}</span>
|
||||
{{/if}}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="create-collapse-{{id}}" class="accordion-collapse collapse {{#if @first}}show{{/if}}" aria-labelledby="create-heading-{{id}}" data-bs-parent="#role-create-permissions-accordion">
|
||||
<div class="accordion-body">
|
||||
<div class="row g-3">
|
||||
{{#each permissions}}
|
||||
<div class="col-12 col-md-6">
|
||||
<label class="form-check card card-outline card-secondary position-relative p-3 h-100 mb-0">
|
||||
<input class="form-check-input position-absolute top-0 end-0 m-3" type="checkbox" name="permission_keys[]" value="{{permission_key}}" data-permission-key="{{permission_key}}" {{#if isSelected}}checked{{/if}} />
|
||||
<span class="form-check-label pe-4">
|
||||
<strong>{{actionLabel}}</strong>
|
||||
<span class="d-block text-body-secondary small">{{#if description}}{{description}}{{else}}No description provided.{{/if}}</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="alert alert-warning mb-0">No permissions are available.</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-flex justify-content-end mt-4">
|
||||
<div class="btn-group" role="group" aria-label="Role actions">
|
||||
{{{saveActionButtons formId="role-create-form" saveLabel="Save" saveAndCloseLabel="Save and Close" saveAndCloseValue="close" showSaveAndNew=false}}}
|
||||
<a class="btn btn-warning" href="/admin/rbac" data-confirm-unsaved="You have unsaved changes. Leave this page?">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
@@ -0,0 +1,134 @@
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h2>Edit role - {{role.name}}</h2>
|
||||
<p>Choose which permissions and users this role receives.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-12 col-xl-4 d-flex flex-column gap-4">
|
||||
<div class="card card-outline card-primary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Role details</h3>
|
||||
</div>
|
||||
<form method="post" action="/admin/rbac/{{role.id}}" id="role-details-form" data-async-save data-async-save-close-url="/admin/rbac">
|
||||
<div class="card-body">
|
||||
<div class="mb-3">
|
||||
<label for="role-name-edit" class="form-label">Role Name</label>
|
||||
<input id="role-name-edit" name="name" class="form-control" value="{{role.name}}" required />
|
||||
</div>
|
||||
<div class="mb-0">
|
||||
<label for="role-description-edit" class="form-label">Description</label>
|
||||
<textarea id="role-description-edit" name="description" class="form-control" rows="5">{{role.description}}</textarea>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer d-flex justify-content-end">
|
||||
<div class="btn-group" role="group" aria-label="Role actions">
|
||||
{{{saveActionButtons formId="role-details-form" saveLabel="Save" saveAndCloseLabel="Save and Close" saveAndCloseValue="close" showSaveAndNew=false}}}
|
||||
</div>
|
||||
{{#unless role.user_count}}
|
||||
<form method="post" action="/admin/rbac/{{role.id}}/delete" class="inline-form" data-confirm-message="Delete {{role.name}}?">
|
||||
<button type="submit" class="btn btn-danger">Delete</button>
|
||||
</form>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="card card-outline card-secondary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Users</h3>
|
||||
</div>
|
||||
<form method="post" action="/admin/rbac/{{role.id}}/users" id="role-users-form" data-async-save data-async-save-close-url="/admin/rbac/{{role.id}}/edit">
|
||||
<div class="card-body p-0">
|
||||
<div class="px-3 pt-3">
|
||||
<p class="text-body-secondary mb-3">Choose the users who should belong to this role.</p>
|
||||
</div>
|
||||
{{#if users.length}}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-sm align-middle mb-0 w-100">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 1%" scope="col">Select</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Username</th>
|
||||
<th scope="col">Roles</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each users}}
|
||||
<tr>
|
||||
<td>
|
||||
<input class="form-check-input" type="checkbox" name="user_ids[]" value="{{id}}" {{#if isSelected}}checked{{/if}} />
|
||||
</td>
|
||||
<td><strong>{{name}}</strong></td>
|
||||
<td class="text-body-secondary">{{username}}</td>
|
||||
<td class="text-body-secondary">{{#if roleNames}}{{roleNames}}{{else}}No roles assigned{{/if}}</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="px-3 pb-3">
|
||||
<div class="alert alert-warning mb-0">Create at least one user before assigning this role.</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-xl-8 d-flex flex-column gap-4">
|
||||
<div class="card card-outline card-secondary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Permissions</h3>
|
||||
</div>
|
||||
<form method="post" action="/admin/rbac/{{role.id}}/permissions" id="role-permissions-form" data-async-save data-async-save-close-url="/admin/rbac/{{role.id}}/edit">
|
||||
<div class="card-body">
|
||||
<p class="text-body-secondary mb-3">Each section below is a resource. Pick the actions this role should have for that resource.</p>
|
||||
{{#if permissionGroups.length}}
|
||||
<div class="accordion" id="role-permissions-accordion">
|
||||
{{#each permissionGroups}}
|
||||
<div class="accordion-item">
|
||||
<h2 class="accordion-header" id="heading-{{id}}">
|
||||
<button class="accordion-button {{#unless @first}}collapsed{{/unless}}" type="button" data-bs-toggle="collapse" data-bs-target="#collapse-{{id}}" aria-expanded="{{#if @first}}true{{else}}false{{/if}}" aria-controls="collapse-{{id}}">
|
||||
<span>{{title}}</span>
|
||||
{{#if categoryName}}
|
||||
<span class="badge text-bg-secondary ms-2">{{categoryName}}</span>
|
||||
{{/if}}
|
||||
</button>
|
||||
</h2>
|
||||
<div id="collapse-{{id}}" class="accordion-collapse collapse {{#if @first}}show{{/if}}" aria-labelledby="heading-{{id}}" data-bs-parent="#role-permissions-accordion">
|
||||
<div class="accordion-body">
|
||||
<div class="row g-3">
|
||||
{{#each permissions}}
|
||||
<div class="col-12 col-md-6">
|
||||
<label class="form-check card card-outline card-secondary position-relative p-3 h-100 mb-0">
|
||||
<input class="form-check-input position-absolute top-0 end-0 m-3" type="checkbox" name="permission_keys[]" value="{{permission_key}}" data-permission-key="{{permission_key}}" {{#if isSelected}}checked{{/if}} />
|
||||
<span class="form-check-label pe-4">
|
||||
<strong>{{actionLabel}}</strong>
|
||||
<span class="d-block text-body-secondary small">{{#if description}}{{description}}{{else}}No description provided.{{/if}}</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="alert alert-warning mb-0">No permissions are available.</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="card-footer d-flex justify-content-end">
|
||||
<div class="btn-group" role="group" aria-label="Permission actions">
|
||||
{{{saveActionButtons formId="role-permissions-form" saveLabel="Save" saveAndCloseLabel="Save and Close" saveAndCloseValue="close" showSaveAndNew=false}}}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,70 @@
|
||||
<div class="page-header">
|
||||
<div>
|
||||
<h2>Roles and permissions</h2>
|
||||
<p>Define roles here, then assign those roles to users from either the role or users screen.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row g-4">
|
||||
<div class="col-12">
|
||||
<div class="card card-outline card-primary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Existing roles</h3>
|
||||
<div class="card-tools">
|
||||
<a class="btn btn-primary btn-sm" href="/admin/rbac/new">Add role</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body table-responsive p-0">
|
||||
<table class="table table-striped w-100 mb-0 users-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Role</th>
|
||||
<th>Description</th>
|
||||
<th>Users</th>
|
||||
<th>Permissions</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#if roles.length}}
|
||||
{{#each roles}}
|
||||
<tr>
|
||||
<td data-label="Role">
|
||||
<div class="user-cell">
|
||||
<div>
|
||||
<strong>{{name}}</strong>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td data-label="Description" title="{{description}}">
|
||||
{{#if description}}
|
||||
<span class="subtle">{{truncateText description 80}}</span>
|
||||
{{else}}
|
||||
<span class="empty">No description provided.</span>
|
||||
{{/if}}
|
||||
</td>
|
||||
<td data-label="Users">{{user_count}}</td>
|
||||
<td data-label="Permissions">{{permission_count}}</td>
|
||||
<td data-label="Actions">
|
||||
<div class="actions users-row-actions">
|
||||
<a class="btn btn-sm btn-primary" href="/admin/rbac/{{id}}/edit">Edit</a>
|
||||
{{#unless user_count}}
|
||||
<form method="post" action="/admin/rbac/{{id}}/delete" class="inline-form" data-confirm-message="Delete {{name}}?">
|
||||
<button type="submit" class="btn btn-sm btn-danger">Delete</button>
|
||||
</form>
|
||||
{{else}}
|
||||
<span class="empty">In use</span>
|
||||
{{/unless}}
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<tr><td colspan="5" class="empty">No roles found.</td></tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
+62
-28
@@ -5,36 +5,70 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="card card-outline card-primary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">User details</h3>
|
||||
<div class="row g-4">
|
||||
<div class="col-12 col-xl-4">
|
||||
<div class="card card-outline card-primary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">User details</h3>
|
||||
</div>
|
||||
<form id="user-form" method="post" action="/admin/users">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-12 col-md-6">
|
||||
<label for="user-username" class="form-label">Username</label>
|
||||
<input id="user-username" type="text" name="username" class="form-control" autocomplete="username" value="{{formValues.username}}" required />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<label for="user-name" class="form-label">Name</label>
|
||||
<input id="user-name" type="text" name="name" class="form-control" autocomplete="name" value="{{formValues.name}}" required />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<label for="user-password" class="form-label">Password</label>
|
||||
<input id="user-password" type="password" name="password" class="form-control" autocomplete="new-password" minlength="8" required />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<label for="user-confirm-password" class="form-label">Confirm password</label>
|
||||
<input id="user-confirm-password" type="password" name="confirm_password" class="form-control" autocomplete="new-password" minlength="8" required />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer d-flex justify-content-end">
|
||||
<div class="btn-group" role="group" aria-label="User actions">
|
||||
{{{saveActionButtons formId="user-form" saveLabel="Save" showSaveAndClose=false showSaveAndNew=false}}}
|
||||
<a class="btn btn-warning" href="/admin/users" data-confirm-unsaved="You have unsaved changes. Leave this page?">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<form id="user-form" method="post" action="/admin/users">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
<div class="col-12 col-md-6">
|
||||
<label for="user-username" class="form-label">Username</label>
|
||||
<input id="user-username" type="text" name="username" class="form-control" autocomplete="username" required />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<label for="user-name" class="form-label">Name</label>
|
||||
<input id="user-name" type="text" name="name" class="form-control" autocomplete="name" required />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<label for="user-password" class="form-label">Password</label>
|
||||
<input id="user-password" type="password" name="password" class="form-control" autocomplete="new-password" minlength="8" required />
|
||||
</div>
|
||||
<div class="col-12 col-md-6">
|
||||
<label for="user-confirm-password" class="form-label">Confirm password</label>
|
||||
<input id="user-confirm-password" type="password" name="confirm_password" class="form-control" autocomplete="new-password" minlength="8" required />
|
||||
|
||||
<div class="col-12 col-xl-8">
|
||||
<div class="card card-outline card-secondary admin-form-card">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Roles</h3>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
{{#if roles.length}}
|
||||
{{#each roles}}
|
||||
<div class="col-4">
|
||||
<label class="form-check card card-outline card-secondary position-relative p-3 h-100 mb-0">
|
||||
<input class="form-check-input position-absolute top-0 end-0 m-3" type="checkbox" name="role_ids[]" value="{{id}}" {{#if isSelected}}checked{{/if}} />
|
||||
<span class="form-check-label pe-4">
|
||||
<strong>{{name}}</strong>
|
||||
<span class="d-block text-body-secondary small">{{#if description}}{{description}}{{else}}No description provided.{{/if}}</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-warning mb-0">Create at least one role before adding users.</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="form-text mt-2">Select at least one role so the new user can sign in with access.</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer d-flex justify-content-end">
|
||||
<div class="btn-group" role="group" aria-label="User actions">
|
||||
{{{saveActionButtons formId="user-form" saveLabel="Save" showSaveAndClose=false showSaveAndNew=false}}}
|
||||
<a class="btn btn-warning" href="/admin/users" data-confirm-unsaved="You have unsaved changes. Leave this page?">Cancel</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
@@ -60,6 +60,42 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-xl-6">
|
||||
<div class="card card-outline card-secondary admin-form-card h-100 mb-0">
|
||||
<div class="card-header">
|
||||
<h3 class="card-title">Roles</h3>
|
||||
</div>
|
||||
<form id="user-roles-form" method="post" action="/admin/users/{{user.id}}/roles" data-async-save data-async-save-close-url="/admin/users">
|
||||
<div class="card-body">
|
||||
<div class="row g-3">
|
||||
{{#if roles.length}}
|
||||
{{#each roles}}
|
||||
<div class="col-12 col-md-6">
|
||||
<label class="form-check card card-outline card-secondary p-3 h-100 mb-0">
|
||||
<input class="form-check-input" type="checkbox" name="role_ids[]" value="{{id}}" {{#if isSelected}}checked{{/if}} />
|
||||
<span class="form-check-label ms-2">
|
||||
<strong>{{name}}</strong>
|
||||
<span class="d-block text-body-secondary small">{{#if description}}{{description}}{{else}}No description provided.{{/if}}</span>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<div class="col-12">
|
||||
<div class="alert alert-warning mb-0">Create at least one role before assigning users.</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-footer d-flex justify-content-end">
|
||||
<div class="btn-group" role="group" aria-label="Role actions">
|
||||
{{{saveActionButtons formId="user-roles-form" saveLabel="Save" saveAndCloseLabel="Save and Close" saveAndCloseValue="close" showSaveAndNew=false}}}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
<tr>
|
||||
<th>User</th>
|
||||
<th>Name</th>
|
||||
<th>Roles</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -28,9 +29,10 @@
|
||||
<td data-label="User">
|
||||
<div class="user-cell">
|
||||
<div>
|
||||
<strong>{{username}}</strong>
|
||||
{{#if isCurrentUser}}
|
||||
<div class="subtle">Current signed-in user</div>
|
||||
<i>{{username}}</i>
|
||||
{{else}}
|
||||
{{username}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -38,7 +40,23 @@
|
||||
<td data-label="Name">
|
||||
<div class="user-cell">
|
||||
<div>
|
||||
<strong>{{#if name}}{{name}}{{else}}-{{/if}}</strong>
|
||||
{{#if isCurrentUser}}
|
||||
<i>{{#if name}}{{name}}{{else}}-{{/if}}</i>
|
||||
{{else}}
|
||||
{{#if name}}{{name}}{{else}}-{{/if}}
|
||||
{{/if}}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td data-label="Roles">
|
||||
<div class="user-cell">
|
||||
<div>
|
||||
{{#if isCurrentUser}}
|
||||
<i>{{#if roleNames}}{{roleNames}}{{else}}No roles assigned{{/if}}</i>
|
||||
{{else}}
|
||||
{{#if roleNames}}{{roleNames}}{{else}}No roles assigned{{/if}}
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
@@ -57,7 +75,7 @@
|
||||
</tr>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<tr><td colspan="3" class="empty">No users found.</td></tr>
|
||||
<tr><td colspan="4" class="empty">No users found.</td></tr>
|
||||
{{/if}}
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
Reference in New Issue
Block a user