Skip to content

Commit e308e2a

Browse files
compscidrclaude
andcommitted
Plugin settings: collapsible cards with enable/disable checkbox
- Plugin cards are collapsed by default, expanded only when enabled - Enabled setting rendered as a Bootstrap switch checkbox in the card header instead of a text input - Toggling the checkbox immediately saves the enabled state and expands/collapses the settings card - The "enabled" field is excluded from the settings form body since it lives in the card header - Save button includes the enabled state along with other settings Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 6162a1a commit e308e2a

4 files changed

Lines changed: 130 additions & 57 deletions

File tree

themes/default/templates/admin_settings.html

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,39 @@ <h1>Site Settings</h1>
3838
</div>
3939

4040
{{ range .plugin_settings }}
41+
{{ $pluginName := .PluginName }}
42+
{{ $values := .CurrentValues }}
43+
{{ $enabled := index $values "enabled" }}
4144
<div class="card mb-4">
42-
<div class="card-header"><strong>Plugin: {{ .DisplayName }}</strong> <span class="text-muted">({{ .PluginName }})</span></div>
43-
<div class="card-body">
44-
<form class="plugin-settings-form" data-plugin="{{ .PluginName }}">
45-
{{ $pluginName := .PluginName }}
46-
{{ $values := .CurrentValues }}
47-
{{ range .Settings }}
48-
<div class="mb-3">
49-
<label for="{{ $pluginName }}.{{ .Key }}" class="form-label">{{ .Label }}</label>
50-
{{ if .Description }}<small class="text-muted d-block mb-1">{{ .Description }}</small>{{ end }}
51-
{{ if eq .Type "textarea" }}
52-
<textarea id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" class="form-control" rows="3">{{ index $values .Key }}</textarea>
53-
{{ else }}
54-
<input type="text" id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" value="{{ index $values .Key }}" class="form-control">
45+
<div class="card-header d-flex justify-content-between align-items-center">
46+
<span><strong>Plugin: {{ .DisplayName }}</strong> <span class="text-muted">({{ .PluginName }})</span></span>
47+
<div class="form-check form-switch mb-0">
48+
<input class="form-check-input plugin-enable-toggle" type="checkbox" id="{{ $pluginName }}.enabled" name="{{ $pluginName }}.enabled" data-plugin="{{ $pluginName }}" {{ if eq $enabled "true" }}checked{{ end }}
49+
onchange="togglePluginEnabled(this);">
50+
<label class="form-check-label" for="{{ $pluginName }}.enabled">Enabled</label>
51+
</div>
52+
</div>
53+
<div class="collapse {{ if eq $enabled "true" }}show{{ end }}" id="plugin-body-{{ $pluginName }}">
54+
<div class="card-body">
55+
<form class="plugin-settings-form" data-plugin="{{ $pluginName }}">
56+
{{ range .Settings }}
57+
{{ if ne .Key "enabled" }}
58+
<div class="mb-3">
59+
<label for="{{ $pluginName }}.{{ .Key }}" class="form-label">{{ .Label }}</label>
60+
{{ if .Description }}<small class="text-muted d-block mb-1">{{ .Description }}</small>{{ end }}
61+
{{ if eq .Type "textarea" }}
62+
<textarea id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" class="form-control" rows="3">{{ index $values .Key }}</textarea>
63+
{{ else }}
64+
<input type="text" id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" value="{{ index $values .Key }}" class="form-control">
65+
{{ end }}
66+
</div>
5567
{{ end }}
56-
</div>
57-
{{ end }}
58-
<button type="button" class="btn btn-primary" onclick="updatePluginSettings(this);">
59-
Save {{ .DisplayName }} Settings
60-
</button>
61-
</form>
68+
{{ end }}
69+
<button type="button" class="btn btn-primary" onclick="updatePluginSettings(this);">
70+
Save {{ .DisplayName }} Settings
71+
</button>
72+
</form>
73+
</div>
6274
</div>
6375
</div>
6476
{{ end }}

themes/forest/templates/admin_settings.html

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,39 @@ <h1>Site Settings</h1>
3838
</div>
3939

4040
{{ range .plugin_settings }}
41+
{{ $pluginName := .PluginName }}
42+
{{ $values := .CurrentValues }}
43+
{{ $enabled := index $values "enabled" }}
4144
<div class="card mb-4">
42-
<div class="card-header"><strong>Plugin: {{ .DisplayName }}</strong> <span class="text-muted">({{ .PluginName }})</span></div>
43-
<div class="card-body">
44-
<form class="plugin-settings-form" data-plugin="{{ .PluginName }}">
45-
{{ $pluginName := .PluginName }}
46-
{{ $values := .CurrentValues }}
47-
{{ range .Settings }}
48-
<div class="mb-3">
49-
<label for="{{ $pluginName }}.{{ .Key }}" class="form-label">{{ .Label }}</label>
50-
{{ if .Description }}<small class="text-muted d-block mb-1">{{ .Description }}</small>{{ end }}
51-
{{ if eq .Type "textarea" }}
52-
<textarea id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" class="form-control" rows="3">{{ index $values .Key }}</textarea>
53-
{{ else }}
54-
<input type="text" id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" value="{{ index $values .Key }}" class="form-control">
45+
<div class="card-header d-flex justify-content-between align-items-center">
46+
<span><strong>Plugin: {{ .DisplayName }}</strong> <span class="text-muted">({{ .PluginName }})</span></span>
47+
<div class="form-check form-switch mb-0">
48+
<input class="form-check-input plugin-enable-toggle" type="checkbox" id="{{ $pluginName }}.enabled" name="{{ $pluginName }}.enabled" data-plugin="{{ $pluginName }}" {{ if eq $enabled "true" }}checked{{ end }}
49+
onchange="togglePluginEnabled(this);">
50+
<label class="form-check-label" for="{{ $pluginName }}.enabled">Enabled</label>
51+
</div>
52+
</div>
53+
<div class="collapse {{ if eq $enabled "true" }}show{{ end }}" id="plugin-body-{{ $pluginName }}">
54+
<div class="card-body">
55+
<form class="plugin-settings-form" data-plugin="{{ $pluginName }}">
56+
{{ range .Settings }}
57+
{{ if ne .Key "enabled" }}
58+
<div class="mb-3">
59+
<label for="{{ $pluginName }}.{{ .Key }}" class="form-label">{{ .Label }}</label>
60+
{{ if .Description }}<small class="text-muted d-block mb-1">{{ .Description }}</small>{{ end }}
61+
{{ if eq .Type "textarea" }}
62+
<textarea id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" class="form-control" rows="3">{{ index $values .Key }}</textarea>
63+
{{ else }}
64+
<input type="text" id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" value="{{ index $values .Key }}" class="form-control">
65+
{{ end }}
66+
</div>
5567
{{ end }}
56-
</div>
57-
{{ end }}
58-
<button type="button" class="btn btn-primary" onclick="updatePluginSettings(this);">
59-
Save {{ .DisplayName }} Settings
60-
</button>
61-
</form>
68+
{{ end }}
69+
<button type="button" class="btn btn-primary" onclick="updatePluginSettings(this);">
70+
Save {{ .DisplayName }} Settings
71+
</button>
72+
</form>
73+
</div>
6274
</div>
6375
</div>
6476
{{ end }}

themes/minimal/templates/admin_settings.html

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,39 @@ <h1>Site Settings</h1>
3838
</div>
3939

4040
{{ range .plugin_settings }}
41+
{{ $pluginName := .PluginName }}
42+
{{ $values := .CurrentValues }}
43+
{{ $enabled := index $values "enabled" }}
4144
<div class="card mb-4">
42-
<div class="card-header"><strong>Plugin: {{ .DisplayName }}</strong> <span class="text-muted">({{ .PluginName }})</span></div>
43-
<div class="card-body">
44-
<form class="plugin-settings-form" data-plugin="{{ .PluginName }}">
45-
{{ $pluginName := .PluginName }}
46-
{{ $values := .CurrentValues }}
47-
{{ range .Settings }}
48-
<div class="mb-3">
49-
<label for="{{ $pluginName }}.{{ .Key }}" class="form-label">{{ .Label }}</label>
50-
{{ if .Description }}<small class="text-muted d-block mb-1">{{ .Description }}</small>{{ end }}
51-
{{ if eq .Type "textarea" }}
52-
<textarea id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" class="form-control" rows="3">{{ index $values .Key }}</textarea>
53-
{{ else }}
54-
<input type="text" id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" value="{{ index $values .Key }}" class="form-control">
45+
<div class="card-header d-flex justify-content-between align-items-center">
46+
<span><strong>Plugin: {{ .DisplayName }}</strong> <span class="text-muted">({{ .PluginName }})</span></span>
47+
<div class="form-check form-switch mb-0">
48+
<input class="form-check-input plugin-enable-toggle" type="checkbox" id="{{ $pluginName }}.enabled" name="{{ $pluginName }}.enabled" data-plugin="{{ $pluginName }}" {{ if eq $enabled "true" }}checked{{ end }}
49+
onchange="togglePluginEnabled(this);">
50+
<label class="form-check-label" for="{{ $pluginName }}.enabled">Enabled</label>
51+
</div>
52+
</div>
53+
<div class="collapse {{ if eq $enabled "true" }}show{{ end }}" id="plugin-body-{{ $pluginName }}">
54+
<div class="card-body">
55+
<form class="plugin-settings-form" data-plugin="{{ $pluginName }}">
56+
{{ range .Settings }}
57+
{{ if ne .Key "enabled" }}
58+
<div class="mb-3">
59+
<label for="{{ $pluginName }}.{{ .Key }}" class="form-label">{{ .Label }}</label>
60+
{{ if .Description }}<small class="text-muted d-block mb-1">{{ .Description }}</small>{{ end }}
61+
{{ if eq .Type "textarea" }}
62+
<textarea id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" class="form-control" rows="3">{{ index $values .Key }}</textarea>
63+
{{ else }}
64+
<input type="text" id="{{ $pluginName }}.{{ .Key }}" name="{{ $pluginName }}.{{ .Key }}" value="{{ index $values .Key }}" class="form-control">
65+
{{ end }}
66+
</div>
5567
{{ end }}
56-
</div>
57-
{{ end }}
58-
<button type="button" class="btn btn-primary" onclick="updatePluginSettings(this);">
59-
Save {{ .DisplayName }} Settings
60-
</button>
61-
</form>
68+
{{ end }}
69+
<button type="button" class="btn btn-primary" onclick="updatePluginSettings(this);">
70+
Save {{ .DisplayName }} Settings
71+
</button>
72+
</form>
73+
</div>
6274
</div>
6375
</div>
6476
{{ end }}

www/js/admin-script.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,48 @@ function rollbackRevision(postId, revisionId) {
231231
return false;
232232
}
233233

234+
function togglePluginEnabled(checkbox) {
235+
var pluginName = $(checkbox).data("plugin");
236+
var enabled = checkbox.checked ? "true" : "false";
237+
var $body = $("#plugin-body-" + pluginName);
238+
239+
if (checkbox.checked) {
240+
$body.collapse("show");
241+
} else {
242+
$body.collapse("hide");
243+
}
244+
245+
// Save the enabled setting immediately
246+
var settings = [{"key": pluginName + ".enabled", "value": enabled, "type": "text"}];
247+
$.ajax({
248+
url: "/api/v1/settings",
249+
type: "patch",
250+
dataType: "json",
251+
contentType: "application/json",
252+
success: function(json) {
253+
$("#ajax-error").html(pluginName + (checkbox.checked ? " enabled" : " disabled")).show();
254+
$("#ajax-error").removeClass("alert-danger").addClass("alert-success");
255+
},
256+
error: function(jqXHR, textStatus, errorThrown) {
257+
$("#ajax-error").html("ERROR: " + textStatus + " " + errorThrown).show();
258+
$("#ajax-error").removeClass("alert-success").addClass("alert-danger");
259+
},
260+
data: JSON.stringify(settings)
261+
});
262+
}
263+
234264
function updatePluginSettings(btn) {
235265
$("#ajax-error").hide();
236266
var settings = [];
267+
var $card = $(btn).closest(".card");
237268
var $form = $(btn).closest("form");
238269

270+
// Include the enabled checkbox from the card header
271+
var $toggle = $card.find(".plugin-enable-toggle");
272+
if ($toggle.length) {
273+
settings.push({"key": $toggle.attr("name"), "value": $toggle.is(":checked") ? "true" : "false", "type": "text"});
274+
}
275+
239276
$form.find(":input").each(function() {
240277
var key = this.name;
241278
var type = this.tagName === "TEXTAREA" ? "textarea" : "text";

0 commit comments

Comments
 (0)