mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Merge pull request #14875 from grafana/page-layout-component
CustomScrollbar on all-React-pages
This commit is contained in:
commit
c913263b23
@ -8,6 +8,7 @@ interface Props {
|
||||
autoHideDuration?: number;
|
||||
autoMaxHeight?: string;
|
||||
hideTracksWhenNotNeeded?: boolean;
|
||||
autoHeightMin?: number | string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -21,6 +22,7 @@ export class CustomScrollbar extends PureComponent<Props> {
|
||||
autoHideDuration: 200,
|
||||
autoMaxHeight: '100%',
|
||||
hideTracksWhenNotNeeded: false,
|
||||
autoHeightMin: '0'
|
||||
};
|
||||
|
||||
render() {
|
||||
@ -32,7 +34,6 @@ export class CustomScrollbar extends PureComponent<Props> {
|
||||
autoHeight={true}
|
||||
// These autoHeightMin & autoHeightMax options affect firefox and chrome differently.
|
||||
// Before these where set to inhert but that caused problems with cut of legends in firefox
|
||||
autoHeightMin={'0'}
|
||||
autoHeightMax={autoMaxHeight}
|
||||
renderTrackHorizontal={props => <div {...props} className="track-horizontal" />}
|
||||
renderTrackVertical={props => <div {...props} className="track-vertical" />}
|
||||
|
@ -7,7 +7,7 @@ exports[`CustomScrollbar renders correctly 1`] = `
|
||||
Object {
|
||||
"height": "auto",
|
||||
"maxHeight": "100%",
|
||||
"minHeight": "0",
|
||||
"minHeight": 0,
|
||||
"overflow": "hidden",
|
||||
"position": "relative",
|
||||
"width": "100%",
|
||||
@ -24,7 +24,7 @@ exports[`CustomScrollbar renders correctly 1`] = `
|
||||
"marginBottom": 0,
|
||||
"marginRight": 0,
|
||||
"maxHeight": "calc(100% + 0px)",
|
||||
"minHeight": "calc(0 + 0px)",
|
||||
"minHeight": 0,
|
||||
"overflow": "scroll",
|
||||
"position": "relative",
|
||||
"right": undefined,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import Transition from 'react-transition-group/Transition';
|
||||
|
||||
interface Props {
|
||||
@ -8,7 +8,7 @@ interface Props {
|
||||
unmountOnExit?: boolean;
|
||||
}
|
||||
|
||||
export const FadeIn: SFC<Props> = props => {
|
||||
export const FadeIn: FC<Props> = props => {
|
||||
const defaultStyle = {
|
||||
transition: `opacity ${props.duration}ms linear`,
|
||||
opacity: 0,
|
||||
|
50
public/app/core/components/Footer/Footer.tsx
Normal file
50
public/app/core/components/Footer/Footer.tsx
Normal file
@ -0,0 +1,50 @@
|
||||
import React, { FC } from 'react';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
|
||||
interface Props {
|
||||
appName: string;
|
||||
buildVersion: string;
|
||||
buildCommit: string;
|
||||
newGrafanaVersionExists: boolean;
|
||||
newGrafanaVersion: string;
|
||||
}
|
||||
|
||||
export const Footer: FC<Props> = React.memo(({appName, buildVersion, buildCommit, newGrafanaVersionExists, newGrafanaVersion}) => {
|
||||
return (
|
||||
<footer className="footer">
|
||||
<div className="text-center">
|
||||
<ul>
|
||||
<li>
|
||||
<a href="http://docs.grafana.org" target="_blank">
|
||||
<i className="fa fa-file-code-o" /> Docs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://grafana.com/services/support" target="_blank">
|
||||
<i className="fa fa-support" /> Support Plans
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://community.grafana.com/" target="_blank">
|
||||
<i className="fa fa-comments-o" /> Community
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="https://grafana.com" target="_blank">{appName}</a> <span>v{buildVersion} (commit: {buildCommit})</span>
|
||||
</li>
|
||||
{newGrafanaVersionExists && (
|
||||
<li>
|
||||
<Tooltip placement="auto" content={newGrafanaVersion}>
|
||||
<a href="https://grafana.com/get" target="_blank">
|
||||
New version available!
|
||||
</a>
|
||||
</Tooltip>
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
});
|
||||
|
||||
export default Footer;
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
export type LayoutMode = LayoutModes.Grid | LayoutModes.List;
|
||||
|
||||
@ -12,7 +12,7 @@ interface Props {
|
||||
onLayoutModeChanged: (mode: LayoutMode) => {};
|
||||
}
|
||||
|
||||
const LayoutSelector: SFC<Props> = props => {
|
||||
const LayoutSelector: FC<Props> = props => {
|
||||
const { mode, onLayoutModeChanged } = props;
|
||||
return (
|
||||
<div className="layout-selector">
|
||||
|
75
public/app/core/components/Page/Page.tsx
Normal file
75
public/app/core/components/Page/Page.tsx
Normal file
@ -0,0 +1,75 @@
|
||||
// Libraries
|
||||
import React, { Component } from 'react';
|
||||
import config from 'app/core/config';
|
||||
import { NavModel } from 'app/types';
|
||||
import { getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
|
||||
// Components
|
||||
import PageHeader from '../PageHeader/PageHeader';
|
||||
import Footer from '../Footer/Footer';
|
||||
import PageContents from './PageContents';
|
||||
import { CustomScrollbar } from '@grafana/ui';
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
children: JSX.Element[] | JSX.Element;
|
||||
navModel: NavModel;
|
||||
}
|
||||
|
||||
class Page extends Component<Props> {
|
||||
private bodyClass = 'is-react';
|
||||
private body = document.body;
|
||||
static Header = PageHeader;
|
||||
static Contents = PageContents;
|
||||
|
||||
componentDidMount() {
|
||||
this.body.classList.add(this.bodyClass);
|
||||
this.updateTitle();
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps: Props) {
|
||||
if (prevProps.title !== this.props.title) {
|
||||
this.updateTitle();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.body.classList.remove(this.bodyClass);
|
||||
}
|
||||
|
||||
updateTitle = () => {
|
||||
const title = this.getPageTitle;
|
||||
document.title = title ? title + ' - Grafana' : 'Grafana';
|
||||
}
|
||||
|
||||
get getPageTitle () {
|
||||
const { navModel } = this.props;
|
||||
if (navModel) {
|
||||
return getTitleFromNavModel(navModel) || undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
render() {
|
||||
const { navModel } = this.props;
|
||||
const { buildInfo } = config;
|
||||
return (
|
||||
<div className="page-scrollbar-wrapper">
|
||||
<CustomScrollbar autoHeightMin={'100%'}>
|
||||
<div className="page-scrollbar-content">
|
||||
<PageHeader model={navModel} />
|
||||
{this.props.children}
|
||||
<Footer
|
||||
appName="Grafana"
|
||||
buildCommit={buildInfo.commit}
|
||||
buildVersion={buildInfo.version}
|
||||
newGrafanaVersion={buildInfo.latestVersion}
|
||||
newGrafanaVersionExists={buildInfo.hasUpdate} />
|
||||
</div>
|
||||
</CustomScrollbar>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Page;
|
26
public/app/core/components/Page/PageContents.tsx
Normal file
26
public/app/core/components/Page/PageContents.tsx
Normal file
@ -0,0 +1,26 @@
|
||||
// Libraries
|
||||
import React, { Component } from 'react';
|
||||
|
||||
// Components
|
||||
import PageLoader from '../PageLoader/PageLoader';
|
||||
|
||||
interface Props {
|
||||
isLoading?: boolean;
|
||||
children: JSX.Element[] | JSX.Element;
|
||||
}
|
||||
|
||||
class PageContents extends Component<Props> {
|
||||
|
||||
render() {
|
||||
const { isLoading } = this.props;
|
||||
|
||||
return (
|
||||
<div className="page-container page-body">
|
||||
{isLoading && <PageLoader />}
|
||||
{this.props.children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PageContents;
|
@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { FormEvent } from 'react';
|
||||
import { NavModel, NavModelItem } from 'app/types';
|
||||
import classNames from 'classnames';
|
||||
import appEvents from 'app/core/app_events';
|
||||
@ -12,8 +12,8 @@ const SelectNav = ({ main, customCss }: { main: NavModelItem; customCss: string
|
||||
return navItem.active === true;
|
||||
});
|
||||
|
||||
const gotoUrl = evt => {
|
||||
const element = evt.target;
|
||||
const gotoUrl = (evt: FormEvent) => {
|
||||
const element = evt.target as HTMLSelectElement;
|
||||
const url = element.options[element.selectedIndex].value;
|
||||
appEvents.emit('location-change', { href: url });
|
||||
};
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
interface Props {
|
||||
pageName: string;
|
||||
pageName?: string;
|
||||
}
|
||||
|
||||
const PageLoader: SFC<Props> = ({ pageName }) => {
|
||||
const PageLoader: FC<Props> = ({ pageName }) => {
|
||||
const loadingText = `Loading ${pageName}...`;
|
||||
return (
|
||||
<div className="page-loader-wrapper">
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC, ReactNode, PureComponent } from 'react';
|
||||
import React, { FC, ReactNode, PureComponent } from 'react';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
|
||||
interface ToggleButtonGroupProps {
|
||||
@ -29,7 +29,7 @@ interface ToggleButtonProps {
|
||||
tooltip?: string;
|
||||
}
|
||||
|
||||
export const ToggleButton: SFC<ToggleButtonProps> = ({
|
||||
export const ToggleButton: FC<ToggleButtonProps> = ({
|
||||
children,
|
||||
selected,
|
||||
className = '',
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
export interface Props {
|
||||
child: any;
|
||||
}
|
||||
|
||||
const DropDownChild: SFC<Props> = props => {
|
||||
const DropDownChild: FC<Props> = props => {
|
||||
const { child } = props;
|
||||
const listItemClassName = child.divider ? 'divider' : '';
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import DropDownChild from './DropDownChild';
|
||||
|
||||
interface Props {
|
||||
link: any;
|
||||
}
|
||||
|
||||
const SideMenuDropDown: SFC<Props> = props => {
|
||||
const SideMenuDropDown: FC<Props> = props => {
|
||||
const { link } = props;
|
||||
return (
|
||||
<ul className="dropdown-menu dropdown-menu--sidemenu" role="menu">
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
const SignIn: SFC<any> = () => {
|
||||
const SignIn: FC<any> = () => {
|
||||
const loginUrl = `login?redirect=${encodeURIComponent(window.location.pathname)}`;
|
||||
return (
|
||||
<div className="sidemenu-item">
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import _ from 'lodash';
|
||||
import TopSectionItem from './TopSectionItem';
|
||||
import config from '../../config';
|
||||
|
||||
const TopSection: SFC<any> = () => {
|
||||
const TopSection: FC<any> = () => {
|
||||
const navTree = _.cloneDeep(config.bootData.navTree);
|
||||
const mainLinks = _.filter(navTree, item => !item.hideFromMenu);
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import SideMenuDropDown from './SideMenuDropDown';
|
||||
|
||||
export interface Props {
|
||||
link: any;
|
||||
}
|
||||
|
||||
const TopSectionItem: SFC<Props> = props => {
|
||||
const TopSectionItem: FC<Props> = props => {
|
||||
const { link } = props;
|
||||
return (
|
||||
<div className="sidemenu-item dropdown">
|
||||
|
@ -6,6 +6,8 @@ export interface BuildInfo {
|
||||
commit: string;
|
||||
isEnterprise: boolean;
|
||||
env: string;
|
||||
latestVersion: string;
|
||||
hasUpdate: boolean;
|
||||
}
|
||||
|
||||
export class Settings {
|
||||
|
@ -41,3 +41,7 @@ export function getNavModel(navIndex: NavIndex, id: string, fallback?: NavModel)
|
||||
|
||||
return getNotFoundModel();
|
||||
}
|
||||
|
||||
export const getTitleFromNavModel = (navModel: NavModel) => {
|
||||
return `${navModel.main.text}${navModel.node.text ? ': ' + navModel.node.text : '' }`;
|
||||
};
|
||||
|
@ -6,7 +6,14 @@ import { getMultipleMockKeys, getMockKey } from './__mocks__/apiKeysMock';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
navModel: {} as NavModel,
|
||||
navModel: {
|
||||
main: {
|
||||
text: 'Configuration'
|
||||
},
|
||||
node: {
|
||||
text: 'Api Keys'
|
||||
}
|
||||
} as NavModel,
|
||||
apiKeys: [] as ApiKey[],
|
||||
searchQuery: '',
|
||||
hasFetched: false,
|
||||
|
@ -6,8 +6,7 @@ import { NavModel, ApiKey, NewApiKey, OrgRole } from 'app/types';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { getApiKeys, getApiKeysCount } from './state/selectors';
|
||||
import { loadApiKeys, deleteApiKey, setSearchQuery, addApiKey } from './state/actions';
|
||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import SlideDown from 'app/core/components/Animations/SlideDown';
|
||||
import ApiKeysAddedModal from './ApiKeysAddedModal';
|
||||
import config from 'app/core/config';
|
||||
@ -240,18 +239,17 @@ export class ApiKeysPage extends PureComponent<Props, any> {
|
||||
const { hasFetched, navModel, apiKeysCount } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader model={navModel} />
|
||||
{hasFetched ? (
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
{hasFetched && (
|
||||
apiKeysCount > 0 ? (
|
||||
this.renderApiKeyList()
|
||||
) : (
|
||||
this.renderEmptyList()
|
||||
)
|
||||
) : (
|
||||
<PageLoader pageName="Api keys" />
|
||||
)}
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,40 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render API keys table if there are any keys 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Api Keys",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
/>
|
||||
<PageLoader
|
||||
pageName="Api keys"
|
||||
/>
|
||||
</div>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render CTA if there are no API keys 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Api Keys",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
>
|
||||
@ -128,5 +147,6 @@ exports[`Render should render CTA if there are no API keys 1`] = `
|
||||
</div>
|
||||
</Component>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import { PanelMenuItem } from '@grafana/ui';
|
||||
|
||||
interface Props {
|
||||
children: any;
|
||||
}
|
||||
|
||||
export const PanelHeaderMenuItem: SFC<Props & PanelMenuItem> = props => {
|
||||
export const PanelHeaderMenuItem: FC<Props & PanelMenuItem> = props => {
|
||||
const isSubMenu = props.type === 'submenu';
|
||||
const isDivider = props.type === 'divider';
|
||||
return isDivider ? (
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import { Tooltip } from '@grafana/ui';
|
||||
|
||||
interface Props {
|
||||
@ -10,7 +10,7 @@ interface Props {
|
||||
tooltipInfo?: any;
|
||||
}
|
||||
|
||||
export const DataSourceOptions: SFC<Props> = ({ label, placeholder, name, value, onChange, tooltipInfo }) => {
|
||||
export const DataSourceOptions: FC<Props> = ({ label, placeholder, name, value, onChange, tooltipInfo }) => {
|
||||
const dsOption = (
|
||||
<div className="gf-form gf-form--flex-end">
|
||||
<label className="gf-form-label">{label}</label>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import { PluginDashboard } from '../../types';
|
||||
|
||||
export interface Props {
|
||||
@ -7,7 +7,7 @@ export interface Props {
|
||||
onRemove: (dashboard) => void;
|
||||
}
|
||||
|
||||
const DashboardsTable: SFC<Props> = ({ dashboards, onImport, onRemove }) => {
|
||||
const DashboardsTable: FC<Props> = ({ dashboards, onImport, onRemove }) => {
|
||||
function buttonText(dashboard: PluginDashboard) {
|
||||
return dashboard.revision !== dashboard.importedRevision ? 'Update' : 'Re-import';
|
||||
}
|
||||
|
@ -10,7 +10,14 @@ const setup = (propOverrides?: object) => {
|
||||
dataSources: [] as DataSource[],
|
||||
layoutMode: LayoutModes.Grid,
|
||||
loadDataSources: jest.fn(),
|
||||
navModel: {} as NavModel,
|
||||
navModel: {
|
||||
main: {
|
||||
text: 'Configuration'
|
||||
},
|
||||
node: {
|
||||
text: 'Data Sources'
|
||||
}
|
||||
} as NavModel,
|
||||
dataSourcesCount: 0,
|
||||
searchQuery: '',
|
||||
setDataSourcesSearchQuery: jest.fn(),
|
||||
|
@ -1,15 +1,15 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import PageHeader from '../../core/components/PageHeader/PageHeader';
|
||||
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||
import OrgActionBar from '../../core/components/OrgActionBar/OrgActionBar';
|
||||
import EmptyListCTA from '../../core/components/EmptyListCTA/EmptyListCTA';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import OrgActionBar from 'app/core/components/OrgActionBar/OrgActionBar';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import DataSourcesList from './DataSourcesList';
|
||||
import { DataSource, NavModel } from 'app/types';
|
||||
import { LayoutMode } from '../../core/components/LayoutSelector/LayoutSelector';
|
||||
import { DataSource, NavModel, StoreState } from 'app/types';
|
||||
import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
|
||||
import { loadDataSources, setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/actions';
|
||||
import { getNavModel } from '../../core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
|
||||
import {
|
||||
getDataSources,
|
||||
getDataSourcesCount,
|
||||
@ -67,10 +67,9 @@ export class DataSourcesListPage extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader model={navModel} />
|
||||
<div className="page-container page-body">
|
||||
{!hasFetched && <PageLoader pageName="Data sources" />}
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
<>
|
||||
{hasFetched && dataSourcesCount === 0 && <EmptyListCTA model={emptyListModel} />}
|
||||
{hasFetched &&
|
||||
dataSourcesCount > 0 && [
|
||||
@ -84,13 +83,14 @@ export class DataSourcesListPage extends PureComponent<Props> {
|
||||
/>,
|
||||
<DataSourcesList dataSources={dataSources} layoutMode={layoutMode} key="list" />,
|
||||
]}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function mapStateToProps(state) {
|
||||
function mapStateToProps(state: StoreState) {
|
||||
return {
|
||||
navModel: getNavModel(state.navIndex, 'datasources'),
|
||||
dataSources: getDataSources(state.dataSources),
|
||||
|
@ -1,12 +1,20 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render action bar and datasources 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Data Sources",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<OrgActionBar
|
||||
key="action-bar"
|
||||
@ -143,21 +151,25 @@ exports[`Render should render action bar and datasources 1`] = `
|
||||
key="list"
|
||||
layoutMode="grid"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Data Sources",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageLoader
|
||||
pageName="Data sources"
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Page>
|
||||
`;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import { FormLabel } from '@grafana/ui';
|
||||
import { Switch } from '../../../core/components/Switch/Switch';
|
||||
|
||||
@ -9,7 +9,7 @@ export interface Props {
|
||||
onDefaultChange: (value: boolean) => void;
|
||||
}
|
||||
|
||||
const BasicSettings: SFC<Props> = ({ dataSourceName, isDefault, onDefaultChange, onNameChange }) => {
|
||||
const BasicSettings: FC<Props> = ({ dataSourceName, isDefault, onDefaultChange, onNameChange }) => {
|
||||
return (
|
||||
<div className="gf-form-group">
|
||||
<div className="gf-form-inline">
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
export interface Props {
|
||||
isReadOnly: boolean;
|
||||
@ -6,7 +6,7 @@ export interface Props {
|
||||
onSubmit: (event) => void;
|
||||
}
|
||||
|
||||
const ButtonRow: SFC<Props> = ({ isReadOnly, onDelete, onSubmit }) => {
|
||||
const ButtonRow: FC<Props> = ({ isReadOnly, onDelete, onSubmit }) => {
|
||||
return (
|
||||
<div className="gf-form-button-row">
|
||||
<button type="submit" className="btn btn-success" disabled={isReadOnly} onClick={event => onSubmit(event)}>
|
||||
|
@ -1,10 +1,10 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
interface Props {
|
||||
message: any;
|
||||
}
|
||||
|
||||
export const Alert: SFC<Props> = props => {
|
||||
export const Alert: FC<Props> = props => {
|
||||
const { message } = props;
|
||||
return (
|
||||
<div className="gf-form-group section">
|
||||
|
@ -6,7 +6,14 @@ import { NavModel, Organization } from '../../types';
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
organization: {} as Organization,
|
||||
navModel: {} as NavModel,
|
||||
navModel: {
|
||||
main: {
|
||||
text: 'Configuration'
|
||||
},
|
||||
node: {
|
||||
text: 'Org details'
|
||||
}
|
||||
} as NavModel,
|
||||
loadOrganization: jest.fn(),
|
||||
setOrganizationName: jest.fn(),
|
||||
updateOrganization: jest.fn(),
|
||||
|
@ -1,13 +1,12 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import PageHeader from '../../core/components/PageHeader/PageHeader';
|
||||
import PageLoader from '../../core/components/PageLoader/PageLoader';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import OrgProfile from './OrgProfile';
|
||||
import SharedPreferences from 'app/core/components/SharedPreferences/SharedPreferences';
|
||||
import { loadOrganization, setOrganizationName, updateOrganization } from './state/actions';
|
||||
import { NavModel, Organization, StoreState } from 'app/types';
|
||||
import { getNavModel } from '../../core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
|
||||
export interface Props {
|
||||
navModel: NavModel;
|
||||
@ -35,10 +34,9 @@ export class OrgDetailsPage extends PureComponent<Props> {
|
||||
const isLoading = Object.keys(organization).length === 0;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader model={navModel} />
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={isLoading}>
|
||||
<div className="page-container page-body">
|
||||
{isLoading && <PageLoader pageName="Organization" />}
|
||||
{!isLoading && (
|
||||
<div>
|
||||
<OrgProfile
|
||||
@ -50,7 +48,8 @@ export class OrgDetailsPage extends PureComponent<Props> {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
export interface Props {
|
||||
orgName: string;
|
||||
@ -6,7 +6,7 @@ export interface Props {
|
||||
onOrgNameChange: (orgName: string) => void;
|
||||
}
|
||||
|
||||
const OrgProfile: SFC<Props> = ({ onSubmit, onOrgNameChange, orgName }) => {
|
||||
const OrgProfile: FC<Props> = ({ onSubmit, onOrgNameChange, orgName }) => {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="page-sub-heading">Organization profile</h3>
|
||||
|
@ -1,25 +1,44 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Org details",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
>
|
||||
<PageLoader
|
||||
pageName="Organization"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render organization and preferences 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Org details",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
>
|
||||
@ -34,5 +53,6 @@ exports[`Render should render organization and preferences 1`] = `
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import PluginListItem from './PluginListItem';
|
||||
import { Plugin } from 'app/types';
|
||||
@ -9,7 +9,7 @@ interface Props {
|
||||
layoutMode: LayoutMode;
|
||||
}
|
||||
|
||||
const PluginList: SFC<Props> = props => {
|
||||
const PluginList: FC<Props> = props => {
|
||||
const { plugins, layoutMode } = props;
|
||||
|
||||
const listStyle = classNames({
|
||||
|
@ -1,11 +1,11 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import { Plugin } from 'app/types';
|
||||
|
||||
interface Props {
|
||||
plugin: Plugin;
|
||||
}
|
||||
|
||||
const PluginListItem: SFC<Props> = props => {
|
||||
const PluginListItem: FC<Props> = props => {
|
||||
const { plugin } = props;
|
||||
|
||||
return (
|
||||
|
@ -6,7 +6,14 @@ import { LayoutModes } from '../../core/components/LayoutSelector/LayoutSelector
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
navModel: {} as NavModel,
|
||||
navModel: {
|
||||
main: {
|
||||
text: 'Configuration'
|
||||
},
|
||||
node: {
|
||||
text: 'Plugins'
|
||||
}
|
||||
} as NavModel,
|
||||
plugins: [] as Plugin[],
|
||||
searchQuery: '',
|
||||
setPluginsSearchQuery: jest.fn(),
|
||||
|
@ -1,15 +1,14 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import OrgActionBar from 'app/core/components/OrgActionBar/OrgActionBar';
|
||||
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||
import PluginList from './PluginList';
|
||||
import { NavModel, Plugin } from 'app/types';
|
||||
import { loadPlugins, setPluginsLayoutMode, setPluginsSearchQuery } from './state/actions';
|
||||
import { getNavModel } from '../../core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { getLayoutMode, getPlugins, getPluginsSearchQuery } from './state/selectors';
|
||||
import { LayoutMode } from '../../core/components/LayoutSelector/LayoutSelector';
|
||||
import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector';
|
||||
|
||||
export interface Props {
|
||||
navModel: NavModel;
|
||||
@ -48,9 +47,9 @@ export class PluginListPage extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader model={navModel} />
|
||||
<div className="page-container page-body">
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
<>
|
||||
<OrgActionBar
|
||||
searchQuery={searchQuery}
|
||||
layoutMode={layoutMode}
|
||||
@ -58,13 +57,12 @@ export class PluginListPage extends PureComponent<Props> {
|
||||
setSearchQuery={query => setPluginsSearchQuery(query)}
|
||||
linkButton={linkButton}
|
||||
/>
|
||||
{hasFetched ? (
|
||||
{hasFetched && plugins && (
|
||||
plugins && <PluginList plugins={plugins} layoutMode={layoutMode} />
|
||||
) : (
|
||||
<PageLoader pageName="Plugins" />
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,20 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Plugins",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
>
|
||||
<OrgActionBar
|
||||
layoutMode="grid"
|
||||
@ -20,20 +28,25 @@ exports[`Render should render component 1`] = `
|
||||
searchQuery=""
|
||||
setSearchQuery={[Function]}
|
||||
/>
|
||||
<PageLoader
|
||||
pageName="Plugins"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render list 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Plugins",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<OrgActionBar
|
||||
layoutMode="grid"
|
||||
@ -51,6 +64,6 @@ exports[`Render should render list 1`] = `
|
||||
layoutMode="grid"
|
||||
plugins={Array []}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
@ -6,7 +6,14 @@ import { getMockTeam, getMultipleMockTeams } from './__mocks__/teamMocks';
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
navModel: {} as NavModel,
|
||||
navModel: {
|
||||
main: {
|
||||
text: 'Configuration'
|
||||
},
|
||||
node: {
|
||||
text: 'Team List'
|
||||
}
|
||||
} as NavModel,
|
||||
teams: [] as Team[],
|
||||
loadTeams: jest.fn(),
|
||||
deleteTeam: jest.fn(),
|
||||
|
@ -1,11 +1,10 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { DeleteButton } from '@grafana/ui';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||
import { NavModel, Team } from '../../types';
|
||||
import { NavModel, Team } from 'app/types';
|
||||
import { loadTeams, deleteTeam, setSearchQuery } from './state/actions';
|
||||
import { getSearchQuery, getTeams, getTeamsCount } from './state/selectors';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
@ -141,10 +140,11 @@ export class TeamList extends PureComponent<Props, any> {
|
||||
const { hasFetched, navModel } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader model={navModel} />
|
||||
{hasFetched ? this.renderList() : <PageLoader pageName="Teams" />}
|
||||
</div>
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
{hasFetched && this.renderList()}
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,21 +1,40 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Team List",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
/>
|
||||
<PageLoader
|
||||
pageName="Teams"
|
||||
/>
|
||||
</div>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render teams table 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Team List",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
>
|
||||
@ -332,5 +351,6 @@ exports[`Render should render teams table 1`] = `
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
@ -11,7 +11,14 @@ jest.mock('../../core/app_events', () => ({
|
||||
|
||||
const setup = (propOverrides?: object) => {
|
||||
const props: Props = {
|
||||
navModel: {} as NavModel,
|
||||
navModel: {
|
||||
main: {
|
||||
text: 'Configuration'
|
||||
},
|
||||
node: {
|
||||
text: 'Users'
|
||||
}
|
||||
} as NavModel,
|
||||
users: [] as OrgUser[],
|
||||
invitees: [] as Invitee[],
|
||||
searchQuery: '',
|
||||
|
@ -2,15 +2,14 @@ import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import Remarkable from 'remarkable';
|
||||
import PageHeader from 'app/core/components/PageHeader/PageHeader';
|
||||
import PageLoader from 'app/core/components/PageLoader/PageLoader';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import UsersActionBar from './UsersActionBar';
|
||||
import UsersTable from './UsersTable';
|
||||
import InviteesTable from './InviteesTable';
|
||||
import { Invitee, NavModel, OrgUser } from 'app/types';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import { loadUsers, loadInvitees, setUsersSearchQuery, updateUser, removeUser } from './state/actions';
|
||||
import { getNavModel } from '../../core/selectors/navModel';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { getInvitees, getUsers, getUsersSearchQuery } from './state/selectors';
|
||||
|
||||
export interface Props {
|
||||
@ -105,16 +104,17 @@ export class UsersListPage extends PureComponent<Props, State> {
|
||||
const externalUserMngInfoHtml = this.externalUserMngInfoHtml;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader model={navModel} />
|
||||
<div className="page-container page-body">
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents isLoading={!hasFetched}>
|
||||
<>
|
||||
<UsersActionBar onShowInvites={this.onShowInvites} showInvites={this.state.showInvites} />
|
||||
{externalUserMngInfoHtml && (
|
||||
<div className="grafana-info-box" dangerouslySetInnerHTML={{ __html: externalUserMngInfoHtml }} />
|
||||
)}
|
||||
{hasFetched ? this.renderTable() : <PageLoader pageName="Users" />}
|
||||
</div>
|
||||
</div>
|
||||
{hasFetched && this.renderTable()}
|
||||
</>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import { OrgUser } from 'app/types';
|
||||
|
||||
export interface Props {
|
||||
@ -7,7 +7,7 @@ export interface Props {
|
||||
onRemoveUser: (user: OrgUser) => void;
|
||||
}
|
||||
|
||||
const UsersTable: SFC<Props> = props => {
|
||||
const UsersTable: FC<Props> = props => {
|
||||
const { users, onRoleChange, onRemoveUser } = props;
|
||||
|
||||
return (
|
||||
|
@ -1,12 +1,20 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Render should render List page 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Users",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={false}
|
||||
>
|
||||
<Connect(UsersActionBar)
|
||||
onShowInvites={[Function]}
|
||||
@ -17,25 +25,30 @@ exports[`Render should render List page 1`] = `
|
||||
onRoleChange={[Function]}
|
||||
users={Array []}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
||||
exports[`Render should render component 1`] = `
|
||||
<div>
|
||||
<PageHeader
|
||||
model={Object {}}
|
||||
/>
|
||||
<div
|
||||
className="page-container page-body"
|
||||
<Page
|
||||
navModel={
|
||||
Object {
|
||||
"main": Object {
|
||||
"text": "Configuration",
|
||||
},
|
||||
"node": Object {
|
||||
"text": "Users",
|
||||
},
|
||||
}
|
||||
}
|
||||
>
|
||||
<PageContents
|
||||
isLoading={true}
|
||||
>
|
||||
<Connect(UsersActionBar)
|
||||
onShowInvites={[Function]}
|
||||
showInvites={false}
|
||||
/>
|
||||
<PageLoader
|
||||
pageName="Users"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import kbn from 'app/core/utils/kbn';
|
||||
@ -14,7 +14,7 @@ export interface Props {
|
||||
usedAlignmentPeriod: string;
|
||||
}
|
||||
|
||||
export const AlignmentPeriods: SFC<Props> = ({
|
||||
export const AlignmentPeriods: FC<Props> = ({
|
||||
alignmentPeriod,
|
||||
templateSrv,
|
||||
onChange,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { MetricSelect } from 'app/core/components/Select/MetricSelect';
|
||||
@ -12,7 +12,7 @@ export interface Props {
|
||||
perSeriesAligner: string;
|
||||
}
|
||||
|
||||
export const Alignments: SFC<Props> = ({ perSeriesAligner, templateSrv, onChange, alignOptions }) => {
|
||||
export const Alignments: FC<Props> = ({ perSeriesAligner, templateSrv, onChange, alignOptions }) => {
|
||||
return (
|
||||
<>
|
||||
<div className="gf-form-group">
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
export const AnnotationsHelp: SFC = () => {
|
||||
export const AnnotationsHelp: FC = () => {
|
||||
return (
|
||||
<div className="gf-form grafana-info-box" style={{ padding: 0 }}>
|
||||
<pre className="gf-form-pre alert alert-info" style={{ marginRight: 0 }}>
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { SFC } from 'react';
|
||||
import React, { FC } from 'react';
|
||||
|
||||
interface Props {
|
||||
onValueChange: (e) => void;
|
||||
@ -7,7 +7,7 @@ interface Props {
|
||||
label: string;
|
||||
}
|
||||
|
||||
const SimpleSelect: SFC<Props> = props => {
|
||||
const SimpleSelect: FC<Props> = props => {
|
||||
const { label, onValueChange, value, options } = props;
|
||||
return (
|
||||
<div className="gf-form max-width-21">
|
||||
|
@ -38,6 +38,14 @@
|
||||
}
|
||||
}
|
||||
|
||||
.is-react .footer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.is-react .custom-scrollbars .footer {
|
||||
display: block;
|
||||
}
|
||||
|
||||
// Keeping footer inside the graphic on Login screen
|
||||
.login-page {
|
||||
.footer {
|
||||
|
@ -20,7 +20,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
.page-scrollbar-wrapper {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.page-scrollbar-content {
|
||||
display: flex;
|
||||
min-height: 100%;
|
||||
flex-direction: column;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.page-container {
|
||||
flex-grow: 1;
|
||||
width: 100%;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
padding-left: $spacer*2;
|
||||
@ -78,7 +94,6 @@
|
||||
|
||||
.page-body {
|
||||
padding-top: $spacer*2;
|
||||
min-height: 500px;
|
||||
}
|
||||
|
||||
.page-heading {
|
||||
|
Loading…
Reference in New Issue
Block a user