mirror of
https://github.com/arsvendg/Stirling-PDF.git
synced 2026-07-16 11:23:10 +02:00
Resolve conflicts using files from Stirling-2.0
This commit is contained in:
@@ -0,0 +1,387 @@
|
||||
/* modern-tables.css - Professional styling for data tables and related elements */
|
||||
|
||||
/* Main container - Reduced max-width from 1100px to 900px */
|
||||
.data-container {
|
||||
max-width: 900px;
|
||||
margin: 2rem auto;
|
||||
background-color: var(--md-sys-color-surface-container-lowest);
|
||||
border-radius: 1rem;
|
||||
padding: 0.5rem;
|
||||
box-shadow: 0 2px 12px rgba(var(--md-sys-color-shadow, 0, 0, 0), 0.05);
|
||||
}
|
||||
|
||||
/* Panel / Card */
|
||||
.data-panel {
|
||||
background-color: var(--md-sys-color-surface);
|
||||
border-radius: 0.75rem;
|
||||
box-shadow: 0 2px 8px rgba(var(--md-sys-color-shadow, 0, 0, 0), 0.08);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
/* Header */
|
||||
.data-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 1.25rem 1.5rem;
|
||||
background-color: var(--md-sys-color-surface-variant);
|
||||
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.data-title {
|
||||
margin: 0;
|
||||
font-size: 1.5rem;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.data-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.5rem;
|
||||
height: 2.5rem;
|
||||
background-color: var(--md-sys-color-primary);
|
||||
color: var(--md-sys-color-on-primary);
|
||||
border-radius: 0.5rem;
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
/* Content area */
|
||||
.data-body {
|
||||
padding: 1.5rem;
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
border-radius: 0.5rem;
|
||||
}
|
||||
|
||||
/* Action buttons container */
|
||||
.data-actions {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 1rem 0 1.5rem;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* Can add these classes for different alignments */
|
||||
.data-actions-start {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.data-actions-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* Button styling */
|
||||
.data-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
padding: 0.625rem 1.25rem;
|
||||
border-radius: 0.5rem;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
/* Fixed button colors - normal state has more contrast now */
|
||||
.data-btn-primary {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
color: var(--md-sys-color-on-primary);
|
||||
}
|
||||
|
||||
.data-btn-primary:hover {
|
||||
background-color: var(--md-sys-color-primary-container);
|
||||
color: var(--md-sys-color-primary);
|
||||
box-shadow: 0 2px 4px rgba(var(--md-sys-color-shadow, 0, 0, 0), 0.1);
|
||||
}
|
||||
|
||||
.data-btn-secondary {
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
}
|
||||
|
||||
.data-btn-secondary:hover {
|
||||
background-color: var(--md-sys-color-secondary-container);
|
||||
color: var(--md-sys-color-secondary);
|
||||
box-shadow: 0 2px 4px rgba(var(--md-sys-color-shadow, 0, 0, 0), 0.1);
|
||||
}
|
||||
|
||||
.data-btn-danger {
|
||||
background-color: var(--md-sys-color-error);
|
||||
color: var(--md-sys-color-on-error);
|
||||
}
|
||||
|
||||
.data-btn-danger:hover {
|
||||
background-color: var(--md-sys-color-error-container);
|
||||
color: var(--md-sys-color-error);
|
||||
box-shadow: 0 2px 4px rgba(var(--md-sys-color-shadow, 0, 0, 0), 0.1);
|
||||
}
|
||||
|
||||
.data-btn-sm {
|
||||
padding: 0.375rem 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
}
|
||||
|
||||
/* Icon button */
|
||||
.data-icon-btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2.25rem;
|
||||
height: 2.25rem;
|
||||
border-radius: 0.5rem;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
/* Fixed icon button colors */
|
||||
.data-icon-btn-primary {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
color: var(--md-sys-color-on-primary);
|
||||
}
|
||||
|
||||
.data-icon-btn-primary:hover {
|
||||
background-color: var(--md-sys-color-primary-container);
|
||||
color: var(--md-sys-color-primary);
|
||||
box-shadow: 0 2px 4px rgba(var(--md-sys-color-shadow, 0, 0, 0), 0.1);
|
||||
}
|
||||
|
||||
.data-icon-btn-danger {
|
||||
background-color: var(--md-sys-color-error);
|
||||
color: var(--md-sys-color-on-error);
|
||||
}
|
||||
|
||||
.data-icon-btn-danger:hover {
|
||||
background-color: var(--md-sys-color-error-container);
|
||||
color: var(--md-sys-color-error);
|
||||
box-shadow: 0 2px 4px rgba(var(--md-sys-color-shadow, 0, 0, 0), 0.1);
|
||||
}
|
||||
|
||||
/* Table styling */
|
||||
.data-table {
|
||||
width: 100%;
|
||||
border-collapse: separate;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
.data-table th {
|
||||
text-align: left;
|
||||
padding: 1rem;
|
||||
background-color: var(--md-sys-color-surface-variant);
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
font-weight: 600;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.data-table th:first-child {
|
||||
border-top-left-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.data-table th:last-child {
|
||||
border-top-right-radius: 0.5rem;
|
||||
}
|
||||
|
||||
.data-table td {
|
||||
padding: 1rem;
|
||||
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.data-table tr:last-child td {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.data-table tr:hover {
|
||||
background-color: rgba(var(--md-sys-color-surface-variant-rgb), 0.5);
|
||||
}
|
||||
|
||||
/* Table action cells */
|
||||
.data-action-cell {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.data-action-cell-center {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.data-action-cell-end {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
/* Status indicators */
|
||||
.data-status {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.375rem;
|
||||
padding: 0.375rem 0.75rem;
|
||||
border-radius: 1rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.data-status-success {
|
||||
background-color: var(--md-sys-color-tertiary-container);
|
||||
color: var(--md-sys-color-tertiary);
|
||||
}
|
||||
|
||||
.data-status-danger {
|
||||
background-color: var(--md-sys-color-error-container);
|
||||
color: var(--md-sys-color-error);
|
||||
}
|
||||
|
||||
.data-status-warning {
|
||||
background-color: var(--md-sys-color-secondary-container);
|
||||
color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.data-status-info {
|
||||
background-color: var(--md-sys-color-primary-container);
|
||||
color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
/* Stats/Info container */
|
||||
.data-stats {
|
||||
display: flex;
|
||||
gap: 1.5rem;
|
||||
margin-bottom: 1.5rem;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.data-stat-card {
|
||||
background-color: var(--md-sys-color-surface-variant);
|
||||
border-radius: 0.5rem;
|
||||
padding: 1.25rem;
|
||||
flex: 1;
|
||||
min-width: 180px;
|
||||
box-shadow: 0 2px 8px rgba(var(--md-sys-color-shadow, 0, 0, 0), 0.05);
|
||||
}
|
||||
|
||||
.data-stat-label {
|
||||
font-size: 0.875rem;
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.data-stat-value {
|
||||
font-size: 1.75rem;
|
||||
font-weight: 700;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
/* Section title */
|
||||
.data-section-title {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin: 1.5rem 0 1rem;
|
||||
padding-bottom: 0.5rem;
|
||||
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
/* Empty state styling */
|
||||
.data-empty {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 3rem;
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
}
|
||||
|
||||
.data-empty-icon {
|
||||
font-size: 4rem;
|
||||
margin-bottom: 1rem;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.data-empty-text {
|
||||
font-size: 1.125rem;
|
||||
margin-bottom: 1.5rem;
|
||||
}
|
||||
|
||||
/* Modal styling */
|
||||
.data-modal {
|
||||
border-radius: 0.75rem;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.data-modal-header {
|
||||
background-color: var(--md-sys-color-surface-variant);
|
||||
padding: 1.25rem;
|
||||
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.data-modal-title {
|
||||
margin: 0;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* Modal close button styling */
|
||||
.data-btn-close {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 2rem;
|
||||
height: 2rem;
|
||||
border-radius: 50%;
|
||||
background-color: var(--md-sys-color-surface-variant);
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
transition: all 0.2s ease;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.data-btn-close:hover {
|
||||
background-color: var(--md-sys-color-surface-container-high);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
.data-btn-close .material-symbols-rounded {
|
||||
font-size: 1.25rem;
|
||||
}
|
||||
|
||||
.data-modal-body {
|
||||
padding: 1.5rem;
|
||||
}
|
||||
|
||||
.data-modal-footer {
|
||||
padding: 1rem 1.5rem;
|
||||
border-top: 1px solid var(--md-sys-color-outline-variant);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
/* Form elements */
|
||||
.data-form-group {
|
||||
margin-bottom: 1.25rem;
|
||||
}
|
||||
|
||||
.data-form-label {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.data-form-control {
|
||||
width: 100%;
|
||||
padding: 0.75rem 1rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{team.details.title}, header=#{team.details.header})}"></th:block>
|
||||
<link rel="stylesheet" th:href="@{/css/modern-tables.css}">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
|
||||
<div class="data-container">
|
||||
<div class="data-panel">
|
||||
<div class="data-header">
|
||||
<h1 class="data-title">
|
||||
<span class="data-icon">
|
||||
<span class="material-symbols-rounded">group</span>
|
||||
</span>
|
||||
<span th:text="'Team: ' + ${team.name}">Team Name</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="data-body">
|
||||
<div class="data-stats">
|
||||
<div class="data-stat-card">
|
||||
<div class="data-stat-label">Total Members:</div>
|
||||
<div class="data-stat-value" th:text="${teamUsers.size()}">1</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="data-actions data-actions-start">
|
||||
<a th:href="@{'/teams'}" class="data-btn data-btn-secondary">
|
||||
<span class="material-symbols-rounded">arrow_back</span>
|
||||
<span th:text="#{team.back}">Back to Teams</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="data-section-title">Members</div>
|
||||
|
||||
<div class="table-responsive">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Username</th>
|
||||
<th>Role</th>
|
||||
<th scope="col" th:title="${@runningProOrHigher} ? #{adminUserSettings.lastRequest} : 'Pro feature'" class="text-overflow" th:text="#{adminUserSettings.lastRequest}">Last Request</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr th:each="user : ${teamUsers}">
|
||||
<td th:text="${user.id}">1</td>
|
||||
<td th:text="${user.username}">username</td>
|
||||
<td th:text="#{${user.roleName}}">Role</td>
|
||||
<td th:text="${@runningProOrHigher} ? (${userLastRequest[user.username] != null ? #dates.format(userLastRequest[user.username], 'yyyy-MM-dd HH:mm:ss') : 'N/A'}) : 'hidden'">2023-01-01 12:00:00</td>
|
||||
<td>
|
||||
<span th:if="${user.enabled}" class="data-status data-status-success">
|
||||
<span class="material-symbols-rounded">person</span>
|
||||
Enabled
|
||||
</span>
|
||||
<span th:unless="${user.enabled}" class="data-status data-status-danger">
|
||||
<span class="material-symbols-rounded">person_off</span>
|
||||
Disabled
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Empty state for when there are no team members -->
|
||||
<div th:if="${teamUsers.empty}" class="data-empty">
|
||||
<span class="material-symbols-rounded data-empty-icon">person_off</span>
|
||||
<p class="data-empty-text">This team has no members yet.</p>
|
||||
<button data-bs-toggle="modal" data-bs-target="#addUserToTeamModal" class="data-btn data-btn-primary">
|
||||
<span class="material-symbols-rounded">person_add</span>
|
||||
<span th:text="#{team.addUser}">Add User to Team</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Add button for non-empty teams too -->
|
||||
<div th:if="${!teamUsers.empty}" class="data-actions data-mt-3">
|
||||
<button data-bs-toggle="modal" data-bs-target="#addUserToTeamModal" class="data-btn data-btn-primary">
|
||||
<span class="material-symbols-rounded">person_add</span>
|
||||
<span th:text="#{team.addUser}">Add User to Team</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- JavaScript for team warning -->
|
||||
<script th:inline="javascript">
|
||||
function checkUserTeam(userId) {
|
||||
// Clear any existing warning
|
||||
const warningDiv = document.getElementById('teamChangeWarning');
|
||||
const warningMessage = document.getElementById('warningMessage');
|
||||
const submitButton = document.getElementById('addUserSubmitBtn');
|
||||
|
||||
// Reset
|
||||
warningDiv.style.display = 'none';
|
||||
submitButton.onclick = null;
|
||||
|
||||
// Get the selected option
|
||||
const selectedOption = document.querySelector('#userId option[value="' + userId + '"]');
|
||||
if (!selectedOption) return;
|
||||
|
||||
// Get team data
|
||||
const currentTeam = selectedOption.getAttribute('data-team');
|
||||
const currentTeamId = selectedOption.getAttribute('data-team-id');
|
||||
const newTeamName = /*[[${team.name}]]*/ 'Current Team';
|
||||
|
||||
// If user is already in a team, show warning
|
||||
if (currentTeam && currentTeam.length > 0) {
|
||||
// Use internationalized message
|
||||
const warningTemplate = /*[[#{team.warning.moveUser}]]*/ 'Warning: This will move the user from "{0}" team to "{1}" team. Are you sure?';
|
||||
const formattedWarning = warningTemplate.replace('{0}', currentTeam).replace('{1}', newTeamName);
|
||||
warningMessage.textContent = formattedWarning;
|
||||
warningDiv.style.display = 'block';
|
||||
|
||||
// Add confirmation to submit button
|
||||
submitButton.onclick = function(e) {
|
||||
// Use internationalized message
|
||||
const confirmTemplate = /*[[#{team.confirm.moveUser}]]*/ 'Are you sure you want to move this user from "{0}" team to "{1}" team?';
|
||||
const formattedConfirm = confirmTemplate.replace('{0}', currentTeam).replace('{1}', newTeamName);
|
||||
if (!confirm(formattedConfirm)) {
|
||||
e.preventDefault();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<!-- Add User to Team Modal -->
|
||||
<div class="modal fade" id="addUserToTeamModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<form th:action="@{'/api/v1/team/addUser'}" method="post" class="modal-content data-modal">
|
||||
<div class="data-modal-header">
|
||||
<h5 class="data-modal-title">
|
||||
<span class="data-icon">
|
||||
<span class="material-symbols-rounded">person_add</span>
|
||||
</span>
|
||||
<span th:text="#{team.addUser}">Add User to Team</span>
|
||||
</h5>
|
||||
<button type="button" class="data-btn-close" data-bs-dismiss="modal" aria-label="Close">
|
||||
<span class="material-symbols-rounded">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="data-modal-body">
|
||||
<input type="hidden" name="teamId" th:value="${team.id}" />
|
||||
|
||||
<div class="data-form-group">
|
||||
<label for="userId" class="data-form-label" th:text="#{team.selectUser}">Select User</label>
|
||||
<select name="userId" id="userId" class="data-form-control" required onchange="checkUserTeam(this.value)">
|
||||
<option value="" disabled selected th:text="#{selectFillter}">-- Select User --</option>
|
||||
<option th:each="user : ${availableUsers}"
|
||||
th:value="${user.id}"
|
||||
th:text="${user.username}"
|
||||
th:data-team="${user.team != null ? user.team.name : ''}"
|
||||
th:data-team-id="${user.team != null ? user.team.id : ''}">
|
||||
Username
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Warning message for users being moved between teams -->
|
||||
<div id="teamChangeWarning" class="alert alert-warning mt-3" style="display: none;">
|
||||
<span class="material-symbols-rounded">warning</span>
|
||||
<span id="warningMessage">Warning: This will move the user from their current team to this team.</span>
|
||||
</div>
|
||||
|
||||
<div class="data-form-actions">
|
||||
<button type="button" class="data-btn data-btn-secondary" data-bs-dismiss="modal">
|
||||
<span class="material-symbols-rounded">close</span>
|
||||
<span th:text="#{cancel}">Cancel</span>
|
||||
</button>
|
||||
<button type="submit" id="addUserSubmitBtn" class="data-btn data-btn-primary">
|
||||
<span class="material-symbols-rounded">check</span>
|
||||
<span th:text="#{team.addUser}">Add User</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,133 @@
|
||||
<!DOCTYPE html>
|
||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}" xmlns:th="https://www.thymeleaf.org">
|
||||
<head>
|
||||
<th:block th:insert="~{fragments/common :: head(title=#{adminUserSettings.manageTeams}, header=#{adminUserSettings.manageTeams})}"></th:block>
|
||||
<link rel="stylesheet" th:href="@{/css/modern-tables.css}">
|
||||
</head>
|
||||
<body>
|
||||
<th:block th:insert="~{fragments/common :: game}"></th:block>
|
||||
<div id="page-container">
|
||||
<div id="content-wrap">
|
||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||
|
||||
<div class="data-container">
|
||||
<div class="data-panel">
|
||||
<div class="data-header">
|
||||
<h1 class="data-title">
|
||||
<span class="data-icon">
|
||||
<span class="material-symbols-rounded">groups</span>
|
||||
</span>
|
||||
<span th:text="#{adminUserSettings.manageTeams}">Team Management</span>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="data-body">
|
||||
<!-- Back Button -->
|
||||
<div class="data-actions data-actions-start">
|
||||
<a href="/adminSettings" class="data-btn data-btn-secondary">
|
||||
<span class="material-symbols-rounded">arrow_back</span>
|
||||
<span th:text="#{back.toSettings}">Back to Settings</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Create New Team Button -->
|
||||
<div class="data-actions">
|
||||
<a href="#"
|
||||
th:data-bs-toggle="${@runningProOrHigher} ? 'modal' : null"
|
||||
th:data-bs-target="${@runningProOrHigher} ? '#addTeamModal' : null"
|
||||
th:class="${@runningProOrHigher} ? 'data-btn data-btn-primary' : 'data-btn data-btn-danger'"
|
||||
th:title="${@runningProOrHigher} ? #{adminUserSettings.createTeam} : #{enterpriseEdition.proTeamFeatureDisabled}">
|
||||
<span class="material-symbols-rounded">group_add</span>
|
||||
<span th:text="#{adminUserSettings.createTeam}">Create New Team</span>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<!-- Team Table -->
|
||||
<div class="table-responsive">
|
||||
<table class="data-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col" th:text="#{adminUserSettings.teamName}">Team Name</th>
|
||||
<th scope="col" th:text="#{adminUserSettings.totalMembers}">Total Members</th>
|
||||
<th scope="col" th:title="${@runningProOrHigher} ? #{adminUserSettings.lastRequest} : 'Pro feature'" class="text-overflow" th:text="#{adminUserSettings.lastRequest}">Last Request</th>
|
||||
<th scope="col" th:text="#{adminUserSettings.actions}">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- Try approach 1 - DTO projection -->
|
||||
<tr th:each="teamDto : ${teamsWithCounts}">
|
||||
<td th:text="${teamDto.name}"></td>
|
||||
<td th:text="${teamDto.userCount}"></td>
|
||||
<td th:text="${@runningProOrHigher} ? (${teamLastRequest[teamDto.id] != null ? #dates.format(teamLastRequest[teamDto.id], 'yyyy-MM-dd HH:mm:ss') : 'N/A'}) : 'hidden'"></td>
|
||||
<td>
|
||||
<div class="data-action-cell">
|
||||
<a th:href="@{'/teams/' + ${teamDto.id}}" class="data-btn data-btn-secondary data-btn-sm" th:title="#{adminUserSettings.viewTeam}">
|
||||
<span class="material-symbols-rounded">search</span> <span th:text="#{view}">View</span>
|
||||
</a>
|
||||
<form th:action="@{'/api/v1/team/delete'}" method="post" style="display:inline-block"
|
||||
onsubmit="return confirmDeleteTeam()">
|
||||
<input type="hidden" name="teamId" th:value="${teamDto.id}" />
|
||||
<button type="submit" class="data-btn data-btn-danger data-btn-sm"
|
||||
th:disabled="${!@runningProOrHigher}"
|
||||
th:classappend="${!@runningProOrHigher} ? 'disabled' : ''"
|
||||
th:title="${@runningProOrHigher} ? #{adminUserSettings.deleteTeam} : #{enterpriseEdition.proTeamFeatureDisabled}">
|
||||
<span class="material-symbols-rounded">delete</span> <span th:text="#{delete}">Delete</span>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- Delete Confirmation Script -->
|
||||
<script th:inline="javascript">
|
||||
const confirmDeleteText = /*[[#{adminUserSettings.confirmDeleteTeam}]]*/ 'Are you sure you want to delete this team?';
|
||||
function confirmDeleteTeam() {
|
||||
return confirm(confirmDeleteText);
|
||||
}
|
||||
</script>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Add Team Modal -->
|
||||
<div class="modal fade" id="addTeamModal" tabindex="-1" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered">
|
||||
<form th:action="@{'/api/v1/team/create'}" method="post" class="modal-content data-modal">
|
||||
<div class="data-modal-header">
|
||||
<h5 class="data-modal-title">
|
||||
<span class="data-icon">
|
||||
<span class="material-symbols-rounded">group_add</span>
|
||||
</span>
|
||||
<span th:text="#{adminUserSettings.createTeam}">Create Team</span>
|
||||
</h5>
|
||||
<button type="button" class="data-btn-close" data-bs-dismiss="modal" aria-label="Close">
|
||||
<span class="material-symbols-rounded">close</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="data-modal-body">
|
||||
<div class="data-form-group">
|
||||
<label for="teamName" class="data-form-label" th:text="#{adminUserSettings.teamName}">Team Name</label>
|
||||
<input type="text" name="name" id="teamName" class="data-form-control" required />
|
||||
</div>
|
||||
<div class="data-form-actions">
|
||||
<button type="button" class="data-btn data-btn-secondary" data-bs-dismiss="modal">
|
||||
<span class="material-symbols-rounded">close</span>
|
||||
<span th:text="#{cancel}">Cancel</span>
|
||||
</button>
|
||||
<button type="submit" class="data-btn data-btn-primary">
|
||||
<span class="material-symbols-rounded">check</span>
|
||||
<span th:text="#{adminUserSettings.createTeam}">Create</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user