Restore dashboards: Add sort by deleted date (#112648)

* Restore dashboards: Add sort by deleted date

* Use Date.parse
This commit is contained in:
Alex Khomenko
2025-10-22 08:25:14 +03:00
committed by GitHub
parent fcf7aa5e2f
commit 0098a68983
4 changed files with 47 additions and 7 deletions
+2
View File
@@ -27,6 +27,8 @@ export interface ObjectMeta {
generation?: number;
// The first time this was saved
creationTimestamp: string;
// The time this resource was marked for deletion
deletionTimestamp?: string;
// General resource annotations -- including the common grafana.app values
annotations?: GrafanaAnnotations & GrafanaClientAnnotations;
// General application level key+value pairs
@@ -70,7 +70,6 @@ export class TrashStateManager extends SearchStateManager {
}
};
// Only alphabetical sorting is supported for deleted dashboards
getSortOptions = async (): Promise<SelectableValue[]> => {
return Promise.resolve([
{
@@ -81,6 +80,14 @@ export class TrashStateManager extends SearchStateManager {
label: t('browse-dashboards.trash-state-manager.label.alphabetically-za', 'Alphabetically (Z–A)'),
value: 'alpha-desc',
},
{
label: t('browse-dashboards.trash-state-manager.label.deleted-oldest', 'Deleted (oldest first)'),
value: 'deleted-asc',
},
{
label: t('browse-dashboards.trash-state-manager.label.deleted-newest', 'Deleted (newest first)'),
value: 'deleted-desc',
},
]);
};
}
+34 -5
View File
@@ -124,6 +124,11 @@ export function queryResultToViewItem(
export function resourceToSearchResult(resource: ResourceList<DashboardDataDTO>): SearchHit[] {
return resource.items.map((item) => {
const field: Record<string, string | number> = {};
if (item.metadata.deletionTimestamp) {
field.deletionTimestamp = item.metadata.deletionTimestamp;
}
const hit = {
resource: 'dashboards',
name: item.metadata.name,
@@ -131,7 +136,7 @@ export function resourceToSearchResult(resource: ResourceList<DashboardDataDTO>)
location: 'general',
folder: item?.metadata?.annotations?.[AnnoKeyFolder] ?? 'general',
tags: item.spec?.tags || [],
field: {},
field,
url: '',
};
if (!hit.folder) {
@@ -165,7 +170,7 @@ export function searchHitsToDashboardSearchHits(searchHits: SearchHit[]): Dashbo
/**
* Filters search results based on query parameters
* This is used when backend filtering is not available (e.g., for deleted dashboards)
* Supports fuzzy search for tags and titles and alphabetical sorting
* Supports fuzzy search for tags and titles, alphabetical sorting, and deletion timestamp sorting
*/
export function filterSearchResults(
results: SearchHit[],
@@ -185,9 +190,33 @@ export function filterSearchResults(
}
if (query.sort) {
const collator = new Intl.Collator();
const mult = query.sort === 'alpha-desc' ? -1 : 1;
filtered.sort((a, b) => mult * collator.compare(a.title, b.title));
if (query.sort === 'deleted-asc' || query.sort === 'deleted-desc') {
const mult = query.sort === 'deleted-desc' ? -1 : 1;
filtered.sort((a, b) => {
const timestampA = a.field.deletionTimestamp;
const timestampB = b.field.deletionTimestamp;
// Handle missing or invalid timestamps - items without timestamps go to the end
if (typeof timestampA !== 'string' && typeof timestampB !== 'string') {
return 0;
}
if (typeof timestampA !== 'string') {
return 1;
}
if (typeof timestampB !== 'string') {
return -1;
}
const timeA = Date.parse(timestampA);
const timeB = Date.parse(timestampB);
return mult * (timeA - timeB);
});
} else {
// Alphabetical sorting
const collator = new Intl.Collator();
const mult = query.sort === 'alpha-desc' ? -1 : 1;
filtered.sort((a, b) => mult * collator.compare(a.title, b.title));
}
}
return filtered;
+3 -1
View File
@@ -3692,7 +3692,9 @@
"trash-state-manager": {
"label": {
"alphabetically-az": "Alphabetically (A–Z)",
"alphabetically-za": "Alphabetically (Z–A)"
"alphabetically-za": "Alphabetically (Z–A)",
"deleted-newest": "Deleted (newest first)",
"deleted-oldest": "Deleted (oldest first)"
}
}
},