import * as plugins from '../plugins.js'; import { apiService, type IMongoCollection } from '../services/index.js'; import { formatCount } from '../utilities/index.js'; import { themeStyles } from '../styles/index.js'; const { html, css, cssManager, customElement, property, state, DeesElement } = plugins; declare global { interface HTMLElementEventMap { 'collection-deleted': CustomEvent<{ databaseName: string; collectionName: string }>; } } @customElement('tsview-mongo-collections') export class TsviewMongoCollections extends DeesElement { @property({ type: String }) public accessor databaseName: string = ''; @property({ type: String }) public accessor selectedCollection: string = ''; @state() private accessor collections: IMongoCollection[] = []; @state() private accessor loading: boolean = false; public static styles = [ cssManager.defaultStyles, themeStyles, css` :host { display: block; } .collections-list { padding-left: 12px; } .collection-item { padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 13px; display: flex; align-items: center; justify-content: space-between; transition: background 0.1s; } .collection-item:hover { background: rgba(255, 255, 255, 0.05); } .collection-item.selected { background: rgba(255, 255, 255, 0.08); color: #e0e0e0; } .collection-name { display: flex; align-items: center; gap: 6px; } .collection-icon { width: 14px; height: 14px; color: #888; } .collection-count { font-size: 11px; color: #666; background: rgba(255, 255, 255, 0.1); padding: 2px 6px; border-radius: 10px; } .loading-state { padding: 8px 12px; color: #666; font-size: 12px; } .empty-state { padding: 8px 12px; color: #666; font-size: 12px; font-style: italic; } .delete-btn { opacity: 0; padding: 4px; background: transparent; border: none; color: #888; cursor: pointer; border-radius: 4px; display: flex; align-items: center; justify-content: center; transition: all 0.15s; } .collection-item:hover .delete-btn { opacity: 1; } .delete-btn:hover { background: rgba(239, 68, 68, 0.2); color: #f87171; } `, ]; async connectedCallback() { super.connectedCallback(); await this.loadCollections(); } updated(changedProperties: Map) { if (changedProperties.has('databaseName')) { this.loadCollections(); } } private async loadCollections() { if (!this.databaseName) return; this.loading = true; try { this.collections = await apiService.listCollections(this.databaseName); } catch (err) { console.error('Error loading collections:', err); this.collections = []; } this.loading = false; } private selectCollection(name: string) { this.dispatchEvent( new CustomEvent('collection-selected', { detail: name, bubbles: true, composed: true, }) ); } private async deleteCollection(name: string, e: Event) { e.stopPropagation(); if (!confirm(`Delete collection "${name}"? This will delete all documents.`)) return; const success = await apiService.dropCollection(this.databaseName, name); if (success) { this.collections = this.collections.filter(c => c.name !== name); this.dispatchEvent( new CustomEvent('collection-deleted', { detail: { databaseName: this.databaseName, collectionName: name }, bubbles: true, composed: true, }) ); } } public async refresh() { await this.loadCollections(); } render() { if (this.loading) { return html`
Loading collections...
`; } if (this.collections.length === 0) { return html`
No collections
`; } return html`
${this.collections.map( (coll) => html`
this.selectCollection(coll.name)} > ${coll.name} ${coll.count !== undefined ? html`${formatCount(coll.count)}` : ''}
` )}
`; } }