Skip to content

Commit 37cc702

Browse files
Fix docker folder row regression and move quick actions to context menu top
1 parent a78d7cc commit 37cc702

8 files changed

Lines changed: 52 additions & 68 deletions

File tree

archive/folderview.plus-2026.03.19.15.txz.sha256

Lines changed: 0 additions & 1 deletion
This file was deleted.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
f76c1f6d11b314a54bd0c3b4bd4506ad38a9ce085139b7e8d542815d377dc95b folderview.plus-2026.03.20.11.txz

folderview.plus.plg

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,19 @@
66
<!ENTITY launch "Settings/FolderViewPlus">
77
<!ENTITY plugdir "/usr/local/emhttp/plugins/&name;">
88
<!ENTITY pluginURL "https://raw.githubusercontent.com/&github;/dev/folderview.plus.plg">
9-
<!ENTITY version "2026.03.20.10">
10-
<!ENTITY md5 "aa32b9e8cb8c6f3139a9c124e8779d9e">
9+
<!ENTITY version "2026.03.20.11">
10+
<!ENTITY md5 "fce4cb8d9ae6540de09ea38d87ecf076">
1111
]>
1212

1313
<PLUGIN name="&name;" author="&author;" version="&version;" launch="&launch;" pluginURL="&pluginURL;" icon="folder-icon.png" support="https://forums.unraid.net/topic/197631-plugin-folderview-plus/" min="7.0.0">
1414
<CHANGES>
1515

16+
###2026.03.20.11
17+
- Fix: Restored Docker folder rows after row-action regression that hid folder names.
18+
- UX: Moved `Focus`, `Pin/Unpin`, and `Lock/Unlock` into the top of the existing folder click menu.
19+
- Regression guard: Restored right-side dropdown gutter/padding contract to prevent Version column clipping.
20+
21+
1622
###2026.03.20.10
1723
- Feature: Added one-click folder-row quick actions for `Focus`, `Pin/Unpin`, and `Lock/Unlock` in Docker tab.
1824
- UX: Added focused-folder mode to isolate a selected folder branch (with nested-aware visibility handling).

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

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2358,16 +2358,10 @@ const createFolder = (folder, id, positionInMainOrder, liveOrderArray, container
23582358
const pinned = isDockerFolderPinned(id);
23592359
const locked = isDockerFolderLocked(id);
23602360
const focused = dockerFocusedFolderId === id;
2361-
const focusTitle = focused ? 'Clear focus' : 'Focus folder';
2362-
const pinTitle = pinned ? 'Unpin folder' : 'Pin folder';
2363-
const lockTitle = locked ? 'Unlock folder' : 'Lock folder';
2364-
const focusIcon = focused ? 'fa-dot-circle-o' : 'fa-bullseye';
2365-
const pinIcon = pinned ? 'fa-star' : 'fa-star-o';
2366-
const lockIcon = locked ? 'fa-lock' : 'fa-unlock-alt';
23672361
const lockedClass = locked ? 'fv-folder-locked' : '';
23682362
const pinnedClass = pinned ? 'fv-folder-pinned' : '';
23692363
const focusedClass = focused ? 'fv-folder-focused' : '';
2370-
const fld = `<tr class="sortable folder-id-${id} ${hoverClass} ${lockedClass} ${pinnedClass} ${focusedClass} folder"><td class="ct-name folder-name"><div class="folder-name-sub"><i class="fa fa-arrows-v mover orange-text"></i><span class="outer folder-outer"><span id="${id}" onclick="addDockerFolderContext('${id}')" class="hand folder-hand"><img src="${safeFolderIcon}" class="img folder-img" onerror='this.src="/plugins/dynamix.docker.manager/images/question.png"'></span><span class="inner folder-inner"><span class="appname" style="display: none;"><a>folder-${id}</a></span><a class="exec folder-appname" onclick='editFolder("${id}")'>${safeFolderName}</a><br><i id="load-folder-${id}" class="fa fa-square stopped folder-load-status"></i><span class="state folder-state fv-folder-state-stopped"> ${$.i18n('stopped')}</span></span></span><span class="fv-folder-row-actions"><button type="button" class="fv-folder-row-action fv-folder-row-action-focus ${focused ? 'is-active' : ''}" data-folder-id="${id}" title="${focusTitle}" aria-label="${focusTitle}" onclick="event.preventDefault();event.stopPropagation();toggleDockerFolderFocus('${id}')"><i class="fa ${focusIcon}" aria-hidden="true"></i></button><button type="button" class="fv-folder-row-action fv-folder-row-action-pin ${pinned ? 'is-active' : ''}" data-folder-id="${id}" title="${pinTitle}" aria-label="${pinTitle}" onclick="event.preventDefault();event.stopPropagation();toggleDockerFolderPin('${id}')"><i class="fa ${pinIcon}" aria-hidden="true"></i></button><button type="button" class="fv-folder-row-action fv-folder-row-action-lock ${locked ? 'is-active' : ''}" data-folder-id="${id}" title="${lockTitle}" aria-label="${lockTitle}" onclick="event.preventDefault();event.stopPropagation();toggleDockerFolderLock('${id}')"><i class="fa ${lockIcon}" aria-hidden="true"></i></button></span><button class="dropDown-${id} folder-dropdown" onclick="dropDownButton('${id}')" ><i class="fa fa-chevron-down" aria-hidden="true"></i></button></div></td><td class="updatecolumn folder-update"><span class="green-text folder-update-text"><i class="fa fa-check fa-fw"></i> ${$.i18n('up-to-date')}</span><div class="advanced" style="display: ${advanced ? 'block' : 'none'};"><a class="exec" onclick="forceUpdateFolder('${id}');"><span style="white-space:nowrap;"><i class="fa fa-cloud-download fa-fw"></i> ${$.i18n('force-update')}</span></a></div></td><td colspan="${colspan}"><div class="folder-storage"></div><div class="folder-preview"></div></td><td class="advanced folder-advanced" ${advanced ? 'style="display: table-cell;"' : ''}><span class="cpu-folder-${id} folder-cpu">0%</span><div class="usage-disk mm folder-load"><span id="cpu-folder-${id}" class="folder-cpu-bar" style="width:0%"></span><span></span></div><br><span class="mem-folder-${id} folder-mem">0 / 0</span></td><td class="folder-autostart"><input type="checkbox" id="folder-${id}-auto" class="autostart" style="display:none"><div style="clear:left"></div></td><td></td></tr>`;
2364+
const fld = `<tr class="sortable folder-id-${id} ${hoverClass} ${lockedClass} ${pinnedClass} ${focusedClass} folder"><td class="ct-name folder-name"><div class="folder-name-sub"><i class="fa fa-arrows-v mover orange-text"></i><span class="outer folder-outer"><span id="${id}" onclick="addDockerFolderContext('${id}')" class="hand folder-hand"><img src="${safeFolderIcon}" class="img folder-img" onerror='this.src="/plugins/dynamix.docker.manager/images/question.png"'></span><span class="inner folder-inner"><span class="appname" style="display: none;"><a>folder-${id}</a></span><a class="exec folder-appname" onclick='editFolder("${id}")'>${safeFolderName}</a><br><i id="load-folder-${id}" class="fa fa-square stopped folder-load-status"></i><span class="state folder-state fv-folder-state-stopped"> ${$.i18n('stopped')}</span></span></span><button class="dropDown-${id} folder-dropdown" onclick="dropDownButton('${id}')" ><i class="fa fa-chevron-down" aria-hidden="true"></i></button></div></td><td class="updatecolumn folder-update"><span class="green-text folder-update-text"><i class="fa fa-check fa-fw"></i> ${$.i18n('up-to-date')}</span><div class="advanced" style="display: ${advanced ? 'block' : 'none'};"><a class="exec" onclick="forceUpdateFolder('${id}');"><span style="white-space:nowrap;"><i class="fa fa-cloud-download fa-fw"></i> ${$.i18n('force-update')}</span></a></div></td><td colspan="${colspan}"><div class="folder-storage"></div><div class="folder-preview"></div></td><td class="advanced folder-advanced" ${advanced ? 'style="display: table-cell;"' : ''}><span class="cpu-folder-${id} folder-cpu">0%</span><div class="usage-disk mm folder-load"><span id="cpu-folder-${id}" class="folder-cpu-bar" style="width:0%"></span><span></span></div><br><span class="mem-folder-${id} folder-mem">0 / 0</span></td><td class="folder-autostart"><input type="checkbox" id="folder-${id}-auto" class="autostart" style="display:none"><div style="clear:left"></div></td><td></td></tr>`;
23712365
if (FOLDER_VIEW_DEBUG_MODE) console.log(`[FV3_DEBUG] createFolder (id: ${id}): colspan=${colspan}. Generated folder HTML (fld).`);
23722366

23732367
if (positionInMainOrder === 0) {
@@ -4169,12 +4163,41 @@ const addDockerFolderContext = (id) => {
41694163
}
41704164
const folderData = globalFolders[id];
41714165
const hasChildren = folderHasChildren(id);
4166+
const focused = dockerFocusedFolderId === id;
4167+
const pinned = isDockerFolderPinned(id);
4168+
const locked = isDockerFolderLocked(id);
41724169
const directScopeContainers = getScopedRuntimeContainersForFolder(id, false);
41734170
const branchScopeContainers = getScopedRuntimeContainersForFolder(id, true);
41744171
const directCounts = summarizeFolderActionCounts(directScopeContainers);
41754172
const branchCounts = summarizeFolderActionCounts(branchScopeContainers);
41764173
if (FOLDER_VIEW_DEBUG_MODE) console.log(`[FV3_DEBUG] addDockerFolderContext (id: ${id}): Folder data:`, {...folderData});
41774174

4175+
opts.push({
4176+
text: focused ? 'Clear focus' : 'Focus folder',
4177+
icon: focused ? 'fa-dot-circle-o' : 'fa-bullseye',
4178+
action: (evt) => {
4179+
evt.preventDefault();
4180+
toggleDockerFolderFocus(id);
4181+
}
4182+
});
4183+
opts.push({
4184+
text: pinned ? 'Unpin folder' : 'Pin folder',
4185+
icon: pinned ? 'fa-star' : 'fa-star-o',
4186+
action: (evt) => {
4187+
evt.preventDefault();
4188+
toggleDockerFolderPin(id);
4189+
}
4190+
});
4191+
opts.push({
4192+
text: locked ? 'Unlock folder' : 'Lock folder',
4193+
icon: locked ? 'fa-lock' : 'fa-unlock-alt',
4194+
action: (evt) => {
4195+
evt.preventDefault();
4196+
toggleDockerFolderLock(id);
4197+
}
4198+
});
4199+
appendDivider();
4200+
41784201

41794202
if (folderData.settings.folder_webui && folderData.settings.folder_webui_url) {
41804203
opts.push({

src/folderview.plus/usr/local/emhttp/plugins/folderview.plus/styles/docker.css

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ td.ct-name.folder-name > .folder-name-sub {
162162
position: absolute;
163163
top: 50%;
164164
left: 8px;
165-
right: 8px;
165+
right: 28px;
166166
transform: translateY(-50%);
167167
min-height: 0;
168168
width: auto;
@@ -176,7 +176,7 @@ td.ct-name.folder-name > .folder-name-sub {
176176
gap: 6px;
177177
min-width: 0;
178178
flex: 1 1 auto;
179-
max-width: calc(var(--fvplus-docker-app-column-width) - 170px);
179+
max-width: calc(var(--fvplus-docker-app-column-width) - 106px);
180180
}
181181

182182
.folder-hand {
@@ -203,7 +203,7 @@ td.ct-name.folder-name > .folder-name-sub {
203203
padding: 0 4px;
204204
min-width: 18px;
205205
height: 18px;
206-
margin: 0 12px 0 4px;
206+
margin: 0 16px 0 auto;
207207
flex: 0 0 auto;
208208
display: inline-flex;
209209
align-items: center;
@@ -214,48 +214,6 @@ td.ct-name.folder-name > .folder-name-sub {
214214
box-shadow: none !important;
215215
}
216216

217-
.fv-folder-row-actions {
218-
display: inline-flex;
219-
align-items: center;
220-
gap: 4px;
221-
margin-left: auto;
222-
flex: 0 0 auto;
223-
}
224-
225-
.fv-folder-row-action {
226-
width: 17px;
227-
height: 17px;
228-
min-width: 17px;
229-
border: 0 !important;
230-
border-radius: 3px;
231-
background: transparent !important;
232-
color: var(--orange) !important;
233-
display: inline-flex;
234-
align-items: center;
235-
justify-content: center;
236-
padding: 0;
237-
line-height: 1;
238-
box-shadow: none !important;
239-
opacity: 0.86;
240-
}
241-
242-
.fv-folder-row-action:hover,
243-
.fv-folder-row-action:focus,
244-
.fv-folder-row-action:active {
245-
background: rgba(255, 138, 36, 0.18) !important;
246-
box-shadow: none !important;
247-
opacity: 1;
248-
}
249-
250-
.fv-folder-row-action.is-active {
251-
background: rgba(255, 138, 36, 0.2) !important;
252-
opacity: 1;
253-
}
254-
255-
.fv-folder-row-action > i {
256-
font-size: 10px;
257-
}
258-
259217
tr.fv-folder-focused td.ct-name.folder-name {
260218
box-shadow: inset 2px 0 0 rgba(0, 170, 255, 0.85);
261219
}
@@ -270,10 +228,6 @@ tr.fv-folder-locked .folder-appname {
270228
pointer-events: none;
271229
}
272230

273-
tr.fv-folder-locked .fv-folder-row-action-lock {
274-
opacity: 1;
275-
}
276-
277231
.fv-folder-focus-hidden {
278232
display: none !important;
279233
}

tests/docker-folder-row-quick-actions.test.mjs

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,14 @@ const dockerScript = fs.readFileSync(
99
'utf8'
1010
);
1111

12-
test('docker runtime renders one-click focus/pin/lock row actions', () => {
13-
assert.match(dockerScript, /fv-folder-row-action-focus/);
14-
assert.match(dockerScript, /fv-folder-row-action-pin/);
15-
assert.match(dockerScript, /fv-folder-row-action-lock/);
16-
assert.match(dockerScript, /toggleDockerFolderFocus\('/);
17-
assert.match(dockerScript, /toggleDockerFolderPin\('/);
18-
assert.match(dockerScript, /toggleDockerFolderLock\('/);
12+
test('docker context menu keeps focus/pin/lock quick actions at the top', () => {
13+
assert.match(dockerScript, /text:\s*focused \? 'Clear focus' : 'Focus folder'/);
14+
assert.match(dockerScript, /text:\s*pinned \? 'Unpin folder' : 'Pin folder'/);
15+
assert.match(dockerScript, /text:\s*locked \? 'Unlock folder' : 'Lock folder'/);
16+
assert.match(dockerScript, /toggleDockerFolderFocus\(id\)/);
17+
assert.match(dockerScript, /toggleDockerFolderPin\(id\)/);
18+
assert.match(dockerScript, /toggleDockerFolderLock\(id\)/);
19+
assert.doesNotMatch(dockerScript, /fv-folder-row-actions/);
1920
});
2021

2122
test('docker runtime exposes and applies focus\/lock state guards', () => {

tests/docker-mobile-name-alignment-guard.test.mjs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ test('docker mobile app-name width contract keeps long names visible before elli
2525

2626
test('docker folder dropdown keeps right gutter to avoid version-column clipping', () => {
2727
assert.match(dockerCss, /\.folder-dropdown\s*\{[\s\S]*min-width:\s*18px/);
28-
assert.match(dockerCss, /\.folder-dropdown\s*\{[\s\S]*margin:\s*0 12px 0 4px/);
29-
assert.match(dockerCss, /\.fv-folder-row-actions\s*\{[\s\S]*margin-left:\s*auto/);
28+
assert.match(dockerCss, /\.folder-dropdown\s*\{[\s\S]*margin:\s*0 16px 0 auto/);
29+
assert.match(dockerCss, /td\.ct-name\.folder-name > \.folder-name-sub\s*\{[\s\S]*right:\s*28px/);
3030
assert.match(dockerCss, /\.folder-dropdown > i\s*\{[\s\S]*font-size:\s*12px/);
3131
});
3232

0 commit comments

Comments
 (0)