feat: DrawerComonent
This commit is contained in:
@@ -21,71 +21,23 @@ class ClusterMembersComponent extends Component {
|
||||
}, 200);
|
||||
|
||||
// Drawer state for desktop
|
||||
this.detailsDrawer = null;
|
||||
this.detailsDrawerContent = null;
|
||||
this.detailsDrawerBackdrop = null;
|
||||
this.activeDrawerComponent = null;
|
||||
this.drawer = new DrawerComponent();
|
||||
}
|
||||
|
||||
// Determine if we should use desktop drawer behavior
|
||||
isDesktop() {
|
||||
try {
|
||||
return window && window.innerWidth >= 1024; // desktop threshold
|
||||
} catch (_) {
|
||||
return false;
|
||||
}
|
||||
return this.drawer.isDesktop();
|
||||
}
|
||||
|
||||
ensureDrawer() {
|
||||
if (this.detailsDrawer) return;
|
||||
// Create backdrop
|
||||
this.detailsDrawerBackdrop = document.createElement('div');
|
||||
this.detailsDrawerBackdrop.className = 'details-drawer-backdrop';
|
||||
document.body.appendChild(this.detailsDrawerBackdrop);
|
||||
|
||||
// Create drawer
|
||||
this.detailsDrawer = document.createElement('div');
|
||||
this.detailsDrawer.className = 'details-drawer';
|
||||
|
||||
// Header with close button
|
||||
const header = document.createElement('div');
|
||||
header.className = 'details-drawer-header';
|
||||
header.innerHTML = `
|
||||
<div class="drawer-title">Node Details</div>
|
||||
<button class="drawer-close" aria-label="Close">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M18 6L6 18M6 6l12 12"/>
|
||||
</svg>
|
||||
</button>
|
||||
`;
|
||||
this.detailsDrawer.appendChild(header);
|
||||
|
||||
// Content container
|
||||
this.detailsDrawerContent = document.createElement('div');
|
||||
this.detailsDrawerContent.className = 'details-drawer-content';
|
||||
this.detailsDrawer.appendChild(this.detailsDrawerContent);
|
||||
|
||||
document.body.appendChild(this.detailsDrawer);
|
||||
|
||||
// Close handlers
|
||||
const close = () => this.closeDrawer();
|
||||
header.querySelector('.drawer-close').addEventListener('click', close);
|
||||
this.detailsDrawerBackdrop.addEventListener('click', close);
|
||||
document.addEventListener('keydown', (e) => {
|
||||
if (e.key === 'Escape') close();
|
||||
});
|
||||
}
|
||||
|
||||
openDrawerForMember(memberIp) {
|
||||
this.ensureDrawer();
|
||||
|
||||
// Set drawer title to member name (hostname) and IP
|
||||
// Get display name for drawer title
|
||||
let displayName = memberIp;
|
||||
try {
|
||||
const members = (this.viewModel && typeof this.viewModel.get === 'function') ? this.viewModel.get('members') : [];
|
||||
const member = Array.isArray(members) ? members.find(m => m && m.ip === memberIp) : null;
|
||||
const hostname = (member && member.hostname) ? member.hostname : '';
|
||||
const ip = (member && member.ip) ? member.ip : memberIp;
|
||||
let displayName = memberIp;
|
||||
|
||||
if (hostname && ip) {
|
||||
displayName = `${hostname} - ${ip}`;
|
||||
@@ -94,46 +46,33 @@ class ClusterMembersComponent extends Component {
|
||||
} else if (ip) {
|
||||
displayName = ip;
|
||||
}
|
||||
|
||||
const titleEl = this.detailsDrawer.querySelector('.drawer-title');
|
||||
if (titleEl) {
|
||||
titleEl.textContent = displayName;
|
||||
}
|
||||
} catch (_) {
|
||||
// no-op if anything goes wrong, default title remains
|
||||
}
|
||||
|
||||
// Clear previous component if any
|
||||
if (this.activeDrawerComponent && typeof this.activeDrawerComponent.unmount === 'function') {
|
||||
try { this.activeDrawerComponent.unmount(); } catch (_) {}
|
||||
}
|
||||
this.detailsDrawerContent.innerHTML = '<div class="loading-details">Loading detailed information...</div>';
|
||||
// Open drawer with content callback
|
||||
this.drawer.openDrawer(displayName, (contentContainer, setActiveComponent) => {
|
||||
// Load and mount NodeDetails into drawer
|
||||
const nodeDetailsVM = new NodeDetailsViewModel();
|
||||
const nodeDetailsComponent = new NodeDetailsComponent(contentContainer, nodeDetailsVM, this.eventBus);
|
||||
setActiveComponent(nodeDetailsComponent);
|
||||
|
||||
// Load and mount NodeDetails into drawer
|
||||
const nodeDetailsVM = new NodeDetailsViewModel();
|
||||
const nodeDetailsComponent = new NodeDetailsComponent(this.detailsDrawerContent, nodeDetailsVM, this.eventBus);
|
||||
this.activeDrawerComponent = nodeDetailsComponent;
|
||||
|
||||
nodeDetailsVM.loadNodeDetails(memberIp).then(() => {
|
||||
nodeDetailsComponent.mount();
|
||||
}).catch((error) => {
|
||||
logger.error('Failed to load node details for drawer:', error);
|
||||
this.detailsDrawerContent.innerHTML = `
|
||||
<div class="error">
|
||||
<strong>Error loading node details:</strong><br>
|
||||
${this.escapeHtml(error.message)}
|
||||
</div>
|
||||
`;
|
||||
nodeDetailsVM.loadNodeDetails(memberIp).then(() => {
|
||||
nodeDetailsComponent.mount();
|
||||
}).catch((error) => {
|
||||
logger.error('Failed to load node details for drawer:', error);
|
||||
contentContainer.innerHTML = `
|
||||
<div class="error">
|
||||
<strong>Error loading node details:</strong><br>
|
||||
${this.escapeHtml(error.message)}
|
||||
</div>
|
||||
`;
|
||||
});
|
||||
});
|
||||
|
||||
// Open drawer
|
||||
this.detailsDrawer.classList.add('open');
|
||||
this.detailsDrawerBackdrop.classList.add('visible');
|
||||
}
|
||||
|
||||
closeDrawer() {
|
||||
if (this.detailsDrawer) this.detailsDrawer.classList.remove('open');
|
||||
if (this.detailsDrawerBackdrop) this.detailsDrawerBackdrop.classList.remove('visible');
|
||||
this.drawer.closeDrawer();
|
||||
}
|
||||
|
||||
mount() {
|
||||
|
||||
Reference in New Issue
Block a user