Skip to content

Commit 2b47e59

Browse files
author
FolderView Plus Test
committed
Theme and native-menu polish for command view
1 parent 109d475 commit 2b47e59

8 files changed

Lines changed: 150 additions & 69 deletions

File tree

archive/folderview.plus-2026.04.14.08.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+
5e40104f4e8d1915b0da036e040bd8fb0a142f289fabbcb98c5da8afcfbc6319 folderview.plus-2026.04.15.21.txz

docs/releases/2026.04.15.21.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
- UX: Docker command-view container cards now restore the outlined member-tile treatment, but the outline colors are theme-aware and use the plugin runtime status/border tokens instead of hardcoded orange chrome.
2+
- UX: Command-view quick actions now reuse the regular FolderView Docker preview action classes, and the branch action buttons gain a subtle theme-token outline so they sit closer to the rest of the plugin controls.
3+
- Fix: Command-view member surfaces now hydrate Unraid's native Docker trigger handlers onto the visible tile itself and hydrate from the staged full runtime payload for WebUI URLs, so clicking a container uses the native Unraid menu path and the WebUI quick action can render when available.

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.04.15.20">
10-
<!ENTITY md5 "cb5c9cfdb68417db5a05e88ac358d01d">
9+
<!ENTITY version "2026.04.15.21">
10+
<!ENTITY md5 "c2077648bc18417418c9c310f5bc550b">
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.04.15.21
17+
- UX: Docker command-view container cards now restore the outlined member-tile treatment, but the outline colors are theme-aware and use the plugin runtime status/border tokens instead of hardcoded orange chrome.
18+
- UX: Command-view quick actions now reuse the regular FolderView Docker preview action classes, and the branch action buttons gain a subtle theme-token outline so they sit closer to the rest of the plugin controls.
19+
- Fix: Command-view member surfaces now hydrate Unraid's native Docker trigger handlers onto the visible tile itself and hydrate from the staged full runtime payload for WebUI URLs, so clicking a container uses the native Unraid menu path and the WebUI quick action can render when available.
20+
21+
1622
###2026.04.15.20
1723
- UX: Docker command-view member tiles no longer render the boxed orange tile chrome; the member strip now stays visually closer to the normal FolderView preview surface.
1824
- UX: Command-view WebUI, console, and log actions now use the regular Docker preview action classes so their icons match the standard FolderView quick actions instead of a custom button style.

src/folderview.plus/usr/local/emhttp/plugins/folderview.plus/scripts/docker.runtime.command-view.js

Lines changed: 64 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,55 @@
284284
return trigger.dispatchEvent(event);
285285
};
286286

287+
const hydrateNativeMemberSurface = (surface, containerName) => {
288+
if (!(surface instanceof HTMLElement)) {
289+
return;
290+
}
291+
const safeName = String(containerName || '').trim();
292+
if (!safeName) {
293+
return;
294+
}
295+
const trigger = getNativeMemberTrigger(safeName);
296+
if (!(trigger instanceof HTMLElement)) {
297+
surface.addEventListener('click', (event) => {
298+
event.preventDefault();
299+
event.stopPropagation();
300+
proxyNativeMemberTrigger(safeName, 'click');
301+
});
302+
surface.addEventListener('contextmenu', (event) => {
303+
event.preventDefault();
304+
event.stopPropagation();
305+
proxyNativeMemberTrigger(safeName, 'contextmenu');
306+
});
307+
return;
308+
}
309+
const inlineClick = String(trigger.getAttribute('onclick') || '').trim();
310+
const inlineContextMenu = String(trigger.getAttribute('oncontextmenu') || '').trim();
311+
const title = String(trigger.getAttribute('title') || '').trim();
312+
surface.classList.add('hand');
313+
if (inlineClick) {
314+
surface.setAttribute('onclick', inlineClick);
315+
} else {
316+
surface.addEventListener('click', (event) => {
317+
event.preventDefault();
318+
event.stopPropagation();
319+
proxyNativeMemberTrigger(safeName, 'click');
320+
});
321+
}
322+
if (inlineContextMenu) {
323+
surface.setAttribute('oncontextmenu', inlineContextMenu);
324+
} else {
325+
surface.addEventListener('contextmenu', (event) => {
326+
event.preventDefault();
327+
event.stopPropagation();
328+
proxyNativeMemberTrigger(safeName, 'contextmenu');
329+
});
330+
}
331+
if (title) {
332+
surface.setAttribute('title', title);
333+
}
334+
};
335+
287336
const computeOrderedFolderIds = (folders, prefs, hostOrder, unraidOrder) => {
288337
const folderMap = folders && typeof folders === 'object' ? folders : {};
289338
const baseOrder = reorderFolderSlotsInBaseOrder(unraidOrder, folderMap, prefs);
@@ -492,6 +541,12 @@
492541
</div>
493542
</div>
494543
`;
544+
root.querySelectorAll('[data-fv-command-member-surface="true"]').forEach((surface) => {
545+
if (!(surface instanceof HTMLElement)) {
546+
return;
547+
}
548+
hydrateNativeMemberSurface(surface, String(surface.getAttribute('data-member-name') || '').trim());
549+
});
495550
return true;
496551
};
497552

@@ -532,18 +587,6 @@
532587
return;
533588
}
534589
}
535-
const memberSurface = event.target instanceof Element
536-
? event.target.closest('[data-fv-command-member-surface="true"]')
537-
: null;
538-
if (memberSurface instanceof HTMLElement) {
539-
const memberName = String(memberSurface.getAttribute('data-member-name') || '').trim();
540-
if (memberName) {
541-
event.preventDefault();
542-
event.stopPropagation();
543-
proxyNativeMemberTrigger(memberName, 'click');
544-
}
545-
return;
546-
}
547590
const button = event.target instanceof Element
548591
? event.target.closest('[data-fv-command-action]')
549592
: null;
@@ -608,25 +651,6 @@
608651
}
609652
};
610653
rootNode.addEventListener('click', clickHandler);
611-
if (contextMenuHandler) {
612-
rootNode.removeEventListener('contextmenu', contextMenuHandler);
613-
}
614-
contextMenuHandler = (event) => {
615-
const memberSurface = event.target instanceof Element
616-
? event.target.closest('[data-fv-command-member-surface="true"]')
617-
: null;
618-
if (!(memberSurface instanceof HTMLElement)) {
619-
return;
620-
}
621-
const memberName = String(memberSurface.getAttribute('data-member-name') || '').trim();
622-
if (!memberName) {
623-
return;
624-
}
625-
event.preventDefault();
626-
event.stopPropagation();
627-
proxyNativeMemberTrigger(memberName, 'contextmenu');
628-
};
629-
rootNode.addEventListener('contextmenu', contextMenuHandler);
630654
};
631655

632656
const resolveSnapshot = async (options = {}) => {
@@ -638,7 +662,15 @@
638662
const folders = parseJsonPayloadSafe(foldersPayload);
639663
const unraidOrder = Object.values(parseJsonPayloadSafe(orderPayload));
640664
const runtimeState = parseJsonPayloadSafe(statePayload);
641-
const runtimeInfoByName = normalizeRuntimeInfoMap(runtimeState);
665+
let runtimeInfoByName = normalizeRuntimeInfoMap(runtimeState);
666+
if (requestBundle.fullInfo) {
667+
try {
668+
const runtimeFull = parseJsonPayloadSafe(await requestBundle.fullInfo);
669+
runtimeInfoByName = normalizeRuntimeInfoMap(runtimeFull, runtimeInfoByName);
670+
} catch (_error) {
671+
// The staged full-info hydration is optional for the experimental surface.
672+
}
673+
}
642674
const prefsResponse = parseJsonPayloadSafe(prefsPayload);
643675
const prefs = normalizePrefs(prefsResponse?.prefs || {});
644676
const hierarchy = buildFolderHierarchy(folders);

0 commit comments

Comments
 (0)