You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

116 lines
4.2 KiB

import React, { useEffect } from 'react';
import { css } from '@emotion/css';
import { usePrevious } from 'react-use';
import { GrafanaTheme2 } from '@grafana/data';
import { useStyles2, TabsBar, TabContent, Tab, Alert, IconName } from '@grafana/ui';
import { locationService } from '@grafana/runtime';
import { Layout } from '@grafana/ui/src/components/Layout/Layout';
import { Page } from 'app/core/components/Page/Page';
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
import { PluginDetailsSignature } from '../components/PluginDetailsSignature';
import { PluginDetailsHeader } from '../components/PluginDetailsHeader';
import { PluginDetailsBody } from '../components/PluginDetailsBody';
import { Page as PluginPage } from '../components/Page';
import { Loader } from '../components/Loader';
import { PluginTabLabels, PluginTabIds, PluginDetailsTab } from '../types';
import { useGetSingle, useFetchStatus, useFetchDetailsStatus } from '../state/hooks';
import { usePluginDetailsTabs } from '../hooks/usePluginDetailsTabs';
import { AppNotificationSeverity } from 'app/types';
import { PluginDetailsDisabledError } from '../components/PluginDetailsDisabledError';
type Props = GrafanaRouteComponentProps<{ pluginId?: string }>;
export default function PluginDetails({ match, queryParams }: Props): JSX.Element | null {
const {
params: { pluginId = '' },
url,
} = match;
const parentUrl = url.substring(0, url.lastIndexOf('/'));
const defaultTabs: PluginDetailsTab[] = [
{
label: PluginTabLabels.OVERVIEW,
icon: 'file-alt',
id: PluginTabIds.OVERVIEW,
href: `${url}?page=${PluginTabIds.OVERVIEW}`,
},
];
const plugin = useGetSingle(pluginId); // fetches the localplugin settings
const { tabs, defaultTab } = usePluginDetailsTabs(plugin, defaultTabs);
const { isLoading: isFetchLoading } = useFetchStatus();
const { isLoading: isFetchDetailsLoading } = useFetchDetailsStatus();
const styles = useStyles2(getStyles);
const prevTabs = usePrevious(tabs);
const pageId = (queryParams.page as PluginTabIds) || defaultTab;
// If an app plugin is uninstalled we need to reset the active tab when the config / dashboards tabs are removed.
useEffect(() => {
const hasUninstalledWithConfigPages = prevTabs && prevTabs.length > tabs.length;
const isViewingAConfigPage = pageId !== PluginTabIds.OVERVIEW && pageId !== PluginTabIds.VERSIONS;
if (hasUninstalledWithConfigPages && isViewingAConfigPage) {
locationService.replace(`${url}?page=${PluginTabIds.OVERVIEW}`);
}
}, [pageId, url, tabs, prevTabs]);
if (isFetchLoading || isFetchDetailsLoading) {
return (
<Page>
<Loader />
</Page>
);
}
if (!plugin) {
return (
<Layout justify="center" align="center">
<Alert severity={AppNotificationSeverity.Warning} title="Plugin not found">
That plugin cannot be found. Please check the url is correct or <br />
go to the <a href={parentUrl}>plugin catalog</a>.
</Alert>
</Layout>
);
}
return (
<Page>
<PluginPage>
<PluginDetailsHeader currentUrl={`${url}?page=${pageId}`} parentUrl={parentUrl} plugin={plugin} />
{/* Tab navigation */}
<TabsBar>
{tabs.map((tab: PluginDetailsTab) => {
return (
<Tab
key={tab.label}
label={tab.label}
href={tab.href}
icon={tab.icon as IconName}
active={tab.id === pageId}
/>
);
})}
</TabsBar>
{/* Active tab */}
<TabContent className={styles.tabContent}>
<PluginDetailsSignature plugin={plugin} className={styles.alert} />
<PluginDetailsDisabledError plugin={plugin} className={styles.alert} />
<PluginDetailsBody queryParams={queryParams} plugin={plugin} pageId={pageId} />
</TabContent>
</PluginPage>
</Page>
);
}
export const getStyles = (theme: GrafanaTheme2) => {
return {
alert: css`
margin: ${theme.spacing(3)};
margin-bottom: 0;
`,
// Needed due to block formatting context
tabContent: css`
overflow: auto;
`,
};
};