feat: integrate generic storage UI and refactor dataset/snippet item handling

This commit is contained in:
2025-10-18 01:49:30 +03:00
parent 9dd681d4f7
commit c84b1fdcfb
3 changed files with 53 additions and 85 deletions

View File

@@ -700,6 +700,7 @@
<script src="src/js/user-settings.js"></script> <script src="src/js/user-settings.js"></script>
<script src="src/js/config.js"></script> <script src="src/js/config.js"></script>
<script src="src/js/generic-storage-ui.js"></script>
<script src="src/js/snippet-manager.js"></script> <script src="src/js/snippet-manager.js"></script>
<script src="src/js/dataset-manager.js"></script> <script src="src/js/dataset-manager.js"></script>
<script src="src/js/panel-manager.js"></script> <script src="src/js/panel-manager.js"></script>

View File

@@ -288,7 +288,7 @@ async function renderDatasetList() {
// Sort by modified date (most recent first) // Sort by modified date (most recent first)
datasets.sort((a, b) => new Date(b.modified) - new Date(a.modified)); datasets.sort((a, b) => new Date(b.modified) - new Date(a.modified));
const html = datasets.map(dataset => { const formatDatasetItem = (dataset) => {
let metaText; let metaText;
if (dataset.source === 'url') { if (dataset.source === 'url') {
// Show metadata if available, otherwise just URL and format // Show metadata if available, otherwise just URL and format
@@ -308,7 +308,7 @@ async function renderDatasetList() {
: ''; : '';
return ` return `
<div class="dataset-item" data-dataset-id="${dataset.id}"> <div class="dataset-item" data-item-id="${dataset.id}">
<div class="dataset-info"> <div class="dataset-info">
<div class="dataset-name">${dataset.name}</div> <div class="dataset-name">${dataset.name}</div>
<div class="dataset-meta">${metaText}</div> <div class="dataset-meta">${metaText}</div>
@@ -316,14 +316,15 @@ async function renderDatasetList() {
${usageBadge} ${usageBadge}
</div> </div>
`; `;
}).join(''); };
const html = datasets.map(formatDatasetItem).join('');
listContainer.innerHTML = html; listContainer.innerHTML = html;
// Attach click handlers // Attach click handlers
document.querySelectorAll('.dataset-item').forEach(item => { document.querySelectorAll('.dataset-item').forEach(item => {
item.addEventListener('click', function() { item.addEventListener('click', function() {
const datasetId = parseFloat(this.dataset.datasetId); const datasetId = parseFloat(this.dataset.itemId);
selectDataset(datasetId); selectDataset(datasetId);
}); });
}); });
@@ -338,7 +339,10 @@ async function selectDataset(datasetId, updateURL = true) {
document.querySelectorAll('.dataset-item').forEach(item => { document.querySelectorAll('.dataset-item').forEach(item => {
item.classList.remove('selected'); item.classList.remove('selected');
}); });
document.querySelector(`[data-dataset-id="${datasetId}"]`).classList.add('selected'); const selectedItem = document.querySelector(`[data-item-id="${datasetId}"]`);
if (selectedItem) {
selectedItem.classList.add('selected');
}
// Show details panel // Show details panel
const detailsPanel = document.getElementById('dataset-details'); const detailsPanel = document.getElementById('dataset-details');
@@ -722,46 +726,28 @@ function showTablePreview(dataset) {
// Update linked snippets display in dataset details panel // Update linked snippets display in dataset details panel
function updateLinkedSnippets(dataset) { function updateLinkedSnippets(dataset) {
const snippetsSection = document.getElementById('dataset-snippets-section');
const snippetsContainer = document.getElementById('dataset-snippets');
if (!snippetsSection || !snippetsContainer) return;
// Find all snippets that reference this dataset // Find all snippets that reference this dataset
const snippets = SnippetStorage.loadSnippets(); const snippets = SnippetStorage.loadSnippets();
const linkedSnippets = snippets.filter(snippet => const linkedSnippets = snippets.filter(snippet =>
snippet.datasetRefs && snippet.datasetRefs.includes(dataset.name) snippet.datasetRefs && snippet.datasetRefs.includes(dataset.name)
); );
if (linkedSnippets.length === 0) { updateGenericLinkedItems(
snippetsSection.style.display = 'none'; linkedSnippets,
return; 'dataset-snippets',
} 'dataset-snippets-section',
(snippet) => `
// Show section and populate with snippet links
snippetsSection.style.display = 'block';
const snippetItems = linkedSnippets.map(snippet => {
return `
<div class="stat-item"> <div class="stat-item">
<span class="stat-label">📄</span> <span class="stat-label">📄</span>
<span> <span>
<a href="#" class="snippet-link" data-snippet-id="${snippet.id}">${snippet.name}</a> <a href="#" class="snippet-link" data-linked-item-id="${snippet.id}">${snippet.name}</a>
</span> </span>
</div> </div>
`; `,
}).join(''); (snippetId) => {
snippetsContainer.innerHTML = snippetItems;
// Attach click handlers to snippet links
snippetsContainer.querySelectorAll('.snippet-link').forEach(link => {
link.addEventListener('click', function(e) {
e.preventDefault();
const snippetId = parseFloat(this.dataset.snippetId);
openSnippetFromDataset(snippetId); openSnippetFromDataset(snippetId);
}); }
}); );
} }
// Close dataset manager and open snippet // Close dataset manager and open snippet
@@ -1157,15 +1143,11 @@ async function deleteCurrentDataset() {
// Check if dataset is in use // Check if dataset is in use
const usageCount = countSnippetUsage(dataset.name); const usageCount = countSnippetUsage(dataset.name);
let confirmMessage = `Delete dataset "${dataset.name}"?`; const warningMessage = usageCount > 0
? `⚠️ Warning: Dataset "${dataset.name}" is currently used by ${usageCount} snippet${usageCount !== 1 ? 's' : ''}.\n\nDeleting this dataset will break those visualizations.`
: null;
if (usageCount > 0) { confirmGenericDeletion(dataset.name, warningMessage, async () => {
confirmMessage = `⚠️ Warning: Dataset "${dataset.name}" is currently used by ${usageCount} snippet${usageCount !== 1 ? 's' : ''}.\n\nDeleting this dataset will break those visualizations. Are you sure you want to delete it?`;
} else {
confirmMessage += ' This action cannot be undone.';
}
if (confirm(confirmMessage)) {
await DatasetStorage.deleteDataset(dataset.id); await DatasetStorage.deleteDataset(dataset.id);
document.getElementById('dataset-details').style.display = 'none'; document.getElementById('dataset-details').style.display = 'none';
window.currentDatasetId = null; window.currentDatasetId = null;
@@ -1175,8 +1157,8 @@ async function deleteCurrentDataset() {
Toast.success('Dataset deleted'); Toast.success('Dataset deleted');
// Track event // Track event
Analytics.track('dataset-delete', 'Delete dataset'); trackEventIfAvailable('dataset-delete', 'Delete dataset');
} });
} }
// Copy dataset reference to clipboard // Copy dataset reference to clipboard

View File

@@ -341,7 +341,9 @@ function renderSnippetList(searchQuery = null) {
`; `;
const currentSort = AppSettings.get('sortBy'); const currentSort = AppSettings.get('sortBy');
const snippetItems = snippets.map(snippet => {
// Use generic formatter
const formatSnippetItem = (snippet) => {
// Show appropriate date based on current sort // Show appropriate date based on current sort
let dateText; let dateText;
if (currentSort === 'created') { if (currentSort === 'created') {
@@ -364,7 +366,7 @@ function renderSnippetList(searchQuery = null) {
const datasetIconHTML = usesDatasets ? '<span class="snippet-dataset-icon" title="Uses external dataset">📁</span>' : ''; const datasetIconHTML = usesDatasets ? '<span class="snippet-dataset-icon" title="Uses external dataset">📁</span>' : '';
return ` return `
<li class="snippet-item" data-snippet-id="${snippet.id}"> <li class="snippet-item" data-item-id="${snippet.id}">
<div class="snippet-info"> <div class="snippet-info">
<div class="snippet-name">${snippet.name}${datasetIconHTML}</div> <div class="snippet-name">${snippet.name}${datasetIconHTML}</div>
<div class="snippet-date">${dateText}</div> <div class="snippet-date">${dateText}</div>
@@ -373,8 +375,9 @@ function renderSnippetList(searchQuery = null) {
<div class="snippet-status ${statusClass}"></div> <div class="snippet-status ${statusClass}"></div>
</li> </li>
`; `;
}).join(''); };
const snippetItems = snippets.map(formatSnippetItem).join('');
snippetList.innerHTML = ghostCard + snippetItems; snippetList.innerHTML = ghostCard + snippetItems;
// Re-attach event listeners for snippet selection // Re-attach event listeners for snippet selection
@@ -484,7 +487,7 @@ function performSearch() {
// Clear selection if current snippet is no longer visible // Clear selection if current snippet is no longer visible
if (window.currentSnippetId) { if (window.currentSnippetId) {
const selectedItem = document.querySelector(`[data-snippet-id="${window.currentSnippetId}"]`); const selectedItem = document.querySelector(`[data-item-id="${window.currentSnippetId}"]`);
if (!selectedItem) { if (!selectedItem) {
clearSelection(); clearSelection();
} else { } else {
@@ -522,7 +525,7 @@ function getCurrentSnippet() {
// Helper: Restore visual selection state for current snippet // Helper: Restore visual selection state for current snippet
function restoreSnippetSelection() { function restoreSnippetSelection() {
if (window.currentSnippetId) { if (window.currentSnippetId) {
const item = document.querySelector(`[data-snippet-id="${window.currentSnippetId}"]`); const item = document.querySelector(`[data-item-id="${window.currentSnippetId}"]`);
if (item) { if (item) {
item.classList.add('selected'); item.classList.add('selected');
return item; return item;
@@ -569,7 +572,7 @@ function attachSnippetEventListeners() {
// Left click to select // Left click to select
item.addEventListener('click', function () { item.addEventListener('click', function () {
const snippetId = parseFloat(this.dataset.snippetId); const snippetId = parseFloat(this.dataset.itemId);
selectSnippet(snippetId); selectSnippet(snippetId);
}); });
}); });
@@ -584,7 +587,10 @@ function selectSnippet(snippetId, updateURL = true) {
document.querySelectorAll('.snippet-item').forEach(item => { document.querySelectorAll('.snippet-item').forEach(item => {
item.classList.remove('selected'); item.classList.remove('selected');
}); });
document.querySelector(`[data-snippet-id="${snippetId}"]`).classList.add('selected'); const selectedItem = document.querySelector(`[data-item-id="${snippetId}"]`);
if (selectedItem) {
selectedItem.classList.add('selected');
}
// Load spec based on current view mode // Load spec based on current view mode
loadSnippetIntoEditor(snippet); loadSnippetIntoEditor(snippet);
@@ -631,43 +637,24 @@ function selectSnippet(snippetId, updateURL = true) {
// Update linked datasets display in metadata panel // Update linked datasets display in metadata panel
function updateLinkedDatasets(snippet) { function updateLinkedDatasets(snippet) {
const datasetsSection = document.getElementById('snippet-datasets-section');
const datasetsContainer = document.getElementById('snippet-datasets');
if (!datasetsSection || !datasetsContainer) return;
// Get dataset references from snippet
const datasetRefs = snippet.datasetRefs || []; const datasetRefs = snippet.datasetRefs || [];
if (datasetRefs.length === 0) { updateGenericLinkedItems(
datasetsSection.style.display = 'none'; datasetRefs,
return; 'snippet-datasets',
} 'snippet-datasets-section',
(datasetName) => `
// Show section and populate with dataset references
datasetsSection.style.display = 'block';
const datasetItems = datasetRefs.map(datasetName => {
return `
<div class="meta-info-item"> <div class="meta-info-item">
<span class="meta-info-label">📁</span> <span class="meta-info-label">📁</span>
<span class="meta-info-value"> <span class="meta-info-value">
<a href="#" class="dataset-link" data-dataset-name="${datasetName}">${datasetName}</a> <a href="#" class="dataset-link" data-linked-item-id="${datasetName}">${datasetName}</a>
</span> </span>
</div> </div>
`; `,
}).join(''); async (datasetName) => {
datasetsContainer.innerHTML = datasetItems;
// Attach click handlers to dataset links
datasetsContainer.querySelectorAll('.dataset-link').forEach(link => {
link.addEventListener('click', async function(e) {
e.preventDefault();
const datasetName = this.dataset.datasetName;
await openDatasetByName(datasetName); await openDatasetByName(datasetName);
}); }
}); );
} }
// Open dataset manager and select dataset by name // Open dataset manager and select dataset by name
@@ -1048,7 +1035,7 @@ function deleteSnippet(snippetId) {
const snippet = SnippetStorage.getSnippet(snippetId); const snippet = SnippetStorage.getSnippet(snippetId);
if (!snippet) return; if (!snippet) return;
if (confirm(`Delete snippet "${snippet.name}"? This action cannot be undone.`)) { const confirmed = confirmGenericDeletion(snippet.name, null, () => {
SnippetStorage.deleteSnippet(snippetId); SnippetStorage.deleteSnippet(snippetId);
// If we deleted the currently selected snippet, clear selection // If we deleted the currently selected snippet, clear selection
@@ -1063,12 +1050,10 @@ function deleteSnippet(snippetId) {
Toast.success('Snippet deleted'); Toast.success('Snippet deleted');
// Track event // Track event
Analytics.track('snippet-delete', 'Delete snippet'); trackEventIfAvailable('snippet-delete', 'Delete snippet');
});
return true; return confirmed;
}
return false;
} }
// Load snippet into editor based on view mode // Load snippet into editor based on view mode