Files
grafana/public/app/features/migrate-to-cloud/onprem/NameCell.tsx
Matheus Macabu 1635a3cd67 CloudMigrations: Add support for migration of Library Elements (Panels) resources (#93898)
* CloudMigrations: create snapshots of Library Elements

* CloudMigrations: render library element resource in resources table

* CloudMigrations: create newtype with necessary fields for library element creation
2024-10-03 11:54:54 +02:00

226 lines
6.1 KiB
TypeScript

import { css } from '@emotion/css';
import { useMemo } from 'react';
import Skeleton from 'react-loading-skeleton';
import { DataSourceInstanceSettings } from '@grafana/data';
import { config } from '@grafana/runtime';
import { CellProps, Stack, Text, Icon, useStyles2 } from '@grafana/ui';
import { getSvgSize } from '@grafana/ui/src/components/Icon/utils';
import { Trans } from 'app/core/internationalization';
import { useGetFolderQuery } from 'app/features/browse-dashboards/api/browseDashboardsAPI';
import { useGetDashboardByUidQuery, useGetLibraryElementByUidQuery } from '../api';
import { ResourceTableItem } from './types';
export function NameCell(props: CellProps<ResourceTableItem>) {
const data = props.row.original;
return (
<Stack direction="row" gap={2} alignItems="center">
<ResourceIcon resource={data} />
<Stack direction="column" gap={0}>
<ResourceInfo data={data} />
</Stack>
</Stack>
);
}
function ResourceInfo({ data }: { data: ResourceTableItem }) {
switch (data.type) {
case 'DASHBOARD':
return <DashboardInfo data={data} />;
case 'DATASOURCE':
return <DatasourceInfo data={data} />;
case 'FOLDER':
return <FolderInfo data={data} />;
case 'LIBRARY_ELEMENT':
return <LibraryElementInfo data={data} />;
}
}
function getDashboardTitle(dashboardData: object) {
if ('title' in dashboardData && typeof dashboardData.title === 'string') {
return dashboardData.title;
}
return undefined;
}
function DatasourceInfo({ data }: { data: ResourceTableItem }) {
const datasourceUID = data.refId;
const datasource = useDatasource(datasourceUID);
if (!datasource) {
return (
<>
<Text>
<Trans i18nKey="migrate-to-cloud.resource-table.unknown-datasource-title">
Data source {{ datasourceUID }}
</Trans>
</Text>
<Text color="secondary">
<Trans i18nKey="migrate-to-cloud.resource-table.unknown-datasource-type">Unknown data source</Trans>
</Text>
</>
);
}
return (
<>
<span>{datasource.name}</span>
<Text color="secondary">{datasource.type}</Text>
</>
);
}
function DashboardInfo({ data }: { data: ResourceTableItem }) {
const dashboardUID = data.refId;
// TODO: really, the API should return this directly
const { data: dashboardData, isError } = useGetDashboardByUidQuery({
uid: dashboardUID,
});
const dashboardName = useMemo(() => {
return (dashboardData?.dashboard && getDashboardTitle(dashboardData.dashboard)) ?? dashboardUID;
}, [dashboardData, dashboardUID]);
if (isError) {
// Not translated because this is only temporary until the data comes through in the MigrationRun API
return (
<>
<Text italic>Unable to load dashboard</Text>
<Text color="secondary">Dashboard {dashboardUID}</Text>
</>
);
}
if (!dashboardData) {
return <InfoSkeleton />;
}
return (
<>
<span>{dashboardName}</span>
<Text color="secondary">{dashboardData.meta?.folderTitle ?? 'Dashboards'}</Text>
</>
);
}
function FolderInfo({ data }: { data: ResourceTableItem }) {
const { data: folderData, isLoading, isError } = useGetFolderQuery(data.refId);
if (isLoading || !folderData) {
return <InfoSkeleton />;
}
if (isError) {
return (
<>
<Text italic>Unable to load dashboard</Text>
<Text color="secondary">Dashboard {data.refId}</Text>
</>
);
}
const parentFolderName = folderData.parents?.[folderData.parents.length - 1]?.title;
return (
<>
<span>{folderData.title}</span>
<Text color="secondary">{parentFolderName ?? 'Dashboards'}</Text>
</>
);
}
function LibraryElementInfo({ data }: { data: ResourceTableItem }) {
const uid = data.refId;
const { data: libraryElementData, isError, isLoading } = useGetLibraryElementByUidQuery({ libraryElementUid: uid });
const name = useMemo(() => {
return data?.name || (libraryElementData?.result?.name ?? uid);
}, [data, libraryElementData, uid]);
if (isError) {
return (
<>
<Text italic>
<Trans i18nKey="migrate-to-cloud.resource-table.error-library-element-title">
Unable to load library element
</Trans>
</Text>
<Text color="secondary">
<Trans i18nKey="migrate-to-cloud.resource-table.error-library-element-sub">Library Element {uid}</Trans>
</Text>
</>
);
}
if (isLoading || !libraryElementData) {
return <InfoSkeleton />;
}
const folderName = libraryElementData?.result?.meta?.folderName ?? 'General';
return (
<>
<span>{name}</span>
<Text color="secondary">{folderName}</Text>
</>
);
}
function InfoSkeleton() {
return (
<>
<Skeleton width={250} />
<Skeleton width={130} />
</>
);
}
function ResourceIcon({ resource }: { resource: ResourceTableItem }) {
const styles = useStyles2(getIconStyles);
const datasource = useDatasource(resource.type === 'DATASOURCE' ? resource.refId : undefined);
if (resource.type === 'DASHBOARD') {
return <Icon size="xl" name="dashboard" />;
} else if (resource.type === 'FOLDER') {
return <Icon size="xl" name="folder" />;
} else if (resource.type === 'DATASOURCE' && datasource?.meta?.info?.logos?.small) {
return <img className={styles.icon} src={datasource.meta.info.logos.small} alt="" />;
} else if (resource.type === 'DATASOURCE') {
return <Icon size="xl" name="database" />;
} else if (resource.type === 'LIBRARY_ELEMENT') {
return <Icon size="xl" name="library-panel" />;
}
return undefined;
}
function getIconStyles() {
return {
icon: css({
display: 'block',
width: getSvgSize('xl'),
height: getSvgSize('xl'),
}),
};
}
function useDatasource(datasourceUID: string | undefined): DataSourceInstanceSettings | undefined {
const datasource = useMemo(() => {
if (!datasourceUID) {
return undefined;
}
return (
config.datasources[datasourceUID] || Object.values(config.datasources).find((ds) => ds.uid === datasourceUID)
);
}, [datasourceUID]);
return datasource;
}