mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Plugins: Fix double page paddings on plugin admin pages (#48315)
This commit is contained in:
parent
103087a1a5
commit
8764040fe3
@ -2,18 +2,14 @@ import React from 'react';
|
||||
|
||||
import { LoadingPlaceholder } from '@grafana/ui';
|
||||
|
||||
import { Page } from './Page';
|
||||
|
||||
export interface Props {
|
||||
text?: string;
|
||||
}
|
||||
|
||||
export const Loader = ({ text = 'Loading...' }: Props) => {
|
||||
return (
|
||||
<Page>
|
||||
<div className="page-loader-wrapper">
|
||||
<LoadingPlaceholder text={text} />
|
||||
</div>
|
||||
</Page>
|
||||
<div className="page-loader-wrapper">
|
||||
<LoadingPlaceholder text={text} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,19 +0,0 @@
|
||||
import { css } from '@emotion/css';
|
||||
import React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
export const Page: React.FC = ({ children }) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
return (
|
||||
<div className="page-container">
|
||||
<div className={styles}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const getStyles = (theme: GrafanaTheme2) =>
|
||||
css`
|
||||
margin-bottom: ${theme.spacing(3)};
|
||||
`;
|
@ -26,75 +26,79 @@ export function PluginDetailsHeader({ plugin, currentUrl, parentUrl }: Props): R
|
||||
const version = plugin.installedVersion || latestCompatibleVersion?.version;
|
||||
|
||||
return (
|
||||
<div className={styles.headerContainer}>
|
||||
<PluginLogo
|
||||
alt={`${plugin.name} logo`}
|
||||
src={plugin.info.logos.small}
|
||||
className={css`
|
||||
object-fit: contain;
|
||||
width: 100%;
|
||||
height: 68px;
|
||||
max-width: 68px;
|
||||
`}
|
||||
/>
|
||||
<div>
|
||||
<div className="page-container">
|
||||
<div className={styles.headerContainer}>
|
||||
<PluginLogo
|
||||
alt={`${plugin.name} logo`}
|
||||
src={plugin.info.logos.small}
|
||||
className={css`
|
||||
object-fit: contain;
|
||||
width: 100%;
|
||||
height: 68px;
|
||||
max-width: 68px;
|
||||
`}
|
||||
/>
|
||||
|
||||
<div className={styles.headerWrapper}>
|
||||
{/* Title & navigation */}
|
||||
<nav className={styles.breadcrumb} aria-label="Breadcrumb">
|
||||
<ol>
|
||||
<li>
|
||||
<a className={styles.textUnderline} href={parentUrl}>
|
||||
Plugins
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={currentUrl} aria-current="page">
|
||||
{plugin.name}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
<div className={styles.headerWrapper}>
|
||||
{/* Title & navigation */}
|
||||
<nav className={styles.breadcrumb} aria-label="Breadcrumb">
|
||||
<ol>
|
||||
<li>
|
||||
<a className={styles.textUnderline} href={parentUrl}>
|
||||
Plugins
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href={currentUrl} aria-current="page">
|
||||
{plugin.name}
|
||||
</a>
|
||||
</li>
|
||||
</ol>
|
||||
</nav>
|
||||
|
||||
<div className={styles.headerInformationRow}>
|
||||
{/* Org name */}
|
||||
<span>{plugin.orgName}</span>
|
||||
<div className={styles.headerInformationRow}>
|
||||
{/* Org name */}
|
||||
<span>{plugin.orgName}</span>
|
||||
|
||||
{/* Links */}
|
||||
{plugin.details?.links.map((link: any) => (
|
||||
<a key={link.name} href={link.url}>
|
||||
{link.name}
|
||||
</a>
|
||||
))}
|
||||
{/* Links */}
|
||||
{plugin.details?.links.map((link: any) => (
|
||||
<a key={link.name} href={link.url}>
|
||||
{link.name}
|
||||
</a>
|
||||
))}
|
||||
|
||||
{/* Downloads */}
|
||||
{plugin.downloads > 0 && (
|
||||
<span>
|
||||
<Icon name="cloud-download" />
|
||||
{` ${new Intl.NumberFormat().format(plugin.downloads)}`}{' '}
|
||||
</span>
|
||||
)}
|
||||
{/* Downloads */}
|
||||
{plugin.downloads > 0 && (
|
||||
<span>
|
||||
<Icon name="cloud-download" />
|
||||
{` ${new Intl.NumberFormat().format(plugin.downloads)}`}{' '}
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Version */}
|
||||
{Boolean(version) && <span>{version}</span>}
|
||||
{/* Version */}
|
||||
{Boolean(version) && <span>{version}</span>}
|
||||
|
||||
{/* Signature information */}
|
||||
<PluginDetailsHeaderSignature plugin={plugin} />
|
||||
{/* Signature information */}
|
||||
<PluginDetailsHeaderSignature plugin={plugin} />
|
||||
|
||||
{plugin.isDisabled && <PluginDisabledBadge error={plugin.error!} />}
|
||||
{plugin.isDisabled && <PluginDisabledBadge error={plugin.error!} />}
|
||||
</div>
|
||||
|
||||
<PluginDetailsHeaderDependencies
|
||||
plugin={plugin}
|
||||
latestCompatibleVersion={latestCompatibleVersion}
|
||||
className={cx(styles.headerInformationRow, styles.headerInformationRowSecondary)}
|
||||
/>
|
||||
|
||||
<p>{plugin.description}</p>
|
||||
|
||||
<HorizontalGroup height="auto">
|
||||
<InstallControls plugin={plugin} latestCompatibleVersion={latestCompatibleVersion} />
|
||||
<GetStartedWithPlugin plugin={plugin} />
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<PluginDetailsHeaderDependencies
|
||||
plugin={plugin}
|
||||
latestCompatibleVersion={latestCompatibleVersion}
|
||||
className={cx(styles.headerInformationRow, styles.headerInformationRowSecondary)}
|
||||
/>
|
||||
|
||||
<p>{plugin.description}</p>
|
||||
|
||||
<HorizontalGroup height="auto">
|
||||
<InstallControls plugin={plugin} latestCompatibleVersion={latestCompatibleVersion} />
|
||||
<GetStartedWithPlugin plugin={plugin} />
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -12,7 +12,6 @@ import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { StoreState } from 'app/types/store';
|
||||
|
||||
import { HorizontalGroup } from '../components/HorizontalGroup';
|
||||
import { Page as PluginPage } from '../components/Page';
|
||||
import { PluginList } from '../components/PluginList';
|
||||
import { SearchField } from '../components/SearchField';
|
||||
import { Sorters } from '../helpers';
|
||||
@ -69,94 +68,92 @@ export default function Browse({ route }: GrafanaRouteComponentProps): ReactElem
|
||||
return (
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents>
|
||||
<PluginPage>
|
||||
<HorizontalGroup wrap>
|
||||
<SearchField value={query} onSearch={onSearch} />
|
||||
<HorizontalGroup wrap className={styles.actionBar}>
|
||||
{/* Filter by type */}
|
||||
<div>
|
||||
<RadioButtonGroup
|
||||
value={filterByType}
|
||||
onChange={onFilterByTypeChange}
|
||||
options={[
|
||||
{ value: 'all', label: 'All' },
|
||||
{ value: 'datasource', label: 'Data sources' },
|
||||
{ value: 'panel', label: 'Panels' },
|
||||
{ value: 'app', label: 'Applications' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Filter by installed / all */}
|
||||
{remotePluginsAvailable ? (
|
||||
<div>
|
||||
<RadioButtonGroup value={filterBy} onChange={onFilterByChange} options={filterByOptions} />
|
||||
</div>
|
||||
) : (
|
||||
<Tooltip
|
||||
content="This filter has been disabled because the Grafana server cannot access grafana.com"
|
||||
placement="top"
|
||||
>
|
||||
<div>
|
||||
<RadioButtonGroup
|
||||
disabled={true}
|
||||
value={filterBy}
|
||||
onChange={onFilterByChange}
|
||||
options={filterByOptions}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
|
||||
{/* Sorting */}
|
||||
<div>
|
||||
<Select
|
||||
menuShouldPortal
|
||||
aria-label="Sort Plugins List"
|
||||
width={24}
|
||||
value={sortBy}
|
||||
onChange={onSortByChange}
|
||||
options={[
|
||||
{ value: 'nameAsc', label: 'Sort by name (A-Z)' },
|
||||
{ value: 'nameDesc', label: 'Sort by name (Z-A)' },
|
||||
{ value: 'updated', label: 'Sort by updated date' },
|
||||
{ value: 'published', label: 'Sort by published date' },
|
||||
{ value: 'downloads', label: 'Sort by downloads' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Display mode */}
|
||||
<div>
|
||||
<RadioButtonGroup<PluginListDisplayMode>
|
||||
className={styles.displayAs}
|
||||
value={displayMode}
|
||||
onChange={setDisplayMode}
|
||||
options={[
|
||||
{
|
||||
value: PluginListDisplayMode.Grid,
|
||||
icon: 'table',
|
||||
description: 'Display plugins in a grid layout',
|
||||
},
|
||||
{ value: PluginListDisplayMode.List, icon: 'list-ul', description: 'Display plugins in list' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</HorizontalGroup>
|
||||
</HorizontalGroup>
|
||||
<div className={styles.listWrap}>
|
||||
{isLoading ? (
|
||||
<LoadingPlaceholder
|
||||
className={css`
|
||||
margin-bottom: 0;
|
||||
`}
|
||||
text="Loading results"
|
||||
<HorizontalGroup wrap>
|
||||
<SearchField value={query} onSearch={onSearch} />
|
||||
<HorizontalGroup wrap className={styles.actionBar}>
|
||||
{/* Filter by type */}
|
||||
<div>
|
||||
<RadioButtonGroup
|
||||
value={filterByType}
|
||||
onChange={onFilterByTypeChange}
|
||||
options={[
|
||||
{ value: 'all', label: 'All' },
|
||||
{ value: 'datasource', label: 'Data sources' },
|
||||
{ value: 'panel', label: 'Panels' },
|
||||
{ value: 'app', label: 'Applications' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Filter by installed / all */}
|
||||
{remotePluginsAvailable ? (
|
||||
<div>
|
||||
<RadioButtonGroup value={filterBy} onChange={onFilterByChange} options={filterByOptions} />
|
||||
</div>
|
||||
) : (
|
||||
<PluginList plugins={plugins} displayMode={displayMode} />
|
||||
<Tooltip
|
||||
content="This filter has been disabled because the Grafana server cannot access grafana.com"
|
||||
placement="top"
|
||||
>
|
||||
<div>
|
||||
<RadioButtonGroup
|
||||
disabled={true}
|
||||
value={filterBy}
|
||||
onChange={onFilterByChange}
|
||||
options={filterByOptions}
|
||||
/>
|
||||
</div>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
</PluginPage>
|
||||
|
||||
{/* Sorting */}
|
||||
<div>
|
||||
<Select
|
||||
menuShouldPortal
|
||||
aria-label="Sort Plugins List"
|
||||
width={24}
|
||||
value={sortBy}
|
||||
onChange={onSortByChange}
|
||||
options={[
|
||||
{ value: 'nameAsc', label: 'Sort by name (A-Z)' },
|
||||
{ value: 'nameDesc', label: 'Sort by name (Z-A)' },
|
||||
{ value: 'updated', label: 'Sort by updated date' },
|
||||
{ value: 'published', label: 'Sort by published date' },
|
||||
{ value: 'downloads', label: 'Sort by downloads' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Display mode */}
|
||||
<div>
|
||||
<RadioButtonGroup<PluginListDisplayMode>
|
||||
className={styles.displayAs}
|
||||
value={displayMode}
|
||||
onChange={setDisplayMode}
|
||||
options={[
|
||||
{
|
||||
value: PluginListDisplayMode.Grid,
|
||||
icon: 'table',
|
||||
description: 'Display plugins in a grid layout',
|
||||
},
|
||||
{ value: PluginListDisplayMode.List, icon: 'list-ul', description: 'Display plugins in list' },
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
</HorizontalGroup>
|
||||
</HorizontalGroup>
|
||||
<div className={styles.listWrap}>
|
||||
{isLoading ? (
|
||||
<LoadingPlaceholder
|
||||
className={css`
|
||||
margin-bottom: 0;
|
||||
`}
|
||||
text="Loading results"
|
||||
/>
|
||||
) : (
|
||||
<PluginList plugins={plugins} displayMode={displayMode} />
|
||||
)}
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
|
@ -4,8 +4,6 @@ import React from 'react';
|
||||
import { NavModel, NavModelItem } from '@grafana/data';
|
||||
import { Page } from 'app/core/components/Page/Page';
|
||||
|
||||
import { Page as PluginPage } from '../components/Page';
|
||||
|
||||
const node: NavModelItem = {
|
||||
id: 'not-found',
|
||||
text: 'The plugin catalog is not enabled',
|
||||
@ -19,18 +17,16 @@ export default function NotEnabled(): JSX.Element | null {
|
||||
return (
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents>
|
||||
<PluginPage>
|
||||
To enable installing plugins via catalog, please refer to the{' '}
|
||||
<a
|
||||
className={css`
|
||||
text-decoration: underline;
|
||||
`}
|
||||
href="https://grafana.com/docs/grafana/latest/plugins/catalog"
|
||||
>
|
||||
Plugin Catalog
|
||||
</a>{' '}
|
||||
instructions
|
||||
</PluginPage>
|
||||
To enable installing plugins via catalog, please refer to the{' '}
|
||||
<a
|
||||
className={css`
|
||||
text-decoration: underline;
|
||||
`}
|
||||
href="https://grafana.com/docs/grafana/latest/plugins/catalog"
|
||||
>
|
||||
Plugin Catalog
|
||||
</a>{' '}
|
||||
instructions
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
|
@ -11,7 +11,6 @@ import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
import { AppNotificationSeverity } from 'app/types';
|
||||
|
||||
import { Loader } from '../components/Loader';
|
||||
import { Page as PluginPage } from '../components/Page';
|
||||
import { PluginDetailsBody } from '../components/PluginDetailsBody';
|
||||
import { PluginDetailsDisabledError } from '../components/PluginDetailsDisabledError';
|
||||
import { PluginDetailsHeader } from '../components/PluginDetailsHeader';
|
||||
@ -75,9 +74,8 @@ export default function PluginDetails({ match, queryParams }: Props): JSX.Elemen
|
||||
|
||||
return (
|
||||
<Page>
|
||||
<PluginPage>
|
||||
<PluginDetailsHeader currentUrl={`${url}?page=${pageId}`} parentUrl={parentUrl} plugin={plugin} />
|
||||
|
||||
<PluginDetailsHeader currentUrl={`${url}?page=${pageId}`} parentUrl={parentUrl} plugin={plugin} />
|
||||
<Page.Contents>
|
||||
{/* Tab navigation */}
|
||||
<TabsBar>
|
||||
{tabs.map((tab: PluginDetailsTab) => {
|
||||
@ -99,7 +97,7 @@ export default function PluginDetails({ match, queryParams }: Props): JSX.Elemen
|
||||
<PluginDetailsDisabledError plugin={plugin} className={styles.alert} />
|
||||
<PluginDetailsBody queryParams={queryParams} plugin={plugin} pageId={pageId} />
|
||||
</TabContent>
|
||||
</PluginPage>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user