Reverted New UI Design of WeKan v8.29 and added more fixes and performance improvements.

Thanks to xet7 !
This commit is contained in:
Lauri Ojansivu 2026-02-08 00:48:39 +02:00
parent d152d8fc1b
commit 1b8b8d2eef
196 changed files with 17659 additions and 10028 deletions

View file

@ -6,12 +6,12 @@ template(name="attachmentSettings")
label {{_ 'writable-path'}}
input.wekan-form-control#filesystem-path(type="text" value="{{filesystemPath}}" readonly)
small.form-text.text-muted {{_ 'filesystem-path-description'}}
.form-group
label {{_ 'attachments-path'}}
input.wekan-form-control#attachments-path(type="text" value="{{attachmentsPath}}" readonly)
small.form-text.text-muted {{_ 'attachments-path-description'}}
.form-group
label {{_ 'avatars-path'}}
input.wekan-form-control#avatars-path(type="text" value="{{avatarsPath}}" readonly)
@ -30,42 +30,42 @@ template(name="attachmentSettings")
label {{_ 's3-enabled'}}
input.wekan-form-control#s3-enabled(type="checkbox" checked="{{s3Enabled}}" disabled)
small.form-text.text-muted {{_ 's3-enabled-description'}}
.form-group
label {{_ 's3-endpoint'}}
input.wekan-form-control#s3-endpoint(type="text" value="{{s3Endpoint}}" readonly)
small.form-text.text-muted {{_ 's3-endpoint-description'}}
.form-group
label {{_ 's3-bucket'}}
input.wekan-form-control#s3-bucket(type="text" value="{{s3Bucket}}" readonly)
small.form-text.text-muted {{_ 's3-bucket-description'}}
.form-group
label {{_ 's3-region'}}
input.wekan-form-control#s3-region(type="text" value="{{s3Region}}" readonly)
small.form-text.text-muted {{_ 's3-region-description'}}
.form-group
label {{_ 's3-access-key'}}
input.wekan-form-control#s3-access-key(type="text" placeholder="{{_ 's3-access-key-placeholder'}}" readonly)
small.form-text.text-muted {{_ 's3-access-key-description'}}
.form-group
label {{_ 's3-secret-key'}}
input.wekan-form-control#s3-secret-key(type="password" placeholder="{{_ 's3-secret-key-placeholder'}}")
small.form-text.text-muted {{_ 's3-secret-key-description'}}
.form-group
label {{_ 's3-ssl-enabled'}}
input.wekan-form-control#s3-ssl-enabled(type="checkbox" checked="{{s3SslEnabled}}" disabled)
small.form-text.text-muted {{_ 's3-ssl-enabled-description'}}
.form-group
label {{_ 's3-port'}}
input.wekan-form-control#s3-port(type="number" value="{{s3Port}}" readonly)
small.form-text.text-muted {{_ 's3-port-description'}}
.form-group
button.js-test-s3-connection.btn.btn-secondary {{_ 'test-s3-connection'}}
button.js-save-s3-settings.btn.btn-primary {{_ 'save-s3-settings'}}
@ -73,19 +73,19 @@ template(name="attachmentSettings")
template(name="storageSettings")
.storage-settings
h3 {{_ 'attachment-storage-configuration'}}
.storage-config-section
h4 {{_ 'filesystem-storage'}}
.form-group
label {{_ 'writable-path'}}
input.wekan-form-control#filesystem-path(type="text" value="{{filesystemPath}}" readonly)
small.form-text.text-muted {{_ 'filesystem-path-description'}}
.form-group
label {{_ 'attachments-path'}}
input.wekan-form-control#attachments-path(type="text" value="{{attachmentsPath}}" readonly)
small.form-text.text-muted {{_ 'attachments-path-description'}}
.form-group
label {{_ 'avatars-path'}}
input.wekan-form-control#avatars-path(type="text" value="{{avatarsPath}}" readonly)
@ -104,37 +104,37 @@ template(name="storageSettings")
label {{_ 's3-enabled'}}
input.wekan-form-control#s3-enabled(type="checkbox" checked="{{s3Enabled}}" disabled)
small.form-text.text-muted {{_ 's3-enabled-description'}}
.form-group
label {{_ 's3-endpoint'}}
input.wekan-form-control#s3-endpoint(type="text" value="{{s3Endpoint}}" readonly)
small.form-text.text-muted {{_ 's3-endpoint-description'}}
.form-group
label {{_ 's3-bucket'}}
input.wekan-form-control#s3-bucket(type="text" value="{{s3Bucket}}" readonly)
small.form-text.text-muted {{_ 's3-bucket-description'}}
.form-group
label {{_ 's3-region'}}
input.wekan-form-control#s3-region(type="text" value="{{s3Region}}" readonly)
small.form-text.text-muted {{_ 's3-region-description'}}
.form-group
label {{_ 's3-access-key'}}
input.wekan-form-control#s3-access-key(type="text" placeholder="{{_ 's3-access-key-placeholder'}}" readonly)
small.form-text.text-muted {{_ 's3-access-key-description'}}
.form-group
label {{_ 's3-secret-key'}}
input.wekan-form-control#s3-secret-key(type="password" placeholder="{{_ 's3-secret-key-placeholder'}}")
small.form-text.text-muted {{_ 's3-secret-key-description'}}
.form-group
label {{_ 's3-ssl-enabled'}}
input.wekan-form-control#s3-ssl-enabled(type="checkbox" checked="{{s3SslEnabled}}" disabled)
small.form-text.text-muted {{_ 's3-ssl-enabled-description'}}
.form-group
label {{_ 's3-port'}}
input.wekan-form-control#s3-port(type="number" value="{{s3Port}}" readonly)
@ -147,18 +147,18 @@ template(name="storageSettings")
template(name="attachmentMigration")
.attachment-migration
h3 {{_ 'attachment-migration'}}
.migration-controls
.form-group
label {{_ 'migration-batch-size'}}
input.wekan-form-control#migration-batch-size(type="number" value="{{migrationBatchSize}}" min="1" max="100")
small.form-text.text-muted {{_ 'migration-batch-size-description'}}
.form-group
label {{_ 'migration-delay-ms'}}
input.wekan-form-control#migration-delay-ms(type="number" value="{{migrationDelayMs}}" min="100" max="10000")
small.form-text.text-muted {{_ 'migration-delay-ms-description'}}
.form-group
label {{_ 'migration-cpu-threshold'}}
input.wekan-form-control#migration-cpu-threshold(type="number" value="{{migrationCpuThreshold}}" min="10" max="90")
@ -169,7 +169,7 @@ template(name="attachmentMigration")
button.js-migrate-all-to-filesystem.btn.btn-primary {{_ 'migrate-all-to-filesystem'}}
button.js-migrate-all-to-gridfs.btn.btn-primary {{_ 'migrate-all-to-gridfs'}}
button.js-migrate-all-to-s3.btn.btn-primary {{_ 'migrate-all-to-s3'}}
.migration-controls
button.js-pause-migration.btn.btn-warning {{_ 'pause-migration'}}
button.js-resume-migration.btn.btn-success {{_ 'resume-migration'}}
@ -180,7 +180,7 @@ template(name="attachmentMigration")
.progress
.progress-bar(role="progressbar" style="width: {{migrationProgress}}%" aria-valuenow="{{migrationProgress}}" aria-valuemin="0" aria-valuemax="100")
| {{migrationProgress}}%
.migration-stats
.stat-item
span.label {{_ 'total-attachments'}}:
@ -203,7 +203,7 @@ template(name="attachmentMigration")
template(name="attachmentMonitoring")
.attachment-monitoring
h3 {{_ 'attachment-monitoring'}}
.monitoring-stats
.stats-grid
.stat-card

View file

@ -19,7 +19,7 @@
.migration-header h2 {
margin: 0;
color: #333;
font-size: 24px;
font-weight: 600;
}
@ -35,8 +35,8 @@
.migration-controls .btn {
padding: 8px 16px;
border-radius: 0.4ch;
font-size: 14px;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.3s ease;
@ -72,7 +72,7 @@
.migration-progress {
background: #f8f9fa;
padding: 20px;
border-radius: 0.8ch;
border-radius: 8px;
margin-bottom: 30px;
border-left: 4px solid #667eea;
}
@ -128,20 +128,20 @@
text-align: center;
font-weight: 700;
color: #667eea;
font-size: 18px;
}
.progress-label {
text-align: center;
color: #666;
font-size: 14px;
margin-top: 4px;
}
.current-step {
text-align: center;
color: #333;
font-size: 16px;
font-weight: 500;
margin-bottom: 16px;
}
@ -154,7 +154,7 @@
.migration-status {
text-align: center;
color: #333;
font-size: 16px;
background-color: #e3f2fd;
padding: 12px 16px;
border-radius: 6px;
@ -173,7 +173,7 @@
.migration-steps h3 {
margin: 0 0 20px 0;
color: #333;
font-size: 20px;
font-weight: 600;
}
@ -181,7 +181,7 @@
max-height: 400px;
overflow-y: auto;
border: 1px solid #e0e0e0;
border-radius: 0.8ch;
border-radius: 8px;
}
.migration-step {
@ -210,7 +210,7 @@
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0.4);
}
70% {
box-shadow: 0 0 0 0.5rem rgba(102, 126, 234, 0);
box-shadow: 0 0 0 10px rgba(102, 126, 234, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0);
@ -225,7 +225,7 @@
.step-icon {
margin-right: 12px;
font-size: 18px;
width: 24px;
text-align: center;
}
@ -249,13 +249,13 @@
.step-name {
font-weight: 600;
color: #333;
font-size: 14px;
margin-bottom: 2px;
}
.step-description {
color: #666;
font-size: 12px;
line-height: 1.3;
}
@ -265,7 +265,7 @@
}
.step-progress .progress-text {
font-size: 12px;
font-weight: 600;
}
@ -302,7 +302,7 @@
.jobs-header h2 {
margin: 0;
color: #333;
font-size: 24px;
font-weight: 600;
}
@ -313,8 +313,8 @@
.jobs-controls .btn {
padding: 8px 16px;
border-radius: 0.4ch;
font-size: 14px;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.3s ease;
@ -337,7 +337,7 @@
width: 100%;
border-collapse: collapse;
background: white;
border-radius: 0.8ch;
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
@ -356,18 +356,18 @@
.table th {
font-weight: 600;
color: #333;
font-size: 14px;
}
.table td {
font-size: 14px;
color: #666;
}
.status-badge {
padding: 4px 8px;
border-radius: 0.4ch;
border-radius: 4px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
}
@ -404,7 +404,7 @@
.btn-group .btn {
padding: 4px 8px;
font-size: 12px;
border-radius: 3px;
border: none;
cursor: pointer;
@ -452,7 +452,7 @@
.add-job-header h2 {
margin: 0;
color: #333;
font-size: 24px;
font-weight: 600;
}
@ -474,15 +474,15 @@
margin-bottom: 8px;
font-weight: 600;
color: #333;
font-size: 14px;
}
.form-control {
width: 100%;
padding: 10px 12px;
border: 1px solid #ddd;
border-radius: 0.4ch;
border-radius: 4px;
font-size: 14px;
transition: border-color 0.3s ease;
}
@ -504,8 +504,8 @@
.form-actions .btn {
padding: 10px 20px;
border-radius: 0.4ch;
font-size: 14px;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.3s ease;
@ -546,7 +546,7 @@
.board-operations-header h2 {
margin: 0;
color: #333;
font-size: 24px;
font-weight: 600;
}
@ -562,8 +562,8 @@
.board-operations-controls .btn {
padding: 8px 16px;
border-radius: 0.4ch;
font-size: 14px;
border-radius: 4px;
border: none;
cursor: pointer;
transition: all 0.3s ease;
@ -590,7 +590,7 @@
.board-operations-stats {
background: #f8f9fa;
padding: 20px;
border-radius: 0.8ch;
border-radius: 8px;
margin-bottom: 30px;
border-left: 4px solid #667eea;
}
@ -606,14 +606,14 @@
}
.stat-value {
font-size: 32px;
font-weight: 700;
color: #667eea;
margin-bottom: 4px;
}
.stat-label {
font-size: 14px;
color: #666;
text-transform: uppercase;
letter-spacing: 0.5px;
@ -622,7 +622,7 @@
.system-resources {
background: #f8f9fa;
padding: 20px;
border-radius: 0.8ch;
border-radius: 8px;
margin-bottom: 30px;
border-left: 4px solid #28a745;
}
@ -641,7 +641,7 @@
min-width: 120px;
font-weight: 600;
color: #333;
font-size: 14px;
}
.resource-bar {
@ -674,7 +674,7 @@
text-align: right;
font-weight: 600;
color: #333;
font-size: 14px;
}
.board-operations-search {
@ -683,7 +683,7 @@
.search-box {
position: relative;
max-width: 50vw;
max-width: 400px;
}
.search-box .form-control {
@ -696,12 +696,12 @@
top: 50%;
transform: translateY(-50%);
color: #999;
font-size: 16px;
}
.board-operations-list {
background: white;
border-radius: 0.8ch;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
@ -718,13 +718,13 @@
.operations-header h3 {
margin: 0;
color: #333;
font-size: 18px;
font-weight: 600;
}
.pagination-info {
color: #666;
font-size: 14px;
}
.operations-table {
@ -751,11 +751,11 @@
.board-id {
font-family: monospace;
font-size: 12px;
color: #666;
background: #f8f9fa;
padding: 4px 8px;
border-radius: 0.4ch;
border-radius: 4px;
display: inline-block;
}
@ -776,19 +776,19 @@
flex: 1;
height: 8px;
background-color: #e0e0e0;
border-radius: 0.4ch;
border-radius: 4px;
overflow: hidden;
}
.progress-container .progress-fill {
height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2);
border-radius: 0.4ch;
border-radius: 4px;
transition: width 0.3s ease;
}
.progress-container .progress-text {
font-size: 12px;
font-weight: 600;
color: #667eea;
min-width: 35px;
@ -806,8 +806,8 @@
.pagination .btn {
padding: 6px 12px;
border-radius: 0.4ch;
font-size: 12px;
border-radius: 4px;
border: 1px solid #ddd;
background: white;
color: #333;
@ -827,7 +827,7 @@
.page-info {
color: #666;
font-size: 14px;
}
/* Responsive design */
@ -846,7 +846,7 @@
}
.table {
font-size: 12px;
}
.table th,
@ -878,7 +878,7 @@
#cron-setting .progress {
height: 30px;
background-color: #e9ecef;
border-radius: 0.4ch;
border-radius: 4px;
overflow: visible;
margin-bottom: 5px;
max-width: calc(100% - 40px);
@ -893,7 +893,7 @@
font-size: 14px;
text-align: center;
transition: width 0.3s ease;
border-radius: 0.4ch;
border-radius: 4px;
}
#cron-setting .progress-text {

View file

@ -8,7 +8,7 @@ template(name="cronSettings")
option(value="0") 0 - {{_ 'all-migrations'}}
each migrationStepsWithIndex
option(value="{{index}}") {{index}} - {{name}}
.form-group
label {{_ 'migration-status'}}
.status-indicator
@ -18,16 +18,16 @@ template(name="cronSettings")
.step-counter
| Step {{migrationCurrentStepNum}}/{{migrationTotalSteps}}
.progress
.progress-bar(role="progressbar" style="width: {{migrationProgress}}%" aria-valuenow="{{migrationProgress}}" aria-valuemin="0" aria-valuemax="100")
.progress-bar(role="progressbar" style="width: {{migrationProgress}}%" aria-valuenow="{{migrationProgress}}" aria-valuemin="0" aria-valuemax="100")
| {{migrationProgress}}%
.progress-text
| {{migrationProgress}}% {{_ 'complete'}}
.form-group
button.js-start-migration.btn.btn-primary(disabled="{{#if isMigrating}}disabled{{/if}}") {{_ 'start'}}
button.js-pause-migration.btn.btn-warning(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'pause'}}
button.js-stop-migration.btn.btn-danger(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'stop'}}
.form-group.migration-errors-section
h4 {{_ 'cron-migration-errors'}}
if hasErrors
@ -49,7 +49,7 @@ template(name="cronSettings")
else
.no-errors
| {{_ 'cron-no-errors'}}
li
h3 {{_ 'board-operations'}}
.form-group
@ -57,7 +57,7 @@ template(name="cronSettings")
button.js-schedule-board-cleanup.btn.btn-primary {{_ 'schedule-board-cleanup'}}
button.js-schedule-board-archive.btn.btn-warning {{_ 'schedule-board-archive'}}
button.js-schedule-board-backup.btn.btn-info {{_ 'schedule-board-backup'}}
li
h3 {{_ 'cron-jobs'}}
.form-group
@ -90,22 +90,22 @@ template(name="cronMigrations")
button.btn.btn-danger.js-stop-all-migrations
i.fa.fa-stop
| {{_ 'stop-all-migrations'}}
.migration-progress
.progress-overview
.progress-bar
.progress-fill(style="width: {{migrationProgress}}%")
.progress-fill(style="width: {{migrationProgress}}%")
.progress-text {{migrationProgress}}%
.progress-label {{_ 'overall-progress'}}
.current-step
i.fa.fa-cog
| {{migrationCurrentStep}}
.migration-status
i.fa.fa-info-circle
| {{migrationStatus}}
.migration-steps
h3 {{_ 'migration-steps'}}
.steps-list
@ -149,7 +149,7 @@ template(name="cronBoardOperations")
button.btn.btn-info.js-force-board-scan
i.fa.fa-search
| {{_ 'force-board-scan'}}
.board-operations-stats
.stats-grid
.stat-item
@ -176,7 +176,7 @@ template(name="cronBoardOperations")
.stat-item
.stat-value {{boardMigrationStats.isScanning}}
.stat-label {{_ 'scanning-status'}}
.system-resources
.resource-item
.resource-label {{_ 'cpu-usage'}}
@ -191,18 +191,18 @@ template(name="cronBoardOperations")
.resource-item
.resource-label {{_ 'cpu-cores'}}
.resource-value {{systemResources.cpuCores}}
.board-operations-search
.search-box
input.form-control.js-search-board-operations(type="text" placeholder="{{_ 'search-boards-or-operations'}}")
i.fa.fa-search.search-icon
.board-operations-list
.operations-header
h3 {{_ 'board-operations'}} ({{pagination.total}})
.pagination-info
| {{_ 'showing'}} {{pagination.start}} - {{pagination.end}} {{_ 'of'}} {{pagination.total}}
.operations-table
table.table.table-striped
thead
@ -242,7 +242,7 @@ template(name="cronBoardOperations")
i.fa.fa-stop
button.btn.btn-sm.btn-info.js-view-details(data-operation="{{id}}")
i.fa.fa-info-circle
.pagination
if pagination.hasPrev
button.btn.btn-sm.btn-default.js-prev-page
@ -265,7 +265,7 @@ template(name="cronJobs")
button.btn.btn-success.js-refresh-jobs
i.fa.fa-refresh
| {{_ 'refresh'}}
.jobs-list
table.table.table-striped
thead
@ -304,17 +304,17 @@ template(name="cronAddJob")
h2
i.fa.fa-plus
| {{_ 'add-cron-job'}}
.add-job-form
form.js-add-cron-job-form
.form-group
label(for="job-name") {{_ 'job-name'}}
input.form-control#job-name(type="text" name="name" required)
.form-group
label(for="job-description") {{_ 'job-description'}}
textarea.form-control#job-description(name="description" rows="3")
.form-group
label(for="job-schedule") {{_ 'schedule'}}
select.form-control#job-schedule(name="schedule")
@ -326,11 +326,11 @@ template(name="cronAddJob")
option(value="every 6 hours") {{_ 'every-6-hours'}}
option(value="every 1 day") {{_ 'every-1-day'}}
option(value="once") {{_ 'run-once'}}
.form-group
label(for="job-weight") {{_ 'weight'}}
input.form-control#job-weight(type="number" name="weight" value="1" min="1" max="10")
.form-actions
button.btn.btn-primary(type="submit")
i.fa.fa-plus

View file

@ -15,7 +15,7 @@
.migration-progress-modal {
background: white;
border-radius: 0.8ch;
border-radius: 8px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
max-width: 500px;
width: 90%;
@ -46,13 +46,13 @@
.migration-progress-title {
margin: 0;
font-size: 18px;
font-weight: 600;
}
.migration-progress-close {
cursor: pointer;
font-size: 16px;
opacity: 0.8;
transition: opacity 0.2s ease;
}
@ -73,7 +73,7 @@
font-weight: 600;
color: #333;
margin-bottom: 8px;
font-size: 14px;
}
.migration-progress-overall-bar {
@ -110,7 +110,7 @@
.migration-progress-overall-percentage {
text-align: right;
font-size: 12px;
color: #666;
font-weight: 600;
}
@ -123,12 +123,12 @@
font-weight: 600;
color: #333;
margin-bottom: 8px;
font-size: 14px;
}
.migration-progress-step-bar {
background: #e9ecef;
border-radius: 0.8ch;
border-radius: 8px;
height: 8px;
overflow: hidden;
margin-bottom: 5px;
@ -137,13 +137,13 @@
.migration-progress-step-fill {
background: linear-gradient(90deg, #007bff, #0056b3);
height: 100%;
border-radius: 0.8ch;
border-radius: 8px;
transition: width 0.3s ease;
}
.migration-progress-step-percentage {
text-align: right;
font-size: 12px;
color: #666;
font-weight: 600;
}
@ -160,12 +160,12 @@
font-weight: 600;
color: #333;
margin-bottom: 5px;
font-size: 13px;
}
.migration-progress-status-text {
color: #555;
font-size: 14px;
line-height: 1.4;
}
@ -181,12 +181,12 @@
font-weight: 600;
color: #1976d2;
margin-bottom: 5px;
font-size: 13px;
}
.migration-progress-details-text {
color: #1565c0;
font-size: 13px;
line-height: 1.4;
}
@ -199,7 +199,7 @@
.migration-progress-note {
text-align: center;
color: #666;
font-size: 13px;
font-style: italic;
}
@ -219,7 +219,7 @@
}
.migration-progress-title {
font-size: 16px;
}
}
@ -285,7 +285,7 @@
align-items: center;
justify-content: center;
z-index: 10;
border-radius: 0.4ch;
border-radius: 4px;
}
.migration-spinner {

View file

@ -8,7 +8,7 @@ template(name="migrationProgress")
| {{_ 'migration-progress-title'}}
.migration-progress-close.js-close-migration-progress
i.fa.fa-times-thin
.migration-progress-content
.migration-progress-overall
.migration-progress-overall-label
@ -17,7 +17,7 @@ template(name="migrationProgress")
.migration-progress-overall-fill(style="{{progressBarStyle}}")
.migration-progress-overall-percentage
| {{overallProgress}}%
.migration-progress-current-step
.migration-progress-step-label
| {{_ 'migration-progress-current-step'}}: {{stepNameFormatted}}
@ -25,20 +25,20 @@ template(name="migrationProgress")
.migration-progress-step-fill(style="{{stepProgressBarStyle}}")
.migration-progress-step-percentage
| {{stepProgress}}%
.migration-progress-status
.migration-progress-status-label
| {{_ 'migration-progress-status'}}:
.migration-progress-status-text
| {{stepStatus}}
if stepDetailsFormatted
.migration-progress-details
.migration-progress-details-label
| {{_ 'migration-progress-details'}}:
.migration-progress-details-text
| {{stepDetailsFormatted}}
.migration-progress-footer
.migration-progress-note
| {{_ 'migration-progress-note'}}

View file

@ -79,7 +79,7 @@ class MigrationProgressManager {
isMigrating.set(false);
migrationProgress.set(100);
migrationStatus.set('Migration completed successfully!');
// Clear step details after a delay
setTimeout(() => {
migrationStepName.set('');
@ -178,7 +178,7 @@ Template.migrationProgress.helpers({
stepNameFormatted() {
const stepName = migrationStepName.get();
if (!stepName) return '';
// Convert snake_case to Title Case
return stepName
.split('_')
@ -189,7 +189,7 @@ Template.migrationProgress.helpers({
stepDetailsFormatted() {
const details = migrationStepDetails.get();
if (!details) return '';
const formatted = [];
for (const [key, value] of Object.entries(details)) {
const formattedKey = key
@ -199,7 +199,7 @@ Template.migrationProgress.helpers({
.replace(/^\w/, c => c.toUpperCase());
formatted.push(`${formattedKey}: ${value}`);
}
return formatted.join(', ');
}
});

View file

@ -39,6 +39,9 @@ table tr:nth-child(even) {
.ext-box button {
min-width: 90px;
}
.content-wrapper {
margin-top: 10px;
}
.buttonsContainer {
display: flex;
}
@ -161,7 +164,7 @@ table td:first-child {
background-color: #27ae60;
color: white;
padding: 10px 20px;
border-radius: 0.4ch;
border-radius: 4px;
z-index: 9999;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
animation: fadeOut 3s ease-in forwards;

View file

@ -512,7 +512,8 @@ template(name="newUserPopup")
span.error.hide.username-taken
| {{_ 'error-username-taken'}}
//if isLdap
// input.js-profile-username(type="text" value=user.username readonly)
//
input.js-profile-username(type="text" value=user.username readonly)
//else
input.js-profile-username(type="text" value="" required)
label
@ -523,7 +524,8 @@ template(name="newUserPopup")
span.error.hide.email-taken
| {{_ 'error-email-taken'}}
//if isLdap
// input.js-profile-email(type="email" value="{{user.emails.[0].address}}" readonly)
//
input.js-profile-email(type="email" value="{{user.emails.[0].address}}" readonly)
//else
input.js-profile-email(type="email" value="" required)
label
@ -596,10 +598,14 @@ template(name="settingsOrgPopup")
// It's not yet possible to impersonate organization. Only impersonate user,
// because that changes current user ID. What would it mean in practice
// to impersonate organization?
// li
// a.impersonate-org
// i.fa.fa-user
// | {{_ 'impersonate-org'}}
//
li
//
a.impersonate-org
//
i.fa.fa-user
//
| {{_ 'impersonate-org'}}
//
//
@ -640,8 +646,10 @@ template(name="settingsUserPopup")
// - wekan/client/components/settings/peopleBody.jade deleteButton
// - wekan/client/components/settings/peopleBody.js deleteButton
// - wekan/client/components/sidebar/sidebar.js Popup.afterConfirm('removeMember'
// that does now remove member from board, card members and assignees correctly,
// but that should be used to remove user from all boards similarly
//
that does now remove member from board, card members and assignees correctly,
//
but that should be used to remove user from all boards similarly
// - wekan/models/users.js Delete is not enabled
template(name="lockedUsersGeneral")

View file

@ -9,32 +9,19 @@
display: flex;
height: 100%;
}
.setting-detail {
display: flex;
flex-direction: column;
flex: 1;
justify-content: stretch;
align-items: stretch;
}
.setting-content {
color: #727479;
background: #dedede;
overflow-y: scroll;
}
.setting-content .wekan-form-control:not([type="radio"]) {
display: flex;
width: 100%;
height: 100%;
position: absolute;
}
.setting-content .content-title {
font-size: 1.3em;
padding: 0.5lh 1ch;
font-size: clamp(16px, 3.5vw, 22px);
}
.setting-content .content-body {
display: flex;
padding-top: 2vh;
height: 100%;
gap: 1.3vw;
}
@ -42,15 +29,8 @@
background-color: #f7f7f7;
border: 1px solid #f0f0f0;
border-radius: 0.5vw;
min-width: fit-content;
width: min(250px, 32vw);
box-shadow: inset -0.2vh -0.2vh 0.4vh rgba(0,0,0,0.05);
display: flex;
flex-direction: column;
padding-right: 2ch;
overflow-y: scroll;
min-height: 20vh;
flex-grow: 1;
}
.setting-content .content-body .side-menu ul li {
margin: 0.2vh 0.3vw;
@ -67,10 +47,12 @@
padding: 1.3vh 0 1.3vh 1.3vw;
width: 95%;
}
.setting-content .content-body .side-menu ul li a span {
font-size: 13px;
}
.setting-content .content-body .side-menu ul li a i {
margin-right: 20px;
}
.setting-content .content-body .main-body {
-webkit-user-select: text;
-moz-user-select: text;
@ -80,9 +62,9 @@
overflow-x: scroll !important;
overflow-y: scroll !important;
scrollbar-gutter: stable;
flex-grow: 5;
padding-right: 2ch;
padding-bottom: 1lh;
/* Force horizontal scrollbar to always be visible */
min-width: 100%;
width: 100%;
}
/* Ensure scrollbars are always visible with proper styling for all admin pages */
@ -135,6 +117,24 @@
padding-bottom: 50px;
}
/* Admin panel buttons should use theme darker color */
.setting-content .content-body .main-body .setting-detail button.btn {
background: #005377;
color: #fff;
border: none;
}
.setting-content .content-body .main-body .setting-detail button.btn:hover,
.setting-content .content-body .main-body .setting-detail button.btn:focus {
background: #004766;
color: #fff;
}
.setting-content .content-body .main-body .setting-detail button.btn:active {
background: #01628c;
color: #fff;
}
/* Force horizontal scrollbar to always be visible at bottom */
.setting-content .content-body .main-body {
position: relative;
@ -144,6 +144,7 @@
.setting-content .content-body .main-body::after {
content: '';
display: block;
width: 100vw;
height: 1px;
position: absolute;
bottom: 0;
@ -154,7 +155,7 @@
padding: 0.5rem 0.5rem;
}
.setting-content .content-body .main-body ul li a .is-checked {
border-bottom: 0.2ch solid #3cb500;
border-bottom: 2px solid #3cb500;
border-right: 2px solid #3cb500;
}
/* Grey checkmarks when grey icons setting is enabled */

View file

@ -107,7 +107,7 @@ template(name="setting")
a.js-setting-menu(data-id="cron-settings")
span.emoji-icon
i.fa.fa-clock
| {{_ 'cron'}}
| {{_ 'migrations'}}
.main-body
if isLoading
+spinner
@ -119,12 +119,12 @@ template(name="setting")
label {{_ 'writable-path'}}
input.wekan-form-control#filesystem-path(type="text" value="{{filesystemPath}}" readonly)
small.form-text.text-muted {{_ 'filesystem-path-description'}}
.form-group
label {{_ 'attachments-path'}}
input.wekan-form-control#attachments-path(type="text" value="{{attachmentsPath}}" readonly)
small.form-text.text-muted {{_ 'attachments-path-description'}}
.form-group
label {{_ 'avatars-path'}}
input.wekan-form-control#avatars-path(type="text" value="{{avatarsPath}}" readonly)
@ -143,49 +143,55 @@ template(name="setting")
label {{_ 's3-enabled'}}
input.wekan-form-control#s3-enabled(type="checkbox" checked="{{s3Enabled}}" disabled)
small.form-text.text-muted {{_ 's3-enabled-description'}}
.form-group
label {{_ 's3-endpoint'}}
input.wekan-form-control#s3-endpoint(type="text" value="{{s3Endpoint}}" readonly)
small.form-text.text-muted {{_ 's3-endpoint-description'}}
.form-group
label {{_ 's3-bucket'}}
input.wekan-form-control#s3-bucket(type="text" value="{{s3Bucket}}" readonly)
small.form-text.text-muted {{_ 's3-bucket-description'}}
.form-group
label {{_ 's3-region'}}
input.wekan-form-control#s3-region(type="text" value="{{s3Region}}" readonly)
small.form-text.text-muted {{_ 's3-region-description'}}
.form-group
label {{_ 's3-access-key'}}
input.wekan-form-control#s3-access-key(type="text" placeholder="{{_ 's3-access-key-placeholder'}}" readonly)
small.form-text.text-muted {{_ 's3-access-key-description'}}
.form-group
label {{_ 's3-secret-key'}}
input.wekan-form-control#s3-secret-key(type="password" placeholder="{{_ 's3-secret-key-placeholder'}}")
small.form-text.text-muted {{_ 's3-secret-key-description'}}
.form-group
label {{_ 's3-ssl-enabled'}}
input.wekan-form-control#s3-ssl-enabled(type="checkbox" checked="{{s3SslEnabled}}" disabled)
small.form-text.text-muted {{_ 's3-ssl-enabled-description'}}
.form-group
label {{_ 's3-port'}}
input.wekan-form-control#s3-port(type="number" value="{{s3Port}}" readonly)
small.form-text.text-muted {{_ 's3-port-description'}}
.form-group
button.js-test-s3-connection.btn.btn-secondary {{_ 'test-s3-connection'}}
button.js-save-s3-settings.btn.btn-primary {{_ 'save-s3-settings'}}
else if isCronSettings
ul#cron-setting.setting-detail
li
h3 {{_ 'cron-migrations'}}
h3 {{_ 'migrations'}}
.form-group
label {{_ 'select-migration'}}
select.js-migration-select.wekan-form-control
option(value="0") 0 - {{_ 'all-migrations'}}
each migrationStepsWithIndex
option(value="{{index}}") {{index}} - {{name}}
.form-group
label {{_ 'migration-status'}}
.status-indicator
@ -193,43 +199,45 @@ template(name="setting")
span.status-value
if isMigrating
i.fa.fa-spinner.fa-spin(style="margin-right: 8px;")
| {{#if isMigrating}}{{migrationStatus}}{{else}}{{_ 'idle'}}{{/if}}
else if isUpdatingMigrationDropdown
i.fa.fa-spinner.fa-spin(style="margin-right: 8px;")
| {{#if isMigrating}}{{migrationStatusLine}}{{else}}{{migrationStatus}}{{/if}}
if isMigrating
.progress-section
if migrationCurrentAction
.step-counter
| {{migrationCurrentAction}}
else if migrationJobTotalSteps
.step-counter
| Step {{migrationJobStepNum}}/{{migrationJobTotalSteps}}
else if migrationTotalSteps
.step-counter
| Migration {{migrationCurrentStepNum}}/{{migrationTotalSteps}}
else
.step-counter
i.fa.fa-spinner.fa-spin(style="margin-right: 8px;")
| Calculating migration scope...
.progress
.progress-bar(role="progressbar" style="width: {{migrationProgress}}%" aria-valuenow="{{migrationProgress}}" aria-valuemin="0" aria-valuemax="100")
| {{migrationProgress}}%
.progress-bar(role="progressbar" style="width: {{migrationJobProgress}}%" aria-valuenow="{{migrationJobProgress}}" aria-valuemin="0" aria-valuemax="100")
| {{migrationJobProgress}}%
.progress-text
| {{migrationProgress}}% {{_ 'complete'}}
| {{migrationJobProgress}}% {{_ 'complete'}}
.migration-details
if migrationJobTotalSteps
if migrationJobTotalSteps gt 1
.detail-line
| Job step: {{migrationJobStepNum}}/{{migrationJobTotalSteps}}
if migrationEtaSeconds
.detail-line
| ETA: {{formatDurationSeconds migrationEtaSeconds}}
if migrationElapsedSeconds
.detail-line
| Elapsed: {{formatDurationSeconds migrationElapsedSeconds}}
.form-group
button.js-start-all-migrations.btn.btn-primary(disabled="{{#if isMigrating}}disabled{{/if}}") {{_ 'start-all-migrations'}}
button.js-pause-all-migrations.btn.btn-warning(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'pause-all-migrations'}}
button.js-stop-all-migrations.btn.btn-danger(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'stop-all-migrations'}}
li
h3 {{_ 'board-operations'}}
.form-group
label {{_ 'scheduled-board-operations'}}
button.js-schedule-board-cleanup.btn.btn-primary {{_ 'schedule-board-cleanup'}}
button.js-schedule-board-archive.btn.btn-warning {{_ 'schedule-board-archive'}}
button.js-schedule-board-backup.btn.btn-info {{_ 'schedule-board-backup'}}
li
h3 {{_ 'cron-jobs'}}
.form-group
label {{_ 'active-cron-jobs'}}
each cronJobs
.job-item
.job-info
.job-name {{name}}
.job-schedule {{schedule}}
.job-status {{status}}
.job-actions
button.js-pause-job.btn.btn-sm.btn-warning(data-job-id="{{_id}}") {{_ 'pause'}}
button.js-delete-job.btn.btn-sm.btn-danger(data-job-id="{{_id}}") {{_ 'delete'}}
.add-job-section
button.js-add-cron-job.btn.btn-success {{_ 'add-cron-job'}}
button.js-start-migration.primary(disabled="{{#if isMigrating}}disabled{{/if}}") {{_ 'start-all-migrations'}}
button.js-pause-all-migrations.primary(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'pause-all-migrations'}}
button.js-stop-all-migrations.primary(disabled="{{#unless isMigrating}}disabled{{/unless}}") {{_ 'stop-all-migrations'}}
else if isGeneralSetting
+general
else if isEmailSetting
@ -285,39 +293,69 @@ template(name="general")
template(name='email')
ul#email-setting.setting-detail
//if isSandstorm
// li.smtp-form
// .title {{_ 'smtp-host'}}
// .description {{_ 'smtp-host-description'}}
// .form-group
// input.wekan-form-control#mail-server-host(type="text", placeholder="smtp.domain.com" value="{{currentSetting.mailServer.host}}")
// li.smtp-form
// .title {{_ 'smtp-port'}}
// .description {{_ 'smtp-port-description'}}
// .form-group
// input.wekan-form-control#mail-server-port(type="text", placeholder="25" value="{{currentSetting.mailServer.port}}")
// li.smtp-form
// .title {{_ 'smtp-username'}}
// .form-group
// input.wekan-form-control#mail-server-username(type="text", placeholder="{{_ 'username'}}" value="{{currentSetting.mailServer.username}}")
// li.smtp-form
// .title {{_ 'smtp-password'}}
// .form-group
// input.wekan-form-control#mail-server-password(type="password", placeholder="{{_ 'password'}}" value="")
// li.smtp-form
// .title {{_ 'smtp-tls'}}
// .form-group
// a.flex.js-toggle-tls
// .materialCheckBox#mail-server-tls(class="{{#if currentSetting.mailServer.enableTLS}}is-checked{{/if}}")
//
// span {{_ 'smtp-tls-description'}}
li.smtp-form
//
// li.smtp-form
// .title {{_ 'send-from'}}
// .form-group
// input.wekan-form-control#mail-server-from(type="email", placeholder="no-reply@domain.com" value="{{currentSetting.mailServer.from}}")
.title {{_ 'smtp-host'}}
//
// li
// button.js-save.primary {{_ 'save'}}
.description {{_ 'smtp-host-description'}}
//
.form-group
//
input.wekan-form-control#mail-server-host(type="text", placeholder="smtp.domain.com" value="{{currentSetting.mailServer.host}}")
//
li.smtp-form
//
.title {{_ 'smtp-port'}}
//
.description {{_ 'smtp-port-description'}}
//
.form-group
//
input.wekan-form-control#mail-server-port(type="text", placeholder="25" value="{{currentSetting.mailServer.port}}")
//
li.smtp-form
//
.title {{_ 'smtp-username'}}
//
.form-group
//
input.wekan-form-control#mail-server-username(type="text", placeholder="{{_ 'username'}}" value="{{currentSetting.mailServer.username}}")
//
li.smtp-form
//
.title {{_ 'smtp-password'}}
//
.form-group
//
input.wekan-form-control#mail-server-password(type="password", placeholder="{{_ 'password'}}" value="")
//
li.smtp-form
//
.title {{_ 'smtp-tls'}}
//
.form-group
//
a.flex.js-toggle-tls
//
.materialCheckBox#mail-server-tls(class="{{#if currentSetting.mailServer.enableTLS}}is-checked{{/if}}")
//
//
span {{_ 'smtp-tls-description'}}
//
//
li.smtp-form
//
.title {{_ 'send-from'}}
//
.form-group
//
input.wekan-form-control#mail-server-from(type="email", placeholder="no-reply@domain.com" value="{{currentSetting.mailServer.from}}")
//
//
li
//
button.js-save.primary {{_ 'save'}}
li
button.js-send-smtp-test-email.primary {{_ 'send-smtp-test'}}

View file

@ -2,15 +2,23 @@ import { ReactiveCache } from '/imports/reactiveCache';
import { TAPi18n } from '/imports/i18n';
import { ALLOWED_WAIT_SPINNERS } from '/config/const';
import LockoutSettings from '/models/lockoutSettings';
import {
cronMigrationProgress,
cronMigrationStatus,
cronMigrationCurrentStep,
cronMigrationSteps,
cronIsMigrating,
import {
cronMigrationProgress,
cronMigrationStatus,
cronMigrationCurrentStep,
cronMigrationSteps,
cronIsMigrating,
cronJobs,
cronMigrationCurrentStepNum,
cronMigrationTotalSteps
cronMigrationTotalSteps,
cronMigrationCurrentAction,
cronMigrationJobProgress,
cronMigrationJobStepNum,
cronMigrationJobTotalSteps,
cronMigrationEtaSeconds,
cronMigrationElapsedSeconds,
cronMigrationCurrentNumber,
cronMigrationCurrentName
} from '/imports/cronMigrationClient';
@ -39,7 +47,7 @@ BlazeComponent.extendComponent({
Meteor.subscribe('accessibilitySettings');
Meteor.subscribe('globalwebhooks');
Meteor.subscribe('lockoutSettings');
// Poll for migration errors
this.errorPollInterval = Meteor.setInterval(() => {
if (this.cronSettings.get()) {
@ -62,7 +70,7 @@ BlazeComponent.extendComponent({
setError(error) {
this.error.set(error);
},
// Template helpers moved to BlazeComponent - using different names to avoid conflicts
isGeneralSetting() {
return this.generalSetting && this.generalSetting.get();
@ -102,41 +110,41 @@ BlazeComponent.extendComponent({
filesystemPath() {
return process.env.WRITABLE_PATH || '/data';
},
attachmentsPath() {
const writablePath = process.env.WRITABLE_PATH || '/data';
return `${writablePath}/attachments`;
},
avatarsPath() {
const writablePath = process.env.WRITABLE_PATH || '/data';
return `${writablePath}/avatars`;
},
gridfsEnabled() {
return process.env.GRIDFS_ENABLED === 'true';
},
s3Enabled() {
return process.env.S3_ENABLED === 'true';
},
s3Endpoint() {
return process.env.S3_ENDPOINT || '';
},
s3Bucket() {
return process.env.S3_BUCKET || '';
},
s3Region() {
return process.env.S3_REGION || '';
},
s3SslEnabled() {
return process.env.S3_SSL_ENABLED === 'true';
},
s3Port() {
return process.env.S3_PORT || 443;
},
@ -145,23 +153,23 @@ BlazeComponent.extendComponent({
migrationStatus() {
return cronMigrationStatus.get() || TAPi18n.__('idle');
},
migrationProgress() {
return cronMigrationProgress.get() || 0;
},
migrationCurrentStep() {
return cronMigrationCurrentStep.get() || '';
},
isMigrating() {
return cronIsMigrating.get() || false;
},
migrationSteps() {
return cronMigrationSteps.get() || [];
},
migrationStepsWithIndex() {
const steps = cronMigrationSteps.get() || [];
return steps.map((step, idx) => ({
@ -169,11 +177,15 @@ BlazeComponent.extendComponent({
index: idx + 1
}));
},
cronJobs() {
return cronJobs.get() || [];
},
isCronJobPaused(status) {
return status === 'paused';
},
migrationCurrentStepNum() {
return cronMigrationCurrentStepNum.get() || 0;
},
@ -182,6 +194,52 @@ BlazeComponent.extendComponent({
return cronMigrationTotalSteps.get() || 0;
},
migrationCurrentAction() {
return cronMigrationCurrentAction.get() || '';
},
migrationJobProgress() {
return cronMigrationJobProgress.get() || 0;
},
migrationJobStepNum() {
return cronMigrationJobStepNum.get() || 0;
},
migrationJobTotalSteps() {
return cronMigrationJobTotalSteps.get() || 0;
},
migrationEtaSeconds() {
return cronMigrationEtaSeconds.get();
},
migrationElapsedSeconds() {
return cronMigrationElapsedSeconds.get();
},
migrationNumber() {
return cronMigrationCurrentNumber.get();
},
migrationName() {
return cronMigrationCurrentName.get() || '';
},
migrationStatusLine() {
const number = cronMigrationCurrentNumber.get();
const name = cronMigrationCurrentName.get();
if (number && name) {
return `${number} - ${name}`;
}
return this.migrationStatus();
},
isUpdatingMigrationDropdown() {
const status = this.migrationStatus();
return status && status.startsWith('Updating Select Migration dropdown menu');
},
migrationErrors() {
return this.migrationErrorsList ? this.migrationErrorsList.get() : [];
},
@ -196,6 +254,19 @@ BlazeComponent.extendComponent({
return moment(date).format('YYYY-MM-DD HH:mm:ss');
},
formatDurationSeconds(seconds) {
if (seconds === null || seconds === undefined) return '';
const total = Math.max(0, Math.floor(seconds));
const hrs = Math.floor(total / 3600);
const mins = Math.floor((total % 3600) / 60);
const secs = total % 60;
const parts = [];
if (hrs > 0) parts.push(String(hrs).padStart(2, '0'));
parts.push(String(mins).padStart(2, '0'));
parts.push(String(secs).padStart(2, '0'));
return parts.join(':');
},
setLoading(w) {
this.loading.set(w);
},
@ -240,8 +311,14 @@ BlazeComponent.extendComponent({
'click button.js-start-migration'(event) {
event.preventDefault();
this.setLoading(true);
cronIsMigrating.set(true);
cronMigrationStatus.set(TAPi18n.__('migration-starting'));
cronMigrationCurrentAction.set('');
cronMigrationJobProgress.set(0);
cronMigrationJobStepNum.set(0);
cronMigrationJobTotalSteps.set(0);
const selectedIndex = parseInt($('.js-migration-select').val() || '0', 10);
if (selectedIndex === 0) {
// Run all migrations
Meteor.call('cron.startAllMigrations', (error, result) => {
@ -258,6 +335,10 @@ BlazeComponent.extendComponent({
this.setLoading(false);
if (error) {
alert(TAPi18n.__('migration-start-failed') + ': ' + error.reason);
} else if (result && result.skipped) {
cronIsMigrating.set(false);
cronMigrationStatus.set(TAPi18n.__('migration-not-needed'));
alert(TAPi18n.__('migration-not-needed'));
} else {
alert(TAPi18n.__('migration-started'));
}
@ -265,9 +346,52 @@ BlazeComponent.extendComponent({
}
},
'click button.js-start-all-migrations'(event) {
event.preventDefault();
this.setLoading(true);
Meteor.call('cron.startAllMigrations', (error) => {
this.setLoading(false);
if (error) {
alert(TAPi18n.__('migration-start-failed') + ': ' + error.reason);
} else {
alert(TAPi18n.__('migration-started'));
}
});
},
'click button.js-pause-all-migrations'(event) {
event.preventDefault();
this.setLoading(true);
Meteor.call('cron.pauseAllMigrations', (error) => {
this.setLoading(false);
if (error) {
alert(TAPi18n.__('migration-pause-failed') + ': ' + error.reason);
} else {
alert(TAPi18n.__('migration-paused'));
}
});
},
'click button.js-stop-all-migrations'(event) {
event.preventDefault();
if (confirm(TAPi18n.__('migration-stop-confirm'))) {
this.setLoading(true);
Meteor.call('cron.stopAllMigrations', (error) => {
this.setLoading(false);
if (error) {
alert(TAPi18n.__('migration-stop-failed') + ': ' + error.reason);
} else {
alert(TAPi18n.__('migration-stopped'));
}
});
}
},
'click button.js-pause-migration'(event) {
event.preventDefault();
this.setLoading(true);
cronIsMigrating.set(false);
cronMigrationStatus.set(TAPi18n.__('migration-pausing'));
Meteor.call('cron.pauseAllMigrations', (error, result) => {
this.setLoading(false);
if (error) {
@ -282,6 +406,12 @@ BlazeComponent.extendComponent({
event.preventDefault();
if (confirm(TAPi18n.__('migration-stop-confirm'))) {
this.setLoading(true);
cronIsMigrating.set(false);
cronMigrationStatus.set(TAPi18n.__('migration-stopping'));
cronMigrationCurrentAction.set('');
cronMigrationJobProgress.set(0);
cronMigrationJobStepNum.set(0);
cronMigrationJobTotalSteps.set(0);
Meteor.call('cron.stopAllMigrations', (error, result) => {
this.setLoading(false);
if (error) {
@ -293,29 +423,25 @@ BlazeComponent.extendComponent({
}
},
'click button.js-schedule-board-cleanup'(event) {
'click button.js-start-job'(event) {
event.preventDefault();
// Placeholder - board cleanup scheduling
alert(TAPi18n.__('board-cleanup-scheduled'));
},
'click button.js-schedule-board-archive'(event) {
event.preventDefault();
// Placeholder - board archive scheduling
alert(TAPi18n.__('board-archive-scheduled'));
},
'click button.js-schedule-board-backup'(event) {
event.preventDefault();
// Placeholder - board backup scheduling
alert(TAPi18n.__('board-backup-scheduled'));
const jobName = $(event.target).data('job-name');
this.setLoading(true);
Meteor.call('cron.startJob', jobName, (error) => {
this.setLoading(false);
if (error) {
alert(TAPi18n.__('cron-job-start-failed') + ': ' + error.reason);
} else {
alert(TAPi18n.__('cron-job-started'));
}
});
},
'click button.js-pause-job'(event) {
event.preventDefault();
const jobId = $(event.target).data('job-id');
const jobName = $(event.target).data('job-name');
this.setLoading(true);
Meteor.call('cron.pauseJob', jobId, (error, result) => {
Meteor.call('cron.pauseJob', jobName, (error) => {
this.setLoading(false);
if (error) {
alert(TAPi18n.__('cron-job-pause-failed') + ': ' + error.reason);
@ -325,12 +451,26 @@ BlazeComponent.extendComponent({
});
},
'click button.js-resume-job'(event) {
event.preventDefault();
const jobName = $(event.target).data('job-name');
this.setLoading(true);
Meteor.call('cron.resumeJob', jobName, (error) => {
this.setLoading(false);
if (error) {
alert(TAPi18n.__('cron-job-resume-failed') + ': ' + error.reason);
} else {
alert(TAPi18n.__('cron-job-resumed'));
}
});
},
'click button.js-delete-job'(event) {
event.preventDefault();
const jobId = $(event.target).data('job-id');
const jobName = $(event.target).data('job-name');
if (confirm(TAPi18n.__('cron-job-delete-confirm'))) {
this.setLoading(true);
Meteor.call('cron.removeJob', jobId, (error, result) => {
Meteor.call('cron.removeJob', jobName, (error) => {
this.setLoading(false);
if (error) {
alert(TAPi18n.__('cron-job-delete-failed') + ': ' + error.reason);
@ -429,7 +569,7 @@ BlazeComponent.extendComponent({
$('.side-menu li.active').removeClass('active');
target.parent().addClass('active');
const targetID = target.data('id');
// Reset all settings to false
this.forgotPasswordSetting.set(false);
this.generalSetting.set(false);
@ -442,7 +582,7 @@ BlazeComponent.extendComponent({
this.webhookSetting.set(false);
this.attachmentSettings.set(false);
this.cronSettings.set(false);
// Set the selected setting to true
if (targetID === 'registration-setting') {
this.generalSetting.set(true);
@ -847,7 +987,7 @@ BlazeComponent.extendComponent({
const content = $('#admin-accessibility-content')
.val()
.trim();
try {
AccessibilitySettings.update(AccessibilitySettings.findOne()._id, {
$set: {

View file

@ -4,7 +4,7 @@
margin-left: 20px;
padding-right: 10px;
height: 28px;
font-size: 13px;
float: left;
overflow: hidden;
line-height: 28px;
@ -26,12 +26,3 @@
margin-top: 1px;
margin-right: 10px;
}
.setting-header-btns {
display: flex;
align-items: center;
gap: 1ch;
padding: 0 1ch;
flex-wrap: wrap;
}

View file

@ -32,6 +32,9 @@ table tr:nth-child(even) {
.ext-box button {
min-width: 90px;
}
.content-wrapper {
margin-top: 10px;
}
.buttonsContainer {
display: flex;
}