mirror of
https://github.com/olehomelchenko/astrolabe-nvc.git
synced 2025-12-21 21:22:23 +00:00
refactor: enhance dataset management with auto-save functionality and improve dataset name editing process
This commit is contained in:
@@ -67,4 +67,5 @@ When implementing changes:
|
||||
- Pay attention to the existing code base style and approaches and try to adhere to the existing style instead of bringing your own vision.
|
||||
- When updating documentation, do not record intermediate changes - write them always as a matter-of-fact information.
|
||||
- When working on the code, if you notice any opportunities to better bring the project to the state above - bring this to user's attention and ask for approval to implement the suggested changes.
|
||||
- When attempting to implement a new feature, research whether a similar method or fuction already exists elsewhere. Propose to either enhance existing one, or create a new method in such cases.
|
||||
- Testing: The user always tests changes manually. Do not start local servers or attempt to run the application.
|
||||
|
||||
@@ -200,7 +200,7 @@
|
||||
<div class="dataset-details" id="dataset-details" style="display: none;">
|
||||
<div class="dataset-detail-section">
|
||||
<div class="dataset-actions">
|
||||
<button class="btn btn-modal primary" id="edit-dataset-btn" title="Edit this dataset">Edit</button>
|
||||
<button class="btn btn-modal primary" id="edit-dataset-btn" title="Edit this dataset contents">Edit Contents</button>
|
||||
<button class="btn btn-modal primary" id="new-snippet-btn" title="Create a new snippet using this dataset">New Snippet</button>
|
||||
<button class="btn btn-modal" id="export-dataset-btn" title="Export this dataset to file">Export</button>
|
||||
<button class="btn btn-modal" id="copy-reference-btn" title="Copy dataset reference to clipboard">Copy Reference</button>
|
||||
|
||||
@@ -35,6 +35,33 @@ function generateDatasetId() {
|
||||
return Date.now() + Math.random() * 1000;
|
||||
}
|
||||
|
||||
// Replace dataset name references in a Vega-Lite spec
|
||||
function replaceDatasetNameInSpec(spec, oldName, newName) {
|
||||
if (!spec || typeof spec !== 'object') return spec;
|
||||
|
||||
// Clone the spec to avoid mutation
|
||||
const newSpec = JSON.parse(JSON.stringify(spec));
|
||||
|
||||
// Recursively traverse and replace dataset name references
|
||||
(function traverse(obj) {
|
||||
if (!obj || typeof obj !== 'object') return;
|
||||
|
||||
// Check if this is a data object with a name property matching oldName
|
||||
if (obj.data && typeof obj.data === 'object' && obj.data.name === oldName) {
|
||||
obj.data.name = newName;
|
||||
}
|
||||
|
||||
// Recursively check all properties
|
||||
for (const key in obj) {
|
||||
if (obj.hasOwnProperty(key)) {
|
||||
traverse(obj[key]);
|
||||
}
|
||||
}
|
||||
})(newSpec);
|
||||
|
||||
return newSpec;
|
||||
}
|
||||
|
||||
// Calculate dataset statistics
|
||||
function calculateDatasetStats(data, format, source) {
|
||||
let rowCount = 0;
|
||||
@@ -465,6 +492,9 @@ async function selectDataset(datasetId, updateURL = true) {
|
||||
// Update linked snippets display
|
||||
updateLinkedSnippets(dataset);
|
||||
|
||||
// Initialize auto-save for detail fields
|
||||
initializeDatasetDetailAutoSave();
|
||||
|
||||
// Update URL state (URLState.update will add 'dataset-' prefix)
|
||||
if (updateURL) {
|
||||
URLState.update({ view: 'datasets', snippetId: null, datasetId: datasetId });
|
||||
@@ -1707,3 +1737,131 @@ async function importDatasetFromFile(fileInput) {
|
||||
fileInput.value = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Auto-save dataset metadata (name and comment)
|
||||
async function autoSaveDatasetMeta() {
|
||||
const nameField = document.getElementById('dataset-detail-name');
|
||||
const commentField = document.getElementById('dataset-detail-comment');
|
||||
if (!nameField || !commentField) return;
|
||||
|
||||
const dataset = await getCurrentDataset();
|
||||
if (!dataset) return;
|
||||
|
||||
const newName = nameField.value.trim();
|
||||
const newComment = commentField.value;
|
||||
|
||||
// Store old name for snippet reference updates
|
||||
const oldName = dataset.name;
|
||||
const nameChanged = newName !== dataset.name;
|
||||
|
||||
// Check if name has changed
|
||||
if (nameChanged) {
|
||||
// Validate name is not empty
|
||||
if (!newName) {
|
||||
Toast.error('Dataset name cannot be empty');
|
||||
nameField.value = dataset.name; // Restore previous value
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if new name already exists
|
||||
if (await DatasetStorage.nameExists(newName)) {
|
||||
Toast.error(`Dataset name "${newName}" already exists`);
|
||||
nameField.value = dataset.name; // Restore previous value
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if any snippets reference this dataset
|
||||
const snippets = SnippetStorage.loadSnippets();
|
||||
const affectedSnippets = snippets.filter(snippet =>
|
||||
snippet.datasetRefs && snippet.datasetRefs.includes(dataset.name)
|
||||
);
|
||||
|
||||
// Show warning if there are affected snippets
|
||||
if (affectedSnippets.length > 0) {
|
||||
const confirmed = confirm(
|
||||
`⚠️ Warning: Renaming this dataset will update ${affectedSnippets.length} snippet${affectedSnippets.length > 1 ? 's' : ''} that reference it.\n\n` +
|
||||
`We'll attempt to update all references automatically, but complex specs with nested data sources may require manual review.\n\n` +
|
||||
`Affected snippets:\n${affectedSnippets.map(s => `• ${s.name}`).join('\n')}\n\n` +
|
||||
`Continue with rename?`
|
||||
);
|
||||
|
||||
if (!confirmed) {
|
||||
nameField.value = dataset.name; // Restore previous value
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update dataset
|
||||
const updatedDataset = await DatasetStorage.updateDataset(dataset.id, {
|
||||
name: newName || dataset.name,
|
||||
comment: newComment
|
||||
});
|
||||
|
||||
// If name changed, update all snippets that reference this dataset
|
||||
if (nameChanged && newName) {
|
||||
const snippets = SnippetStorage.loadSnippets();
|
||||
const affectedSnippets = snippets.filter(snippet =>
|
||||
snippet.datasetRefs && snippet.datasetRefs.includes(oldName)
|
||||
);
|
||||
|
||||
affectedSnippets.forEach(snippet => {
|
||||
// Update spec and draftSpec by replacing dataset name references
|
||||
snippet.spec = replaceDatasetNameInSpec(snippet.spec, oldName, newName);
|
||||
snippet.draftSpec = replaceDatasetNameInSpec(snippet.draftSpec, oldName, newName);
|
||||
|
||||
// Re-extract dataset references from updated specs
|
||||
// extractDatasetRefs is a global function from snippet-manager.js
|
||||
if (typeof extractDatasetRefs === 'function') {
|
||||
snippet.datasetRefs = extractDatasetRefs(snippet.spec);
|
||||
}
|
||||
|
||||
SnippetStorage.saveSnippet(snippet);
|
||||
});
|
||||
|
||||
// Show success message
|
||||
if (affectedSnippets.length > 0) {
|
||||
Toast.success(`Updated ${affectedSnippets.length} snippet${affectedSnippets.length > 1 ? 's' : ''}`);
|
||||
}
|
||||
|
||||
// Refresh linked snippets display
|
||||
updateLinkedSnippets(updatedDataset);
|
||||
}
|
||||
|
||||
// Update the modified timestamp in the UI
|
||||
document.getElementById('dataset-detail-modified').textContent = new Date(updatedDataset.modified).toLocaleString();
|
||||
|
||||
// Update the dataset list display to reflect the new name
|
||||
await renderDatasetList();
|
||||
|
||||
// Restore selection after re-render
|
||||
const selectedItem = document.querySelector(`[data-item-id="${dataset.id}"]`);
|
||||
if (selectedItem) {
|
||||
selectedItem.classList.add('selected');
|
||||
}
|
||||
}
|
||||
|
||||
// Debounced auto-save for dataset metadata
|
||||
let datasetMetaAutoSaveTimeout;
|
||||
function debouncedAutoSaveDatasetMeta() {
|
||||
clearTimeout(datasetMetaAutoSaveTimeout);
|
||||
datasetMetaAutoSaveTimeout = setTimeout(autoSaveDatasetMeta, 1000);
|
||||
}
|
||||
|
||||
// Initialize auto-save for dataset detail fields
|
||||
function initializeDatasetDetailAutoSave() {
|
||||
const nameField = document.getElementById('dataset-detail-name');
|
||||
const commentField = document.getElementById('dataset-detail-comment');
|
||||
|
||||
if (nameField) {
|
||||
// Remove any existing event listener to prevent duplicates
|
||||
nameField.removeEventListener('input', debouncedAutoSaveDatasetMeta);
|
||||
nameField.addEventListener('input', debouncedAutoSaveDatasetMeta);
|
||||
}
|
||||
|
||||
if (commentField) {
|
||||
// Remove any existing event listener to prevent duplicates
|
||||
commentField.removeEventListener('input', debouncedAutoSaveDatasetMeta);
|
||||
commentField.addEventListener('input', debouncedAutoSaveDatasetMeta);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user