Skip to content

Commit 95da60f

Browse files
feat: ship import safety, backups, diagnostics, and rule/bulk tools
1 parent e7503c8 commit 95da60f

12 files changed

Lines changed: 1427 additions & 231 deletions

File tree

185 KB
Binary file not shown.

folderview.plus.plg

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,22 @@
66
<!ENTITY launch "Settings/FolderViewPlus">
77
<!ENTITY plugdir "/usr/local/emhttp/plugins/&name;">
88
<!ENTITY pluginURL "https://raw.githubusercontent.com/&github;/main/folderview.plus.plg">
9-
<!ENTITY version "2026.03.05.5">
10-
<!ENTITY md5 "b4f90f1ec6b356adda4fc4b69aa9277c">
9+
<!ENTITY version "2026.03.05.6">
10+
<!ENTITY md5 "72678bc4e4c539d3fc904dfd40e69937">
1111
]>
1212

1313
<PLUGIN name="&name;" author="&author;" version="&version;" launch="&launch;" pluginURL="&pluginURL;" icon="folder-open-o" support="https://github.com/alexphillips-dev/FolderView-Plus/issues" min="7.0.0">
1414
<CHANGES>
1515

16+
###2026.03.05.6
17+
- Add full Import Preview + selective apply with merge modes (replace/merge/skip) and schema metadata validation.
18+
- Add one-click Undo backups for risky operations (import, clear/delete, bulk assign, and restore actions).
19+
- Add rule priority controls with up/down ordering and a rule tester for Docker/VM matching.
20+
- Add bulk assignment workflows for Docker/VM with multi-select item targeting.
21+
- Add backup management UI for create/list/restore/download/delete operations.
22+
- Add diagnostics panel with health report, repair actions, and diagnostics JSON export.
23+
- Add folder badge preference handling in settings and runtime for running/stopped/update visibility.
24+
1625
###2026.03.05.5
1726
- Move VMs directly below Docker in settings for clearer top-to-bottom workflow.
1827
- Move Docker and VM auto-assignment rule editors into a single dedicated section at the bottom.

src/folderview.plus/usr/local/emhttp/plugins/folderview.plus/FolderViewPlus.page

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,12 @@ require_once('/usr/local/emhttp/plugins/folderview.plus/langs/script.php');
4040
<option value="alpha">Name (A-Z)</option>
4141
</select>
4242
<div class="hint-line">Use manual mode and the up/down buttons in the first column to set custom order.</div>
43+
<div class="badge-toggle-row">
44+
<span class="badge-toggle-title">Folder badges</span>
45+
<label><input id="docker-badge-running" type="checkbox" onchange="changeBadgePref('docker', 'running', this.checked)"> Running</label>
46+
<label><input id="docker-badge-stopped" type="checkbox" onchange="changeBadgePref('docker', 'stopped', this.checked)"> Stopped</label>
47+
<label><input id="docker-badge-updates" type="checkbox" onchange="changeBadgePref('docker', 'updates', this.checked)"> Updates</label>
48+
</div>
4349
</div>
4450
</div>
4551
<div class="table-wrap">
@@ -83,6 +89,11 @@ require_once('/usr/local/emhttp/plugins/folderview.plus/langs/script.php');
8389
<option value="alpha">Name (A-Z)</option>
8490
</select>
8591
<div class="hint-line">Use manual mode and the up/down buttons in the first column to set custom order.</div>
92+
<div class="badge-toggle-row">
93+
<span class="badge-toggle-title">Folder badges</span>
94+
<label><input id="vm-badge-running" type="checkbox" onchange="changeBadgePref('vm', 'running', this.checked)"> Running</label>
95+
<label><input id="vm-badge-stopped" type="checkbox" onchange="changeBadgePref('vm', 'stopped', this.checked)"> Stopped</label>
96+
</div>
8697
</div>
8798
</div>
8899
<div class="table-wrap">
@@ -127,9 +138,17 @@ require_once('/usr/local/emhttp/plugins/folderview.plus/langs/script.php');
127138
<input id="docker-rule-label-value" type="text" placeholder="Label value (optional, blank means any value)" style="display:none;">
128139
<button class="rules-add-btn" onclick="addAutoRule('docker')"><i class="fa fa-plus"></i> Add rule</button>
129140
</div>
141+
<div class="rule-tester">
142+
<input id="docker-rule-test-name" type="text" placeholder="Test name (example: media-server)">
143+
<input id="docker-rule-test-label-key" type="text" placeholder="Test label key (optional)">
144+
<input id="docker-rule-test-label-value" type="text" placeholder="Test label value (optional)">
145+
<button onclick="testAutoRule('docker')"><i class="fa fa-flask"></i> Test rule priority</button>
146+
<div id="docker-rule-test-output" class="rule-test-output"></div>
147+
</div>
130148
<table class="rules-table">
131149
<thead>
132150
<tr>
151+
<th>Priority</th>
133152
<th>Folder</th>
134153
<th>Match</th>
135154
<th>Action</th>
@@ -152,9 +171,15 @@ require_once('/usr/local/emhttp/plugins/folderview.plus/langs/script.php');
152171
<input id="vm-rule-pattern" type="text" placeholder="Regex pattern (example: ^prod-)">
153172
<button class="rules-add-btn" onclick="addAutoRule('vm')"><i class="fa fa-plus"></i> Add rule</button>
154173
</div>
174+
<div class="rule-tester">
175+
<input id="vm-rule-test-name" type="text" placeholder="Test VM name (example: prod-db)">
176+
<button onclick="testAutoRule('vm')"><i class="fa fa-flask"></i> Test rule priority</button>
177+
<div id="vm-rule-test-output" class="rule-test-output"></div>
178+
</div>
155179
<table class="rules-table">
156180
<thead>
157181
<tr>
182+
<th>Priority</th>
158183
<th>Folder</th>
159184
<th>Match</th>
160185
<th>Action</th>
@@ -164,6 +189,100 @@ require_once('/usr/local/emhttp/plugins/folderview.plus/langs/script.php');
164189
</table>
165190
</div>
166191
</div>
192+
<hr>
193+
194+
<h2>Bulk assignment</h2>
195+
<div class="bulk-assign-grid">
196+
<div class="rules-panel">
197+
<div class="rules-header">
198+
<h3>Docker bulk assignment</h3>
199+
<span class="rules-help">Select multiple containers and assign them to one folder in a single action.</span>
200+
</div>
201+
<div class="bulk-row">
202+
<select id="docker-bulk-folder"></select>
203+
<button onclick="assignSelectedItems('docker')"><i class="fa fa-share-square-o"></i> Assign selected</button>
204+
</div>
205+
<select id="docker-bulk-items" multiple size="10"></select>
206+
</div>
207+
208+
<div class="rules-panel">
209+
<div class="rules-header">
210+
<h3>VM bulk assignment</h3>
211+
<span class="rules-help">Select multiple VMs and assign them to one folder in a single action.</span>
212+
</div>
213+
<div class="bulk-row">
214+
<select id="vm-bulk-folder"></select>
215+
<button onclick="assignSelectedItems('vm')"><i class="fa fa-share-square-o"></i> Assign selected</button>
216+
</div>
217+
<select id="vm-bulk-items" multiple size="10"></select>
218+
</div>
219+
</div>
220+
<hr>
221+
222+
<h2>Backups</h2>
223+
<div class="backup-grid">
224+
<div class="rules-panel">
225+
<div class="rules-header">
226+
<h3>Docker backups</h3>
227+
<span class="rules-help">Create, restore, download, or delete backup snapshots.</span>
228+
</div>
229+
<div class="backup-actions">
230+
<button onclick="createManualBackup('docker')"><i class="fa fa-camera"></i> Create backup now</button>
231+
<button onclick="restoreLatestBackup('docker')"><i class="fa fa-history"></i> Restore latest</button>
232+
<button onclick="refreshBackups('docker')"><i class="fa fa-refresh"></i> Refresh list</button>
233+
</div>
234+
<table class="rules-table">
235+
<thead>
236+
<tr>
237+
<th>Created</th>
238+
<th>Reason</th>
239+
<th>Folders</th>
240+
<th>Action</th>
241+
</tr>
242+
</thead>
243+
<tbody id="docker-backups"></tbody>
244+
</table>
245+
</div>
246+
247+
<div class="rules-panel">
248+
<div class="rules-header">
249+
<h3>VM backups</h3>
250+
<span class="rules-help">Create, restore, download, or delete backup snapshots.</span>
251+
</div>
252+
<div class="backup-actions">
253+
<button onclick="createManualBackup('vm')"><i class="fa fa-camera"></i> Create backup now</button>
254+
<button onclick="restoreLatestBackup('vm')"><i class="fa fa-history"></i> Restore latest</button>
255+
<button onclick="refreshBackups('vm')"><i class="fa fa-refresh"></i> Refresh list</button>
256+
</div>
257+
<table class="rules-table">
258+
<thead>
259+
<tr>
260+
<th>Created</th>
261+
<th>Reason</th>
262+
<th>Folders</th>
263+
<th>Action</th>
264+
</tr>
265+
</thead>
266+
<tbody id="vm-backups"></tbody>
267+
</table>
268+
</div>
269+
</div>
270+
<hr>
271+
272+
<h2>Diagnostics</h2>
273+
<div class="rules-panel">
274+
<div class="rules-header">
275+
<h3>Health checks and quick repair</h3>
276+
<span class="rules-help">Check plugin health, then run one-click repair actions when needed.</span>
277+
</div>
278+
<div class="backup-actions">
279+
<button onclick="runDiagnostics()"><i class="fa fa-stethoscope"></i> Run health check</button>
280+
<button onclick="repairDiagnostics('sync_docker_order')"><i class="fa fa-sort"></i> Rebuild Docker order index</button>
281+
<button onclick="repairDiagnostics('normalize_prefs')"><i class="fa fa-wrench"></i> Validate and normalize prefs</button>
282+
<button onclick="exportDiagnostics()"><i class="fa fa-download"></i> Export diagnostics JSON</button>
283+
</div>
284+
<pre id="diagnostics-output" class="diagnostics-output">Run health check to view diagnostics.</pre>
285+
</div>
167286

168287
<div id="import-preview-dialog" style="display:none;">
169288
<p><strong>Import summary</strong></p>
@@ -174,6 +293,7 @@ require_once('/usr/local/emhttp/plugins/folderview.plus/langs/script.php');
174293
<option value="replace">Replace</option>
175294
<option value="skip">Skip existing</option>
176295
</select>
296+
<div id="import-preview-selection" class="import-selection"></div>
177297
<textarea id="import-preview-text" readonly></textarea>
178298
</div>
179299

src/folderview.plus/usr/local/emhttp/plugins/folderview.plus/scripts/docker.js

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
const FOLDER_VIEW_DEBUG_MODE = false;
22
const utils = window.FolderViewPlusUtils || {
3-
normalizePrefs: () => ({ sortMode: 'created', manualOrder: [], autoRules: [] }),
3+
normalizePrefs: () => ({
4+
sortMode: 'created',
5+
manualOrder: [],
6+
autoRules: [],
7+
badges: { running: true, stopped: false, updates: true }
8+
}),
49
getAutoRuleMatches: () => []
510
};
611

@@ -1011,6 +1016,20 @@ const createFolder = (folder, id, positionInMainOrder, liveOrderArray, container
10111016
$(`tr.folder-id-${id} span.folder-state`).text(`${started}/${Object.entries(folder.containers).length} ${$.i18n('started')}`);
10121017
if (FOLDER_VIEW_DEBUG_MODE) console.log(`[FV3_DEBUG] createFolder (id: ${id}): Set 'started' status. Count: ${started}/${Object.entries(folder.containers).length}.`);
10131018
}
1019+
const badgePrefs = folderTypePrefs?.badges || {};
1020+
const showRunningBadge = badgePrefs.running !== false;
1021+
const showStoppedBadge = badgePrefs.stopped === true;
1022+
const showUpdateBadge = badgePrefs.updates !== false;
1023+
const folderIsRunning = started > 0;
1024+
1025+
if (!showUpdateBadge && !folder.settings.update_column) {
1026+
$(`tr.folder-id-${id} > td.updatecolumn`).next().attr('colspan', 6).end().remove();
1027+
}
1028+
1029+
if ((folderIsRunning && !showRunningBadge) || (!folderIsRunning && !showStoppedBadge)) {
1030+
$(`tr.folder-id-${id} i#load-folder-${id}, tr.folder-id-${id} span.folder-state`).hide();
1031+
}
1032+
10141033
if (!managerTypes.has('dockerman')) {
10151034
$(`tr.folder-id-${id} td.folder-autostart`).empty();
10161035
if (FOLDER_VIEW_DEBUG_MODE) console.log(`[FV3_DEBUG] createFolder (id: ${id}): No dockerman containers — removed autostart toggle.`);

0 commit comments

Comments
 (0)