|
551 | 551 | `; |
552 | 552 | return true; |
553 | 553 | } |
554 | | - if (!folderModels[selectedFolderId]) { |
555 | | - selectedFolderId = orderedIds[0]; |
556 | | - } |
557 | | - const selectedFolder = folderModels[selectedFolderId]; |
| 554 | + const hasSelectedFolder = Boolean(selectedFolderId && folderModels[selectedFolderId]); |
| 555 | + const selectedFolder = hasSelectedFolder ? folderModels[selectedFolderId] : null; |
558 | 556 | const selectedMembers = Array.isArray(selectedFolder?.directMembers) ? selectedFolder.directMembers : []; |
559 | 557 | if (!selectedMembers.some((member) => member.name === selectedMemberName)) { |
560 | 558 | selectedMemberName = ''; |
561 | 559 | } |
562 | 560 | const selectedMember = selectedMembers.find((member) => member.name === selectedMemberName) || null; |
563 | | - const breadcrumbs = buildBreadcrumbs(selectedFolderId, snapshot, folderModels); |
| 561 | + const breadcrumbs = hasSelectedFolder ? buildBreadcrumbs(selectedFolderId, snapshot, folderModels) : []; |
564 | 562 | const relatedFolderIds = (() => { |
| 563 | + if (!selectedFolder) { |
| 564 | + return orderedIds.filter((folderId) => !folderModels[folderId]?.parentId); |
| 565 | + } |
565 | 566 | if (selectedFolder.childIds.length) { |
566 | 567 | return selectedFolder.childIds.slice(); |
567 | 568 | } |
|
583 | 584 | running: model.running, |
584 | 585 | updates: model.updates |
585 | 586 | })); |
586 | | - const memberOrbit = layoutOrbitNodes(selectedFolder.directMembers, { |
| 587 | + const memberOrbit = layoutOrbitNodes(selectedFolder?.directMembers || [], { |
587 | 588 | startRadius: 256, |
588 | 589 | ringStep: 132, |
589 | 590 | baseCapacity: 8, |
|
625 | 626 | <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="clear-member-selection">Back to folder summary</button> |
626 | 627 | </div> |
627 | 628 | </div> |
628 | | - ` : ` |
| 629 | + ` : hasSelectedFolder ? ` |
629 | 630 | <div class="fv-docker-orbit-inspector-card"> |
630 | 631 | <div class="fv-docker-orbit-inspector-title">Folder summary</div> |
631 | 632 | <div class="fv-docker-orbit-inspector-list"> |
632 | | - <div><span>Direct members</span><strong>${selectedFolder.directMemberCount}</strong></div> |
633 | | - <div><span>Branch members</span><strong>${selectedFolder.branchMemberCount}</strong></div> |
634 | | - <div><span>Child folders</span><strong>${selectedFolder.childIds.length}</strong></div> |
635 | | - <div><span>Updates</span><strong>${selectedFolder.updates}</strong></div> |
| 633 | + <div><span>Direct members</span><strong>${selectedFolder?.directMemberCount || 0}</strong></div> |
| 634 | + <div><span>Branch members</span><strong>${selectedFolder?.branchMemberCount || 0}</strong></div> |
| 635 | + <div><span>Child folders</span><strong>${selectedFolder?.childIds.length || 0}</strong></div> |
| 636 | + <div><span>Updates</span><strong>${selectedFolder?.updates || 0}</strong></div> |
636 | 637 | </div> |
637 | 638 | <p class="fv-docker-orbit-inspector-note">Click a container orbit to inspect it, or select a child folder orbit to move deeper into the branch.</p> |
638 | 639 | </div> |
| 640 | + ` : ` |
| 641 | + <div class="fv-docker-orbit-inspector-card"> |
| 642 | + <div class="fv-docker-orbit-inspector-title">Folder summary</div> |
| 643 | + <p class="fv-docker-orbit-inspector-note">Select a folder orbit to focus it here. Containers will appear only after a folder is selected.</p> |
| 644 | + </div> |
639 | 645 | `; |
640 | 646 | root.innerHTML = ` |
641 | 647 | <div class="fv-docker-orbit-shell"> |
|
651 | 657 | </div> |
652 | 658 | <div class="fv-docker-orbit-layout"> |
653 | 659 | <section class="fv-docker-orbit-main"> |
654 | | - <div class="fv-docker-orbit-breadcrumbs"> |
| 660 | + ${breadcrumbs.length ? `<div class="fv-docker-orbit-breadcrumbs"> |
655 | 661 | ${breadcrumbs.map((crumb, index) => ` |
656 | 662 | <button type="button" class="fv-docker-orbit-crumb${crumb.folderId === selectedFolderId ? ' is-current' : ''}" data-fv-orbit-action="select-folder" data-folder-id="${escapeHtml(crumb.folderId)}">${escapeHtml(crumb.name)}</button> |
657 | 663 | ${index < breadcrumbs.length - 1 ? '<span class="fv-docker-orbit-crumb-sep">/</span>' : ''} |
658 | 664 | `).join('')} |
659 | | - </div> |
| 665 | + </div>` : ''} |
660 | 666 | <div class="fv-docker-orbit-stage-wrap"> |
661 | 667 | <div class="fv-docker-orbit-stage" style="--fv-docker-orbit-stage-size:${stageSize}px;"> |
662 | 668 | <div class="fv-docker-orbit-rings">${ringMarkup}</div> |
663 | | - <article class="fv-docker-orbit-hub" data-folder-id="${escapeHtml(selectedFolderId)}"> |
| 669 | + <article class="fv-docker-orbit-hub${hasSelectedFolder ? '' : ' is-placeholder'}" ${hasSelectedFolder ? `data-folder-id="${escapeHtml(selectedFolderId)}"` : ''}> |
664 | 670 | <div class="fv-docker-orbit-hub-head"> |
665 | | - <img src="${selectedFolder.icon}" class="fv-docker-orbit-folder-icon" alt="" loading="lazy" onerror='this.src="${DEFAULT_FOLDER_ICON}"'> |
| 671 | + <img src="${hasSelectedFolder ? selectedFolder.icon : DEFAULT_FOLDER_ICON}" class="fv-docker-orbit-folder-icon" alt="" loading="lazy" onerror='this.src="${DEFAULT_FOLDER_ICON}"'> |
666 | 672 | <div> |
667 | | - <div class="fv-docker-orbit-folder-title">${escapeHtml(selectedFolder.name)}</div> |
668 | | - <div class="fv-docker-orbit-folder-meta">${selectedFolder.directMemberCount} direct • ${selectedFolder.branchMemberCount} in branch • ${selectedFolder.childIds.length} child folders</div> |
| 673 | + <div class="fv-docker-orbit-folder-title">${escapeHtml(hasSelectedFolder ? selectedFolder.name : 'Select a folder')}</div> |
| 674 | + <div class="fv-docker-orbit-folder-meta">${escapeHtml(hasSelectedFolder ? `${selectedFolder.directMemberCount} direct • ${selectedFolder.branchMemberCount} in branch • ${selectedFolder.childIds.length} child folders` : 'Choose a folder from orbit to focus it in the center.')}</div> |
669 | 675 | </div> |
670 | 676 | </div> |
671 | | - <div class="fv-docker-orbit-hub-stats"> |
672 | | - <span class="fv-docker-orbit-pill running"><i class="fa fa-play"></i> ${selectedFolder.running}</span> |
673 | | - <span class="fv-docker-orbit-pill paused"><i class="fa fa-pause"></i> ${selectedFolder.paused}</span> |
674 | | - <span class="fv-docker-orbit-pill stopped"><i class="fa fa-stop"></i> ${selectedFolder.stopped}</span> |
675 | | - <span class="fv-docker-orbit-pill update"><i class="fa fa-cloud-download"></i> ${selectedFolder.updates}</span> |
676 | | - ${selectedFolder.pinned ? '<span class="fv-docker-orbit-pill pin"><i class="fa fa-star"></i> pinned</span>' : ''} |
677 | | - ${selectedFolder.locked ? '<span class="fv-docker-orbit-pill lock"><i class="fa fa-lock"></i> locked</span>' : ''} |
678 | | - </div> |
679 | | - <div class="fv-docker-orbit-hub-actions"> |
680 | | - <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="start-branch" data-folder-id="${escapeHtml(selectedFolderId)}">Start branch</button> |
681 | | - <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="stop-branch" data-folder-id="${escapeHtml(selectedFolderId)}">Stop branch</button> |
682 | | - <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="${selectedFolder.actionCounts.updateReady > 0 ? 'update-branch' : 'force-update-branch'}" data-folder-id="${escapeHtml(selectedFolderId)}">${selectedFolder.actionCounts.updateReady > 0 ? 'Update branch' : 'Force update'}</button> |
683 | | - <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="open-webui" data-folder-id="${escapeHtml(selectedFolderId)}">Open WebUIs</button> |
684 | | - <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="edit-folder" data-folder-id="${escapeHtml(selectedFolderId)}">Edit</button> |
685 | | - <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="toggle-pin" data-folder-id="${escapeHtml(selectedFolderId)}">${selectedFolder.pinned ? 'Unpin' : 'Pin'}</button> |
686 | | - <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="toggle-lock" data-folder-id="${escapeHtml(selectedFolderId)}">${selectedFolder.locked ? 'Unlock' : 'Lock'}</button> |
687 | | - </div> |
| 677 | + ${hasSelectedFolder ? ` |
| 678 | + <div class="fv-docker-orbit-hub-stats"> |
| 679 | + <span class="fv-docker-orbit-pill running"><i class="fa fa-play"></i> ${selectedFolder.running}</span> |
| 680 | + <span class="fv-docker-orbit-pill paused"><i class="fa fa-pause"></i> ${selectedFolder.paused}</span> |
| 681 | + <span class="fv-docker-orbit-pill stopped"><i class="fa fa-stop"></i> ${selectedFolder.stopped}</span> |
| 682 | + <span class="fv-docker-orbit-pill update"><i class="fa fa-cloud-download"></i> ${selectedFolder.updates}</span> |
| 683 | + ${selectedFolder.pinned ? '<span class="fv-docker-orbit-pill pin"><i class="fa fa-star"></i> pinned</span>' : ''} |
| 684 | + ${selectedFolder.locked ? '<span class="fv-docker-orbit-pill lock"><i class="fa fa-lock"></i> locked</span>' : ''} |
| 685 | + </div> |
| 686 | + <div class="fv-docker-orbit-hub-actions"> |
| 687 | + <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="start-branch" data-folder-id="${escapeHtml(selectedFolderId)}">Start branch</button> |
| 688 | + <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="stop-branch" data-folder-id="${escapeHtml(selectedFolderId)}">Stop branch</button> |
| 689 | + <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="${selectedFolder.actionCounts.updateReady > 0 ? 'update-branch' : 'force-update-branch'}" data-folder-id="${escapeHtml(selectedFolderId)}">${selectedFolder.actionCounts.updateReady > 0 ? 'Update branch' : 'Force update'}</button> |
| 690 | + <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="open-webui" data-folder-id="${escapeHtml(selectedFolderId)}">Open WebUIs</button> |
| 691 | + <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="edit-folder" data-folder-id="${escapeHtml(selectedFolderId)}">Edit</button> |
| 692 | + <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="toggle-pin" data-folder-id="${escapeHtml(selectedFolderId)}">${selectedFolder.pinned ? 'Unpin' : 'Pin'}</button> |
| 693 | + <button type="button" class="fv-docker-orbit-button" data-fv-orbit-action="toggle-lock" data-folder-id="${escapeHtml(selectedFolderId)}">${selectedFolder.locked ? 'Unlock' : 'Lock'}</button> |
| 694 | + </div> |
| 695 | + ` : ''} |
688 | 696 | </article> |
689 | 697 | ${memberOrbit.nodes.map((member) => ` |
690 | 698 | <button |
|
0 commit comments