|
import { api } from '../api.js';
|
|
import { BaseFileList } from './base-file-list.js';
|
|
|
|
export class StarredItems extends BaseFileList {
|
|
constructor() {
|
|
super();
|
|
}
|
|
|
|
async connectedCallback() {
|
|
super.connectedCallback();
|
|
await this.loadStarredItems();
|
|
}
|
|
|
|
async loadStarredItems() {
|
|
try {
|
|
this.files = await api.listStarredFiles();
|
|
this.folders = await api.listStarredFolders();
|
|
this.selectedFiles.clear();
|
|
this.selectedFolders.clear();
|
|
this.render();
|
|
} catch (error) {
|
|
console.error('Failed to load starred items:', error);
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
|
detail: { message: 'Failed to load starred items: ' + error.message, type: 'error' }
|
|
}));
|
|
}
|
|
}
|
|
|
|
render() {
|
|
const allStarred = [...this.folders, ...this.files];
|
|
const hasSelected = this.selectedFiles.size > 0 || this.selectedFolders.size > 0;
|
|
const totalItems = this.files.length + this.folders.length;
|
|
const totalSelected = this.selectedFiles.size + this.selectedFolders.size;
|
|
const allFilesSelected = this.files.length > 0 && this.selectedFiles.size === this.files.length;
|
|
const allFoldersSelected = this.folders.length > 0 && this.selectedFolders.size === this.folders.length;
|
|
const allSelected = totalItems > 0 && allFilesSelected && allFoldersSelected;
|
|
const someSelected = hasSelected && !allSelected;
|
|
|
|
if (allStarred.length === 0) {
|
|
this.innerHTML = `
|
|
<div class="file-list-container">
|
|
<div class="file-list-header">
|
|
<h2>Starred Items</h2>
|
|
</div>
|
|
<p class="empty-state">No starred items found.</p>
|
|
</div>
|
|
`;
|
|
return;
|
|
}
|
|
|
|
this.innerHTML = `
|
|
<div class="file-list-container">
|
|
<div class="file-list-header">
|
|
<div class="header-left">
|
|
<h2>Starred Items</h2>
|
|
${totalItems > 0 ? `
|
|
<div class="selection-controls">
|
|
<input type="checkbox" id="select-all" ${allSelected ? 'checked' : ''} ${someSelected ? 'data-indeterminate="true"' : ''}>
|
|
<label for="select-all">
|
|
${hasSelected ? `${totalSelected} selected` : 'Select all'}
|
|
</label>
|
|
</div>
|
|
` : ''}
|
|
</div>
|
|
</div>
|
|
|
|
${hasSelected ? `
|
|
<div class="batch-actions">
|
|
<button class="button button-small" id="batch-unstar-btn">Unstar Selected</button>
|
|
<button class="button button-small" id="clear-selection-btn">Clear Selection</button>
|
|
</div>
|
|
` : ''}
|
|
|
|
<div class="file-grid">
|
|
${this.folders.map(folder => this.renderFolder(folder)).join('')}
|
|
${this.files.map(file => this.renderFile(file)).join('')}
|
|
</div>
|
|
</div>
|
|
`;
|
|
this.attachListeners();
|
|
this.updateIndeterminateState();
|
|
}
|
|
|
|
getFolderActions(folder) {
|
|
return `<button class="action-btn star-btn" data-action="unstar-folder" data-id="${folder.id}">★</button>`;
|
|
}
|
|
|
|
getFileActions(file) {
|
|
return `
|
|
<button class="action-btn" data-action="download" data-id="${file.id}">Download</button>
|
|
<button class="action-btn star-btn" data-action="unstar-file" data-id="${file.id}">★</button>
|
|
`;
|
|
}
|
|
|
|
createBatchActionsBar() {
|
|
const container = this.querySelector('.file-list-container');
|
|
const header = container.querySelector('.file-list-header');
|
|
const batchBar = document.createElement('div');
|
|
batchBar.className = 'batch-actions';
|
|
batchBar.innerHTML = `
|
|
<button class="button button-small" id="batch-unstar-btn">Unstar Selected</button>
|
|
<button class="button button-small" id="clear-selection-btn">Clear Selection</button>
|
|
`;
|
|
header.insertAdjacentElement('afterend', batchBar);
|
|
}
|
|
|
|
attachListeners() {
|
|
const batchUnstarBtn = this.querySelector('#batch-unstar-btn');
|
|
if (batchUnstarBtn) {
|
|
batchUnstarBtn.addEventListener('click', () => this.handleBatchUnstar());
|
|
}
|
|
}
|
|
|
|
async handleBatchUnstar() {
|
|
const totalSelected = this.selectedFiles.size + this.selectedFolders.size;
|
|
if (totalSelected === 0) return;
|
|
|
|
if (!confirm(`Unstar ${totalSelected} items?`)) return;
|
|
|
|
try {
|
|
for (const fileId of this.selectedFiles) {
|
|
await api.unstarFile(fileId);
|
|
}
|
|
for (const folderId of this.selectedFolders) {
|
|
await api.unstarFolder(folderId);
|
|
}
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
|
detail: { message: 'Items unstarred successfully!', type: 'success' }
|
|
}));
|
|
await this.loadStarredItems();
|
|
} catch (error) {
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
|
detail: { message: 'Failed to unstar items: ' + error.message, type: 'error' }
|
|
}));
|
|
}
|
|
}
|
|
|
|
async handleAction(action, id) {
|
|
try {
|
|
switch (action) {
|
|
case 'download':
|
|
const blob = await api.downloadFile(id);
|
|
const file = this.files.find(f => f.id === id);
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = file.name;
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
|
detail: { message: 'File downloaded successfully!', type: 'success' }
|
|
}));
|
|
break;
|
|
case 'unstar-file':
|
|
await api.unstarFile(id);
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
|
detail: { message: 'File unstarred successfully!', type: 'success' }
|
|
}));
|
|
await this.loadStarredItems();
|
|
break;
|
|
case 'unstar-folder':
|
|
await api.unstarFolder(id);
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
|
detail: { message: 'Folder unstarred successfully!', type: 'success' }
|
|
}));
|
|
await this.loadStarredItems();
|
|
break;
|
|
}
|
|
} catch (error) {
|
|
document.dispatchEvent(new CustomEvent('show-toast', {
|
|
detail: { message: 'Action failed: ' + error.message, type: 'error' }
|
|
}));
|
|
}
|
|
}
|
|
}
|
|
|
|
customElements.define('starred-items', StarredItems);
|