Dynamic dashboards: Deduplicate titles of new rows and tabs (#103330)
Deduplicate titles of new rows and tabs
This commit is contained in:
@@ -16,6 +16,7 @@ import { DefaultGridLayoutManager } from '../layout-default/DefaultGridLayoutMan
|
||||
import { RowRepeaterBehavior } from '../layout-default/RowRepeaterBehavior';
|
||||
import { TabsLayoutManager } from '../layout-tabs/TabsLayoutManager';
|
||||
import { getRowFromClipboard } from '../layouts-shared/paste';
|
||||
import { generateUniqueTitle } from '../layouts-shared/utils';
|
||||
import { DashboardLayoutManager } from '../types/DashboardLayoutManager';
|
||||
import { LayoutRegistryItem } from '../types/LayoutRegistryItem';
|
||||
|
||||
@@ -95,6 +96,13 @@ export class RowsLayoutManager extends SceneObjectBase<RowsLayoutManagerState> i
|
||||
|
||||
public addNewRow(row?: RowItem): RowItem {
|
||||
const newRow = row ?? new RowItem({ isNew: true });
|
||||
const existingNames = new Set(this.state.rows.map((row) => row.state.title).filter((title) => title !== undefined));
|
||||
|
||||
const newTitle = generateUniqueTitle(newRow.state.title, existingNames);
|
||||
if (newTitle !== newRow.state.title) {
|
||||
newRow.setState({ title: newTitle });
|
||||
}
|
||||
|
||||
this.setState({ rows: [...this.state.rows, newRow] });
|
||||
this.publishEvent(new NewObjectAddedToCanvasEvent(newRow), true);
|
||||
return newRow;
|
||||
|
||||
@@ -18,6 +18,7 @@ import { getDashboardSceneFor } from '../../utils/utils';
|
||||
import { RowItem } from '../layout-rows/RowItem';
|
||||
import { RowsLayoutManager } from '../layout-rows/RowsLayoutManager';
|
||||
import { getTabFromClipboard } from '../layouts-shared/paste';
|
||||
import { generateUniqueTitle } from '../layouts-shared/utils';
|
||||
import { DashboardLayoutManager } from '../types/DashboardLayoutManager';
|
||||
import { LayoutRegistryItem } from '../types/LayoutRegistryItem';
|
||||
|
||||
@@ -125,6 +126,12 @@ export class TabsLayoutManager extends SceneObjectBase<TabsLayoutManagerState> i
|
||||
|
||||
public addNewTab(tab?: TabItem) {
|
||||
const newTab = tab ?? new TabItem({ isNew: true });
|
||||
const existingNames = new Set(this.state.tabs.map((tab) => tab.state.title).filter((title) => title !== undefined));
|
||||
const newTitle = generateUniqueTitle(newTab.state.title, existingNames);
|
||||
if (newTitle !== newTab.state.title) {
|
||||
newTab.setState({ title: newTitle });
|
||||
}
|
||||
|
||||
this.setState({ tabs: [...this.state.tabs, newTab], currentTabIndex: this.state.tabs.length });
|
||||
this.publishEvent(new NewObjectAddedToCanvasEvent(newTab), true);
|
||||
return newTab;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
import { generateUniqueTitle } from './utils';
|
||||
|
||||
describe('generateUniqueTitle', () => {
|
||||
it('should return the original title if it is not in the existing titles', () => {
|
||||
const title = 'My Title';
|
||||
const existingTitles = new Set<string>(['Other Title', 'Another Title']);
|
||||
expect(generateUniqueTitle(title, existingTitles)).toBe(title);
|
||||
});
|
||||
|
||||
it('should handle undefined title by using empty string as base', () => {
|
||||
const existingTitles = new Set<string>(['Title 1', 'Title 2']);
|
||||
expect(generateUniqueTitle(undefined, existingTitles)).toBe('');
|
||||
});
|
||||
|
||||
it('should append "1" to a title that does not end with a number', () => {
|
||||
const title = 'My Title';
|
||||
const existingTitles = new Set<string>(['My Title']);
|
||||
expect(generateUniqueTitle(title, existingTitles)).toBe('My Title 1');
|
||||
});
|
||||
|
||||
it('should increment a number at the end of a title', () => {
|
||||
const title = 'My Title 1';
|
||||
const existingTitles = new Set<string>(['My Title 1', 'My Title 2']);
|
||||
expect(generateUniqueTitle(title, existingTitles)).toBe('My Title 3');
|
||||
});
|
||||
|
||||
it('should handle multiple increments when needed', () => {
|
||||
const title = 'My Title';
|
||||
const existingTitles = new Set<string>(['My Title', 'My Title 1', 'My Title 2', 'My Title 3']);
|
||||
expect(generateUniqueTitle(title, existingTitles)).toBe('My Title 4');
|
||||
});
|
||||
|
||||
it('should handle titles with multiple numbers', () => {
|
||||
const title = 'My Title 123';
|
||||
const existingTitles = new Set<string>(['My Title 123', 'My Title 124']);
|
||||
expect(generateUniqueTitle(title, existingTitles)).toBe('My Title 125');
|
||||
});
|
||||
|
||||
it('should handle titles with spaces before the number', () => {
|
||||
const title = 'My Title 1';
|
||||
const existingTitles = new Set<string>(['My Title 1', 'My Title 2']);
|
||||
expect(generateUniqueTitle(title, existingTitles)).toBe('My Title 3');
|
||||
});
|
||||
|
||||
it('should handle empty existing titles set', () => {
|
||||
const title = 'My Title';
|
||||
const existingTitles = new Set<string>();
|
||||
expect(generateUniqueTitle(title, existingTitles)).toBe(title);
|
||||
});
|
||||
});
|
||||
@@ -34,3 +34,35 @@ export function useEditPaneInputAutoFocus({ autoFocus }: EditPaneInputAutoFocusP
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
export function generateUniqueTitle(title: string | undefined, existingTitles: Set<string>): string {
|
||||
const baseTitle = title ?? '';
|
||||
|
||||
if (existingTitles.has(baseTitle)) {
|
||||
const titleMatch = baseTitle.match(/^(.*?)(\d+)$/);
|
||||
if (titleMatch) {
|
||||
// If title ends with a number, increment it
|
||||
const baseTitle = titleMatch[1];
|
||||
const currentNumber = parseInt(titleMatch[2], 10);
|
||||
let newTitle = `${baseTitle}${currentNumber + 1}`;
|
||||
|
||||
// Keep incrementing until we find an unused title
|
||||
while (existingTitles.has(newTitle)) {
|
||||
const nextNumber = parseInt(newTitle.match(/\d+$/)![0], 10) + 1;
|
||||
newTitle = `${baseTitle}${nextNumber}`;
|
||||
}
|
||||
return newTitle;
|
||||
} else {
|
||||
// If title doesn't end with a number, append "1"
|
||||
let i = 1;
|
||||
let newTitle = `${baseTitle} ${i}`;
|
||||
while (existingTitles.has(newTitle)) {
|
||||
i++;
|
||||
newTitle = `${baseTitle} ${i}`;
|
||||
}
|
||||
return newTitle;
|
||||
}
|
||||
}
|
||||
|
||||
return baseTitle;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user