mirror of
https://github.com/Stirling-Tools/Stirling-PDF.git
synced 2025-06-23 16:05:09 +00:00
i18n
This commit is contained in:
parent
e0116106c1
commit
43c5a1970f
@ -2,6 +2,19 @@
|
||||
margin-bottom: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||||
background-color: var(--md-sys-color-surface-container);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
border: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.card-header {
|
||||
background-color: var(--md-sys-color-surface-container-high);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
border-bottom: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.card-body {
|
||||
background-color: var(--md-sys-color-surface-container);
|
||||
}
|
||||
.stat-card {
|
||||
text-align: center;
|
||||
@ -13,7 +26,7 @@
|
||||
}
|
||||
.stat-label {
|
||||
font-size: 1rem;
|
||||
color: #666;
|
||||
color: var(--md-sys-color-on-surface-variant);
|
||||
}
|
||||
.chart-container {
|
||||
position: relative;
|
||||
@ -23,6 +36,9 @@
|
||||
.filter-card {
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
border: 1px solid var(--md-sys-color-outline-variant);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.loading-overlay {
|
||||
position: absolute;
|
||||
@ -30,7 +46,7 @@
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(255, 255, 255, 0.7);
|
||||
background-color: var(--md-sys-color-surface-container-high, rgba(229, 232, 241, 0.8));
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
@ -44,26 +60,42 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
.level-0 {
|
||||
background-color: #dc3545; /* Red */
|
||||
background-color: var(--md-sys-color-error, #dc3545); /* Red */
|
||||
}
|
||||
.level-1 {
|
||||
background-color: #fd7e14; /* Orange */
|
||||
background-color: var(--md-sys-color-secondary, #fd7e14); /* Orange */
|
||||
}
|
||||
.level-2 {
|
||||
background-color: #28a745; /* Green */
|
||||
background-color: var(--md-nav-section-color-other, #28a745); /* Green */
|
||||
}
|
||||
.level-3 {
|
||||
background-color: #17a2b8; /* Teal */
|
||||
background-color: var(--md-sys-color-tertiary, #17a2b8); /* Teal */
|
||||
}
|
||||
/* Custom data table styling */
|
||||
.audit-table {
|
||||
font-size: 0.9rem;
|
||||
color: var(--md-sys-color-on-surface);
|
||||
border-color: var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.audit-table tbody tr {
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
}
|
||||
|
||||
.audit-table tbody tr:nth-child(even) {
|
||||
background-color: var(--md-sys-color-surface-container);
|
||||
}
|
||||
|
||||
.audit-table tbody tr:hover {
|
||||
background-color: var(--md-sys-color-surface-container-high);
|
||||
}
|
||||
.audit-table th {
|
||||
background-color: #f8f9fa;
|
||||
background-color: var(--md-sys-color-surface-container-high);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 10;
|
||||
font-weight: bold;
|
||||
}
|
||||
.table-responsive {
|
||||
max-height: 600px;
|
||||
@ -74,7 +106,8 @@
|
||||
align-items: center;
|
||||
margin-top: 15px;
|
||||
padding: 10px 0;
|
||||
border-top: 1px solid #dee2e6;
|
||||
border-top: 1px solid var(--md-sys-color-outline-variant);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
}
|
||||
|
||||
.pagination .page-item.active .page-link {
|
||||
@ -93,13 +126,15 @@
|
||||
background-color: var(--bs-light);
|
||||
}
|
||||
.json-viewer {
|
||||
background-color: #f8f9fa;
|
||||
background-color: var(--md-sys-color-surface-container-low);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
border-radius: 4px;
|
||||
padding: 10px;
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
font-family: monospace;
|
||||
white-space: pre-wrap;
|
||||
border: 1px solid var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
/* Simple, minimal radio styling - no extras */
|
||||
@ -113,14 +148,14 @@
|
||||
right: 0;
|
||||
width: 400px;
|
||||
height: 200px;
|
||||
background: rgba(0,0,0,0.8);
|
||||
color: #0f0;
|
||||
background: var(--md-sys-color-surface-container-highest, rgba(0,0,0,0.8));
|
||||
color: var(--md-sys-color-tertiary, #0f0);
|
||||
font-family: monospace;
|
||||
font-size: 12px;
|
||||
z-index: 9999;
|
||||
overflow-y: auto;
|
||||
padding: 10px;
|
||||
border: 1px solid #0f0;
|
||||
border: 1px solid var(--md-sys-color-outline);
|
||||
display: none; /* Changed to none by default, enable with key command */
|
||||
}
|
||||
|
||||
@ -128,13 +163,64 @@
|
||||
label.btn-outline-primary {
|
||||
cursor: pointer;
|
||||
transition: all 0.2s;
|
||||
border-color: var(--md-sys-color-primary);
|
||||
color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
label.btn-outline-primary.active {
|
||||
background-color: var(--bs-primary);
|
||||
color: white;
|
||||
background-color: var(--md-sys-color-primary);
|
||||
color: var(--md-sys-color-on-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
label.btn-outline-primary input[type="radio"] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* Modal overrides for dark mode */
|
||||
.modal-content {
|
||||
background-color: var(--md-sys-color-surface-container);
|
||||
color: var(--md-sys-color-on-surface);
|
||||
border-color: var(--md-sys-color-outline);
|
||||
}
|
||||
|
||||
.modal-header {
|
||||
border-bottom-color: var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
.modal-footer {
|
||||
border-top-color: var(--md-sys-color-outline-variant);
|
||||
}
|
||||
|
||||
/* Button overrides for theme consistency */
|
||||
.btn-outline-primary {
|
||||
color: var(--md-sys-color-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-outline-primary:hover {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
color: var(--md-sys-color-on-primary);
|
||||
}
|
||||
|
||||
.btn-outline-secondary {
|
||||
color: var(--md-sys-color-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.btn-outline-secondary:hover {
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--md-sys-color-primary);
|
||||
color: var(--md-sys-color-on-primary);
|
||||
border-color: var(--md-sys-color-primary);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--md-sys-color-secondary);
|
||||
color: var(--md-sys-color-on-secondary);
|
||||
border-color: var(--md-sys-color-secondary);
|
||||
}
|
@ -80,6 +80,31 @@ document.addEventListener('keydown', function(e) {
|
||||
});
|
||||
|
||||
// Initialize page
|
||||
// Theme change listener to redraw charts when theme changes
|
||||
function setupThemeChangeListener() {
|
||||
// Watch for theme changes (usually by a class on body or html element)
|
||||
const observer = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
if (mutation.attributeName === 'data-bs-theme' || mutation.attributeName === 'class') {
|
||||
// Redraw charts with new theme colors if they exist
|
||||
if (typeChart && userChart && timeChart) {
|
||||
debugLog('Theme changed, redrawing charts');
|
||||
// If we have stats data cached, use it
|
||||
if (window.cachedStatsData) {
|
||||
renderCharts(window.cachedStatsData);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Observe the document element for theme changes
|
||||
observer.observe(document.documentElement, { attributes: true });
|
||||
|
||||
// Also observe body for class changes
|
||||
observer.observe(document.body, { attributes: true });
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
debugLog('Page initialized');
|
||||
|
||||
@ -106,7 +131,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// Show a loading message immediately
|
||||
if (auditTableBody) {
|
||||
auditTableBody.innerHTML =
|
||||
'<tr><td colspan="5" class="text-center"><div class="spinner-border spinner-border-sm" role="status"></div> Loading audit data...</td></tr>';
|
||||
'<tr><td colspan="5" class="text-center"><div class="spinner-border spinner-border-sm" role="status"></div> ' + window.i18n.loading + '</td></tr>';
|
||||
} else {
|
||||
debugLog('ERROR: auditTableBody element not found!');
|
||||
}
|
||||
@ -117,6 +142,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
||||
// Load statistics for dashboard
|
||||
loadStats(7);
|
||||
|
||||
// Setup theme change listener
|
||||
setupThemeChangeListener();
|
||||
|
||||
// Set up event listeners
|
||||
pageSizeSelect.addEventListener('change', function() {
|
||||
pageSize = parseInt(this.value);
|
||||
@ -350,7 +378,7 @@ function loadAuditData(targetPage, realPageSize) {
|
||||
.catch(error => {
|
||||
debugLog('Error loading data', error.message);
|
||||
if (auditTableBody) {
|
||||
auditTableBody.innerHTML = `<tr><td colspan="5" class="text-center">Error loading data: ${error.message}</td></tr>`;
|
||||
auditTableBody.innerHTML = `<tr><td colspan="5" class="text-center">${window.i18n.errorLoading} ${error.message}</td></tr>`;
|
||||
}
|
||||
hideLoading('table-loading');
|
||||
|
||||
@ -375,6 +403,8 @@ function loadStats(days) {
|
||||
.then(response => response.json())
|
||||
.then(data => {
|
||||
document.getElementById('total-events').textContent = data.totalEvents;
|
||||
// Cache stats data for theme changes
|
||||
window.cachedStatsData = data;
|
||||
renderCharts(data);
|
||||
hideLoading('type-chart-loading');
|
||||
hideLoading('user-chart-loading');
|
||||
@ -412,7 +442,7 @@ function renderTable(events) {
|
||||
|
||||
if (!events || events.length === 0) {
|
||||
debugLog('No events to render');
|
||||
auditTableBody.innerHTML = '<tr><td colspan="5" class="text-center">No audit events found matching the current filters</td></tr>';
|
||||
auditTableBody.innerHTML = '<tr><td colspan="5" class="text-center">' + window.i18n.noEventsFound + '</td></tr>';
|
||||
return;
|
||||
}
|
||||
|
||||
@ -452,7 +482,7 @@ function renderTable(events) {
|
||||
debugLog('Table rendering complete');
|
||||
} catch (e) {
|
||||
debugLog('Error in renderTable', e.message);
|
||||
auditTableBody.innerHTML = '<tr><td colspan="5" class="text-center">Error rendering table: ' + e.message + '</td></tr>';
|
||||
auditTableBody.innerHTML = '<tr><td colspan="5" class="text-center">' + window.i18n.errorRendering + ' ' + e.message + '</td></tr>';
|
||||
}
|
||||
}
|
||||
|
||||
@ -521,6 +551,9 @@ function goToPage(page) {
|
||||
|
||||
// Render charts
|
||||
function renderCharts(data) {
|
||||
// Get theme colors
|
||||
const colors = getThemeColors();
|
||||
|
||||
// Prepare data for charts
|
||||
const typeLabels = Object.keys(data.eventsByType);
|
||||
const typeValues = Object.values(data.eventsByType);
|
||||
@ -532,6 +565,10 @@ function renderCharts(data) {
|
||||
const timeLabels = Object.keys(data.eventsByDay).sort();
|
||||
const timeValues = timeLabels.map(day => data.eventsByDay[day] || 0);
|
||||
|
||||
// Chart.js global defaults for dark mode compatibility
|
||||
Chart.defaults.color = colors.text;
|
||||
Chart.defaults.borderColor = colors.grid;
|
||||
|
||||
// Type chart
|
||||
if (typeChart) {
|
||||
typeChart.destroy();
|
||||
@ -543,19 +580,84 @@ function renderCharts(data) {
|
||||
data: {
|
||||
labels: typeLabels,
|
||||
datasets: [{
|
||||
label: 'Events by Type',
|
||||
label: window.i18n.eventsByType,
|
||||
data: typeValues,
|
||||
backgroundColor: getChartColors(typeLabels.length),
|
||||
borderColor: getChartColors(typeLabels.length, 1), // Full opacity for borders
|
||||
backgroundColor: colors.chartColors.slice(0, typeLabels.length),
|
||||
borderColor: colors.chartColors.slice(0, typeLabels.length),
|
||||
borderWidth: 1
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
labels: {
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 14
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
titleFont: {
|
||||
weight: 'bold',
|
||||
size: 14
|
||||
},
|
||||
bodyFont: {
|
||||
size: 13
|
||||
},
|
||||
backgroundColor: colors.isDarkMode ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)',
|
||||
titleColor: colors.isDarkMode ? '#ffffff' : '#000000',
|
||||
bodyColor: colors.isDarkMode ? '#ffffff' : '#000000',
|
||||
borderColor: colors.grid,
|
||||
borderWidth: 1
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 12
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
color: colors.grid
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Count',
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 14
|
||||
}
|
||||
}
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 12
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
color: colors.grid
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Event Type',
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -572,15 +674,58 @@ function renderCharts(data) {
|
||||
data: {
|
||||
labels: userLabels,
|
||||
datasets: [{
|
||||
label: 'Events by User',
|
||||
label: window.i18n.eventsByUser,
|
||||
data: userValues,
|
||||
backgroundColor: getChartColors(userLabels.length),
|
||||
borderWidth: 1
|
||||
backgroundColor: colors.chartColors.slice(0, userLabels.length),
|
||||
borderWidth: 1,
|
||||
borderColor: colors.isDarkMode ? 'rgba(255, 255, 255, 0.5)' : 'rgba(0, 0, 0, 0.2)'
|
||||
}]
|
||||
},
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
position: 'right',
|
||||
labels: {
|
||||
color: colors.text,
|
||||
font: {
|
||||
size: colors.isDarkMode ? 14 : 12,
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal'
|
||||
},
|
||||
padding: 15,
|
||||
// Add a box around each label for better contrast in dark mode
|
||||
generateLabels: function(chart) {
|
||||
const original = Chart.overrides.pie.plugins.legend.labels.generateLabels;
|
||||
const labels = original.call(this, chart);
|
||||
|
||||
if (colors.isDarkMode) {
|
||||
labels.forEach(label => {
|
||||
label.fillStyle = 'rgba(0, 0, 0, 0.7)'; // Dark background for text
|
||||
label.strokeStyle = label.strokeStyle; // Keep original color for border
|
||||
label.lineWidth = 2; // Thicker border
|
||||
});
|
||||
}
|
||||
|
||||
return labels;
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
titleFont: {
|
||||
weight: 'bold',
|
||||
size: 14
|
||||
},
|
||||
bodyFont: {
|
||||
size: 13
|
||||
},
|
||||
backgroundColor: colors.isDarkMode ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)',
|
||||
titleColor: colors.isDarkMode ? '#ffffff' : '#000000',
|
||||
bodyColor: colors.isDarkMode ? '#ffffff' : '#000000',
|
||||
borderColor: colors.grid,
|
||||
borderWidth: 1
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@ -595,10 +740,10 @@ function renderCharts(data) {
|
||||
data: {
|
||||
labels: timeLabels,
|
||||
datasets: [{
|
||||
label: 'Events Over Time',
|
||||
label: window.i18n.eventsOverTime,
|
||||
data: timeValues,
|
||||
backgroundColor: 'rgba(75, 192, 192, 0.2)',
|
||||
borderColor: 'rgba(75, 192, 192, 1)',
|
||||
backgroundColor: colors.chartColors[0] + '40', // 40 = 25% opacity
|
||||
borderColor: colors.chartColors[0],
|
||||
tension: 0.1,
|
||||
fill: true
|
||||
}]
|
||||
@ -606,9 +751,74 @@ function renderCharts(data) {
|
||||
options: {
|
||||
responsive: true,
|
||||
maintainAspectRatio: false,
|
||||
plugins: {
|
||||
legend: {
|
||||
labels: {
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 14
|
||||
}
|
||||
}
|
||||
},
|
||||
tooltip: {
|
||||
titleFont: {
|
||||
weight: 'bold',
|
||||
size: 14
|
||||
},
|
||||
bodyFont: {
|
||||
size: 13
|
||||
},
|
||||
backgroundColor: colors.isDarkMode ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)',
|
||||
titleColor: colors.isDarkMode ? '#ffffff' : '#000000',
|
||||
bodyColor: colors.isDarkMode ? '#ffffff' : '#000000',
|
||||
borderColor: colors.grid,
|
||||
borderWidth: 1
|
||||
}
|
||||
},
|
||||
scales: {
|
||||
y: {
|
||||
beginAtZero: true
|
||||
beginAtZero: true,
|
||||
ticks: {
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 12
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
color: colors.grid
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Number of Events',
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 14
|
||||
}
|
||||
}
|
||||
},
|
||||
x: {
|
||||
ticks: {
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 12
|
||||
}
|
||||
},
|
||||
grid: {
|
||||
color: colors.grid
|
||||
},
|
||||
title: {
|
||||
display: true,
|
||||
text: 'Date',
|
||||
color: colors.text,
|
||||
font: {
|
||||
weight: colors.isDarkMode ? 'bold' : 'normal',
|
||||
size: 14
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -684,8 +894,63 @@ function loadEventTypes() {
|
||||
});
|
||||
}
|
||||
|
||||
// Get theme colors for charts
|
||||
function getThemeColors() {
|
||||
const isDarkMode = document.documentElement.getAttribute('data-bs-theme') === 'dark';
|
||||
|
||||
// In dark mode, use higher contrast colors for text
|
||||
const textColor = isDarkMode ?
|
||||
'rgb(255, 255, 255)' : // White for dark mode for maximum contrast
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-sys-color-on-surface').trim();
|
||||
|
||||
// Use a more visible grid color in dark mode
|
||||
const gridColor = isDarkMode ?
|
||||
'rgba(255, 255, 255, 0.2)' : // Semi-transparent white for dark mode
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-sys-color-outline-variant').trim();
|
||||
|
||||
return {
|
||||
text: textColor,
|
||||
grid: gridColor,
|
||||
backgroundColor: getComputedStyle(document.documentElement).getPropertyValue('--md-sys-color-surface-container').trim(),
|
||||
chartColors: [
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-sys-color-primary').trim(),
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-sys-color-secondary').trim(),
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-sys-color-tertiary').trim(),
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-nav-section-color-other').trim(),
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-nav-section-color-convert').trim(),
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-nav-section-color-sign').trim(),
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-nav-section-color-security').trim(),
|
||||
getComputedStyle(document.documentElement).getPropertyValue('--md-nav-section-color-convertto').trim(),
|
||||
],
|
||||
isDarkMode: isDarkMode
|
||||
};
|
||||
}
|
||||
|
||||
// Function to generate a palette of colors for charts
|
||||
function getChartColors(count, opacity = 0.6) {
|
||||
try {
|
||||
// Use theme colors first
|
||||
const themeColors = getThemeColors();
|
||||
if (themeColors && themeColors.chartColors && themeColors.chartColors.length > 0) {
|
||||
const result = [];
|
||||
for (let i = 0; i < count; i++) {
|
||||
// Get the raw color and add opacity
|
||||
let color = themeColors.chartColors[i % themeColors.chartColors.length];
|
||||
// If it's rgb() format, convert to rgba()
|
||||
if (color.startsWith('rgb(')) {
|
||||
color = color.replace('rgb(', '').replace(')', '');
|
||||
result.push(`rgba(${color}, ${opacity})`);
|
||||
} else {
|
||||
// Just use the color directly
|
||||
result.push(color);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Error using theme colors, falling back to default colors', e);
|
||||
}
|
||||
|
||||
// Base colors - a larger palette than the default
|
||||
const colors = [
|
||||
[54, 162, 235], // blue
|
||||
|
42
proprietary/src/main/resources/templates/AUDIT_HELP.md
Normal file
42
proprietary/src/main/resources/templates/AUDIT_HELP.md
Normal file
@ -0,0 +1,42 @@
|
||||
# Audit System Help
|
||||
|
||||
## About the Audit System
|
||||
The Stirling PDF audit system records user actions and system events for security monitoring, compliance, and troubleshooting purposes.
|
||||
|
||||
## Audit Levels
|
||||
|
||||
| Level | Name | Description | Use Case |
|
||||
|-------|------|-------------|----------|
|
||||
| 0 | OFF | Minimal auditing, only critical security events | Development environments |
|
||||
| 1 | BASIC | Authentication events, security events, and errors | Production environments with minimal storage |
|
||||
| 2 | STANDARD | All HTTP requests and operations (default) | Normal production use |
|
||||
| 3 | VERBOSE | Detailed information including headers, parameters, and results | Troubleshooting and detailed analysis |
|
||||
|
||||
## Configuration
|
||||
Audit settings are configured in the `settings.yml` file under the `premium.proFeatures.audit` section:
|
||||
|
||||
```yaml
|
||||
premium:
|
||||
proFeatures:
|
||||
audit:
|
||||
enabled: true # Enable/disable audit logging
|
||||
level: 2 # Audit level (0=OFF, 1=BASIC, 2=STANDARD, 3=VERBOSE)
|
||||
retentionDays: 90 # Number of days to retain audit logs
|
||||
```
|
||||
|
||||
## Common Event Types
|
||||
|
||||
### BASIC Events:
|
||||
- USER_LOGIN - User login
|
||||
- USER_LOGOUT - User logout
|
||||
- USER_FAILED_LOGIN - Failed login attempt
|
||||
- USER_PROFILE_UPDATE - User or profile operations
|
||||
|
||||
### STANDARD Events:
|
||||
- HTTP_REQUEST - GET requests for viewing
|
||||
- PDF_PROCESS - PDF processing operations
|
||||
- FILE_OPERATION - File-related operations
|
||||
- SETTINGS_CHANGED - System or admin settings operations
|
||||
|
||||
### VERBOSE Events:
|
||||
- Detailed versions of STANDARD events with parameters and results
|
File diff suppressed because it is too large
Load Diff
@ -1636,6 +1636,83 @@ validateSignature.cert.keyUsage=Key Usage
|
||||
validateSignature.cert.selfSigned=Self-Signed
|
||||
validateSignature.cert.bits=bits
|
||||
|
||||
# Audit Dashboard
|
||||
audit.dashboard.title=Audit Dashboard
|
||||
audit.dashboard.systemStatus=Audit System Status
|
||||
audit.dashboard.status=Status
|
||||
audit.dashboard.enabled=Enabled
|
||||
audit.dashboard.disabled=Disabled
|
||||
audit.dashboard.currentLevel=Current Level
|
||||
audit.dashboard.retentionPeriod=Retention Period
|
||||
audit.dashboard.days=days
|
||||
audit.dashboard.totalEvents=Total Events
|
||||
|
||||
# Audit Dashboard Tabs
|
||||
audit.dashboard.tab.dashboard=Dashboard
|
||||
audit.dashboard.tab.events=Audit Events
|
||||
audit.dashboard.tab.export=Export
|
||||
# Dashboard Charts
|
||||
audit.dashboard.eventsByType=Events by Type
|
||||
audit.dashboard.eventsByUser=Events by User
|
||||
audit.dashboard.eventsOverTime=Events Over Time
|
||||
audit.dashboard.period.7days=7 Days
|
||||
audit.dashboard.period.30days=30 Days
|
||||
audit.dashboard.period.90days=90 Days
|
||||
|
||||
# Events Tab
|
||||
audit.dashboard.auditEvents=Audit Events
|
||||
audit.dashboard.filter.eventType=Event Type
|
||||
audit.dashboard.filter.allEventTypes=All event types
|
||||
audit.dashboard.filter.user=User
|
||||
audit.dashboard.filter.userPlaceholder=Filter by user
|
||||
audit.dashboard.filter.startDate=Start Date
|
||||
audit.dashboard.filter.endDate=End Date
|
||||
audit.dashboard.filter.apply=Apply Filters
|
||||
audit.dashboard.filter.reset=Reset Filters
|
||||
|
||||
# Table Headers
|
||||
audit.dashboard.table.id=ID
|
||||
audit.dashboard.table.time=Time
|
||||
audit.dashboard.table.user=User
|
||||
audit.dashboard.table.type=Type
|
||||
audit.dashboard.table.details=Details
|
||||
|
||||
# Pagination
|
||||
audit.dashboard.pagination.show=Show
|
||||
audit.dashboard.pagination.entries=entries
|
||||
audit.dashboard.pagination.pageInfo1=Page
|
||||
audit.dashboard.pagination.pageInfo2=of
|
||||
audit.dashboard.pagination.totalRecords=Total records:
|
||||
|
||||
# Modal
|
||||
audit.dashboard.modal.eventDetails=Event Details
|
||||
audit.dashboard.modal.id=ID
|
||||
audit.dashboard.modal.user=User
|
||||
audit.dashboard.modal.type=Type
|
||||
audit.dashboard.modal.time=Time
|
||||
audit.dashboard.modal.data=Data
|
||||
|
||||
# Export Tab
|
||||
audit.dashboard.export.title=Export Audit Data
|
||||
audit.dashboard.export.format=Export Format
|
||||
audit.dashboard.export.csv=CSV (Comma Separated Values)
|
||||
audit.dashboard.export.json=JSON (JavaScript Object Notation)
|
||||
audit.dashboard.export.button=Export Data
|
||||
audit.dashboard.export.infoTitle=Export Information
|
||||
audit.dashboard.export.infoDesc1=The export will include all audit events matching the selected filters. For large datasets, the export may take a few moments to generate.
|
||||
audit.dashboard.export.infoDesc2=Exported data will include:
|
||||
audit.dashboard.export.infoItem1=Event ID
|
||||
audit.dashboard.export.infoItem2=User
|
||||
audit.dashboard.export.infoItem3=Event Type
|
||||
audit.dashboard.export.infoItem4=Timestamp
|
||||
audit.dashboard.export.infoItem5=Event Data
|
||||
|
||||
# JavaScript i18n keys
|
||||
audit.dashboard.js.noEventsFound=No audit events found matching the current filters
|
||||
audit.dashboard.js.errorLoading=Error loading data:
|
||||
audit.dashboard.js.errorRendering=Error rendering table:
|
||||
audit.dashboard.js.loadingPage=Loading page
|
||||
|
||||
####################
|
||||
# Cookie banner #
|
||||
####################
|
||||
|
Loading…
x
Reference in New Issue
Block a user