history UI

This commit is contained in:
Ryan McKinley
2024-06-27 12:08:46 +03:00
parent 1043efe3db
commit 2fab168fb1
6 changed files with 57 additions and 45 deletions
@@ -11,17 +11,17 @@ import { getDashboardSceneFor } from '../utils/utils';
import { DashboardEditView, DashboardEditViewState, useDashboardEditPageNav } from './utils';
import {
RevisionsModel,
VersionHistoryComparison,
VersionHistoryHeader,
VersionHistoryTable,
VersionsHistoryButtons,
historySrv,
} from './version-history';
import { VersionModel, getHistorySrv } from './version-history/HistorySrv';
export const VERSIONS_FETCH_LIMIT = 10;
export type DecoratedRevisionModel = RevisionsModel & {
export type DecoratedRevisionModel = VersionModel & {
checked: boolean;
createdDateString: string;
ageString: string;
};
@@ -102,7 +102,7 @@ export class VersionsEditView extends SceneObjectBase<VersionsEditViewState> imp
this.setState({ isAppending: append });
historySrv
getHistorySrv()
.getHistoryList(uid, { limit: this._limit, start: this._start })
.then((result) => {
this.setState({
@@ -128,8 +128,8 @@ export class VersionsEditView extends SceneObjectBase<VersionsEditViewState> imp
return;
}
const lhs = await historySrv.getDashboardVersion(this._dashboard.state.uid, baseInfo.version);
const rhs = await historySrv.getDashboardVersion(this._dashboard.state.uid, newInfo.version);
const lhs = await getHistorySrv().getDashboardVersion(this._dashboard.state.uid, baseInfo.version);
const rhs = await getHistorySrv().getDashboardVersion(this._dashboard.state.uid, newInfo.version);
this.setState({
baseInfo,
@@ -138,8 +138,8 @@ export class VersionsEditView extends SceneObjectBase<VersionsEditViewState> imp
newInfo,
viewMode: 'compare',
diffData: {
lhs: lhs.data,
rhs: rhs.data,
lhs: JSON.stringify(lhs),
rhs: JSON.stringify(rhs),
},
});
};
@@ -158,15 +158,15 @@ export class VersionsEditView extends SceneObjectBase<VersionsEditViewState> imp
});
};
public onCheck = (ev: React.FormEvent<HTMLInputElement>, versionId: number) => {
public onCheck = (ev: React.FormEvent<HTMLInputElement>, versionId: number|string) => {
this.setState({
versions: this.versions.map((version) =>
version.id === versionId ? { ...version, checked: ev.currentTarget.checked } : version
version.version === versionId ? { ...version, checked: ev.currentTarget.checked } : version
),
});
};
private decorateVersions(versions: RevisionsModel[]): DecoratedRevisionModel[] {
private decorateVersions(versions: VersionModel[]): DecoratedRevisionModel[] {
const timeZone = this.getTimeRange().getTimeZone();
return versions.map((version) => {
@@ -1,6 +1,6 @@
import { createDashboardModelFixture } from 'app/features/dashboard/state/__fixtures__/dashboardFixtures';
import { HistorySrv } from './HistorySrv';
import { getHistorySrv } from './HistorySrv';
import { restore, versions } from './__mocks__/dashboardHistoryMocks';
const getMock = jest.fn().mockResolvedValue({});
@@ -27,7 +27,7 @@ describe('historySrv', () => {
const versionsResponse = versions();
const restoreResponse = restore;
let historySrv = new HistorySrv();
let historySrv = getHistorySrv();
const dash = createDashboardModelFixture({ uid: '_U4zObQMz' });
const emptyDash = createDashboardModelFixture();
@@ -40,7 +40,7 @@ describe('historySrv', () => {
describe('getHistoryList', () => {
it('should return a versions array for the given dashboard id', () => {
getMock.mockImplementation(() => Promise.resolve(versionsResponse));
historySrv = new HistorySrv();
historySrv = getHistorySrv();
return historySrv.getHistoryList(dash.uid, historyListOpts).then((versions) => {
expect(versions).toEqual(versionsResponse);
@@ -63,7 +63,7 @@ describe('historySrv', () => {
describe('getDashboardVersion', () => {
it('should return a version object for the given dashboard id and version', () => {
getMock.mockImplementation(() => Promise.resolve(versionsResponse[0]));
historySrv = new HistorySrv();
historySrv = getHistorySrv();
return historySrv.getDashboardVersion(dash.uid, 4).then((version) => {
expect(version).toEqual(versionsResponse[0]);
@@ -71,7 +71,7 @@ describe('historySrv', () => {
});
it('should return an empty object when not given an id', async () => {
historySrv = new HistorySrv();
historySrv = getHistorySrv();
const rsp = await historySrv.getDashboardVersion(emptyDash.uid, 6);
expect(rsp).toEqual({});
@@ -82,14 +82,14 @@ describe('historySrv', () => {
it('should return a success response given valid parameters', () => {
const version = 6;
postMock.mockImplementation(() => Promise.resolve(restoreResponse(version)));
historySrv = new HistorySrv();
historySrv = getHistorySrv();
return historySrv.restoreDashboard(dash.uid, version).then((response) => {
expect(response).toEqual(restoreResponse(version));
});
});
it('should return an empty object when not given an id', async () => {
historySrv = new HistorySrv();
historySrv = getHistorySrv();
const rsp = await historySrv.restoreDashboard(emptyDash.uid, 6);
expect(rsp).toEqual({});
});
@@ -1,43 +1,48 @@
import { getBackendSrv } from '@grafana/runtime';
import { Dashboard } from '@grafana/schema';
import { SaveDashboardResponseDTO } from 'app/types';
export interface HistoryListOpts {
limit: number;
start: number;
}
export interface RevisionsModel {
id: number;
checked: boolean;
// The raw version from
export interface VersionModel {
uid: string;
parentVersion: number;
version: number;
created: Date;
version: number | string; // resourceVersion in k8s
created: string;
createdBy: string;
message: string;
data: Dashboard;
}
export class HistorySrv {
export interface HistorySrv {
getHistoryList(dashboardUID: string, options: HistoryListOpts): Promise<VersionModel[]>;
getDashboardVersion(dashboardUID: string, version: number | string): Promise<Dashboard>; // Just the spec (for now)
restoreDashboard(dashboardUID: string, version: number | string): Promise<SaveDashboardResponseDTO>;
}
class LegacyHistorySrv implements HistorySrv {
getHistoryList(dashboardUID: string, options: HistoryListOpts) {
if (typeof dashboardUID !== 'string') {
return Promise.resolve([]);
}
return getBackendSrv().get(`api/dashboards/uid/${dashboardUID}/versions`, options);
return getBackendSrv().get<VersionModel[]>(`api/dashboards/uid/${dashboardUID}/versions`, options);
}
getDashboardVersion(dashboardUID: string, version: number) {
async getDashboardVersion(dashboardUID: string, version: number): Promise<Dashboard> {
if (typeof dashboardUID !== 'string') {
return Promise.resolve({});
return Promise.reject('invalid uid')
}
return getBackendSrv().get(`api/dashboards/uid/${dashboardUID}/versions/${version}`);
const info = await getBackendSrv().get(`api/dashboards/uid/${dashboardUID}/versions/${version}`);
return info.data; // the dashboard body
}
restoreDashboard(dashboardUID: string, version: number) {
restoreDashboard(dashboardUID: string, version: number): Promise<SaveDashboardResponseDTO> {
if (typeof dashboardUID !== 'string') {
return Promise.resolve({});
return Promise.reject('invalid uid')
}
const url = `api/dashboards/uid/${dashboardUID}/restore`;
@@ -46,5 +51,12 @@ export class HistorySrv {
}
}
const historySrv = new HistorySrv();
export { historySrv };
let historySrv: HistorySrv|undefined = undefined;
export function getHistorySrv(): HistorySrv {
if (!historySrv) {
historySrv = new LegacyHistorySrv()
}
return historySrv
}
@@ -6,8 +6,8 @@ import { Icon, IconButton, useStyles2 } from '@grafana/ui';
type VersionHistoryHeaderProps = {
onClick?: () => void;
baseVersion?: number;
newVersion?: number;
baseVersion?: number | string;
newVersion?: number | string;
isNewLatest?: boolean;
};
@@ -11,7 +11,7 @@ import { RevertDashboardModal } from './RevertDashboardModal';
type VersionsTableProps = {
versions: DecoratedRevisionModel[];
canCompare: boolean;
onCheck: (ev: React.FormEvent<HTMLInputElement>, versionId: number) => void;
onCheck: (ev: React.FormEvent<HTMLInputElement>, versionId: number | string) => void;
onRestore: (version: DecoratedRevisionModel) => Promise<boolean>;
};
@@ -33,7 +33,7 @@ export const VersionHistoryTable = ({ versions, canCompare, onCheck, onRestore }
</thead>
<tbody>
{versions.map((version, idx) => (
<tr key={version.id}>
<tr key={version.version}>
<td>
<Checkbox
aria-label={`Toggle selection of version ${version.version}`}
@@ -41,7 +41,7 @@ export const VersionHistoryTable = ({ versions, canCompare, onCheck, onRestore }
display: 'inline',
})}
checked={version.checked}
onChange={(ev) => onCheck(ev, version.id)}
onChange={(ev) => onCheck(ev, version.version)}
disabled={!version.checked && canCompare}
/>
</td>
@@ -4,11 +4,11 @@ import * as React from 'react';
import { Spinner, HorizontalGroup } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import {
historySrv,
RevisionsModel,
VersionHistoryHeader,
VersionsHistoryButtons,
} from 'app/features/dashboard-scene/settings/version-history';
import { getHistorySrv } from 'app/features/dashboard-scene/settings/version-history/HistorySrv';
import { VersionHistoryComparison } from '../VersionHistory/VersionHistoryComparison';
import { VersionHistoryTable } from '../VersionHistory/VersionHistoryTable';
@@ -62,7 +62,7 @@ export class VersionsSettings extends PureComponent<Props, State> {
getVersions = (append = false) => {
this.setState({ isAppending: append });
historySrv
getHistorySrv()
.getHistoryList(this.props.dashboard.uid, { limit: this.limit, start: this.start })
.then((res) => {
this.setState({
@@ -84,8 +84,8 @@ export class VersionsSettings extends PureComponent<Props, State> {
isLoading: true,
});
const lhs = await historySrv.getDashboardVersion(this.props.dashboard.uid, baseInfo.version);
const rhs = await historySrv.getDashboardVersion(this.props.dashboard.uid, newInfo.version);
const lhs = await getHistorySrv().getDashboardVersion(this.props.dashboard.uid, baseInfo.version);
const rhs = await getHistorySrv().getDashboardVersion(this.props.dashboard.uid, newInfo.version);
this.setState({
baseInfo,
@@ -94,8 +94,8 @@ export class VersionsSettings extends PureComponent<Props, State> {
newInfo,
viewMode: 'compare',
diffData: {
lhs: lhs.data,
rhs: rhs.data,
lhs: JSON.stringify(lhs),
rhs: JSON.stringify(rhs),
},
});
};