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/config.js"></script>
<script src="src/js/generic-storage-ui.js"></script>
<script src="src/js/snippet-manager.js"></script>
<script src="src/js/dataset-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)
datasets.sort((a, b) => new Date(b.modified) - new Date(a.modified));
const html = datasets.map(dataset => {
const formatDatasetItem = (dataset) => {
let metaText;
if (dataset.source === 'url') {
// Show metadata if available, otherwise just URL and format
@@ -308,7 +308,7 @@ async function renderDatasetList() {
: '';
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-name">${dataset.name}</div>
<div class="dataset-meta">${metaText}</div>
@@ -316,14 +316,15 @@ async function renderDatasetList() {
${usageBadge}
</div>
`;
}).join('');
};
const html = datasets.map(formatDatasetItem).join('');
listContainer.innerHTML = html;
// Attach click handlers
document.querySelectorAll('.dataset-item').forEach(item => {
item.addEventListener('click', function() {
const datasetId = parseFloat(this.dataset.datasetId);
const datasetId = parseFloat(this.dataset.itemId);
selectDataset(datasetId);
});
});
@@ -338,7 +339,10 @@ async function selectDataset(datasetId, updateURL = true) {
document.querySelectorAll('.dataset-item').forEach(item => {
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
const detailsPanel = document.getElementById('dataset-details');
@@ -722,46 +726,28 @@ function showTablePreview(dataset) {
// Update linked snippets display in dataset details panel
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
const snippets = SnippetStorage.loadSnippets();
const linkedSnippets = snippets.filter(snippet =>
snippet.datasetRefs && snippet.datasetRefs.includes(dataset.name)
);
if (linkedSnippets.length === 0) {
snippetsSection.style.display = 'none';
return;
}
// Show section and populate with snippet links
snippetsSection.style.display = 'block';
const snippetItems = linkedSnippets.map(snippet => {
return `
updateGenericLinkedItems(
linkedSnippets,
'dataset-snippets',
'dataset-snippets-section',
(snippet) => `
<div class="stat-item">
<span class="stat-label">📄</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>
</div>
`;
}).join('');
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);
`,
(snippetId) => {
openSnippetFromDataset(snippetId);
});
});
}
);
}
// Close dataset manager and open snippet
@@ -1157,15 +1143,11 @@ async function deleteCurrentDataset() {
// Check if dataset is in use
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) {
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)) {
confirmGenericDeletion(dataset.name, warningMessage, async () => {
await DatasetStorage.deleteDataset(dataset.id);
document.getElementById('dataset-details').style.display = 'none';
window.currentDatasetId = null;
@@ -1175,8 +1157,8 @@ async function deleteCurrentDataset() {
Toast.success('Dataset deleted');
// Track event
Analytics.track('dataset-delete', 'Delete dataset');
}
trackEventIfAvailable('dataset-delete', 'Delete dataset');
});
}
// Copy dataset reference to clipboard

View File

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