浏览代码

simple select

Peter Holmberg 7 年之前
父节点
当前提交
a98f7e548f

+ 33 - 0
public/app/core/components/Picker/SimplePicker.tsx

@@ -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;

+ 16 - 25
public/app/core/components/Tooltip/Tooltip.tsx

@@ -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 (

+ 2 - 2
public/app/features/dashboard/state/reducers.test.ts

@@ -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 - 2
public/app/features/dashboard/state/reducers.ts

@@ -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 {

+ 57 - 76
public/app/features/org/OrgDetailsPage.tsx

@@ -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 = () => {};
 
-  render() {
-    const { navModel, preferences } = this.props;
+  onSubmitPreferences = () => {};
 
-    const themes: any = [
-      { value: '', text: 'Default' },
-      { value: 'dark', text: 'Dark' },
-      { value: 'light', text: 'Light' },
-    ];
+  onDashboardSelected = dashboard => {
+    this.setState({
+      selectedDashboard: dashboard,
+    });
+  };
+
+  render() {
+    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>
-            </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>
+          {!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>
-          </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 - 0
public/app/features/org/OrgPreferences.tsx

@@ -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 - 0
public/app/features/org/OrgProfile.tsx

@@ -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;

+ 30 - 7
public/app/features/org/state/actions.ts

@@ -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));
+
+    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;
   };
 }

+ 6 - 2
public/app/features/org/state/reducers.ts

@@ -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;

+ 2 - 2
public/app/types/index.ts

@@ -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,
 };

+ 5 - 2
public/app/types/organisation.ts → public/app/types/organization.ts

@@ -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[];
 }