mirror of
https://github.com/LightZirconite/Microsoft-Rewards-Bot.git
synced 2026-01-10 17:26:17 +00:00
feat: Refactor configuration management to disable editing via dashboard and implement persistent stats tracking
This commit is contained in:
@@ -712,25 +712,31 @@ function exportLogs() {
|
||||
}
|
||||
|
||||
function openConfig() {
|
||||
showModal('Configuration Editor', `
|
||||
showModal('Configuration Viewer', `
|
||||
<div class="config-loading">Loading configuration...</div>
|
||||
`, [])
|
||||
|
||||
// Fetch current config
|
||||
// Fetch config (read-only view)
|
||||
fetch('/api/config')
|
||||
.then(r => r.json())
|
||||
.then(config => {
|
||||
.then(data => {
|
||||
const body = `
|
||||
<div class="config-editor">
|
||||
<textarea id="configEditor" class="config-textarea">${JSON.stringify(config, null, 2)}</textarea>
|
||||
<p class="config-hint">⚠️ Advanced users only. Invalid JSON will break the bot.</p>
|
||||
<div class="config-warning">
|
||||
⚠️ <strong>Read-Only View</strong><br>
|
||||
This is a simplified preview. To edit config:<br>
|
||||
1. Open <code>src/config.jsonc</code> in a text editor<br>
|
||||
2. Make your changes<br>
|
||||
3. Save and restart the bot
|
||||
</div>
|
||||
<textarea id="configEditor" class="config-textarea" readonly>${JSON.stringify(data.config, null, 2)}</textarea>
|
||||
<p class="config-hint">💡 Manual editing preserves comments and complex settings</p>
|
||||
</div>
|
||||
`
|
||||
const buttons = [
|
||||
{ cls: 'btn btn-sm btn-secondary', action: 'closeModal()', text: 'Cancel' },
|
||||
{ cls: 'btn btn-sm btn-primary', action: 'saveConfig()', text: 'Save Changes' }
|
||||
{ cls: 'btn btn-sm btn-secondary', action: 'closeModal()', text: 'Close' }
|
||||
]
|
||||
showModal('Configuration Editor', body, buttons)
|
||||
showModal('Configuration Viewer', body, buttons)
|
||||
})
|
||||
.catch(e => {
|
||||
showToast('Failed to load config: ' + e.message, 'error')
|
||||
@@ -739,32 +745,9 @@ function openConfig() {
|
||||
}
|
||||
|
||||
function saveConfig() {
|
||||
const editor = document.getElementById('configEditor')
|
||||
if (!editor) return
|
||||
|
||||
try {
|
||||
const newConfig = JSON.parse(editor.value)
|
||||
|
||||
fetch('/api/config', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify(newConfig)
|
||||
})
|
||||
.then(r => r.json())
|
||||
.then(data => {
|
||||
if (data.success) {
|
||||
showToast('Configuration saved! Restart bot for changes to apply.', 'success')
|
||||
closeModal()
|
||||
} else {
|
||||
showToast('Save failed: ' + (data.error || 'Unknown error'), 'error')
|
||||
}
|
||||
})
|
||||
.catch(e => {
|
||||
showToast('Save failed: ' + e.message, 'error')
|
||||
})
|
||||
} catch (e) {
|
||||
showToast('Invalid JSON format: ' + e.message, 'error')
|
||||
}
|
||||
// Config editing is disabled - this function is now unused
|
||||
showToast('Config editing disabled. Edit src/config.jsonc manually.', 'warning')
|
||||
closeModal()
|
||||
}
|
||||
|
||||
function viewHistory() {
|
||||
|
||||
@@ -8,27 +8,7 @@
|
||||
<link rel="icon" type="image/svg+xml"
|
||||
href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Ctext y='.9em' font-size='90'%3E🎯%3C/text%3E%3C/svg%3E">
|
||||
<link rel="stylesheet" href="/style.css">
|
||||
<link rel="stylesheet" href="/style-extensions.css">
|
||||
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.1/dist/chart.umd.min.js"></script>
|
||||
<style>
|
||||
/* Inline SVG icon styles */
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
fill: currentColor;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
|
||||
.icon-lg {
|
||||
width: 1.25em;
|
||||
height: 1.25em;
|
||||
}
|
||||
|
||||
.icon-sm {
|
||||
width: 0.625em;
|
||||
height: 0.625em;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,82 +0,0 @@
|
||||
/* Dashboard Extensions - Config Editor & History Viewer */
|
||||
|
||||
/* Config Editor Styles */
|
||||
.config-editor {
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.config-textarea {
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
padding: var(--spacing-md);
|
||||
background: var(--bg-tertiary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--text-primary);
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
resize: vertical;
|
||||
transition: border-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.config-textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-blue);
|
||||
box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.2);
|
||||
}
|
||||
|
||||
.config-hint {
|
||||
margin-top: var(--spacing-sm);
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.config-loading {
|
||||
text-align: center;
|
||||
padding: var(--spacing-xl);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
/* History Viewer Styles */
|
||||
.history-list {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.history-row {
|
||||
padding: var(--spacing-md);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
background: var(--bg-tertiary);
|
||||
border-radius: var(--radius-md);
|
||||
border-left: 3px solid var(--accent-blue);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.history-row:hover {
|
||||
background: var(--bg-secondary);
|
||||
border-left-color: var(--accent-green);
|
||||
transform: translateX(2px);
|
||||
}
|
||||
|
||||
.history-date {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.history-stats {
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.history-stats span {
|
||||
padding: 2px 8px;
|
||||
background: var(--bg-primary);
|
||||
border-radius: var(--radius-sm);
|
||||
}
|
||||
324
public/style.css
324
public/style.css
@@ -877,4 +877,328 @@ body {
|
||||
.control-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* =================================================================== */
|
||||
/* ICON STYLES (moved from inline) */
|
||||
/* =================================================================== */
|
||||
|
||||
.icon {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
fill: currentColor;
|
||||
vertical-align: -0.125em;
|
||||
}
|
||||
|
||||
.icon-lg {
|
||||
width: 1.25em;
|
||||
height: 1.25em;
|
||||
}
|
||||
|
||||
.icon-sm {
|
||||
width: 0.625em;
|
||||
height: 0.625em;
|
||||
}
|
||||
|
||||
/* =================================================================== */
|
||||
/* CONFIG EDITOR & HISTORY VIEWER (moved from style-extensions.css) */
|
||||
/* =================================================================== */
|
||||
|
||||
.config-editor {
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
}
|
||||
|
||||
.config-textarea {
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
padding: var(--spacing-md);
|
||||
background: var(--bg-tertiary);
|
||||
border: 1px solid var(--border-color);
|
||||
border-radius: var(--radius-md);
|
||||
color: var(--text-primary);
|
||||
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.6;
|
||||
resize: vertical;
|
||||
transition: border-color var(--transition-fast);
|
||||
}
|
||||
|
||||
.config-textarea:focus {
|
||||
outline: none;
|
||||
border-color: var(--accent-blue);
|
||||
box-shadow: 0 0 0 2px rgba(88, 166, 255, 0.2);
|
||||
}
|
||||
|
||||
.config-hint {
|
||||
margin-top: var(--spacing-sm);
|
||||
font-size: 13px;
|
||||
color: var(--text-muted);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.config-warning {
|
||||
padding: var(--spacing-md);
|
||||
margin-bottom: var(--spacing-md);
|
||||
background: var(--accent-orange);
|
||||
color: var(--bg-primary);
|
||||
border-radius: var(--radius-md);
|
||||
font-size: 14px;
|
||||
line-height: 1.8;
|
||||
}
|
||||
|
||||
.config-warning strong {
|
||||
font-weight: 600;
|
||||
display: block;
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.config-warning code {
|
||||
background: rgba(0, 0, 0, 0.2);
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.config-loading {
|
||||
text-align: center;
|
||||
padding: var(--spacing-xl);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.history-list {
|
||||
max-height: 500px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.history-row {
|
||||
padding: var(--spacing-md);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
background: var(--bg-tertiary);
|
||||
border-radius: var(--radius-md);
|
||||
border-left: 3px solid var(--accent-blue);
|
||||
transition: all var(--transition-fast);
|
||||
animation: slideInLeft 0.3s ease-out;
|
||||
}
|
||||
|
||||
.history-row:hover {
|
||||
background: var(--bg-secondary);
|
||||
border-left-color: var(--accent-green);
|
||||
transform: translateX(4px);
|
||||
}
|
||||
|
||||
.history-date {
|
||||
font-size: 14px;
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.history-stats {
|
||||
display: flex;
|
||||
gap: var(--spacing-md);
|
||||
font-size: 13px;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.history-stats span {
|
||||
padding: 2px 8px;
|
||||
background: var(--bg-primary);
|
||||
border-radius: var(--radius-sm);
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.history-stats span:hover {
|
||||
background: var(--accent-blue);
|
||||
color: var(--bg-primary);
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
/* =================================================================== */
|
||||
/* PROFESSIONAL ANIMATIONS */
|
||||
/* =================================================================== */
|
||||
|
||||
@keyframes fadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInLeft {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(-20px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInRight {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateX(20px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
|
||||
0%,
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
50% {
|
||||
opacity: 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes scaleIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: scale(0.9);
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
background-position: -1000px 0;
|
||||
}
|
||||
|
||||
100% {
|
||||
background-position: 1000px 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply animations to elements */
|
||||
.card {
|
||||
animation: slideInUp 0.4s ease-out;
|
||||
}
|
||||
|
||||
.stat-card {
|
||||
animation: scaleIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
.stat-card:nth-child(2) {
|
||||
animation-delay: 0.1s;
|
||||
}
|
||||
|
||||
.stat-card:nth-child(3) {
|
||||
animation-delay: 0.2s;
|
||||
}
|
||||
|
||||
.stat-card:nth-child(4) {
|
||||
animation-delay: 0.3s;
|
||||
}
|
||||
|
||||
.log-entry {
|
||||
animation: slideInLeft 0.2s ease-out;
|
||||
}
|
||||
|
||||
.account-item {
|
||||
animation: slideInRight 0.3s ease-out;
|
||||
}
|
||||
|
||||
.toast {
|
||||
animation: slideInRight 0.3s ease-out;
|
||||
}
|
||||
|
||||
.modal.show {
|
||||
animation: fadeIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
.modal-content {
|
||||
animation: scaleIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
.status-badge {
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.status-badge.status-running {
|
||||
animation: pulse 2s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* Loading skeleton animation */
|
||||
.loading-skeleton {
|
||||
background: linear-gradient(90deg,
|
||||
var(--bg-tertiary) 0%,
|
||||
var(--bg-secondary) 50%,
|
||||
var(--bg-tertiary) 100%);
|
||||
background-size: 200% 100%;
|
||||
animation: shimmer 1.5s ease-in-out infinite;
|
||||
border-radius: var(--radius-md);
|
||||
}
|
||||
|
||||
/* Smooth transitions for interactive elements */
|
||||
.btn,
|
||||
.control-btn,
|
||||
.action-btn,
|
||||
.period-btn {
|
||||
transition: all var(--transition-fast);
|
||||
}
|
||||
|
||||
.btn:hover,
|
||||
.control-btn:hover,
|
||||
.action-btn:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
.btn:active,
|
||||
.control-btn:active,
|
||||
.action-btn:active {
|
||||
transform: translateY(0);
|
||||
}
|
||||
|
||||
/* Chart containers smooth entry */
|
||||
.chart-container {
|
||||
animation: fadeIn 0.5s ease-out;
|
||||
}
|
||||
|
||||
/* Stats value counter animation */
|
||||
.stat-value {
|
||||
transition: all var(--transition-normal);
|
||||
}
|
||||
|
||||
.stat-value.updating {
|
||||
animation: pulse 0.5s ease-out;
|
||||
}
|
||||
Reference in New Issue
Block a user