268 lines
7.6 KiB
TypeScript
268 lines
7.6 KiB
TypeScript
import * as React from 'react';
|
|
|
|
import { PageLayoutType, dateTimeFormat, dateTimeFormatTimeAgo } from '@grafana/data';
|
|
import { config } from '@grafana/runtime';
|
|
import { SceneComponentProps, SceneObjectBase, sceneGraph } from '@grafana/scenes';
|
|
import { Spinner, Stack } from '@grafana/ui';
|
|
import { Page } from 'app/core/components/Page/Page';
|
|
|
|
import { DashboardScene } from '../scene/DashboardScene';
|
|
import { NavToolbarActions } from '../scene/NavToolbarActions';
|
|
import { getDashboardSceneFor } from '../utils/utils';
|
|
|
|
import { DashboardEditView, DashboardEditViewState, useDashboardEditPageNav } from './utils';
|
|
import {
|
|
RevisionsModel,
|
|
VersionHistoryComparison,
|
|
VersionHistoryHeader,
|
|
VersionHistoryTable,
|
|
VersionsHistoryButtons,
|
|
historySrv,
|
|
} from './version-history';
|
|
|
|
export const VERSIONS_FETCH_LIMIT = 10;
|
|
|
|
export type DecoratedRevisionModel = RevisionsModel & {
|
|
createdDateString: string;
|
|
ageString: string;
|
|
};
|
|
|
|
export interface VersionsEditViewState extends DashboardEditViewState {
|
|
versions?: DecoratedRevisionModel[];
|
|
isLoading?: boolean;
|
|
isAppending?: boolean;
|
|
viewMode?: 'list' | 'compare';
|
|
diffData?: { lhs: string; rhs: string };
|
|
newInfo?: DecoratedRevisionModel;
|
|
baseInfo?: DecoratedRevisionModel;
|
|
isNewLatest?: boolean;
|
|
}
|
|
|
|
export class VersionsEditView extends SceneObjectBase<VersionsEditViewState> implements DashboardEditView {
|
|
public static Component = VersionsEditorSettingsListView;
|
|
private _limit: number = VERSIONS_FETCH_LIMIT;
|
|
private _start = 0;
|
|
private _continueToken = '';
|
|
|
|
constructor(state: VersionsEditViewState) {
|
|
super({
|
|
...state,
|
|
versions: [],
|
|
isLoading: true,
|
|
isAppending: true,
|
|
viewMode: 'list',
|
|
isNewLatest: false,
|
|
diffData: {
|
|
lhs: '',
|
|
rhs: '',
|
|
},
|
|
});
|
|
|
|
this.addActivationHandler(() => {
|
|
this.fetchVersions();
|
|
});
|
|
}
|
|
|
|
private get _dashboard(): DashboardScene {
|
|
return getDashboardSceneFor(this);
|
|
}
|
|
|
|
public get diffData(): { lhs: string; rhs: string } {
|
|
return this.state.diffData ?? { lhs: '', rhs: '' };
|
|
}
|
|
|
|
public get versions(): DecoratedRevisionModel[] {
|
|
return this.state.versions ?? [];
|
|
}
|
|
|
|
public get limit(): number {
|
|
return this._limit;
|
|
}
|
|
|
|
public get start(): number {
|
|
return this._start;
|
|
}
|
|
|
|
public getUrlKey(): string {
|
|
return 'versions';
|
|
}
|
|
|
|
public getDashboard(): DashboardScene {
|
|
return this._dashboard;
|
|
}
|
|
|
|
public getTimeRange() {
|
|
return sceneGraph.getTimeRange(this._dashboard);
|
|
}
|
|
|
|
public fetchVersions = (append = false): void => {
|
|
const uid = this._dashboard.state.uid;
|
|
|
|
if (!uid) {
|
|
return;
|
|
}
|
|
|
|
this.setState({ isAppending: append });
|
|
|
|
const requestOptions = this._continueToken
|
|
? { limit: this._limit, start: this._start, continueToken: this._continueToken }
|
|
: { limit: this._limit, start: this._start };
|
|
|
|
historySrv
|
|
.getHistoryList(uid, requestOptions)
|
|
.then((result) => {
|
|
this.setState({
|
|
isLoading: false,
|
|
versions: [...(this.state.versions ?? []), ...this.decorateVersions(result.versions)],
|
|
});
|
|
this._start += this._limit;
|
|
// Update the continueToken for the next request, if available
|
|
this._continueToken = result.continueToken ?? '';
|
|
})
|
|
.catch((err) => console.log(err))
|
|
.finally(() => this.setState({ isAppending: false }));
|
|
};
|
|
|
|
public getDiff = async () => {
|
|
const selectedVersions = this.versions.filter((version) => version.checked);
|
|
const [newInfo, baseInfo] = selectedVersions;
|
|
const isNewLatest = newInfo.version === this._dashboard.state.version;
|
|
|
|
this.setState({
|
|
isLoading: true,
|
|
});
|
|
|
|
if (!this._dashboard.state.uid) {
|
|
return;
|
|
}
|
|
let lhs, rhs;
|
|
if (config.featureToggles.kubernetesClientDashboardsFolders) {
|
|
// the id here is the resource version in k8s, use this instead to get the specific version
|
|
lhs = await historySrv.getDashboardVersion(this._dashboard.state.uid, baseInfo.id);
|
|
rhs = await historySrv.getDashboardVersion(this._dashboard.state.uid, newInfo.id);
|
|
} else {
|
|
lhs = await historySrv.getDashboardVersion(this._dashboard.state.uid, baseInfo.version);
|
|
rhs = await historySrv.getDashboardVersion(this._dashboard.state.uid, newInfo.version);
|
|
}
|
|
|
|
this.setState({
|
|
baseInfo,
|
|
isLoading: false,
|
|
isNewLatest,
|
|
newInfo,
|
|
viewMode: 'compare',
|
|
diffData: {
|
|
lhs: lhs.data,
|
|
rhs: rhs.data,
|
|
},
|
|
});
|
|
};
|
|
|
|
public reset = () => {
|
|
this._continueToken = '';
|
|
this.setState({
|
|
baseInfo: undefined,
|
|
diffData: {
|
|
lhs: '',
|
|
rhs: '',
|
|
},
|
|
isNewLatest: false,
|
|
newInfo: undefined,
|
|
versions: this.versions.map((version) => ({ ...version, checked: false })),
|
|
viewMode: 'list',
|
|
});
|
|
};
|
|
|
|
public onCheck = (ev: React.FormEvent<HTMLInputElement>, versionId: number) => {
|
|
this.setState({
|
|
versions: this.versions.map((version) =>
|
|
version.id === versionId ? { ...version, checked: ev.currentTarget.checked } : version
|
|
),
|
|
});
|
|
};
|
|
|
|
private decorateVersions(versions: RevisionsModel[]): DecoratedRevisionModel[] {
|
|
const timeZone = this.getTimeRange().getTimeZone();
|
|
|
|
return versions.map((version) => {
|
|
return {
|
|
...version,
|
|
createdDateString: dateTimeFormat(version.created, { timeZone: timeZone }),
|
|
ageString: dateTimeFormatTimeAgo(version.created, { timeZone: timeZone }),
|
|
checked: false,
|
|
};
|
|
});
|
|
}
|
|
}
|
|
|
|
function VersionsEditorSettingsListView({ model }: SceneComponentProps<VersionsEditView>) {
|
|
const dashboard = model.getDashboard();
|
|
const { isLoading, isAppending, viewMode, baseInfo, newInfo, isNewLatest } = model.useState();
|
|
const { navModel, pageNav } = useDashboardEditPageNav(dashboard, model.getUrlKey());
|
|
const canCompare = model.versions.filter((version) => version.checked).length === 2;
|
|
const showButtons = model.versions.length > 1;
|
|
const hasMore = model.versions.length >= model.limit;
|
|
const isLastPage = model.versions.find((rev) => rev.version === 1);
|
|
|
|
const viewModeCompare = (
|
|
<>
|
|
<VersionHistoryHeader
|
|
onClick={model.reset}
|
|
baseVersion={baseInfo?.version}
|
|
newVersion={newInfo?.version}
|
|
isNewLatest={isNewLatest}
|
|
/>
|
|
{isLoading ? (
|
|
<VersionsHistorySpinner msg="Fetching changes…" />
|
|
) : (
|
|
<VersionHistoryComparison
|
|
newInfo={newInfo!}
|
|
baseInfo={baseInfo!}
|
|
isNewLatest={isNewLatest!}
|
|
diffData={model.diffData}
|
|
onRestore={dashboard.onRestore}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
|
|
const viewModeList = (
|
|
<>
|
|
{isLoading ? (
|
|
<VersionsHistorySpinner msg="Fetching history list…" />
|
|
) : (
|
|
<VersionHistoryTable
|
|
versions={model.versions}
|
|
onCheck={model.onCheck}
|
|
canCompare={canCompare}
|
|
onRestore={dashboard.onRestore}
|
|
/>
|
|
)}
|
|
{isAppending && <VersionsHistorySpinner msg="Fetching more entries…" />}
|
|
{showButtons && (
|
|
<VersionsHistoryButtons
|
|
hasMore={hasMore}
|
|
canCompare={canCompare}
|
|
getVersions={model.fetchVersions}
|
|
getDiff={model.getDiff}
|
|
isLastPage={!!isLastPage}
|
|
/>
|
|
)}
|
|
</>
|
|
);
|
|
|
|
return (
|
|
<Page navModel={navModel} pageNav={pageNav} layout={PageLayoutType.Standard}>
|
|
<NavToolbarActions dashboard={dashboard} />
|
|
{viewMode === 'compare' ? viewModeCompare : viewModeList}
|
|
</Page>
|
|
);
|
|
}
|
|
|
|
const VersionsHistorySpinner = ({ msg }: { msg: string }) => (
|
|
<Stack>
|
|
<Spinner />
|
|
<em>{msg}</em>
|
|
</Stack>
|
|
);
|