diff --git a/src/dashboard/Data/Views/EditViewDialog.react.js b/src/dashboard/Data/Views/EditViewDialog.react.js index 84f3fe317..1186b6ae4 100644 --- a/src/dashboard/Data/Views/EditViewDialog.react.js +++ b/src/dashboard/Data/Views/EditViewDialog.react.js @@ -30,6 +30,7 @@ export default class EditViewDialog extends React.Component { } this.state = { + id: view.id, // Preserve the view ID name: view.name || '', className: view.className || '', dataSourceType, @@ -73,6 +74,7 @@ export default class EditViewDialog extends React.Component { onCancel={onCancel} onConfirm={() => onConfirm({ + id: this.state.id, // Preserve the view ID name: this.state.name, className: this.state.dataSourceType === 'query' ? this.state.className : null, query: this.state.dataSourceType === 'query' ? JSON.parse(this.state.query) : null, diff --git a/src/dashboard/Data/Views/Views.react.js b/src/dashboard/Data/Views/Views.react.js index ebb1282a8..a7cd42ff4 100644 --- a/src/dashboard/Data/Views/Views.react.js +++ b/src/dashboard/Data/Views/Views.react.js @@ -721,8 +721,13 @@ class Views extends TableView { classes={classNames} onCancel={() => this.setState({ showCreate: false })} onConfirm={view => { + // Generate UUID for new view + const newView = { + ...view, + id: this.viewPreferencesManager.generateViewId() + }; this.setState( - state => ({ showCreate: false, views: [...state.views, view] }), + state => ({ showCreate: false, views: [...state.views, newView] }), async () => { if (this.viewPreferencesManager) { try { diff --git a/src/lib/ViewPreferencesManager.js b/src/lib/ViewPreferencesManager.js index 27558851a..5822deb85 100644 --- a/src/lib/ViewPreferencesManager.js +++ b/src/lib/ViewPreferencesManager.js @@ -183,7 +183,7 @@ export default class ViewPreferencesManager { ); // Delete views that are no longer in the new views array - const newViewIds = views.map(view => view.id || this._generateViewId(view)); + const newViewIds = views.map(view => view.id || this._generateViewId()); const viewsToDelete = existingViewIds.filter(id => !newViewIds.includes(id)); await Promise.all( @@ -195,7 +195,7 @@ export default class ViewPreferencesManager { // Save or update current views await Promise.all( views.map(view => { - const viewId = view.id || this._generateViewId(view); + const viewId = view.id || this._generateViewId(); const viewConfig = { ...view }; delete viewConfig.id; // Don't store ID in the config itself @@ -263,18 +263,19 @@ export default class ViewPreferencesManager { } /** - * Generates a unique ID for a view + * Generates a unique ID for a new view + * @returns {string} A UUID string + */ + generateViewId() { + return this._generateViewId(); + } + + /** + * Generates a unique ID for a view using UUID * @private */ - _generateViewId(view) { - if (view.id) { - return view.id; - } - // Generate a unique ID based on view name, timestamp, and random component - const timestamp = Date.now().toString(36); - const random = Math.random().toString(36).substr(2, 5); - const nameHash = view.name ? view.name.replace(/[^a-zA-Z0-9]/g, '').toLowerCase() : 'view'; - return `${nameHash}_${timestamp}_${random}`; + _generateViewId() { + return crypto.randomUUID(); } }