mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Pages: update react components to use v2 theme (#33413)
* chore: expose theme types / functions * fix(grafana-ui): withTheme2 extends themeable2 * feat: migrate page components to use new theme * refactor(pages): replace legacy form components with latest form components * refactor(dashboardimport): update page component to use theme spacing * refactor(alerting-ng): update page component to use v2 theme * test(dashboardpage): update test for v2 theme * test(apikeyspage): update test to select InlineSwitch component * test(createteam): update snapshot * refactor(playlist): update page components to use v2 theme * refactor(page): put back classes on page-container and background colors
This commit is contained in:
parent
22ac0fc3cd
commit
249004ebef
@ -1,7 +1,7 @@
|
||||
export { createTheme } from './createTheme';
|
||||
export { ThemeRichColor, GrafanaThemeV2 } from './types';
|
||||
export { ThemeColors } from './createColors';
|
||||
export { ThemeBreakpoints } from './breakpoints';
|
||||
export { ThemeBreakpoints, ThemeBreakpointsKey } from './breakpoints';
|
||||
export { ThemeShadows } from './createShadows';
|
||||
export { ThemeShape } from './createShape';
|
||||
export { ThemeTypography, ThemeTypographyVariant } from './createTypography';
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { createTheme, GrafanaTheme, GrafanaThemeV2 } from '@grafana/data';
|
||||
import hoistNonReactStatics from 'hoist-non-react-statics';
|
||||
import React, { useContext } from 'react';
|
||||
import { Themeable } from '../types/theme';
|
||||
import { Themeable, Themeable2 } from '../types/theme';
|
||||
import { stylesFactory } from './stylesFactory';
|
||||
|
||||
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
|
||||
@ -42,8 +42,8 @@ export const withTheme = <P extends Themeable, S extends {} = {}>(Component: Rea
|
||||
};
|
||||
|
||||
/** @alpha */
|
||||
export const withTheme2 = <P extends Themeable, S extends {} = {}>(Component: React.ComponentType<P>) => {
|
||||
const WithTheme: React.FunctionComponent<Subtract<P, Themeable>> = (props) => {
|
||||
export const withTheme2 = <P extends Themeable2, S extends {} = {}>(Component: React.ComponentType<P>) => {
|
||||
const WithTheme: React.FunctionComponent<Subtract<P, Themeable2>> = (props) => {
|
||||
/**
|
||||
* If theme context is mocked, let's use it instead of the original context
|
||||
* This is used in tests when mocking theme using mockThemeContext function defined below
|
||||
|
@ -1,4 +1,13 @@
|
||||
export { ThemeContext, withTheme, useTheme, useTheme2, useStyles, useStyles2, mockThemeContext } from './ThemeContext';
|
||||
export {
|
||||
ThemeContext,
|
||||
withTheme,
|
||||
withTheme2,
|
||||
useTheme,
|
||||
useTheme2,
|
||||
useStyles,
|
||||
useStyles2,
|
||||
mockThemeContext,
|
||||
} from './ThemeContext';
|
||||
export { getTheme, mockTheme } from './getTheme';
|
||||
export { stylesFactory } from './stylesFactory';
|
||||
export { GlobalStyles } from './GlobalStyles/GlobalStyles';
|
||||
|
@ -6,15 +6,15 @@ import { getTitleFromNavModel } from 'app/core/selectors/navModel';
|
||||
import PageHeader from '../PageHeader/PageHeader';
|
||||
import { Footer } from '../Footer/Footer';
|
||||
import { PageContents } from './PageContents';
|
||||
import { CustomScrollbar, useStyles } from '@grafana/ui';
|
||||
import { GrafanaTheme, NavModel } from '@grafana/data';
|
||||
import { CustomScrollbar, useStyles2 } from '@grafana/ui';
|
||||
import { GrafanaThemeV2, NavModel, ThemeBreakpointsKey } from '@grafana/data';
|
||||
import { Branding } from '../Branding/Branding';
|
||||
import { css, cx } from '@emotion/css';
|
||||
|
||||
interface Props extends HTMLAttributes<HTMLDivElement> {
|
||||
children: React.ReactNode;
|
||||
navModel: NavModel;
|
||||
contentWidth?: keyof GrafanaTheme['breakpoints'];
|
||||
contentWidth?: ThemeBreakpointsKey;
|
||||
}
|
||||
|
||||
export interface PageType extends FC<Props> {
|
||||
@ -23,7 +23,7 @@ export interface PageType extends FC<Props> {
|
||||
}
|
||||
|
||||
export const Page: PageType = ({ navModel, children, className, contentWidth, ...otherProps }) => {
|
||||
const styles = useStyles(getStyles);
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
useEffect(() => {
|
||||
const title = getTitleFromNavModel(navModel);
|
||||
@ -51,17 +51,17 @@ Page.Contents = PageContents;
|
||||
|
||||
export default Page;
|
||||
|
||||
const getStyles = (theme: GrafanaTheme) => ({
|
||||
const getStyles = (theme: GrafanaThemeV2) => ({
|
||||
wrapper: css`
|
||||
background: ${theme.colors.background.primary};
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
background: ${theme.colors.bg1};
|
||||
`,
|
||||
contentWidth: (size: keyof GrafanaTheme['breakpoints']) => css`
|
||||
contentWidth: (size: ThemeBreakpointsKey) => css`
|
||||
.page-container {
|
||||
max-width: ${theme.breakpoints[size]};
|
||||
max-width: ${theme.breakpoints.values[size]}px;
|
||||
}
|
||||
`,
|
||||
});
|
||||
|
@ -2,9 +2,9 @@ import React, { FormEvent, PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect, ConnectedProps } from 'react-redux';
|
||||
import { css } from '@emotion/css';
|
||||
import { GrafanaTheme, SelectableValue } from '@grafana/data';
|
||||
import { GrafanaThemeV2, SelectableValue } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { PageToolbar, stylesFactory, ToolbarButton } from '@grafana/ui';
|
||||
import { PageToolbar, stylesFactory, ToolbarButton, withTheme2, Themeable2 } from '@grafana/ui';
|
||||
import { config } from 'app/core/config';
|
||||
import { SplitPaneWrapper } from 'app/core/components/SplitPaneWrapper/SplitPaneWrapper';
|
||||
import { AlertingQueryEditor } from './components/AlertingQueryEditor';
|
||||
@ -48,13 +48,13 @@ const connector = connect(mapStateToProps, mapDispatchToProps);
|
||||
|
||||
interface RouteProps extends GrafanaRouteComponentProps<{ id: string }> {}
|
||||
|
||||
interface OwnProps {
|
||||
interface OwnProps extends Themeable2 {
|
||||
saveDefinition: typeof createAlertDefinition | typeof updateAlertDefinition;
|
||||
}
|
||||
|
||||
type Props = OwnProps & ConnectedProps<typeof connector>;
|
||||
|
||||
class NextGenAlertingPageUnconnected extends PureComponent<Props> {
|
||||
class UnthemedNextGenAlertingPage extends PureComponent<Props> {
|
||||
componentDidMount() {
|
||||
const { getAlertDefinition, pageId } = this.props;
|
||||
|
||||
@ -122,9 +122,9 @@ class NextGenAlertingPageUnconnected extends PureComponent<Props> {
|
||||
}
|
||||
|
||||
render() {
|
||||
const { alertDefinition, uiState, updateAlertDefinitionUiState, getInstances } = this.props;
|
||||
const { alertDefinition, uiState, updateAlertDefinitionUiState, getInstances, theme } = this.props;
|
||||
|
||||
const styles = getStyles(config.theme);
|
||||
const styles = getStyles(theme);
|
||||
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
@ -154,16 +154,18 @@ class NextGenAlertingPageUnconnected extends PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const NextGenAlertingPageUnconnected = withTheme2(UnthemedNextGenAlertingPage);
|
||||
|
||||
export default hot(module)(connector(NextGenAlertingPageUnconnected));
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => ({
|
||||
const getStyles = stylesFactory((theme: GrafanaThemeV2) => ({
|
||||
wrapper: css`
|
||||
width: calc(100% - 55px);
|
||||
height: 100%;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
background: ${theme.colors.dashboardBg};
|
||||
background: ${theme.colors.background.canvas};
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`,
|
||||
|
@ -187,8 +187,8 @@ describe('ApiKeysPage', () => {
|
||||
});
|
||||
|
||||
function toggleShowExpired() {
|
||||
expect(screen.getByText(/show expired/i)).toBeInTheDocument();
|
||||
userEvent.click(screen.getByText(/show expired/i));
|
||||
expect(screen.queryByLabelText(/show expired/i)).toBeInTheDocument();
|
||||
userEvent.click(screen.getByLabelText(/show expired/i));
|
||||
}
|
||||
|
||||
async function addAndVerifyApiKey(addApiKeyMock: jest.Mock, includeExpired: boolean) {
|
||||
|
@ -11,7 +11,7 @@ import { ApiKeysAddedModal } from './ApiKeysAddedModal';
|
||||
import config from 'app/core/config';
|
||||
import appEvents from 'app/core/app_events';
|
||||
import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA';
|
||||
import { LegacyForms } from '@grafana/ui';
|
||||
import { InlineField, InlineSwitch } from '@grafana/ui';
|
||||
import { rangeUtil } from '@grafana/data';
|
||||
import { getTimeZone } from 'app/features/profile/state/selectors';
|
||||
import { setSearchQuery } from './state/reducers';
|
||||
@ -21,8 +21,6 @@ import { ApiKeysTable } from './ApiKeysTable';
|
||||
import { ApiKeysController } from './ApiKeysController';
|
||||
import { ShowModalReactEvent } from 'app/types/events';
|
||||
|
||||
const { Switch } = LegacyForms;
|
||||
|
||||
function mapStateToProps(state: StoreState) {
|
||||
return {
|
||||
navModel: getNavModel(state.navIndex, 'apikeys'),
|
||||
@ -154,7 +152,9 @@ export class ApiKeysPageUnconnected extends PureComponent<Props, State> {
|
||||
{showTable ? (
|
||||
<>
|
||||
<h3 className="page-heading">Existing API keys</h3>
|
||||
<Switch label="Show expired" checked={includeExpired} onChange={this.onIncludeExpiredChange} />
|
||||
<InlineField label="Show expired">
|
||||
<InlineSwitch id="showExpired" value={includeExpired} onChange={this.onIncludeExpiredChange} />
|
||||
</InlineField>
|
||||
<ApiKeysTable apiKeys={apiKeys} timeZone={timeZone} onDelete={this.onDeleteApiKey} />
|
||||
</>
|
||||
) : null}
|
||||
|
@ -8,7 +8,7 @@ import { notifyApp } from 'app/core/actions';
|
||||
import { cleanUpDashboardAndVariables } from '../state/actions';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { getRouteComponentProps } from 'app/core/navigation/__mocks__/routeProps';
|
||||
import { getTheme } from '@grafana/ui';
|
||||
import { createTheme } from '@grafana/data';
|
||||
|
||||
jest.mock('app/features/dashboard/components/DashboardSettings/GeneralSettings', () => ({}));
|
||||
|
||||
@ -68,7 +68,7 @@ function dashboardPageScenario(description: string, scenarioFn: (ctx: ScenarioCo
|
||||
cancelVariables: jest.fn(),
|
||||
templateVarsChangedInUrl: jest.fn(),
|
||||
dashboard: null,
|
||||
theme: getTheme(),
|
||||
theme: createTheme(),
|
||||
};
|
||||
|
||||
Object.assign(props, propOverrides);
|
||||
|
@ -5,7 +5,7 @@ import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { selectors } from '@grafana/e2e-selectors';
|
||||
import { CustomScrollbar, stylesFactory, Themeable, withTheme } from '@grafana/ui';
|
||||
import { CustomScrollbar, stylesFactory, Themeable2, withTheme2 } from '@grafana/ui';
|
||||
|
||||
import { createErrorNotification } from 'app/core/copy/appNotification';
|
||||
import { Branding } from 'app/core/components/Branding/Branding';
|
||||
@ -26,7 +26,7 @@ import { dashboardWatcher } from 'app/features/live/dashboard/dashboardWatcher';
|
||||
import { GrafanaRouteComponentProps } from 'app/core/navigation/types';
|
||||
import { getTimeSrv } from '../services/TimeSrv';
|
||||
import { getKioskMode } from 'app/core/navigation/kiosk';
|
||||
import { GrafanaTheme, UrlQueryValue } from '@grafana/data';
|
||||
import { GrafanaThemeV2, UrlQueryValue } from '@grafana/data';
|
||||
import { DashboardLoading } from '../components/DashboardLoading/DashboardLoading';
|
||||
import { DashboardFailed } from '../components/DashboardLoading/DashboardFailed';
|
||||
|
||||
@ -50,7 +50,7 @@ type DashboardPageRouteSearchParams = {
|
||||
};
|
||||
|
||||
export interface Props
|
||||
extends Themeable,
|
||||
extends Themeable2,
|
||||
GrafanaRouteComponentProps<DashboardPageRouteParams, DashboardPageRouteSearchParams> {
|
||||
initPhase: DashboardInitPhase;
|
||||
isInitSlow: boolean;
|
||||
@ -373,7 +373,7 @@ const mapDispatchToProps = {
|
||||
/*
|
||||
* Styles
|
||||
*/
|
||||
export const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
export const getStyles = stylesFactory((theme: GrafanaThemeV2) => {
|
||||
return {
|
||||
dashboardContainer: css`
|
||||
position: absolute;
|
||||
@ -392,13 +392,13 @@ export const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
display: flex;
|
||||
`,
|
||||
dashboardContent: css`
|
||||
padding: ${theme.spacing.md};
|
||||
padding: ${theme.spacing(2)};
|
||||
flex-basis: 100%;
|
||||
flex-grow: 1;
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
||||
export const DashboardPage = withTheme(UnthemedDashboardPage);
|
||||
export const DashboardPage = withTheme2(UnthemedDashboardPage);
|
||||
DashboardPage.displayName = 'DashboardPage';
|
||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(DashboardPage));
|
||||
|
@ -1,8 +1,19 @@
|
||||
import React, { FormEvent, PureComponent } from 'react';
|
||||
import { MapDispatchToProps, MapStateToProps } from 'react-redux';
|
||||
import { css } from '@emotion/css';
|
||||
import { AppEvents, NavModel } from '@grafana/data';
|
||||
import { Button, stylesFactory, Input, TextArea, Field, Form, Legend, FileUpload } from '@grafana/ui';
|
||||
import { AppEvents, GrafanaThemeV2, NavModel } from '@grafana/data';
|
||||
import {
|
||||
Button,
|
||||
stylesFactory,
|
||||
withTheme2,
|
||||
Input,
|
||||
TextArea,
|
||||
Field,
|
||||
Form,
|
||||
Legend,
|
||||
FileUpload,
|
||||
Themeable2,
|
||||
} from '@grafana/ui';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { connectWithCleanUp } from 'app/core/components/connectWithCleanUp';
|
||||
import { ImportDashboardOverview } from './components/ImportDashboardOverview';
|
||||
@ -12,7 +23,7 @@ import appEvents from 'app/core/app_events';
|
||||
import { getNavModel } from 'app/core/selectors/navModel';
|
||||
import { StoreState } from 'app/types';
|
||||
|
||||
interface OwnProps {}
|
||||
interface OwnProps extends Themeable2 {}
|
||||
|
||||
interface ConnectedProps {
|
||||
navModel: NavModel;
|
||||
@ -26,7 +37,7 @@ interface DispatchProps {
|
||||
|
||||
type Props = OwnProps & ConnectedProps & DispatchProps;
|
||||
|
||||
class DashboardImportUnConnected extends PureComponent<Props> {
|
||||
class UnthemedDashboardImport extends PureComponent<Props> {
|
||||
onFileUpload = (event: FormEvent<HTMLInputElement>) => {
|
||||
const { importDashboardJson } = this.props;
|
||||
const file = event.currentTarget.files && event.currentTarget.files.length > 0 && event.currentTarget.files[0];
|
||||
@ -72,7 +83,7 @@ class DashboardImportUnConnected extends PureComponent<Props> {
|
||||
};
|
||||
|
||||
renderImportForm() {
|
||||
const styles = importStyles();
|
||||
const styles = importStyles(this.props.theme);
|
||||
|
||||
return (
|
||||
<>
|
||||
@ -134,6 +145,8 @@ class DashboardImportUnConnected extends PureComponent<Props> {
|
||||
}
|
||||
}
|
||||
|
||||
const DashboardImportUnConnected = withTheme2(UnthemedDashboardImport);
|
||||
|
||||
const mapStateToProps: MapStateToProps<ConnectedProps, OwnProps, StoreState> = (state: StoreState) => ({
|
||||
navModel: getNavModel(state.navIndex, 'import', undefined, true),
|
||||
isLoaded: state.importDashboard.isLoaded,
|
||||
@ -154,10 +167,10 @@ export default DashboardImportPage;
|
||||
|
||||
DashboardImportPage.displayName = 'DashboardImport';
|
||||
|
||||
const importStyles = stylesFactory(() => {
|
||||
const importStyles = stylesFactory((theme: GrafanaThemeV2) => {
|
||||
return {
|
||||
option: css`
|
||||
margin-bottom: 32px;
|
||||
margin-bottom: ${theme.spacing(4)};
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
@ -2,7 +2,7 @@ import React, { FC } from 'react';
|
||||
import { connect, MapStateToProps } from 'react-redux';
|
||||
import { NavModel } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { useStyles } from '@grafana/ui';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { StoreState } from 'app/types';
|
||||
@ -25,7 +25,7 @@ export interface RouteParams {
|
||||
interface Props extends ConnectedProps, GrafanaRouteComponentProps<RouteParams> {}
|
||||
|
||||
export const PlaylistEditPage: FC<Props> = ({ navModel, match }) => {
|
||||
const styles = useStyles(getPlaylistStyles);
|
||||
const styles = useStyles2(getPlaylistStyles);
|
||||
const { playlist, loading } = usePlaylist(match.params.id);
|
||||
const onSubmit = async (playlist: Playlist) => {
|
||||
await updatePlaylist(match.params.id, playlist);
|
||||
|
@ -2,7 +2,7 @@ import React, { FC } from 'react';
|
||||
import { connect, MapStateToProps } from 'react-redux';
|
||||
import { NavModel } from '@grafana/data';
|
||||
import { locationService } from '@grafana/runtime';
|
||||
import { useStyles } from '@grafana/ui';
|
||||
import { useStyles2 } from '@grafana/ui';
|
||||
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { StoreState } from 'app/types';
|
||||
@ -21,7 +21,7 @@ interface ConnectedProps {
|
||||
interface Props extends ConnectedProps, GrafanaRouteComponentProps {}
|
||||
|
||||
export const PlaylistNewPage: FC<Props> = ({ navModel }) => {
|
||||
const styles = useStyles(getPlaylistStyles);
|
||||
const styles = useStyles2(getPlaylistStyles);
|
||||
const { playlist, loading } = usePlaylist();
|
||||
const onSubmit = async (playlist: Playlist) => {
|
||||
await createPlaylist(playlist);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { GrafanaThemeV2 } from '@grafana/data';
|
||||
import { css } from '@emotion/css';
|
||||
|
||||
export function getPlaylistStyles(theme: GrafanaTheme) {
|
||||
export function getPlaylistStyles(theme: GrafanaThemeV2) {
|
||||
return {
|
||||
description: css`
|
||||
label: description;
|
||||
@ -10,7 +10,7 @@ export function getPlaylistStyles(theme: GrafanaTheme) {
|
||||
`,
|
||||
subHeading: css`
|
||||
label: sub-heading;
|
||||
margin-bottom: ${theme.spacing.md};
|
||||
margin-bottom: ${theme.spacing(2)};
|
||||
`,
|
||||
};
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import Page from 'app/core/components/Page/Page';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { Button, LegacyForms } from '@grafana/ui';
|
||||
const { FormField } = LegacyForms;
|
||||
import { Button, Form, Field, Input, FieldSet, Label, Tooltip, Icon } from '@grafana/ui';
|
||||
import { NavModel } from '@grafana/data';
|
||||
import { getBackendSrv, locationService } from '@grafana/runtime';
|
||||
import { connect } from 'react-redux';
|
||||
@ -13,78 +12,50 @@ export interface Props {
|
||||
navModel: NavModel;
|
||||
}
|
||||
|
||||
interface State {
|
||||
interface TeamDTO {
|
||||
name: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export class CreateTeam extends PureComponent<Props, State> {
|
||||
state: State = {
|
||||
name: '',
|
||||
email: '',
|
||||
};
|
||||
|
||||
create = async (event: React.FormEvent<HTMLFormElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
const { name, email } = this.state;
|
||||
|
||||
const result = await getBackendSrv().post('/api/teams', { name, email });
|
||||
export class CreateTeam extends PureComponent<Props> {
|
||||
create = async (formModel: TeamDTO) => {
|
||||
const result = await getBackendSrv().post('/api/teams', formModel);
|
||||
if (result.teamId) {
|
||||
locationService.push(`/org/teams/edit/${result.teamId}`);
|
||||
}
|
||||
};
|
||||
|
||||
onEmailChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
email: event.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
onNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
this.setState({
|
||||
name: event.target.value,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navModel } = this.props;
|
||||
const { name, email } = this.state;
|
||||
|
||||
return (
|
||||
<Page navModel={navModel}>
|
||||
<Page.Contents>
|
||||
<>
|
||||
<h3 className="page-sub-heading">New Team</h3>
|
||||
|
||||
<form className="gf-form-group" onSubmit={this.create}>
|
||||
<FormField
|
||||
className="gf-form"
|
||||
label="Name"
|
||||
value={name}
|
||||
onChange={this.onNameChange}
|
||||
inputWidth={30}
|
||||
labelWidth={10}
|
||||
required
|
||||
/>
|
||||
<FormField
|
||||
type="email"
|
||||
className="gf-form"
|
||||
label="Email"
|
||||
value={email}
|
||||
onChange={this.onEmailChange}
|
||||
inputWidth={30}
|
||||
labelWidth={10}
|
||||
placeholder="email@test.com"
|
||||
tooltip="This is optional and is primarily used for allowing custom team avatars."
|
||||
/>
|
||||
<div className="gf-form-button-row">
|
||||
<Button type="submit" variant="primary">
|
||||
Create
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</>
|
||||
<Form onSubmit={this.create}>
|
||||
{({ register }) => (
|
||||
<FieldSet label="New Team">
|
||||
<Field label="Name">
|
||||
<Input name="name" ref={register({ required: true })} width={60} />
|
||||
</Field>
|
||||
<Field
|
||||
label={
|
||||
<Label>
|
||||
<span>Email</span>
|
||||
<Tooltip content="This is optional and is primarily used for allowing custom team avatars.">
|
||||
<Icon name="info-circle" style={{ marginLeft: 6 }} />
|
||||
</Tooltip>
|
||||
</Label>
|
||||
}
|
||||
>
|
||||
<Input type="email" name="email" ref={register()} placeholder="email@test.com" width={60} />
|
||||
</Field>
|
||||
<div className="gf-form-button-row">
|
||||
<Button type="submit" variant="primary">
|
||||
Create
|
||||
</Button>
|
||||
</div>
|
||||
</FieldSet>
|
||||
)}
|
||||
</Form>
|
||||
</Page.Contents>
|
||||
</Page>
|
||||
);
|
||||
|
@ -5,46 +5,11 @@ exports[`Render should render component 1`] = `
|
||||
navModel={Object {}}
|
||||
>
|
||||
<PageContents>
|
||||
<h3
|
||||
className="page-sub-heading"
|
||||
>
|
||||
New Team
|
||||
</h3>
|
||||
<form
|
||||
className="gf-form-group"
|
||||
<Form
|
||||
onSubmit={[Function]}
|
||||
>
|
||||
<FormField
|
||||
className="gf-form"
|
||||
inputWidth={30}
|
||||
label="Name"
|
||||
labelWidth={10}
|
||||
onChange={[Function]}
|
||||
required={true}
|
||||
value=""
|
||||
/>
|
||||
<FormField
|
||||
className="gf-form"
|
||||
inputWidth={30}
|
||||
label="Email"
|
||||
labelWidth={10}
|
||||
onChange={[Function]}
|
||||
placeholder="email@test.com"
|
||||
tooltip="This is optional and is primarily used for allowing custom team avatars."
|
||||
type="email"
|
||||
value=""
|
||||
/>
|
||||
<div
|
||||
className="gf-form-button-row"
|
||||
>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="primary"
|
||||
>
|
||||
Create
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
<Component />
|
||||
</Form>
|
||||
</PageContents>
|
||||
</Page>
|
||||
`;
|
||||
|
Loading…
Reference in New Issue
Block a user