mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Migration: Settings forms (#24741)
* Migrate shared preferences * Remove unused import * Migrate org name form * Update TeamSettings * Convert user settings * Fix inital default values * Update snapshots * Fix CI errors * Fix failing Ci * Update snapshots * Large spacing * Move use Form for OrgSettings and add FieldSet * Remove snapshots * Add snapshots * Remove unused prop
This commit is contained in:
parent
1e38a24b88
commit
d3299796f5
@ -23,6 +23,7 @@ export { UnitPicker } from './UnitPicker/UnitPicker';
|
|||||||
export { StatsPicker } from './StatsPicker/StatsPicker';
|
export { StatsPicker } from './StatsPicker/StatsPicker';
|
||||||
export { RefreshPicker } from './RefreshPicker/RefreshPicker';
|
export { RefreshPicker } from './RefreshPicker/RefreshPicker';
|
||||||
export { TimeRangePicker } from './TimePicker/TimeRangePicker';
|
export { TimeRangePicker } from './TimePicker/TimeRangePicker';
|
||||||
|
export { TimeZonePicker } from './TimePicker/TimeZonePicker';
|
||||||
export { TimeOfDayPicker } from './TimePicker/TimeOfDayPicker';
|
export { TimeOfDayPicker } from './TimePicker/TimeOfDayPicker';
|
||||||
export { List } from './List/List';
|
export { List } from './List/List';
|
||||||
export { TagsInput } from './TagsInput/TagsInput';
|
export { TagsInput } from './TagsInput/TagsInput';
|
||||||
|
@ -10,6 +10,7 @@ import { loadOrganization, updateOrganization } from './state/actions';
|
|||||||
import { Organization, StoreState } from 'app/types';
|
import { Organization, StoreState } from 'app/types';
|
||||||
import { getNavModel } from 'app/core/selectors/navModel';
|
import { getNavModel } from 'app/core/selectors/navModel';
|
||||||
import { setOrganizationName } from './state/reducers';
|
import { setOrganizationName } from './state/reducers';
|
||||||
|
import { VerticalGroup } from '@grafana/ui';
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
navModel: NavModel;
|
navModel: NavModel;
|
||||||
@ -24,11 +25,8 @@ export class OrgDetailsPage extends PureComponent<Props> {
|
|||||||
await this.props.loadOrganization();
|
await this.props.loadOrganization();
|
||||||
}
|
}
|
||||||
|
|
||||||
onOrgNameChange = (name: string) => {
|
onUpdateOrganization = (orgName: string) => {
|
||||||
this.props.setOrganizationName(name);
|
this.props.setOrganizationName(orgName);
|
||||||
};
|
|
||||||
|
|
||||||
onUpdateOrganization = () => {
|
|
||||||
this.props.updateOrganization();
|
this.props.updateOrganization();
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -40,14 +38,10 @@ export class OrgDetailsPage extends PureComponent<Props> {
|
|||||||
<Page navModel={navModel}>
|
<Page navModel={navModel}>
|
||||||
<Page.Contents isLoading={isLoading}>
|
<Page.Contents isLoading={isLoading}>
|
||||||
{!isLoading && (
|
{!isLoading && (
|
||||||
<div>
|
<VerticalGroup>
|
||||||
<OrgProfile
|
<OrgProfile onSubmit={this.onUpdateOrganization} orgName={organization.name} />
|
||||||
onOrgNameChange={name => this.onOrgNameChange(name)}
|
|
||||||
onSubmit={this.onUpdateOrganization}
|
|
||||||
orgName={organization.name}
|
|
||||||
/>
|
|
||||||
<SharedPreferences resourceUri="org" />
|
<SharedPreferences resourceUri="org" />
|
||||||
</div>
|
</VerticalGroup>
|
||||||
)}
|
)}
|
||||||
</Page.Contents>
|
</Page.Contents>
|
||||||
</Page>
|
</Page>
|
||||||
|
@ -6,7 +6,6 @@ const setup = () => {
|
|||||||
const props: Props = {
|
const props: Props = {
|
||||||
orgName: 'Main org',
|
orgName: 'Main org',
|
||||||
onSubmit: jest.fn(),
|
onSubmit: jest.fn(),
|
||||||
onOrgNameChange: jest.fn(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return shallow(<OrgProfile {...props} />);
|
return shallow(<OrgProfile {...props} />);
|
||||||
|
@ -1,43 +1,28 @@
|
|||||||
import React, { ChangeEvent, FC } from 'react';
|
import React, { FC } from 'react';
|
||||||
import { LegacyForms } from '@grafana/ui';
|
import { Input, Field, FieldSet, Button, Form } from '@grafana/ui';
|
||||||
const { Input } = LegacyForms;
|
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
orgName: string;
|
orgName: string;
|
||||||
onSubmit: () => void;
|
onSubmit: (orgName: string) => void;
|
||||||
onOrgNameChange: (orgName: string) => void;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const OrgProfile: FC<Props> = ({ onSubmit, onOrgNameChange, orgName }) => {
|
interface FormDTO {
|
||||||
|
orgName: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const OrgProfile: FC<Props> = ({ onSubmit, orgName }) => {
|
||||||
return (
|
return (
|
||||||
<div>
|
<Form defaultValues={{ orgName }} onSubmit={({ orgName }: FormDTO) => onSubmit(orgName)}>
|
||||||
<h3 className="page-sub-heading">Organization profile</h3>
|
{({ register }) => (
|
||||||
<form
|
<FieldSet label="Organization profile">
|
||||||
name="orgForm"
|
<Field label="Organization name">
|
||||||
className="gf-form-group"
|
<Input name="orgName" type="text" ref={register({ required: true })} />
|
||||||
onSubmit={event => {
|
</Field>
|
||||||
event.preventDefault();
|
|
||||||
onSubmit();
|
<Button type="submit">Update organization name</Button>
|
||||||
}}
|
</FieldSet>
|
||||||
>
|
)}
|
||||||
<div className="gf-form-inline">
|
</Form>
|
||||||
<div className="gf-form max-width-28">
|
|
||||||
<span className="gf-form-label">Organization name</span>
|
|
||||||
<Input
|
|
||||||
className="gf-form-input"
|
|
||||||
type="text"
|
|
||||||
onChange={(event: ChangeEvent<HTMLInputElement>) => onOrgNameChange(event.target.value)}
|
|
||||||
value={orgName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="gf-form-button-row">
|
|
||||||
<button type="submit" className="btn btn-primary">
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,16 +35,15 @@ exports[`Render should render organization and preferences 1`] = `
|
|||||||
<PageContents
|
<PageContents
|
||||||
isLoading={false}
|
isLoading={false}
|
||||||
>
|
>
|
||||||
<div>
|
<Component>
|
||||||
<OrgProfile
|
<OrgProfile
|
||||||
onOrgNameChange={[Function]}
|
|
||||||
onSubmit={[Function]}
|
onSubmit={[Function]}
|
||||||
orgName="Cool org"
|
orgName="Cool org"
|
||||||
/>
|
/>
|
||||||
<SharedPreferences
|
<SharedPreferences
|
||||||
resourceUri="org"
|
resourceUri="org"
|
||||||
/>
|
/>
|
||||||
</div>
|
</Component>
|
||||||
</PageContents>
|
</PageContents>
|
||||||
</Page>
|
</Page>
|
||||||
`;
|
`;
|
||||||
|
@ -1,46 +1,14 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Render should render component 1`] = `
|
exports[`Render should render component 1`] = `
|
||||||
<div>
|
<Form
|
||||||
<h3
|
defaultValues={
|
||||||
className="page-sub-heading"
|
Object {
|
||||||
>
|
"orgName": "Main org",
|
||||||
Organization profile
|
}
|
||||||
</h3>
|
}
|
||||||
<form
|
onSubmit={[Function]}
|
||||||
className="gf-form-group"
|
>
|
||||||
name="orgForm"
|
<Component />
|
||||||
onSubmit={[Function]}
|
</Form>
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="gf-form-inline"
|
|
||||||
>
|
|
||||||
<div
|
|
||||||
className="gf-form max-width-28"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="gf-form-label"
|
|
||||||
>
|
|
||||||
Organization name
|
|
||||||
</span>
|
|
||||||
<Input
|
|
||||||
className="gf-form-input"
|
|
||||||
onChange={[Function]}
|
|
||||||
type="text"
|
|
||||||
value="Main org"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="gf-form-button-row"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="btn btn-primary"
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
`;
|
`;
|
||||||
|
@ -12,7 +12,7 @@ const setup = (propOverrides?: object) => {
|
|||||||
Object.assign(props, propOverrides);
|
Object.assign(props, propOverrides);
|
||||||
|
|
||||||
const wrapper = shallow(<TeamSettings {...props} />);
|
const wrapper = shallow(<TeamSettings {...props} />);
|
||||||
const instance = wrapper.instance() as TeamSettings;
|
const instance = wrapper.instance() as any;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
wrapper,
|
wrapper,
|
||||||
@ -27,18 +27,3 @@ describe('Render', () => {
|
|||||||
expect(wrapper).toMatchSnapshot();
|
expect(wrapper).toMatchSnapshot();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Functions', () => {
|
|
||||||
it('should update team', () => {
|
|
||||||
const { instance } = setup();
|
|
||||||
const mockEvent = { preventDefault: jest.fn() };
|
|
||||||
|
|
||||||
instance.setState({
|
|
||||||
name: 'test11',
|
|
||||||
});
|
|
||||||
|
|
||||||
instance.onUpdate(mockEvent);
|
|
||||||
|
|
||||||
expect(instance.props.updateTeam).toHaveBeenCalledWith('test11', 'test@test.com');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React from 'react';
|
import React, { FC } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { InlineFormLabel, LegacyForms } from '@grafana/ui';
|
import { Input, Field, Form, Button, FieldSet, VerticalGroup } from '@grafana/ui';
|
||||||
const { Input } = LegacyForms;
|
|
||||||
|
|
||||||
import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences';
|
import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences';
|
||||||
import { updateTeam } from './state/actions';
|
import { updateTeam } from './state/actions';
|
||||||
@ -14,78 +13,37 @@ export interface Props {
|
|||||||
updateTeam: typeof updateTeam;
|
updateTeam: typeof updateTeam;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
export const TeamSettings: FC<Props> = ({ team, updateTeam }) => {
|
||||||
name: string;
|
return (
|
||||||
email: string;
|
<VerticalGroup>
|
||||||
}
|
<FieldSet label="Team Settings">
|
||||||
|
<Form
|
||||||
|
defaultValues={{ ...team }}
|
||||||
|
onSubmit={(formTeam: Team) => {
|
||||||
|
updateTeam(formTeam.name, formTeam.email);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{({ register }) => (
|
||||||
|
<>
|
||||||
|
<Field label="Name">
|
||||||
|
<Input name="name" ref={register({ required: true })} />
|
||||||
|
</Field>
|
||||||
|
|
||||||
export class TeamSettings extends React.Component<Props, State> {
|
<Field
|
||||||
constructor(props: Props) {
|
label="Email"
|
||||||
super(props);
|
description="This is optional and is primarily used to set the team profile avatar (via gravatar service)"
|
||||||
|
>
|
||||||
this.state = {
|
<Input placeholder="team@email.com" type="email" name="email" ref={register} />
|
||||||
name: props.team.name,
|
</Field>
|
||||||
email: props.team.email,
|
<Button type="submit">Update</Button>
|
||||||
};
|
</>
|
||||||
}
|
)}
|
||||||
|
</Form>
|
||||||
onChangeName = (event: any) => {
|
</FieldSet>
|
||||||
this.setState({ name: event.target.value });
|
<SharedPreferences resourceUri={`teams/${team.id}`} />
|
||||||
};
|
</VerticalGroup>
|
||||||
|
);
|
||||||
onChangeEmail = (event: any) => {
|
};
|
||||||
this.setState({ email: event.target.value });
|
|
||||||
};
|
|
||||||
|
|
||||||
onUpdate = (event: any) => {
|
|
||||||
const { name, email } = this.state;
|
|
||||||
event.preventDefault();
|
|
||||||
this.props.updateTeam(name, email);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { team } = this.props;
|
|
||||||
const { name, email } = this.state;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h3 className="page-sub-heading">Team Settings</h3>
|
|
||||||
<form name="teamDetailsForm" className="gf-form-group" onSubmit={this.onUpdate}>
|
|
||||||
<div className="gf-form max-width-30">
|
|
||||||
<InlineFormLabel>Name</InlineFormLabel>
|
|
||||||
<Input
|
|
||||||
type="text"
|
|
||||||
required
|
|
||||||
value={name}
|
|
||||||
className="gf-form-input max-width-22"
|
|
||||||
onChange={this.onChangeName}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="gf-form max-width-30">
|
|
||||||
<InlineFormLabel tooltip="This is optional and is primarily used to set the team profile avatar (via gravatar service)">
|
|
||||||
Email
|
|
||||||
</InlineFormLabel>
|
|
||||||
<Input
|
|
||||||
type="email"
|
|
||||||
className="gf-form-input max-width-22"
|
|
||||||
value={email}
|
|
||||||
placeholder="team@email.com"
|
|
||||||
onChange={this.onChangeEmail}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="gf-form-button-row">
|
|
||||||
<button type="submit" className="btn btn-primary">
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<SharedPreferences resourceUri={`teams/${team.id}`} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapStateToProps(state: any) {
|
function mapStateToProps(state: any) {
|
||||||
const teamId = getRouteParamsId(state.location);
|
const teamId = getRouteParamsId(state.location);
|
||||||
|
@ -44,7 +44,7 @@ exports[`Render should render settings and preferences page 1`] = `
|
|||||||
<PageContents
|
<PageContents
|
||||||
isLoading={true}
|
isLoading={true}
|
||||||
>
|
>
|
||||||
<Connect(TeamSettings) />
|
<Connect(Component) />
|
||||||
</PageContents>
|
</PageContents>
|
||||||
</Page>
|
</Page>
|
||||||
`;
|
`;
|
||||||
@ -66,7 +66,7 @@ exports[`Render when feature toggle editorsCanAdmin is turned on should render s
|
|||||||
<PageContents
|
<PageContents
|
||||||
isLoading={true}
|
isLoading={true}
|
||||||
>
|
>
|
||||||
<Connect(TeamSettings) />
|
<Connect(Component) />
|
||||||
</PageContents>
|
</PageContents>
|
||||||
</Page>
|
</Page>
|
||||||
`;
|
`;
|
||||||
|
@ -1,60 +1,28 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`Render should render component 1`] = `
|
exports[`Render should render component 1`] = `
|
||||||
<div>
|
<Component>
|
||||||
<h3
|
<Component
|
||||||
className="page-sub-heading"
|
label="Team Settings"
|
||||||
>
|
>
|
||||||
Team Settings
|
<Form
|
||||||
</h3>
|
defaultValues={
|
||||||
<form
|
Object {
|
||||||
className="gf-form-group"
|
"avatarUrl": "some/url/",
|
||||||
name="teamDetailsForm"
|
"email": "test@test.com",
|
||||||
onSubmit={[Function]}
|
"id": 1,
|
||||||
>
|
"memberCount": 1,
|
||||||
<div
|
"name": "test",
|
||||||
className="gf-form max-width-30"
|
"permission": 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onSubmit={[Function]}
|
||||||
>
|
>
|
||||||
<Component>
|
<Component />
|
||||||
Name
|
</Form>
|
||||||
</Component>
|
</Component>
|
||||||
<Input
|
|
||||||
className="gf-form-input max-width-22"
|
|
||||||
onChange={[Function]}
|
|
||||||
required={true}
|
|
||||||
type="text"
|
|
||||||
value="test"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="gf-form max-width-30"
|
|
||||||
>
|
|
||||||
<Component
|
|
||||||
tooltip="This is optional and is primarily used to set the team profile avatar (via gravatar service)"
|
|
||||||
>
|
|
||||||
Email
|
|
||||||
</Component>
|
|
||||||
<Input
|
|
||||||
className="gf-form-input max-width-22"
|
|
||||||
onChange={[Function]}
|
|
||||||
placeholder="team@email.com"
|
|
||||||
type="email"
|
|
||||||
value="test@test.com"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className="gf-form-button-row"
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className="btn btn-primary"
|
|
||||||
type="submit"
|
|
||||||
>
|
|
||||||
Update
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
<SharedPreferences
|
<SharedPreferences
|
||||||
resourceUri="teams/1"
|
resourceUri="teams/1"
|
||||||
/>
|
/>
|
||||||
</div>
|
</Component>
|
||||||
`;
|
`;
|
||||||
|
Loading…
Reference in New Issue
Block a user