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; const { DeesContextmenu } = plugins.deesCatalog; 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; } .overview-item { padding: 6px 12px; border-radius: 4px; cursor: pointer; font-size: 13px; display: flex; align-items: center; gap: 6px; transition: background 0.1s; color: #a5d6a7; margin-bottom: 4px; } .overview-item:hover { background: rgba(255, 255, 255, 0.05); } .overview-item.selected { background: rgba(165, 214, 167, 0.15); color: #a5d6a7; } .overview-item svg { width: 14px; height: 14px; } `, ]; 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) { 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, }) ); } } private handleCollectionContextMenu(event: MouseEvent, collection: IMongoCollection) { event.preventDefault(); DeesContextmenu.openContextMenuWithOptions(event, [ { name: 'View Documents', iconName: 'lucide:fileText', action: async () => { this.selectCollection(collection.name); }, }, { divider: true }, { name: 'Delete Collection', iconName: 'lucide:trash2', action: async () => { await this.deleteCollection(collection.name); }, }, ]); } public async refresh() { await this.loadCollections(); } private selectOverview() { this.dispatchEvent( new CustomEvent('collection-selected', { detail: '__overview__', bubbles: true, composed: true, }) ); } render() { if (this.loading) { return html`
Loading collections...
`; } return html`
this.selectOverview()} > Overview
${this.collections.length === 0 ? html`
No collections
` : this.collections.map( (coll) => html`
this.selectCollection(coll.name)} @contextmenu=${(e: MouseEvent) => this.handleCollectionContextMenu(e, coll)} > ${coll.name} ${coll.count !== undefined ? html`${formatCount(coll.count)}` : ''}
` )}
`; } }