mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
simple select
This commit is contained in:
parent
1f8b61f9a6
commit
a98f7e548f
33
public/app/core/components/Picker/SimplePicker.tsx
Normal file
33
public/app/core/components/Picker/SimplePicker.tsx
Normal file
@ -0,0 +1,33 @@
|
||||
import React, { SFC } from 'react';
|
||||
import Select from 'react-select';
|
||||
import DescriptionOption from './DescriptionOption';
|
||||
import ResetStyles from './ResetStyles';
|
||||
|
||||
interface Props {
|
||||
options: any[];
|
||||
className?: string;
|
||||
onSelected: (item: any) => {} | void;
|
||||
getOptionValue: (item: any) => string;
|
||||
getOptionLabel: (item: any) => string;
|
||||
}
|
||||
|
||||
const SimplePicker: SFC<Props> = ({ className, getOptionLabel, getOptionValue, onSelected, options }) => {
|
||||
return (
|
||||
<Select
|
||||
isSearchable={false}
|
||||
classNamePrefix={`gf-form-select-box`}
|
||||
className={`width-7 gf-form-input gf-form-input--form-dropdown ${className || ''}`}
|
||||
placeholder="Choose"
|
||||
options={options}
|
||||
onChange={onSelected}
|
||||
components={{
|
||||
Option: DescriptionOption,
|
||||
}}
|
||||
styles={ResetStyles}
|
||||
getOptionValue={getOptionValue}
|
||||
getOptionLabel={getOptionLabel}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
export default SimplePicker;
|
@ -1,37 +1,28 @@
|
||||
import React from 'react';
|
||||
import React, { PureComponent } from 'react';
|
||||
import withTooltip from './withTooltip';
|
||||
import { Target } from 'react-popper';
|
||||
|
||||
interface TooltipProps {
|
||||
interface Props {
|
||||
tooltipSetState: (prevState: object) => void;
|
||||
}
|
||||
|
||||
class Tooltip extends React.Component<TooltipProps, any> {
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.showTooltip = this.showTooltip.bind(this);
|
||||
this.hideTooltip = this.hideTooltip.bind(this);
|
||||
}
|
||||
|
||||
showTooltip() {
|
||||
class Tooltip extends PureComponent<Props> {
|
||||
showTooltip = () => {
|
||||
const { tooltipSetState } = this.props;
|
||||
tooltipSetState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
show: true,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
hideTooltip() {
|
||||
tooltipSetState(prevState => ({
|
||||
...prevState,
|
||||
show: true,
|
||||
}));
|
||||
};
|
||||
|
||||
hideTooltip = () => {
|
||||
const { tooltipSetState } = this.props;
|
||||
tooltipSetState(prevState => {
|
||||
return {
|
||||
...prevState,
|
||||
show: false,
|
||||
};
|
||||
});
|
||||
}
|
||||
tooltipSetState(prevState => ({
|
||||
...prevState,
|
||||
show: false,
|
||||
}));
|
||||
};
|
||||
|
||||
render() {
|
||||
return (
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Action, ActionTypes } from './actions';
|
||||
import { OrgRole, PermissionLevel, DashboardState } from 'app/types';
|
||||
import { inititalState, dashboardReducer } from './reducers';
|
||||
import { initialState, dashboardReducer } from './reducers';
|
||||
|
||||
describe('dashboard reducer', () => {
|
||||
describe('loadDashboardPermissions', () => {
|
||||
@ -14,7 +14,7 @@ describe('dashboard reducer', () => {
|
||||
{ id: 3, dashboardId: 1, role: OrgRole.Editor, permission: PermissionLevel.Edit },
|
||||
],
|
||||
};
|
||||
state = dashboardReducer(inititalState, action);
|
||||
state = dashboardReducer(initialState, action);
|
||||
});
|
||||
|
||||
it('should add permissions to state', async () => {
|
||||
|
@ -2,11 +2,11 @@ import { DashboardState } from 'app/types';
|
||||
import { Action, ActionTypes } from './actions';
|
||||
import { processAclItems } from 'app/core/utils/acl';
|
||||
|
||||
export const inititalState: DashboardState = {
|
||||
export const initialState: DashboardState = {
|
||||
permissions: [],
|
||||
};
|
||||
|
||||
export const dashboardReducer = (state = inititalState, action: Action): DashboardState => {
|
||||
export const dashboardReducer = (state = initialState, action: Action): DashboardState => {
|
||||
switch (action.type) {
|
||||
case ActionTypes.LoadDashboardPermissions:
|
||||
return {
|
||||
|
@ -2,30 +2,50 @@ import React, { PureComponent } from 'react';
|
||||
import { hot } from 'react-hot-loader';
|
||||
import { connect } from 'react-redux';
|
||||
import PageHeader from '../../core/components/PageHeader/PageHeader';
|
||||
import { loadOrganisation } from './state/actions';
|
||||
import { NavModel, Organisation, OrganisationPreferences, StoreState } from 'app/types';
|
||||
import PageLoader from '../../core/components/PageLoader/PageLoader';
|
||||
import { loadOrganization, loadOrganizationPreferences } from './state/actions';
|
||||
import { DashboardAcl, NavModel, Organization, OrganisationPreferences, StoreState } from 'app/types';
|
||||
import { getNavModel } from '../../core/selectors/navModel';
|
||||
import OrgProfile from './OrgProfile';
|
||||
import OrgPreferences from './OrgPreferences';
|
||||
|
||||
export interface Props {
|
||||
navModel: NavModel;
|
||||
organisation: Organisation;
|
||||
organization: Organization;
|
||||
preferences: OrganisationPreferences;
|
||||
loadOrganisation: typeof loadOrganisation;
|
||||
starredDashboards: DashboardAcl[];
|
||||
loadOrganization: typeof loadOrganization;
|
||||
loadOrganizationPreferences: typeof loadOrganizationPreferences;
|
||||
}
|
||||
|
||||
interface State {
|
||||
orgName: string;
|
||||
hasSet: boolean;
|
||||
theme: string;
|
||||
isReady: boolean;
|
||||
selectedDashboard: DashboardAcl;
|
||||
}
|
||||
|
||||
export class OrgDetailsPage extends PureComponent<Props, State> {
|
||||
state = {
|
||||
orgName: '',
|
||||
hasSet: false,
|
||||
theme: '',
|
||||
isReady: false,
|
||||
selectedDashboard: null,
|
||||
};
|
||||
|
||||
async componentDidMount() {
|
||||
await this.props.loadOrganisation();
|
||||
this.fetchOrganisation();
|
||||
}
|
||||
|
||||
async fetchOrganisation() {
|
||||
const organization = await this.props.loadOrganization();
|
||||
// const preferences = await this.props.loadOrganizationPreferences();
|
||||
|
||||
this.setState({
|
||||
orgName: organization.name,
|
||||
// theme: preferences.theme,
|
||||
isReady: true,
|
||||
});
|
||||
}
|
||||
|
||||
onOrgNameChange = event => {
|
||||
@ -34,82 +54,41 @@ export class OrgDetailsPage extends PureComponent<Props, State> {
|
||||
});
|
||||
};
|
||||
|
||||
onSubmitForm = event => {};
|
||||
onSubmitForm = () => {};
|
||||
|
||||
onSubmitPreferences = () => {};
|
||||
|
||||
onDashboardSelected = dashboard => {
|
||||
this.setState({
|
||||
selectedDashboard: dashboard,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const { navModel, preferences } = this.props;
|
||||
|
||||
const themes: any = [
|
||||
{ value: '', text: 'Default' },
|
||||
{ value: 'dark', text: 'Dark' },
|
||||
{ value: 'light', text: 'Light' },
|
||||
];
|
||||
const { navModel, preferences, starredDashboards } = this.props;
|
||||
|
||||
return (
|
||||
<div>
|
||||
<PageHeader model={navModel} />
|
||||
<div className="page-container page-body">
|
||||
<h3 className="page-sub-heading">Organisation profile</h3>
|
||||
<form name="orgForm" className="gf-form-group" onSubmit={this.onSubmitForm}>
|
||||
<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"
|
||||
type="text"
|
||||
onChange={this.onOrgNameChange}
|
||||
value={this.state.orgName}
|
||||
/>
|
||||
</div>
|
||||
{!this.state.isReady ? (
|
||||
<PageLoader pageName="Organisation" />
|
||||
) : (
|
||||
<div>
|
||||
<OrgProfile
|
||||
onOrgNameChange={name => this.onOrgNameChange(name)}
|
||||
onSubmit={this.onSubmitForm}
|
||||
orgName={this.state.orgName}
|
||||
/>
|
||||
<OrgPreferences
|
||||
preferences={preferences}
|
||||
starredDashboards={starredDashboards}
|
||||
onDashboardSelected={dashboard => this.onDashboardSelected(dashboard)}
|
||||
onTimeZoneChange={() => {}}
|
||||
onSubmit={this.onSubmitPreferences}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="gf-form-button-row">
|
||||
<button type="submit" className="btn btn-success">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
<form name="ctrl.prefsForm" className="section gf-form-group">
|
||||
<h3 className="page-heading">Preferences</h3>
|
||||
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-11">UI Theme</span>
|
||||
<div className="gf-form-select-wrapper max-width-20">
|
||||
<select className="gf-form-input" value={preferences.theme}>
|
||||
{themes.map((theme, index) => {
|
||||
return (
|
||||
<option key={`${theme.value}-${index}`} value={theme.value}>
|
||||
{theme.text}
|
||||
</option>
|
||||
);
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-11">
|
||||
Home Dashboard
|
||||
{/*<info-popover mode="right-normal">*/}
|
||||
{/*Not finding dashboard you want? Star it first, then it should appear in this select box.*/}
|
||||
{/*</info-popover>*/}
|
||||
</span>
|
||||
{/*<dashboard-selector className="gf-form-select-wrapper max-width-20" model="ctrl.prefs.homeDashboardId" />*/}
|
||||
</div>
|
||||
|
||||
<div className="gf-form">
|
||||
<label className="gf-form-label width-11">Timezone</label>
|
||||
<div className="gf-form-select-wrapper max-width-20">
|
||||
<select className="gf-form-input" ng-model="ctrl.prefs.timezone" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="gf-form-button-row">
|
||||
<button type="submit" className="btn btn-success" ng-click="ctrl.updatePrefs()">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
@ -121,11 +100,13 @@ function mapStateToProps(state: StoreState) {
|
||||
navModel: getNavModel(state.navIndex, 'org-settings'),
|
||||
organisation: state.organisation.organisation,
|
||||
preferences: state.organisation.preferences,
|
||||
starredDashboards: state.organisation.starredDashboards,
|
||||
};
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
loadOrganisation,
|
||||
loadOrganization,
|
||||
loadOrganizationPreferences,
|
||||
};
|
||||
|
||||
export default hot(module)(connect(mapStateToProps, mapDispatchToProps)(OrgDetailsPage));
|
||||
|
83
public/app/features/org/OrgPreferences.tsx
Normal file
83
public/app/features/org/OrgPreferences.tsx
Normal file
@ -0,0 +1,83 @@
|
||||
import React, { SFC } from 'react';
|
||||
import Tooltip from '../../core/components/Tooltip/Tooltip';
|
||||
import { DashboardAcl, OrganisationPreferences } from 'app/types';
|
||||
import SimplePicker from '../../core/components/Picker/SimplePicker';
|
||||
|
||||
interface Props {
|
||||
preferences: OrganisationPreferences;
|
||||
starredDashboards: DashboardAcl[];
|
||||
onDashboardSelected: (dashboard: DashboardAcl) => void;
|
||||
onTimeZoneChange: (timeZone: string) => void;
|
||||
onSubmit: () => void;
|
||||
}
|
||||
|
||||
const OrgPreferences: SFC<Props> = ({
|
||||
preferences,
|
||||
starredDashboards,
|
||||
onDashboardSelected,
|
||||
onSubmit,
|
||||
onTimeZoneChange,
|
||||
}) => {
|
||||
const themes = [{ value: '', text: 'Default' }, { value: 'dark', text: 'Dark' }, { value: 'light', text: 'Light' }];
|
||||
|
||||
const timezones = [
|
||||
{ value: '', text: 'Default' },
|
||||
{ value: 'browser', text: 'Local browser time' },
|
||||
{ value: 'utc', text: 'UTC' },
|
||||
];
|
||||
|
||||
return (
|
||||
<form className="section gf-form-group" onSubmit={onSubmit}>
|
||||
<h3 className="page-heading">Preferences</h3>
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-11">UI Theme</span>
|
||||
<SimplePicker
|
||||
options={themes}
|
||||
getOptionValue={i => i.value}
|
||||
getOptionLabel={i => i.text}
|
||||
onSelected={theme => {
|
||||
console.log(theme);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<span className="gf-form-label width-11">
|
||||
Home Dashboard
|
||||
<Tooltip
|
||||
className="gf-form-help-icon gf-form-help-icon--right-normal"
|
||||
placement="right"
|
||||
content="Not finding dashboard you want? Star it first, then it should appear in this select box."
|
||||
>
|
||||
<i className="fa fa-info-circle" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
<SimplePicker
|
||||
getOptionLabel={i => i.title}
|
||||
getOptionValue={i => i.id}
|
||||
onSelected={dashboard => onDashboardSelected(dashboard)}
|
||||
options={starredDashboards}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form">
|
||||
<label className="gf-form-label width-11">Timezone</label>
|
||||
|
||||
<SimplePicker
|
||||
className="gf-form-input"
|
||||
onSelected={timezone => {
|
||||
console.log(timezone);
|
||||
}}
|
||||
options={timezones}
|
||||
getOptionLabel={i => i.text}
|
||||
getOptionValue={i => i.value}
|
||||
/>
|
||||
</div>
|
||||
<div className="gf-form-button-row">
|
||||
<button type="submit" className="btn btn-success">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrgPreferences;
|
37
public/app/features/org/OrgProfile.tsx
Normal file
37
public/app/features/org/OrgProfile.tsx
Normal file
@ -0,0 +1,37 @@
|
||||
import React, { SFC } from 'react';
|
||||
|
||||
interface Props {
|
||||
orgName: string;
|
||||
onSubmit: () => void;
|
||||
onOrgNameChange: (orgName: string) => void;
|
||||
}
|
||||
|
||||
const OrgProfile: SFC<Props> = ({ onSubmit, onOrgNameChange, orgName }) => {
|
||||
return (
|
||||
<div>
|
||||
<h3 className="page-sub-heading">Organization profile</h3>
|
||||
<form name="orgForm" className="gf-form-group" onSubmit={onSubmit}>
|
||||
<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"
|
||||
type="text"
|
||||
onChange={event => {
|
||||
onOrgNameChange(event.target.value);
|
||||
}}
|
||||
value={orgName}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="gf-form-button-row">
|
||||
<button type="submit" className="btn btn-success">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default OrgProfile;
|
@ -1,15 +1,16 @@
|
||||
import { ThunkAction } from 'redux-thunk';
|
||||
import { Organisation, OrganisationPreferences, StoreState } from 'app/types';
|
||||
import { DashboardAcl, Organization, OrganisationPreferences, StoreState } from 'app/types';
|
||||
import { getBackendSrv } from '../../../core/services/backend_srv';
|
||||
|
||||
export enum ActionTypes {
|
||||
LoadOrganisation = 'LOAD_ORGANISATION',
|
||||
LoadPreferences = 'LOAD_PREFERENCES',
|
||||
LoadStarredDashboards = 'LOAD_STARRED_DASHBOARDS',
|
||||
}
|
||||
|
||||
interface LoadOrganisationAction {
|
||||
interface LoadOrganizationAction {
|
||||
type: ActionTypes.LoadOrganisation;
|
||||
payload: Organisation;
|
||||
payload: Organization;
|
||||
}
|
||||
|
||||
interface LoadPreferencesAction {
|
||||
@ -17,7 +18,12 @@ interface LoadPreferencesAction {
|
||||
payload: OrganisationPreferences;
|
||||
}
|
||||
|
||||
const organisationLoaded = (organisation: Organisation) => ({
|
||||
interface LoadStarredDashboardsAction {
|
||||
type: ActionTypes.LoadStarredDashboards;
|
||||
payload: DashboardAcl[];
|
||||
}
|
||||
|
||||
const organisationLoaded = (organisation: Organization) => ({
|
||||
type: ActionTypes.LoadOrganisation,
|
||||
payload: organisation,
|
||||
});
|
||||
@ -27,14 +33,31 @@ const preferencesLoaded = (preferences: OrganisationPreferences) => ({
|
||||
payload: preferences,
|
||||
});
|
||||
|
||||
export type Action = LoadOrganisationAction | LoadPreferencesAction;
|
||||
const starredDashboardsLoaded = (dashboards: DashboardAcl[]) => ({
|
||||
type: ActionTypes.LoadStarredDashboards,
|
||||
payload: dashboards,
|
||||
});
|
||||
|
||||
export type Action = LoadOrganizationAction | LoadPreferencesAction | LoadStarredDashboardsAction;
|
||||
type ThunkResult<R> = ThunkAction<R, StoreState, undefined, any>;
|
||||
|
||||
export function loadOrganisation(): ThunkResult<void> {
|
||||
export function loadOrganization(): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
const organisationResponse = await getBackendSrv().get('/api/org');
|
||||
const preferencesResponse = await getBackendSrv().get('/api/org/preferences');
|
||||
dispatch(organisationLoaded(organisationResponse));
|
||||
dispatch(preferencesLoaded(preferencesResponse));
|
||||
|
||||
return organisationResponse;
|
||||
};
|
||||
}
|
||||
|
||||
export function loadOrganizationPreferences(): ThunkResult<void> {
|
||||
return async dispatch => {
|
||||
const preferencesResponse = await getBackendSrv().get('/api/org/preferences');
|
||||
dispatch(preferencesLoaded(preferencesResponse));
|
||||
|
||||
const starredDashboards = await getBackendSrv().search({ starred: true });
|
||||
dispatch(starredDashboardsLoaded(starredDashboards));
|
||||
|
||||
return preferencesResponse;
|
||||
};
|
||||
}
|
||||
|
@ -1,9 +1,10 @@
|
||||
import { Organisation, OrganisationPreferences, OrganisationState } from 'app/types';
|
||||
import { DashboardAcl, Organization, OrganisationPreferences, OrganisationState } from 'app/types';
|
||||
import { Action, ActionTypes } from './actions';
|
||||
|
||||
const initialState: OrganisationState = {
|
||||
organisation: {} as Organisation,
|
||||
organisation: {} as Organization,
|
||||
preferences: {} as OrganisationPreferences,
|
||||
starredDashboards: [] as DashboardAcl[],
|
||||
};
|
||||
|
||||
const organisationReducer = (state = initialState, action: Action): OrganisationState => {
|
||||
@ -13,6 +14,9 @@ const organisationReducer = (state = initialState, action: Action): Organisation
|
||||
|
||||
case ActionTypes.LoadPreferences:
|
||||
return { ...state, preferences: action.payload };
|
||||
|
||||
case ActionTypes.LoadStarredDashboards:
|
||||
return { ...state, starredDashboards: action.payload };
|
||||
}
|
||||
|
||||
return state;
|
||||
|
@ -22,7 +22,7 @@ import {
|
||||
} from './series';
|
||||
import { PanelProps } from './panel';
|
||||
import { PluginDashboard, PluginMeta, Plugin, PluginsState } from './plugins';
|
||||
import { Organisation, OrganisationPreferences, OrganisationState } from './organisation';
|
||||
import { Organization, OrganisationPreferences, OrganisationState } from './organization';
|
||||
|
||||
export {
|
||||
Team,
|
||||
@ -71,7 +71,7 @@ export {
|
||||
DataQueryResponse,
|
||||
DataQueryOptions,
|
||||
PluginDashboard,
|
||||
Organisation,
|
||||
Organization,
|
||||
OrganisationState,
|
||||
OrganisationPreferences,
|
||||
};
|
||||
|
@ -1,4 +1,6 @@
|
||||
export interface Organisation {
|
||||
import { DashboardAcl } from './acl';
|
||||
|
||||
export interface Organization {
|
||||
name: string;
|
||||
id: number;
|
||||
}
|
||||
@ -10,6 +12,7 @@ export interface OrganisationPreferences {
|
||||
}
|
||||
|
||||
export interface OrganisationState {
|
||||
organisation: Organisation;
|
||||
organisation: Organization;
|
||||
preferences: OrganisationPreferences;
|
||||
starredDashboards: DashboardAcl[];
|
||||
}
|
Loading…
Reference in New Issue
Block a user