From ac62e4a99201de9070dd736759ee12f0fb8fc491 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Mon, 14 Jan 2019 22:09:06 +0000 Subject: [PATCH 01/36] FormGroup component and implements --- .../src/components/FormGroup/FormGroup.tsx | 27 +++++++ .../src}/components/Label/Label.tsx | 0 packages/grafana-ui/src/components/index.ts | 6 +- .../SharedPreferences/SharedPreferences.tsx | 2 +- .../datasources/settings/BasicSettings.tsx | 2 +- public/app/features/teams/TeamSettings.tsx | 2 +- .../panel/gauge/GaugeOptionsEditor.tsx | 20 ++--- public/app/plugins/panel/gauge/MappingRow.tsx | 80 ++++++++++--------- .../app/plugins/panel/gauge/ValueOptions.tsx | 49 +++++++----- 9 files changed, 114 insertions(+), 74 deletions(-) create mode 100644 packages/grafana-ui/src/components/FormGroup/FormGroup.tsx rename {public/app/core => packages/grafana-ui/src}/components/Label/Label.tsx (100%) diff --git a/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx b/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx new file mode 100644 index 00000000000..ac761fa5d2c --- /dev/null +++ b/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx @@ -0,0 +1,27 @@ +import React, { SFC } from 'react'; +import { Label } from '..'; + +interface Props { + label: string; + inputProps: {}; + labelWidth?: number; + inputWidth?: number; +} + +const defaultProps = { + labelWidth: 6, + inputProps: {}, + inputWidth: 12, +}; + +const FormGroup: SFC = ({ label, labelWidth, inputProps, inputWidth }) => { + return ( +
+ + +
+ ); +}; + +FormGroup.defaultProps = defaultProps; +export { FormGroup }; diff --git a/public/app/core/components/Label/Label.tsx b/packages/grafana-ui/src/components/Label/Label.tsx similarity index 100% rename from public/app/core/components/Label/Label.tsx rename to packages/grafana-ui/src/components/Label/Label.tsx diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 5420fcf14b7..ab0edf45ed0 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -9,12 +9,16 @@ export { IndicatorsContainer } from './Select/IndicatorsContainer'; export { NoOptionsMessage } from './Select/NoOptionsMessage'; export { default as resetSelectStyles } from './Select/resetSelectStyles'; +// Forms +export { GfFormLabel } from './GfFormLabel/GfFormLabel'; +export { FormGroup } from './FormGroup/FormGroup'; +export { Label } from './Label/Label'; + export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder'; export { ColorPicker } from './ColorPicker/ColorPicker'; export { SeriesColorPickerPopover } from './ColorPicker/SeriesColorPickerPopover'; export { SeriesColorPicker } from './ColorPicker/SeriesColorPicker'; export { ThresholdsEditor } from './ThresholdsEditor/ThresholdsEditor'; -export { GfFormLabel } from './GfFormLabel/GfFormLabel'; export { Graph } from './Graph/Graph'; export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup'; export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid'; diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index b13393ab2e1..ca933332db9 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; -import { Label } from 'app/core/components/Label/Label'; +import { Label } from '../../../../../packages/grafana-ui/src/components/Label/Label'; import { Select } from '@grafana/ui'; import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv'; diff --git a/public/app/features/datasources/settings/BasicSettings.tsx b/public/app/features/datasources/settings/BasicSettings.tsx index 120e002ac68..55dc9b54211 100644 --- a/public/app/features/datasources/settings/BasicSettings.tsx +++ b/public/app/features/datasources/settings/BasicSettings.tsx @@ -1,5 +1,5 @@ import React, { SFC } from 'react'; -import { Label } from 'app/core/components/Label/Label'; +import { Label } from '../../../../../packages/grafana-ui/src/components/Label/Label'; import { Switch } from '../../../core/components/Switch/Switch'; export interface Props { diff --git a/public/app/features/teams/TeamSettings.tsx b/public/app/features/teams/TeamSettings.tsx index 5e058289bf0..3424f39d22c 100644 --- a/public/app/features/teams/TeamSettings.tsx +++ b/public/app/features/teams/TeamSettings.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; -import { Label } from 'app/core/components/Label/Label'; +import { Label } from '../../../../packages/grafana-ui/src/components/Label/Label'; import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences'; import { updateTeam } from './state/actions'; import { getRouteParamsId } from 'app/core/selectors/location'; diff --git a/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx b/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx index f1f78ab1172..c7758642080 100644 --- a/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx +++ b/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx @@ -2,7 +2,7 @@ import React, { PureComponent } from 'react'; import { GaugeOptions, PanelOptionsProps, PanelOptionsGroup } from '@grafana/ui'; import { Switch } from 'app/core/components/Switch/Switch'; -import { Label } from '../../../core/components/Label/Label'; +import { FormGroup } from '@grafana/ui/src'; export default class GaugeOptionsEditor extends PureComponent> { onToggleThresholdLabels = () => @@ -21,14 +21,16 @@ export default class GaugeOptionsEditor extends PureComponent -
- - -
-
- - -
+ this.onMinValueChange(event), value: minValue }} + /> + this.onMaxValueChange(event), value: maxValue }} + /> { if (type === MappingType.RangeToText) { return ( <> -
- - -
-
- - -
-
- - -
+ this.onMappingFromChange(event), + onBlur: () => this.updateMapping(), + value: from, + }} + inputWidth={8} + /> + this.updateMapping, + onChange: event => this.onMappingToChange(event), + value: to, + }} + inputWidth={8} + /> + this.updateMapping, + onChange: event => this.onMappingTextChange(event), + value: text, + }} + inputWidth={10} + /> ); } return ( <> -
- - -
+ this.updateMapping, + onChange: event => this.onMappingValueChange(event), + value: value, + }} + inputWidth={8} + />
Unit
-
- - -
-
- - -
-
- - -
+ this.onDecimalChange(event), + value: decimals || '', + type: 'number', + }} + /> + this.onPrefixChange(event), + value: prefix || '', + }} + /> + this.onSuffixChange(event), + value: suffix || '', + }} + /> ); } From 58094faa12f8440083ea8a4c0aee0761470ee45b Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Tue, 15 Jan 2019 17:31:42 +0000 Subject: [PATCH 02/36] test and minor fix on mapping row --- .../components/FormGroup/FormGroup.test.tsx | 26 +++++++++++++++++++ .../__snapshots__/FormGroup.test.tsx.snap | 19 ++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 packages/grafana-ui/src/components/FormGroup/FormGroup.test.tsx create mode 100644 packages/grafana-ui/src/components/FormGroup/__snapshots__/FormGroup.test.tsx.snap diff --git a/packages/grafana-ui/src/components/FormGroup/FormGroup.test.tsx b/packages/grafana-ui/src/components/FormGroup/FormGroup.test.tsx new file mode 100644 index 00000000000..4f8b4be9540 --- /dev/null +++ b/packages/grafana-ui/src/components/FormGroup/FormGroup.test.tsx @@ -0,0 +1,26 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import { FormGroup, Props } from './FormGroup'; + +const setup = (propOverrides?: object) => { + const props: Props = { + label: 'Test', + labelWidth: 11, + inputProps: { + value: 10, + onChange: jest.fn(), + }, + }; + + Object.assign(props, propOverrides); + + return shallow(); +}; + +describe('Render', () => { + it('should render component', () => { + const wrapper = setup(); + + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/packages/grafana-ui/src/components/FormGroup/__snapshots__/FormGroup.test.tsx.snap b/packages/grafana-ui/src/components/FormGroup/__snapshots__/FormGroup.test.tsx.snap new file mode 100644 index 00000000000..e88ff774981 --- /dev/null +++ b/packages/grafana-ui/src/components/FormGroup/__snapshots__/FormGroup.test.tsx.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Render should render component 1`] = ` +
+ + Test + + +
+`; From 83fbf52aac51fa6cc0c16eed9b48529b26fb489c Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Tue, 15 Jan 2019 17:33:42 +0000 Subject: [PATCH 03/36] fixing imports, minor fix on mapping row --- .../src/components/FormGroup/FormGroup.tsx | 2 +- .../grafana-ui/src/components/Label/Label.tsx | 2 +- .../SharedPreferences/SharedPreferences.tsx | 3 +-- .../datasources/settings/BasicSettings.tsx | 2 +- public/app/features/teams/TeamSettings.tsx | 2 +- public/app/plugins/panel/gauge/MappingRow.tsx | 19 +++++++++---------- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx b/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx index ac761fa5d2c..a0088032079 100644 --- a/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx +++ b/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx @@ -1,7 +1,7 @@ import React, { SFC } from 'react'; import { Label } from '..'; -interface Props { +export interface Props { label: string; inputProps: {}; labelWidth?: number; diff --git a/packages/grafana-ui/src/components/Label/Label.tsx b/packages/grafana-ui/src/components/Label/Label.tsx index 5d60efa056a..b31ed45e32a 100644 --- a/packages/grafana-ui/src/components/Label/Label.tsx +++ b/packages/grafana-ui/src/components/Label/Label.tsx @@ -1,5 +1,5 @@ import React, { SFC, ReactNode } from 'react'; -import { Tooltip } from '@grafana/ui'; +import { Tooltip } from '..'; interface Props { tooltip?: string; diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index ca933332db9..0b11d32b668 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -1,7 +1,6 @@ import React, { PureComponent } from 'react'; -import { Label } from '../../../../../packages/grafana-ui/src/components/Label/Label'; -import { Select } from '@grafana/ui'; +import { Label, Select } from '@grafana/ui'; import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv'; import { DashboardSearchHit } from 'app/types'; diff --git a/public/app/features/datasources/settings/BasicSettings.tsx b/public/app/features/datasources/settings/BasicSettings.tsx index 55dc9b54211..21a548a5045 100644 --- a/public/app/features/datasources/settings/BasicSettings.tsx +++ b/public/app/features/datasources/settings/BasicSettings.tsx @@ -1,5 +1,5 @@ import React, { SFC } from 'react'; -import { Label } from '../../../../../packages/grafana-ui/src/components/Label/Label'; +import { Label } from '@grafana/ui'; import { Switch } from '../../../core/components/Switch/Switch'; export interface Props { diff --git a/public/app/features/teams/TeamSettings.tsx b/public/app/features/teams/TeamSettings.tsx index 3424f39d22c..22815dbb7ec 100644 --- a/public/app/features/teams/TeamSettings.tsx +++ b/public/app/features/teams/TeamSettings.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; -import { Label } from '../../../../packages/grafana-ui/src/components/Label/Label'; +import { Label } from '@grafana/ui'; import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences'; import { updateTeam } from './state/actions'; import { getRouteParamsId } from 'app/core/selectors/location'; diff --git a/public/app/plugins/panel/gauge/MappingRow.tsx b/public/app/plugins/panel/gauge/MappingRow.tsx index b05da5514aa..91dff549677 100644 --- a/public/app/plugins/panel/gauge/MappingRow.tsx +++ b/public/app/plugins/panel/gauge/MappingRow.tsx @@ -81,16 +81,15 @@ export default class MappingRow extends PureComponent { }} inputWidth={8} /> - this.updateMapping, - onChange: event => this.onMappingTextChange(event), - value: text, - }} - inputWidth={10} - /> +
+ + +
); } From 639dc6c3c35df2c7aa9558f80da917aaa027d0a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Wed, 16 Jan 2019 10:28:05 +0100 Subject: [PATCH 04/36] Moved Label to grafana/ui/components --- .../grafana-ui/src}/components/Label/Label.tsx | 2 +- packages/grafana-ui/src/components/index.ts | 1 + .../core/components/SharedPreferences/SharedPreferences.tsx | 3 +-- public/app/features/datasources/settings/BasicSettings.tsx | 3 ++- public/app/features/teams/TeamSettings.tsx | 2 +- public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx | 3 +-- public/app/plugins/panel/gauge/MappingRow.tsx | 4 +--- public/app/plugins/panel/gauge/ValueOptions.tsx | 4 +--- 8 files changed, 9 insertions(+), 13 deletions(-) rename {public/app/core => packages/grafana-ui/src}/components/Label/Label.tsx (93%) diff --git a/public/app/core/components/Label/Label.tsx b/packages/grafana-ui/src/components/Label/Label.tsx similarity index 93% rename from public/app/core/components/Label/Label.tsx rename to packages/grafana-ui/src/components/Label/Label.tsx index 5d60efa056a..270b0161226 100644 --- a/public/app/core/components/Label/Label.tsx +++ b/packages/grafana-ui/src/components/Label/Label.tsx @@ -1,5 +1,5 @@ import React, { SFC, ReactNode } from 'react'; -import { Tooltip } from '@grafana/ui'; +import { Tooltip } from '../Tooltip/Tooltip'; interface Props { tooltip?: string; diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 5420fcf14b7..51b601f2921 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -2,6 +2,7 @@ export { DeleteButton } from './DeleteButton/DeleteButton'; export { Tooltip } from './Tooltip/Tooltip'; export { Portal } from './Portal/Portal'; export { CustomScrollbar } from './CustomScrollbar/CustomScrollbar'; +export { Label } from './Label/Label'; // Select export { Select, AsyncSelect, SelectOptionItem } from './Select/Select'; diff --git a/public/app/core/components/SharedPreferences/SharedPreferences.tsx b/public/app/core/components/SharedPreferences/SharedPreferences.tsx index b13393ab2e1..ed27de39cb8 100644 --- a/public/app/core/components/SharedPreferences/SharedPreferences.tsx +++ b/public/app/core/components/SharedPreferences/SharedPreferences.tsx @@ -1,7 +1,6 @@ import React, { PureComponent } from 'react'; +import { Select, Label } from '@grafana/ui'; -import { Label } from 'app/core/components/Label/Label'; -import { Select } from '@grafana/ui'; import { getBackendSrv, BackendSrv } from 'app/core/services/backend_srv'; import { DashboardSearchHit } from 'app/types'; diff --git a/public/app/features/datasources/settings/BasicSettings.tsx b/public/app/features/datasources/settings/BasicSettings.tsx index 120e002ac68..2d36b79a44c 100644 --- a/public/app/features/datasources/settings/BasicSettings.tsx +++ b/public/app/features/datasources/settings/BasicSettings.tsx @@ -1,5 +1,6 @@ import React, { SFC } from 'react'; -import { Label } from 'app/core/components/Label/Label'; +import { Label } from '@grafana/ui'; + import { Switch } from '../../../core/components/Switch/Switch'; export interface Props { diff --git a/public/app/features/teams/TeamSettings.tsx b/public/app/features/teams/TeamSettings.tsx index 5e058289bf0..87c67b6e597 100644 --- a/public/app/features/teams/TeamSettings.tsx +++ b/public/app/features/teams/TeamSettings.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { connect } from 'react-redux'; +import { Label } from '@grafana/ui'; -import { Label } from 'app/core/components/Label/Label'; import { SharedPreferences } from 'app/core/components/SharedPreferences/SharedPreferences'; import { updateTeam } from './state/actions'; import { getRouteParamsId } from 'app/core/selectors/location'; diff --git a/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx b/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx index f1f78ab1172..cf60411ffe2 100644 --- a/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx +++ b/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx @@ -1,8 +1,7 @@ import React, { PureComponent } from 'react'; -import { GaugeOptions, PanelOptionsProps, PanelOptionsGroup } from '@grafana/ui'; +import { GaugeOptions, PanelOptionsProps, PanelOptionsGroup, Label } from '@grafana/ui'; import { Switch } from 'app/core/components/Switch/Switch'; -import { Label } from '../../../core/components/Label/Label'; export default class GaugeOptionsEditor extends PureComponent> { onToggleThresholdLabels = () => diff --git a/public/app/plugins/panel/gauge/MappingRow.tsx b/public/app/plugins/panel/gauge/MappingRow.tsx index b975821f27a..4aeb85a52d3 100644 --- a/public/app/plugins/panel/gauge/MappingRow.tsx +++ b/public/app/plugins/panel/gauge/MappingRow.tsx @@ -1,7 +1,5 @@ import React, { PureComponent } from 'react'; -import { MappingType, RangeMap, Select, ValueMap } from '@grafana/ui'; - -import { Label } from 'app/core/components/Label/Label'; +import { MappingType, RangeMap, Select, ValueMap, Label } from '@grafana/ui'; interface Props { mapping: ValueMap | RangeMap; diff --git a/public/app/plugins/panel/gauge/ValueOptions.tsx b/public/app/plugins/panel/gauge/ValueOptions.tsx index 7cfbb382f7b..accdb0b03fa 100644 --- a/public/app/plugins/panel/gauge/ValueOptions.tsx +++ b/public/app/plugins/panel/gauge/ValueOptions.tsx @@ -1,8 +1,6 @@ import React, { PureComponent } from 'react'; -import { GaugeOptions, PanelOptionsProps, PanelOptionsGroup } from '@grafana/ui'; +import { GaugeOptions, PanelOptionsProps, PanelOptionsGroup, Label, Select } from '@grafana/ui'; -import { Label } from 'app/core/components/Label/Label'; -import { Select} from '@grafana/ui'; import UnitPicker from 'app/core/components/Select/UnitPicker'; const statOptions = [ From c90979a8f0602703942dd2c143c20e89ff64ea4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Wed, 16 Jan 2019 10:49:48 +0100 Subject: [PATCH 05/36] Moved ValueMappings to grafana/ui/component and renamed it ValueMappingsEditor --- .../ValueMappingsEditor}/MappingRow.tsx | 5 +- .../ValueMappingsEditor.test.tsx | 11 ++-- .../ValueMappingsEditor.tsx | 6 +- .../_ValueMappingsEditor.scss | 0 .../ValueMappingsEditor.test.tsx.snap | 56 +++++++++++++++++++ packages/grafana-ui/src/components/index.scss | 1 + packages/grafana-ui/src/components/index.ts | 1 + .../plugins/panel/gauge/GaugePanelOptions.tsx | 4 +- public/sass/_grafana.scss | 3 +- 9 files changed, 75 insertions(+), 12 deletions(-) rename {public/app/plugins/panel/gauge => packages/grafana-ui/src/components/ValueMappingsEditor}/MappingRow.tsx (95%) rename public/app/plugins/panel/gauge/ValueMappings.test.tsx => packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.test.tsx (84%) rename public/app/plugins/panel/gauge/ValueMappings.tsx => packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.tsx (88%) rename public/sass/components/_value-mappings.scss => packages/grafana-ui/src/components/ValueMappingsEditor/_ValueMappingsEditor.scss (100%) create mode 100644 packages/grafana-ui/src/components/ValueMappingsEditor/__snapshots__/ValueMappingsEditor.test.tsx.snap diff --git a/public/app/plugins/panel/gauge/MappingRow.tsx b/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx similarity index 95% rename from public/app/plugins/panel/gauge/MappingRow.tsx rename to packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx index 4aeb85a52d3..8d3407329bf 100644 --- a/public/app/plugins/panel/gauge/MappingRow.tsx +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx @@ -1,5 +1,8 @@ import React, { PureComponent } from 'react'; -import { MappingType, RangeMap, Select, ValueMap, Label } from '@grafana/ui'; + +import { ValueMap, RangeMap, MappingType } from '../../types/panel'; +import { Label } from '../Label/Label'; +import { Select } from '../Select/Select'; interface Props { mapping: ValueMap | RangeMap; diff --git a/public/app/plugins/panel/gauge/ValueMappings.test.tsx b/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.test.tsx similarity index 84% rename from public/app/plugins/panel/gauge/ValueMappings.test.tsx rename to packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.test.tsx index 07db4028c68..fcb614f8e6f 100644 --- a/public/app/plugins/panel/gauge/ValueMappings.test.tsx +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.test.tsx @@ -1,9 +1,10 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { GaugeOptions, MappingType, PanelOptionsProps } from '@grafana/ui'; -import { defaultProps } from 'app/plugins/panel/gauge/GaugePanelOptions'; -import ValueMappings from './ValueMappings'; +import { defaultProps } from 'app/plugins/panel/gauge/GaugePanelOptions'; +import { ValueMappingsEditor } from './ValueMappingsEditor'; +import { PanelOptionsProps, MappingType } from '../../types/panel'; +import { GaugeOptions } from '../../types/gauge'; const setup = (propOverrides?: object) => { const props: PanelOptionsProps = { @@ -19,9 +20,9 @@ const setup = (propOverrides?: object) => { Object.assign(props, propOverrides); - const wrapper = shallow(); + const wrapper = shallow(); - const instance = wrapper.instance() as ValueMappings; + const instance = wrapper.instance() as ValueMappingsEditor; return { instance, diff --git a/public/app/plugins/panel/gauge/ValueMappings.tsx b/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.tsx similarity index 88% rename from public/app/plugins/panel/gauge/ValueMappings.tsx rename to packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.tsx index 9a3f87450f4..ae0ff092a06 100644 --- a/public/app/plugins/panel/gauge/ValueMappings.tsx +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.tsx @@ -1,14 +1,16 @@ import React, { PureComponent } from 'react'; -import { GaugeOptions, PanelOptionsProps, MappingType, RangeMap, ValueMap, PanelOptionsGroup } from '@grafana/ui'; import MappingRow from './MappingRow'; +import { PanelOptionsProps, ValueMap, RangeMap, MappingType } from '../../types/panel'; +import { GaugeOptions } from '../../types/gauge'; +import { PanelOptionsGroup } from '../PanelOptionsGroup/PanelOptionsGroup'; interface State { mappings: Array; nextIdToAdd: number; } -export default class ValueMappings extends PureComponent, State> { +export class ValueMappingsEditor extends PureComponent, State> { constructor(props) { super(props); diff --git a/public/sass/components/_value-mappings.scss b/packages/grafana-ui/src/components/ValueMappingsEditor/_ValueMappingsEditor.scss similarity index 100% rename from public/sass/components/_value-mappings.scss rename to packages/grafana-ui/src/components/ValueMappingsEditor/_ValueMappingsEditor.scss diff --git a/packages/grafana-ui/src/components/ValueMappingsEditor/__snapshots__/ValueMappingsEditor.test.tsx.snap b/packages/grafana-ui/src/components/ValueMappingsEditor/__snapshots__/ValueMappingsEditor.test.tsx.snap new file mode 100644 index 00000000000..592b3326421 --- /dev/null +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/__snapshots__/ValueMappingsEditor.test.tsx.snap @@ -0,0 +1,56 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Render should render component 1`] = ` + +
+ + +
+
+
+ +
+
+ Add mapping +
+
+
+`; diff --git a/packages/grafana-ui/src/components/index.scss b/packages/grafana-ui/src/components/index.scss index b894cf73c1a..fa8d0135756 100644 --- a/packages/grafana-ui/src/components/index.scss +++ b/packages/grafana-ui/src/components/index.scss @@ -6,3 +6,4 @@ @import 'PanelOptionsGroup/PanelOptionsGroup'; @import 'PanelOptionsGrid/PanelOptionsGrid'; @import 'ColorPicker/ColorPicker'; +@import 'ValueMappingsEditor/ValueMappingsEditor'; diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 51b601f2921..1b2d2fce972 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -19,3 +19,4 @@ export { GfFormLabel } from './GfFormLabel/GfFormLabel'; export { Graph } from './Graph/Graph'; export { PanelOptionsGroup } from './PanelOptionsGroup/PanelOptionsGroup'; export { PanelOptionsGrid } from './PanelOptionsGrid/PanelOptionsGrid'; +export { ValueMappingsEditor } from './ValueMappingsEditor/ValueMappingsEditor'; diff --git a/public/app/plugins/panel/gauge/GaugePanelOptions.tsx b/public/app/plugins/panel/gauge/GaugePanelOptions.tsx index a5334b0c6e1..3e82ca0e27b 100644 --- a/public/app/plugins/panel/gauge/GaugePanelOptions.tsx +++ b/public/app/plugins/panel/gauge/GaugePanelOptions.tsx @@ -6,10 +6,10 @@ import { ThresholdsEditor, Threshold, PanelOptionsGrid, + ValueMappingsEditor, } from '@grafana/ui'; import ValueOptions from 'app/plugins/panel/gauge/ValueOptions'; -import ValueMappings from 'app/plugins/panel/gauge/ValueMappings'; import GaugeOptionsEditor from './GaugeOptionsEditor'; export const defaultProps = { @@ -44,7 +44,7 @@ export default class GaugePanelOptions extends PureComponent - + ); } diff --git a/public/sass/_grafana.scss b/public/sass/_grafana.scss index 93fd26b7ca8..e8859ff8255 100644 --- a/public/sass/_grafana.scss +++ b/public/sass/_grafana.scss @@ -1,4 +1,4 @@ - // DEPENDENCIES +// DEPENDENCIES @import '../../node_modules/react-table/react-table.css'; // VENDOR @@ -97,7 +97,6 @@ @import 'components/add_data_source.scss'; @import 'components/page_loader'; @import 'components/toggle_button_group'; -@import 'components/value-mappings'; @import 'components/popover-box'; // LOAD @grafana/ui components From 013d46b707f82522d1f3c0ae973fdde5a6fa7455 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Wed, 16 Jan 2019 12:14:43 +0100 Subject: [PATCH 06/36] Refactored ValueMappings --- .../ValueMappingsEditor/MappingRow.tsx | 36 ++++++------- .../ValueMappingsEditor.test.tsx | 27 +++++----- .../ValueMappingsEditor.tsx | 52 ++++++++++--------- .../ValueMappingsEditor.test.tsx.snap | 12 ++--- packages/grafana-ui/src/types/gauge.ts | 16 ------ packages/grafana-ui/src/types/index.ts | 1 - packages/grafana-ui/src/types/panel.ts | 2 + .../panel/gauge/GaugeOptionsEditor.tsx | 3 +- public/app/plugins/panel/gauge/GaugePanel.tsx | 3 +- .../plugins/panel/gauge/GaugePanelOptions.tsx | 19 +++++-- .../app/plugins/panel/gauge/ValueOptions.tsx | 3 +- public/app/plugins/panel/gauge/types.ts | 16 +++++- public/app/viz/Gauge.test.tsx | 2 +- public/app/viz/Gauge.tsx | 31 ++++------- 14 files changed, 112 insertions(+), 111 deletions(-) delete mode 100644 packages/grafana-ui/src/types/gauge.ts diff --git a/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx b/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx index 8d3407329bf..9705304d354 100644 --- a/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx @@ -1,23 +1,23 @@ import React, { PureComponent } from 'react'; -import { ValueMap, RangeMap, MappingType } from '../../types/panel'; +import { MappingType, ValueMapping } from '../../types/panel'; import { Label } from '../Label/Label'; import { Select } from '../Select/Select'; -interface Props { - mapping: ValueMap | RangeMap; - updateMapping: (mapping) => void; - removeMapping: () => void; +export interface Props { + valueMapping: ValueMapping; + updateValueMapping: (valueMapping: ValueMapping) => void; + removeValueMapping: () => void; } interface State { - from: string; + from?: string; id: number; operator: string; text: string; - to: string; + to?: string; type: MappingType; - value: string; + value?: string; } const mappingOptions = [ @@ -26,36 +26,34 @@ const mappingOptions = [ ]; export default class MappingRow extends PureComponent { - constructor(props) { + constructor(props: Props) { super(props); - this.state = { - ...props.mapping, - }; + this.state = { ...props.valueMapping }; } - onMappingValueChange = event => { + onMappingValueChange = (event: React.ChangeEvent) => { this.setState({ value: event.target.value }); }; - onMappingFromChange = event => { + onMappingFromChange = (event: React.ChangeEvent) => { this.setState({ from: event.target.value }); }; - onMappingToChange = event => { + onMappingToChange = (event: React.ChangeEvent) => { this.setState({ to: event.target.value }); }; - onMappingTextChange = event => { + onMappingTextChange = (event: React.ChangeEvent) => { this.setState({ text: event.target.value }); }; - onMappingTypeChange = mappingType => { + onMappingTypeChange = (mappingType: MappingType) => { this.setState({ type: mappingType }); }; updateMapping = () => { - this.props.updateMapping({ ...this.state }); + this.props.updateValueMapping({ ...this.state } as ValueMapping); }; renderRow() { @@ -137,7 +135,7 @@ export default class MappingRow extends PureComponent { {this.renderRow()}
-
diff --git a/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.test.tsx b/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.test.tsx index fcb614f8e6f..bbad3e5a7ca 100644 --- a/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.test.tsx +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.test.tsx @@ -1,21 +1,16 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { defaultProps } from 'app/plugins/panel/gauge/GaugePanelOptions'; -import { ValueMappingsEditor } from './ValueMappingsEditor'; -import { PanelOptionsProps, MappingType } from '../../types/panel'; -import { GaugeOptions } from '../../types/gauge'; +import { ValueMappingsEditor, Props } from './ValueMappingsEditor'; +import { MappingType } from '../../types/panel'; const setup = (propOverrides?: object) => { - const props: PanelOptionsProps = { + const props: Props = { onChange: jest.fn(), - options: { - ...defaultProps.options, - mappings: [ - { id: 1, operator: '', type: MappingType.ValueToText, value: '20', text: 'Ok' }, - { id: 2, operator: '', type: MappingType.RangeToText, from: '21', to: '30', text: 'Meh' }, - ], - }, + valueMappings: [ + { id: 1, operator: '', type: MappingType.ValueToText, value: '20', text: 'Ok' }, + { id: 2, operator: '', type: MappingType.RangeToText, from: '21', to: '30', text: 'Meh' }, + ], }; Object.assign(props, propOverrides); @@ -41,18 +36,20 @@ describe('Render', () => { describe('On remove mapping', () => { it('Should remove mapping with id 0', () => { const { instance } = setup(); + instance.onRemoveMapping(1); - expect(instance.state.mappings).toEqual([ + expect(instance.state.valueMappings).toEqual([ { id: 2, operator: '', type: MappingType.RangeToText, from: '21', to: '30', text: 'Meh' }, ]); }); it('should remove mapping with id 1', () => { const { instance } = setup(); + instance.onRemoveMapping(2); - expect(instance.state.mappings).toEqual([ + expect(instance.state.valueMappings).toEqual([ { id: 1, operator: '', type: MappingType.ValueToText, value: '20', text: 'Ok' }, ]); }); @@ -68,7 +65,7 @@ describe('Next id to add', () => { }); it('should default to 1', () => { - const { instance } = setup({ options: { ...defaultProps.options } }); + const { instance } = setup({ valueMappings: [] }); expect(instance.state.nextIdToAdd).toEqual(1); }); diff --git a/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.tsx b/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.tsx index ae0ff092a06..ca0a6e71f4a 100644 --- a/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.tsx +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/ValueMappingsEditor.tsx @@ -1,35 +1,39 @@ import React, { PureComponent } from 'react'; import MappingRow from './MappingRow'; -import { PanelOptionsProps, ValueMap, RangeMap, MappingType } from '../../types/panel'; -import { GaugeOptions } from '../../types/gauge'; +import { MappingType, ValueMapping } from '../../types/panel'; import { PanelOptionsGroup } from '../PanelOptionsGroup/PanelOptionsGroup'; +export interface Props { + valueMappings: ValueMapping[]; + onChange: (valueMappings: ValueMapping[]) => void; +} + interface State { - mappings: Array; + valueMappings: ValueMapping[]; nextIdToAdd: number; } -export class ValueMappingsEditor extends PureComponent, State> { - constructor(props) { +export class ValueMappingsEditor extends PureComponent { + constructor(props: Props) { super(props); - const mappings = props.options.mappings; + const mappings = props.valueMappings; this.state = { - mappings: mappings || [], - nextIdToAdd: mappings.length > 0 ? this.getMaxIdFromMappings(mappings) : 1, + valueMappings: mappings, + nextIdToAdd: mappings.length > 0 ? this.getMaxIdFromValueMappings(mappings) : 1, }; } - getMaxIdFromMappings(mappings) { + getMaxIdFromValueMappings(mappings: ValueMapping[]) { return Math.max.apply(null, mappings.map(mapping => mapping.id).map(m => m)) + 1; } addMapping = () => this.setState(prevState => ({ - mappings: [ - ...prevState.mappings, + valueMappings: [ + ...prevState.valueMappings, { id: prevState.nextIdToAdd, operator: '', @@ -43,23 +47,23 @@ export class ValueMappingsEditor extends PureComponent { + onRemoveMapping = (id: number) => { this.setState( prevState => ({ - mappings: prevState.mappings.filter(m => { + valueMappings: prevState.valueMappings.filter(m => { return m.id !== id; }), }), () => { - this.props.onChange({ ...this.props.options, mappings: this.state.mappings }); + this.props.onChange(this.state.valueMappings); } ); }; - updateGauge = mapping => { + updateGauge = (mapping: ValueMapping) => { this.setState( prevState => ({ - mappings: prevState.mappings.map(m => { + valueMappings: prevState.valueMappings.map(m => { if (m.id === mapping.id) { return { ...mapping }; } @@ -68,24 +72,24 @@ export class ValueMappingsEditor extends PureComponent { - this.props.onChange({ ...this.props.options, mappings: this.state.mappings }); + this.props.onChange(this.state.valueMappings); } ); }; render() { - const { mappings } = this.state; + const { valueMappings } = this.state; return (
- {mappings.length > 0 && - mappings.map((mapping, index) => ( + {valueMappings.length > 0 && + valueMappings.map((valueMapping, index) => ( this.onRemoveMapping(mapping.id)} + key={`${valueMapping.text}-${index}`} + valueMapping={valueMapping} + updateValueMapping={this.updateGauge} + removeValueMapping={() => this.onRemoveMapping(valueMapping.id)} /> ))}
diff --git a/packages/grafana-ui/src/components/ValueMappingsEditor/__snapshots__/ValueMappingsEditor.test.tsx.snap b/packages/grafana-ui/src/components/ValueMappingsEditor/__snapshots__/ValueMappingsEditor.test.tsx.snap index 592b3326421..8a465ff88df 100644 --- a/packages/grafana-ui/src/components/ValueMappingsEditor/__snapshots__/ValueMappingsEditor.test.tsx.snap +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/__snapshots__/ValueMappingsEditor.test.tsx.snap @@ -7,7 +7,9 @@ exports[`Render should render component 1`] = `
; - maxValue: number; - minValue: number; - prefix: string; - showThresholdLabels: boolean; - showThresholdMarkers: boolean; - stat: string; - suffix: string; - thresholds: Threshold[]; - unit: string; -} diff --git a/packages/grafana-ui/src/types/index.ts b/packages/grafana-ui/src/types/index.ts index 814ab0478db..f618ce6db34 100644 --- a/packages/grafana-ui/src/types/index.ts +++ b/packages/grafana-ui/src/types/index.ts @@ -1,4 +1,3 @@ export * from './series'; export * from './time'; export * from './panel'; -export * from './gauge'; diff --git a/packages/grafana-ui/src/types/panel.ts b/packages/grafana-ui/src/types/panel.ts index 17ef712b0dd..7e4012ad529 100644 --- a/packages/grafana-ui/src/types/panel.ts +++ b/packages/grafana-ui/src/types/panel.ts @@ -56,6 +56,8 @@ interface BaseMap { type: MappingType; } +export type ValueMapping = ValueMap | RangeMap; + export interface ValueMap extends BaseMap { value: string; } diff --git a/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx b/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx index cf60411ffe2..93fd67d608c 100644 --- a/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx +++ b/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx @@ -1,7 +1,8 @@ import React, { PureComponent } from 'react'; -import { GaugeOptions, PanelOptionsProps, PanelOptionsGroup, Label } from '@grafana/ui'; +import { PanelOptionsProps, PanelOptionsGroup, Label } from '@grafana/ui'; import { Switch } from 'app/core/components/Switch/Switch'; +import { GaugeOptions } from './types'; export default class GaugeOptionsEditor extends PureComponent> { onToggleThresholdLabels = () => diff --git a/public/app/plugins/panel/gauge/GaugePanel.tsx b/public/app/plugins/panel/gauge/GaugePanel.tsx index fd3d812f21e..cfce719b5a6 100644 --- a/public/app/plugins/panel/gauge/GaugePanel.tsx +++ b/public/app/plugins/panel/gauge/GaugePanel.tsx @@ -1,8 +1,9 @@ import React, { PureComponent } from 'react'; -import { GaugeOptions, PanelProps, NullValueMode } from '@grafana/ui'; +import { PanelProps, NullValueMode } from '@grafana/ui'; import { getTimeSeriesVMs } from 'app/viz/state/timeSeries'; import Gauge from 'app/viz/Gauge'; +import { GaugeOptions } from './types'; interface Props extends PanelProps {} diff --git a/public/app/plugins/panel/gauge/GaugePanelOptions.tsx b/public/app/plugins/panel/gauge/GaugePanelOptions.tsx index 3e82ca0e27b..9729416b7e6 100644 --- a/public/app/plugins/panel/gauge/GaugePanelOptions.tsx +++ b/public/app/plugins/panel/gauge/GaugePanelOptions.tsx @@ -1,16 +1,17 @@ import React, { PureComponent } from 'react'; import { BasicGaugeColor, - GaugeOptions, PanelOptionsProps, ThresholdsEditor, Threshold, PanelOptionsGrid, ValueMappingsEditor, + ValueMapping, } from '@grafana/ui'; import ValueOptions from 'app/plugins/panel/gauge/ValueOptions'; import GaugeOptionsEditor from './GaugeOptionsEditor'; +import { GaugeOptions } from './types'; export const defaultProps = { options: { @@ -24,7 +25,7 @@ export const defaultProps = { decimals: 0, stat: 'avg', unit: 'none', - mappings: [], + valueMappings: [], thresholds: [], }, }; @@ -32,7 +33,17 @@ export const defaultProps = { export default class GaugePanelOptions extends PureComponent> { static defaultProps = defaultProps; - onThresholdsChanged = (thresholds: Threshold[]) => this.props.onChange({ ...this.props.options, thresholds }); + onThresholdsChanged = (thresholds: Threshold[]) => + this.props.onChange({ + ...this.props.options, + thresholds, + }); + + onValueMappingsChanged = (valueMappings: ValueMapping[]) => + this.props.onChange({ + ...this.props.options, + valueMappings, + }); render() { const { onChange, options } = this.props; @@ -44,7 +55,7 @@ export default class GaugePanelOptions extends PureComponent - + ); } diff --git a/public/app/plugins/panel/gauge/ValueOptions.tsx b/public/app/plugins/panel/gauge/ValueOptions.tsx index accdb0b03fa..3bc529f0611 100644 --- a/public/app/plugins/panel/gauge/ValueOptions.tsx +++ b/public/app/plugins/panel/gauge/ValueOptions.tsx @@ -1,7 +1,8 @@ import React, { PureComponent } from 'react'; -import { GaugeOptions, PanelOptionsProps, PanelOptionsGroup, Label, Select } from '@grafana/ui'; +import { PanelOptionsProps, PanelOptionsGroup, Label, Select } from '@grafana/ui'; import UnitPicker from 'app/core/components/Select/UnitPicker'; +import { GaugeOptions } from './types'; const statOptions = [ { value: 'min', label: 'Min' }, diff --git a/public/app/plugins/panel/gauge/types.ts b/public/app/plugins/panel/gauge/types.ts index 139597f9cb0..b698a3389c2 100644 --- a/public/app/plugins/panel/gauge/types.ts +++ b/public/app/plugins/panel/gauge/types.ts @@ -1,2 +1,16 @@ +import { Threshold, ValueMapping } from '@grafana/ui'; - +export interface GaugeOptions { + baseColor: string; + decimals: number; + valueMappings: ValueMapping[]; + maxValue: number; + minValue: number; + prefix: string; + showThresholdLabels: boolean; + showThresholdMarkers: boolean; + stat: string; + suffix: string; + thresholds: Threshold[]; + unit: string; +} diff --git a/public/app/viz/Gauge.test.tsx b/public/app/viz/Gauge.test.tsx index f0c4a874649..69c7733f44b 100644 --- a/public/app/viz/Gauge.test.tsx +++ b/public/app/viz/Gauge.test.tsx @@ -12,7 +12,7 @@ const setup = (propOverrides?: object) => { const props: Props = { baseColor: BasicGaugeColor.Green, maxValue: 100, - mappings: [], + valueMappings: [], minValue: 0, prefix: '', showThresholdMarkers: true, diff --git a/public/app/viz/Gauge.tsx b/public/app/viz/Gauge.tsx index d5e4eb94884..094e630a1c0 100644 --- a/public/app/viz/Gauge.tsx +++ b/public/app/viz/Gauge.tsx @@ -1,6 +1,6 @@ import React, { PureComponent } from 'react'; import $ from 'jquery'; -import { BasicGaugeColor, Threshold, TimeSeriesVMs, RangeMap, ValueMap, MappingType } from '@grafana/ui'; +import { BasicGaugeColor, Threshold, TimeSeriesVMs, MappingType, ValueMapping } from '@grafana/ui'; import config from '../core/config'; import kbn from '../core/utils/kbn'; @@ -9,7 +9,7 @@ export interface Props { baseColor: string; decimals: number; height: number; - mappings: Array; + valueMappings: ValueMapping[]; maxValue: number; minValue: number; prefix: string; @@ -29,7 +29,7 @@ export class Gauge extends PureComponent { static defaultProps = { baseColor: BasicGaugeColor.Green, maxValue: 100, - mappings: [], + valueMappings: [], minValue: 0, prefix: '', showThresholdMarkers: true, @@ -64,20 +64,17 @@ export class Gauge extends PureComponent { } })[0]; - return { - rangeMap, - valueMap, - }; + return { rangeMap, valueMap }; } formatValue(value) { - const { decimals, mappings, prefix, suffix, unit } = this.props; + const { decimals, valueMappings, prefix, suffix, unit } = this.props; const formatFunc = kbn.valueFormats[unit]; const formattedValue = formatFunc(value, decimals); - if (mappings.length > 0) { - const { rangeMap, valueMap } = this.formatWithMappings(mappings, formattedValue); + if (valueMappings.length > 0) { + const { rangeMap, valueMap } = this.formatWithMappings(valueMappings, formattedValue); if (valueMap) { return `${prefix} ${valueMap} ${suffix}`; @@ -148,10 +145,7 @@ export class Gauge extends PureComponent { color: index === 0 ? threshold.color : thresholds[index].color, }; }), - { - value: maxValue, - color: thresholds.length > 0 ? BasicGaugeColor.Red : baseColor, - }, + { value: maxValue, color: thresholds.length > 0 ? BasicGaugeColor.Red : baseColor }, ]; const options = { @@ -184,19 +178,14 @@ export class Gauge extends PureComponent { formatter: () => { return this.formatValue(value); }, - font: { - size: fontSize, - family: '"Helvetica Neue", Helvetica, Arial, sans-serif', - }, + font: { size: fontSize, family: '"Helvetica Neue", Helvetica, Arial, sans-serif' }, }, show: true, }, }, }; - const plotSeries = { - data: [[0, value]], - }; + const plotSeries = { data: [[0, value]] }; try { $.plot(this.canvasElement, [plotSeries], options); From 8df11e93a1aaca5dda4d2a029b1e8f6e08a9f5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Hugo=20H=C3=A4ggmark?= Date: Wed, 16 Jan 2019 12:46:43 +0100 Subject: [PATCH 07/36] Removed snapshot --- .../__snapshots__/ValueMappings.test.tsx.snap | 56 ------------------- 1 file changed, 56 deletions(-) delete mode 100644 public/app/plugins/panel/gauge/__snapshots__/ValueMappings.test.tsx.snap diff --git a/public/app/plugins/panel/gauge/__snapshots__/ValueMappings.test.tsx.snap b/public/app/plugins/panel/gauge/__snapshots__/ValueMappings.test.tsx.snap deleted file mode 100644 index 592b3326421..00000000000 --- a/public/app/plugins/panel/gauge/__snapshots__/ValueMappings.test.tsx.snap +++ /dev/null @@ -1,56 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Render should render component 1`] = ` - -
- - -
-
-
- -
-
- Add mapping -
-
-
-`; From cc8b450799852028a5cf9cb8ddab030aff502198 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 16 Jan 2019 14:36:01 +0100 Subject: [PATCH 08/36] minor style change --- .../components/ThresholdsEditor/_ThresholdsEditor.scss | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/packages/grafana-ui/src/components/ThresholdsEditor/_ThresholdsEditor.scss b/packages/grafana-ui/src/components/ThresholdsEditor/_ThresholdsEditor.scss index 50c92a6bcc5..f95ecac46a2 100644 --- a/packages/grafana-ui/src/components/ThresholdsEditor/_ThresholdsEditor.scss +++ b/packages/grafana-ui/src/components/ThresholdsEditor/_ThresholdsEditor.scss @@ -8,6 +8,12 @@ height: 70px; } +.thresholds-row:first-child > .thresholds-row-color-indicator { + border-top-left-radius: $border-radius; + border-top-right-radius: $border-radius; + overflow: hidden; +} + .thresholds-row:last-child > .thresholds-row-color-indicator { border-bottom-left-radius: $border-radius; border-bottom-right-radius: $border-radius; @@ -33,7 +39,7 @@ } .thresholds-row-color-indicator { - width: 20px; + width: 10px; } .thresholds-row-input { From 4c40274313f38cf57a525c3fd780213e9ee0e0a2 Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Wed, 16 Jan 2019 13:46:57 +0000 Subject: [PATCH 09/36] renaming after pr feedback --- .../{FormGroup.test.tsx => FormField.test.tsx} | 4 ++-- .../FormGroup/{FormGroup.tsx => FormField.tsx} | 10 +++++----- .../GfFormLabel.tsx => FormLabel/FormLabel.tsx} | 2 +- packages/grafana-ui/src/components/index.ts | 4 ++-- .../features/dashboard/panel_editor/QueryOptions.tsx | 4 ++-- public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx | 6 +++--- public/app/plugins/panel/gauge/MappingRow.tsx | 8 ++++---- public/app/plugins/panel/gauge/ValueOptions.tsx | 8 ++++---- 8 files changed, 23 insertions(+), 23 deletions(-) rename packages/grafana-ui/src/components/FormGroup/{FormGroup.test.tsx => FormField.test.tsx} (82%) rename packages/grafana-ui/src/components/FormGroup/{FormGroup.tsx => FormField.tsx} (58%) rename packages/grafana-ui/src/components/{GfFormLabel/GfFormLabel.tsx => FormLabel/FormLabel.tsx} (81%) diff --git a/packages/grafana-ui/src/components/FormGroup/FormGroup.test.tsx b/packages/grafana-ui/src/components/FormGroup/FormField.test.tsx similarity index 82% rename from packages/grafana-ui/src/components/FormGroup/FormGroup.test.tsx rename to packages/grafana-ui/src/components/FormGroup/FormField.test.tsx index 4f8b4be9540..4474b0680c5 100644 --- a/packages/grafana-ui/src/components/FormGroup/FormGroup.test.tsx +++ b/packages/grafana-ui/src/components/FormGroup/FormField.test.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { FormGroup, Props } from './FormGroup'; +import { FormField, Props } from './FormField'; const setup = (propOverrides?: object) => { const props: Props = { @@ -14,7 +14,7 @@ const setup = (propOverrides?: object) => { Object.assign(props, propOverrides); - return shallow(); + return shallow(); }; describe('Render', () => { diff --git a/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx b/packages/grafana-ui/src/components/FormGroup/FormField.tsx similarity index 58% rename from packages/grafana-ui/src/components/FormGroup/FormGroup.tsx rename to packages/grafana-ui/src/components/FormGroup/FormField.tsx index a0088032079..ae86d4115b0 100644 --- a/packages/grafana-ui/src/components/FormGroup/FormGroup.tsx +++ b/packages/grafana-ui/src/components/FormGroup/FormField.tsx @@ -1,9 +1,9 @@ -import React, { SFC } from 'react'; +import React, { InputHTMLAttributes, FunctionComponent } from 'react'; import { Label } from '..'; export interface Props { label: string; - inputProps: {}; + inputProps: InputHTMLAttributes; labelWidth?: number; inputWidth?: number; } @@ -14,7 +14,7 @@ const defaultProps = { inputWidth: 12, }; -const FormGroup: SFC = ({ label, labelWidth, inputProps, inputWidth }) => { +const FormField: FunctionComponent = ({ label, labelWidth, inputProps, inputWidth }) => { return (
@@ -23,5 +23,5 @@ const FormGroup: SFC = ({ label, labelWidth, inputProps, inputWidth }) => ); }; -FormGroup.defaultProps = defaultProps; -export { FormGroup }; +FormField.defaultProps = defaultProps; +export { FormField }; diff --git a/packages/grafana-ui/src/components/GfFormLabel/GfFormLabel.tsx b/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx similarity index 81% rename from packages/grafana-ui/src/components/GfFormLabel/GfFormLabel.tsx rename to packages/grafana-ui/src/components/FormLabel/FormLabel.tsx index 8b80de64696..d6ac3da9394 100644 --- a/packages/grafana-ui/src/components/GfFormLabel/GfFormLabel.tsx +++ b/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx @@ -9,7 +9,7 @@ interface Props { isInvalid?: boolean; } -export const GfFormLabel: SFC = ({ children, isFocused, isInvalid, className, htmlFor, ...rest }) => { +export const FormLabel: SFC = ({ children, isFocused, isInvalid, className, htmlFor, ...rest }) => { const classes = classNames('gf-form-label', className, { 'gf-form-label--is-focused': isFocused, 'gf-form-label--is-invalid': isInvalid, diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index ab0edf45ed0..3a29623838a 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -10,8 +10,8 @@ export { NoOptionsMessage } from './Select/NoOptionsMessage'; export { default as resetSelectStyles } from './Select/resetSelectStyles'; // Forms -export { GfFormLabel } from './GfFormLabel/GfFormLabel'; -export { FormGroup } from './FormGroup/FormGroup'; +export { FormLabel } from './FormLabel/FormLabel'; +export { FormField } from './FormGroup/FormField'; export { Label } from './Label/Label'; export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder'; diff --git a/public/app/features/dashboard/panel_editor/QueryOptions.tsx b/public/app/features/dashboard/panel_editor/QueryOptions.tsx index fad70d92990..d6187a89b7b 100644 --- a/public/app/features/dashboard/panel_editor/QueryOptions.tsx +++ b/public/app/features/dashboard/panel_editor/QueryOptions.tsx @@ -10,7 +10,7 @@ import { Input } from 'app/core/components/Form'; import { EventsWithValidation } from 'app/core/components/Form/Input'; import { InputStatus } from 'app/core/components/Form/Input'; import DataSourceOption from './DataSourceOption'; -import { GfFormLabel } from '@grafana/ui'; +import { FormLabel } from '@grafana/ui'; // Types import { PanelModel } from '../panel_model'; @@ -164,7 +164,7 @@ export class QueryOptions extends PureComponent { {this.renderOptions()}
- Relative time + Relative time > { onToggleThresholdLabels = () => @@ -21,12 +21,12 @@ export default class GaugeOptionsEditor extends PureComponent - this.onMinValueChange(event), value: minValue }} /> - this.onMaxValueChange(event), value: maxValue }} diff --git a/public/app/plugins/panel/gauge/MappingRow.tsx b/public/app/plugins/panel/gauge/MappingRow.tsx index 91dff549677..47647b1b9ae 100644 --- a/public/app/plugins/panel/gauge/MappingRow.tsx +++ b/public/app/plugins/panel/gauge/MappingRow.tsx @@ -1,5 +1,5 @@ import React, { PureComponent } from 'react'; -import { FormGroup, Label, MappingType, RangeMap, Select, ValueMap } from '@grafana/ui'; +import { FormField, Label, MappingType, RangeMap, Select, ValueMap } from '@grafana/ui'; interface Props { mapping: ValueMap | RangeMap; @@ -61,7 +61,7 @@ export default class MappingRow extends PureComponent { if (type === MappingType.RangeToText) { return ( <> - { }} inputWidth={8} /> - { return ( <> - Unit
- - - Date: Wed, 16 Jan 2019 13:52:38 +0000 Subject: [PATCH 10/36] move styling --- .../{FormGroup => FormField}/FormField.test.tsx | 0 .../{FormGroup => FormField}/FormField.tsx | 2 +- .../src/components/FormField/_FormField.scss | 12 ++++++++++++ .../__snapshots__/FormField.test.tsx.snap} | 0 packages/grafana-ui/src/components/index.scss | 1 + packages/grafana-ui/src/components/index.ts | 2 +- 6 files changed, 15 insertions(+), 2 deletions(-) rename packages/grafana-ui/src/components/{FormGroup => FormField}/FormField.test.tsx (100%) rename packages/grafana-ui/src/components/{FormGroup => FormField}/FormField.tsx (95%) create mode 100644 packages/grafana-ui/src/components/FormField/_FormField.scss rename packages/grafana-ui/src/components/{FormGroup/__snapshots__/FormGroup.test.tsx.snap => FormField/__snapshots__/FormField.test.tsx.snap} (100%) diff --git a/packages/grafana-ui/src/components/FormGroup/FormField.test.tsx b/packages/grafana-ui/src/components/FormField/FormField.test.tsx similarity index 100% rename from packages/grafana-ui/src/components/FormGroup/FormField.test.tsx rename to packages/grafana-ui/src/components/FormField/FormField.test.tsx diff --git a/packages/grafana-ui/src/components/FormGroup/FormField.tsx b/packages/grafana-ui/src/components/FormField/FormField.tsx similarity index 95% rename from packages/grafana-ui/src/components/FormGroup/FormField.tsx rename to packages/grafana-ui/src/components/FormField/FormField.tsx index ae86d4115b0..aa026a74197 100644 --- a/packages/grafana-ui/src/components/FormGroup/FormField.tsx +++ b/packages/grafana-ui/src/components/FormField/FormField.tsx @@ -16,7 +16,7 @@ const defaultProps = { const FormField: FunctionComponent = ({ label, labelWidth, inputProps, inputWidth }) => { return ( -
+
diff --git a/packages/grafana-ui/src/components/FormField/_FormField.scss b/packages/grafana-ui/src/components/FormField/_FormField.scss new file mode 100644 index 00000000000..36955e2fca6 --- /dev/null +++ b/packages/grafana-ui/src/components/FormField/_FormField.scss @@ -0,0 +1,12 @@ +.form-field { + margin-bottom: $gf-form-margin; + display: flex; + flex-direction: row; + align-items: center; + text-align: left; + position: relative; + + &--grow { + flex-grow: 1; + } +} diff --git a/packages/grafana-ui/src/components/FormGroup/__snapshots__/FormGroup.test.tsx.snap b/packages/grafana-ui/src/components/FormField/__snapshots__/FormField.test.tsx.snap similarity index 100% rename from packages/grafana-ui/src/components/FormGroup/__snapshots__/FormGroup.test.tsx.snap rename to packages/grafana-ui/src/components/FormField/__snapshots__/FormField.test.tsx.snap diff --git a/packages/grafana-ui/src/components/index.scss b/packages/grafana-ui/src/components/index.scss index b894cf73c1a..eaf64561ae8 100644 --- a/packages/grafana-ui/src/components/index.scss +++ b/packages/grafana-ui/src/components/index.scss @@ -6,3 +6,4 @@ @import 'PanelOptionsGroup/PanelOptionsGroup'; @import 'PanelOptionsGrid/PanelOptionsGrid'; @import 'ColorPicker/ColorPicker'; +@import "FormField/FormField"; diff --git a/packages/grafana-ui/src/components/index.ts b/packages/grafana-ui/src/components/index.ts index 3a29623838a..ac06c07951b 100644 --- a/packages/grafana-ui/src/components/index.ts +++ b/packages/grafana-ui/src/components/index.ts @@ -11,7 +11,7 @@ export { default as resetSelectStyles } from './Select/resetSelectStyles'; // Forms export { FormLabel } from './FormLabel/FormLabel'; -export { FormField } from './FormGroup/FormField'; +export { FormField } from './FormField/FormField'; export { Label } from './Label/Label'; export { LoadingPlaceholder } from './LoadingPlaceholder/LoadingPlaceholder'; From 05b82bede3a11a0b4a1034b64800b0ca4a03e172 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 16 Jan 2019 15:13:59 +0100 Subject: [PATCH 11/36] More style tweaks to thresholds --- .../ThresholdsEditor/_ThresholdsEditor.scss | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/packages/grafana-ui/src/components/ThresholdsEditor/_ThresholdsEditor.scss b/packages/grafana-ui/src/components/ThresholdsEditor/_ThresholdsEditor.scss index f95ecac46a2..61278321572 100644 --- a/packages/grafana-ui/src/components/ThresholdsEditor/_ThresholdsEditor.scss +++ b/packages/grafana-ui/src/components/ThresholdsEditor/_ThresholdsEditor.scss @@ -51,18 +51,6 @@ display: flex; justify-content: center; flex-direction: row; - height: 42px; -} - -.thresholds-row-input-inner > div { - border-left: 1px solid $input-label-border-color; - border-top: 1px solid $input-label-border-color; - border-bottom: 1px solid $input-label-border-color; -} - -.thresholds-row-input-inner > *:nth-child(2) { - border-top-left-radius: $border-radius; - border-bottom-left-radius: $border-radius; } .thresholds-row-input-inner > *:last-child { @@ -80,9 +68,11 @@ } .thresholds-row-input-inner-value > input { - height: 100%; - padding: 8px 10px; + height: $gf-form-input-height; + padding: $input-padding-y $input-padding-x; width: 150px; + border-top: 1px solid $input-label-border-color; + border-bottom: 1px solid $input-label-border-color; } .thresholds-row-input-inner-color { @@ -91,6 +81,7 @@ align-items: center; justify-content: center; background-color: $input-bg; + border: 1px solid $input-label-border-color; } .thresholds-row-input-inner-color-colorpicker { @@ -105,8 +96,10 @@ display: flex; align-items: center; justify-content: center; - height: 42px; + height: $gf-form-input-height; + padding: $input-padding-y $input-padding-x; width: 42px; - background-color: $input-label-border-color; + background-color: $input-label-bg; + border: 1px solid $input-label-border-color; cursor: pointer; } From 8fef2138b2b629d84a757929f2c324e82130e29c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Wed, 16 Jan 2019 15:35:32 +0100 Subject: [PATCH 12/36] another minor style change --- .../src/components/PanelOptionsGroup/_PanelOptionsGroup.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/grafana-ui/src/components/PanelOptionsGroup/_PanelOptionsGroup.scss b/packages/grafana-ui/src/components/PanelOptionsGroup/_PanelOptionsGroup.scss index 9f5d4f02695..87d5b00f3b1 100644 --- a/packages/grafana-ui/src/components/PanelOptionsGroup/_PanelOptionsGroup.scss +++ b/packages/grafana-ui/src/components/PanelOptionsGroup/_PanelOptionsGroup.scss @@ -6,7 +6,7 @@ } .panel-options-group__header { - padding: 4px 20px; + padding: 4px 8px; font-size: 1.1rem; background: $panel-options-group-header-bg; position: relative; From 01251927b3c085aee6df85c4bf1bc54b5a61355f Mon Sep 17 00:00:00 2001 From: Peter Holmberg Date: Wed, 16 Jan 2019 14:43:22 +0000 Subject: [PATCH 13/36] redoing input props --- .../components/FormField/FormField.test.tsx | 6 ++--- .../src/components/FormField/FormField.tsx | 6 ++--- .../ValueMappingsEditor/MappingRow.tsx | 24 +++++++------------ .../panel/gauge/GaugeOptionsEditor.tsx | 12 ++-------- .../app/plugins/panel/gauge/ValueOptions.tsx | 24 +++++++------------ 5 files changed, 24 insertions(+), 48 deletions(-) diff --git a/packages/grafana-ui/src/components/FormField/FormField.test.tsx b/packages/grafana-ui/src/components/FormField/FormField.test.tsx index 4474b0680c5..3c89a347e86 100644 --- a/packages/grafana-ui/src/components/FormField/FormField.test.tsx +++ b/packages/grafana-ui/src/components/FormField/FormField.test.tsx @@ -6,10 +6,8 @@ const setup = (propOverrides?: object) => { const props: Props = { label: 'Test', labelWidth: 11, - inputProps: { - value: 10, - onChange: jest.fn(), - }, + value: 10, + onChange: jest.fn(), }; Object.assign(props, propOverrides); diff --git a/packages/grafana-ui/src/components/FormField/FormField.tsx b/packages/grafana-ui/src/components/FormField/FormField.tsx index aa026a74197..14bec79b57f 100644 --- a/packages/grafana-ui/src/components/FormField/FormField.tsx +++ b/packages/grafana-ui/src/components/FormField/FormField.tsx @@ -1,20 +1,18 @@ import React, { InputHTMLAttributes, FunctionComponent } from 'react'; import { Label } from '..'; -export interface Props { +export interface Props extends InputHTMLAttributes { label: string; - inputProps: InputHTMLAttributes; labelWidth?: number; inputWidth?: number; } const defaultProps = { labelWidth: 6, - inputProps: {}, inputWidth: 12, }; -const FormField: FunctionComponent = ({ label, labelWidth, inputProps, inputWidth }) => { +const FormField: FunctionComponent = ({ label, labelWidth, inputWidth, ...inputProps }) => { return (
diff --git a/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx b/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx index 3da2cfc2d98..db970046fc4 100644 --- a/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx @@ -64,22 +64,18 @@ export default class MappingRow extends PureComponent { ) => this.onMappingFromChange(event), - onBlur: () => this.updateMapping(), - value: from, - }} inputWidth={8} + onChange={(event: ChangeEvent) => this.onMappingFromChange(event)} + onBlur={() => this.updateMapping()} + value={from} /> this.updateMapping, - onChange: (event: ChangeEvent) => this.onMappingToChange(event), - value: to, - }} inputWidth={8} + onBlur={() => this.updateMapping} + onChange={(event: ChangeEvent) => this.onMappingToChange(event)} + value={to} />
@@ -99,11 +95,9 @@ export default class MappingRow extends PureComponent { this.updateMapping, - onChange: (event: ChangeEvent) => this.onMappingValueChange(event), - value: value, - }} + onBlur={() => this.updateMapping} + onChange={(event: ChangeEvent) => this.onMappingValueChange(event)} + value={value} inputWidth={8} />
diff --git a/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx b/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx index b971e67939c..6b8c92e3fe7 100644 --- a/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx +++ b/public/app/plugins/panel/gauge/GaugeOptionsEditor.tsx @@ -21,16 +21,8 @@ export default class GaugeOptionsEditor extends PureComponent - this.onMinValueChange(event), value: minValue }} - /> - this.onMaxValueChange(event), value: maxValue }} - /> + this.onMinValueChange(event)} value={minValue} /> + this.onMaxValueChange(event)} value={maxValue} /> this.onDecimalChange(event), - value: decimals || '', - type: 'number', - }} + placeholder="auto" + onChange={event => this.onDecimalChange(event)} + value={decimals || ''} + type="number" /> this.onPrefixChange(event), - value: prefix || '', - }} + onChange={event => this.onPrefixChange(event)} + value={prefix || ''} /> this.onSuffixChange(event), - value: suffix || '', - }} + onChange={event => this.onSuffixChange(event)} + value={suffix || ''} /> ); From 7f4a479451370f3d80e2aaa2876a2c205afb9edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Tue, 8 Jan 2019 08:38:43 +0100 Subject: [PATCH 14/36] POC of page layout component --- public/app/core/components/Page/Page.tsx | 26 ++++++++++ .../app/core/components/Page/PageContents.tsx | 29 +++++++++++ .../core/components/PageLoader/PageLoader.tsx | 2 +- .../datasources/DataSourcesListPage.tsx | 50 +++++++++---------- 4 files changed, 81 insertions(+), 26 deletions(-) create mode 100644 public/app/core/components/Page/Page.tsx create mode 100644 public/app/core/components/Page/PageContents.tsx diff --git a/public/app/core/components/Page/Page.tsx b/public/app/core/components/Page/Page.tsx new file mode 100644 index 00000000000..087ac0e111b --- /dev/null +++ b/public/app/core/components/Page/Page.tsx @@ -0,0 +1,26 @@ +// Libraries +import React, { Component } from 'react'; + +// Components +import PageHeader from '../PageHeader/PageHeader'; +import PageContents from './PageContents'; + +interface Props { + title: string; + children: JSX.Element[] | JSX.Element; +} + +class Page extends Component { + static Header = PageHeader; + static Contents = PageContents; + + render() { + return ( +
+ {this.props.children} +
+ ); + } +} + +export default Page; diff --git a/public/app/core/components/Page/PageContents.tsx b/public/app/core/components/Page/PageContents.tsx new file mode 100644 index 00000000000..bf5e3ba7385 --- /dev/null +++ b/public/app/core/components/Page/PageContents.tsx @@ -0,0 +1,29 @@ +// Libraries +import React, { Component } from 'react'; + +// Components +import CustomScrollbar from '../CustomScrollbar/CustomScrollbar'; +import PageLoader from '../PageLoader/PageLoader'; + +interface Props { + isLoading?: boolean; + children: JSX.Element[] | JSX.Element; +} + +class PageContents extends Component { + + render() { + const { isLoading } = this.props; + + return ( +
+ + {isLoading && } + {this.props.children} + +
+ ); + } +} + +export default PageContents; diff --git a/public/app/core/components/PageLoader/PageLoader.tsx b/public/app/core/components/PageLoader/PageLoader.tsx index dcb67dde220..5fff00b2f6f 100644 --- a/public/app/core/components/PageLoader/PageLoader.tsx +++ b/public/app/core/components/PageLoader/PageLoader.tsx @@ -1,7 +1,7 @@ import React, { SFC } from 'react'; interface Props { - pageName: string; + pageName?: string; } const PageLoader: SFC = ({ pageName }) => { diff --git a/public/app/features/datasources/DataSourcesListPage.tsx b/public/app/features/datasources/DataSourcesListPage.tsx index 6a292d63e53..de9dba34d73 100644 --- a/public/app/features/datasources/DataSourcesListPage.tsx +++ b/public/app/features/datasources/DataSourcesListPage.tsx @@ -1,15 +1,14 @@ 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 { 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,25 +66,26 @@ export class DataSourcesListPage extends PureComponent { }; return ( -
- -
- {!hasFetched && } - {hasFetched && dataSourcesCount === 0 && } - {hasFetched && - dataSourcesCount > 0 && [ - setDataSourcesLayoutMode(mode)} - setSearchQuery={query => setDataSourcesSearchQuery(query)} - linkButton={linkButton} - key="action-bar" - />, - , - ]} -
-
+ + + + <> + {hasFetched && dataSourcesCount === 0 && } + {hasFetched && + dataSourcesCount > 0 && [ + setDataSourcesLayoutMode(mode)} + setSearchQuery={query => setDataSourcesSearchQuery(query)} + linkButton={linkButton} + key="action-bar" + />, + , + ]} + + + ); } } From 1d8e036bcbf779faaf4e70c30cefbe0805a7b7eb Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Wed, 9 Jan 2019 16:31:28 +0100 Subject: [PATCH 15/36] fix: Fix import path after Scrollbar move to @grafana/ui --- public/app/core/components/Page/PageContents.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/app/core/components/Page/PageContents.tsx b/public/app/core/components/Page/PageContents.tsx index bf5e3ba7385..4c740584e69 100644 --- a/public/app/core/components/Page/PageContents.tsx +++ b/public/app/core/components/Page/PageContents.tsx @@ -2,7 +2,7 @@ import React, { Component } from 'react'; // Components -import CustomScrollbar from '../CustomScrollbar/CustomScrollbar'; +import { CustomScrollbar } from '@grafana/ui'; import PageLoader from '../PageLoader/PageLoader'; interface Props { From 9e0e91a90a84b072ecd0ed363990bcdb8b2467ac Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Thu, 10 Jan 2019 08:33:39 +0100 Subject: [PATCH 16/36] test: Snapshot update --- .../DataSourcesListPage.test.tsx.snap | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap b/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap index c26ac50fed8..e523816c021 100644 --- a/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap +++ b/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap @@ -1,12 +1,14 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Render should render action bar and datasources 1`] = ` -
+ -
-
-
+ + `; exports[`Render should render component 1`] = ` -
+ -
- -
-
+ + `; From 47d86ee81898753d2567d03f5e529be6172ba15d Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Thu, 10 Jan 2019 08:36:38 +0100 Subject: [PATCH 17/36] fix: Proper types for linter --- public/app/core/components/PageHeader/PageHeader.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/public/app/core/components/PageHeader/PageHeader.tsx b/public/app/core/components/PageHeader/PageHeader.tsx index c176095afa4..83066054f88 100644 --- a/public/app/core/components/PageHeader/PageHeader.tsx +++ b/public/app/core/components/PageHeader/PageHeader.tsx @@ -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 }); }; From 8237c22e24a83224c61a7a0fe06a931e4622272c Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 14 Jan 2019 16:05:49 +0100 Subject: [PATCH 18/36] fix: Add CustomScroller on DataSources page --- .../CustomScrollbar/CustomScrollbar.tsx | 3 +- public/app/core/components/Page/Page.tsx | 28 +++++++++++++++++-- .../app/core/components/Page/PageContents.tsx | 7 ++--- .../datasources/DataSourcesListPage.tsx | 4 +-- public/sass/components/_footer.scss | 8 ++++++ public/sass/layout/_page.scss | 17 ++++++++++- 6 files changed, 56 insertions(+), 11 deletions(-) diff --git a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx index 519e755b474..7f43936481f 100644 --- a/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx +++ b/packages/grafana-ui/src/components/CustomScrollbar/CustomScrollbar.tsx @@ -8,6 +8,7 @@ interface Props { autoHideDuration?: number; autoMaxHeight?: string; hideTracksWhenNotNeeded?: boolean; + autoHeightMin?: number | string; } /** @@ -21,6 +22,7 @@ export class CustomScrollbar extends PureComponent { autoHideDuration: 200, autoMaxHeight: '100%', hideTracksWhenNotNeeded: false, + autoHeightMin: '0' }; render() { @@ -32,7 +34,6 @@ export class CustomScrollbar extends PureComponent { 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 =>
} renderTrackVertical={props =>
} diff --git a/public/app/core/components/Page/Page.tsx b/public/app/core/components/Page/Page.tsx index 087ac0e111b..f225d4d3170 100644 --- a/public/app/core/components/Page/Page.tsx +++ b/public/app/core/components/Page/Page.tsx @@ -4,6 +4,7 @@ import React, { Component } from 'react'; // Components import PageHeader from '../PageHeader/PageHeader'; import PageContents from './PageContents'; +import { CustomScrollbar } from '@grafana/ui'; interface Props { title: string; @@ -11,13 +12,36 @@ interface Props { } class Page extends Component { + private bodyClass = 'is-react'; + private body = document.getElementsByTagName('body')[0]; + private footer = document.getElementsByClassName('footer')[0].cloneNode(true); + private scrollbarElementRef = React.createRef(); static Header = PageHeader; static Contents = PageContents; + + componentDidMount() { + this.body.classList.add(this.bodyClass); + this.copyFooter(); + } + + componentWillUnmount() { + this.body.classList.remove(this.bodyClass); + } + + copyFooter = () => { + const c = this.scrollbarElementRef.current; + c.append(this.footer); + } + render() { return ( -
- {this.props.children} +
+ +
+ {this.props.children} +
+
); } diff --git a/public/app/core/components/Page/PageContents.tsx b/public/app/core/components/Page/PageContents.tsx index 4c740584e69..6970857d383 100644 --- a/public/app/core/components/Page/PageContents.tsx +++ b/public/app/core/components/Page/PageContents.tsx @@ -2,7 +2,6 @@ import React, { Component } from 'react'; // Components -import { CustomScrollbar } from '@grafana/ui'; import PageLoader from '../PageLoader/PageLoader'; interface Props { @@ -17,10 +16,8 @@ class PageContents extends Component { return (
- - {isLoading && } - {this.props.children} - + {isLoading && } + {this.props.children}
); } diff --git a/public/app/features/datasources/DataSourcesListPage.tsx b/public/app/features/datasources/DataSourcesListPage.tsx index de9dba34d73..d81caae663c 100644 --- a/public/app/features/datasources/DataSourcesListPage.tsx +++ b/public/app/features/datasources/DataSourcesListPage.tsx @@ -5,7 +5,7 @@ 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 { DataSource, NavModel, StoreState } from 'app/types'; import { LayoutMode } from 'app/core/components/LayoutSelector/LayoutSelector'; import { loadDataSources, setDataSourcesLayoutMode, setDataSourcesSearchQuery } from './state/actions'; import { getNavModel } from 'app/core/selectors/navModel'; @@ -90,7 +90,7 @@ export class DataSourcesListPage extends PureComponent { } } -function mapStateToProps(state) { +function mapStateToProps(state: StoreState) { return { navModel: getNavModel(state.navIndex, 'datasources'), dataSources: getDataSources(state.dataSources), diff --git a/public/sass/components/_footer.scss b/public/sass/components/_footer.scss index 893eea02914..b5617f4e387 100644 --- a/public/sass/components/_footer.scss +++ b/public/sass/components/_footer.scss @@ -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 { diff --git a/public/sass/layout/_page.scss b/public/sass/layout/_page.scss index 818dc6c3e60..425cbc903c0 100644 --- a/public/sass/layout/_page.scss +++ b/public/sass/layout/_page.scss @@ -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 { From 06d8243ab590e81ffb3721f788672d995a6c0a3a Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 14 Jan 2019 16:51:43 +0100 Subject: [PATCH 19/36] feat: Possibility to change document title on pages using the Page component --- public/app/core/components/Page/Page.tsx | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/public/app/core/components/Page/Page.tsx b/public/app/core/components/Page/Page.tsx index f225d4d3170..eeba4b3037b 100644 --- a/public/app/core/components/Page/Page.tsx +++ b/public/app/core/components/Page/Page.tsx @@ -7,7 +7,7 @@ import PageContents from './PageContents'; import { CustomScrollbar } from '@grafana/ui'; interface Props { - title: string; + title?: string; children: JSX.Element[] | JSX.Element; } @@ -23,12 +23,24 @@ class Page extends Component { componentDidMount() { this.body.classList.add(this.bodyClass); this.copyFooter(); + this.updateTitle(); + } + + componentDidUpdate(prevProps: Props) { + if (prevProps.title !== this.props.title) { + this.updateTitle(); + } } componentWillUnmount() { this.body.classList.remove(this.bodyClass); } + updateTitle = () => { + const { title } = this.props; + document.title = title ? title + ' - Grafana' : 'Grafana'; + } + copyFooter = () => { const c = this.scrollbarElementRef.current; c.append(this.footer); @@ -37,11 +49,11 @@ class Page extends Component { render() { return (
- -
- {this.props.children} -
-
+ +
+ {this.props.children} +
+
); } From b2961a4b4a9f3336331a5fa59063a8f331c5d9ce Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 14 Jan 2019 16:53:26 +0100 Subject: [PATCH 20/36] fix: Configuration: Users should also use the Page component --- .../datasources/DataSourcesListPage.tsx | 2 +- public/app/features/users/UsersListPage.tsx | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/public/app/features/datasources/DataSourcesListPage.tsx b/public/app/features/datasources/DataSourcesListPage.tsx index d81caae663c..12eb49cb856 100644 --- a/public/app/features/datasources/DataSourcesListPage.tsx +++ b/public/app/features/datasources/DataSourcesListPage.tsx @@ -66,7 +66,7 @@ export class DataSourcesListPage extends PureComponent { }; return ( - + <> diff --git a/public/app/features/users/UsersListPage.tsx b/public/app/features/users/UsersListPage.tsx index ff0ac8f1239..ece431158fd 100644 --- a/public/app/features/users/UsersListPage.tsx +++ b/public/app/features/users/UsersListPage.tsx @@ -2,8 +2,7 @@ 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'; @@ -105,16 +104,18 @@ export class UsersListPage extends PureComponent { const externalUserMngInfoHtml = this.externalUserMngInfoHtml; return ( -
- -
+ + + + <> {externalUserMngInfoHtml && (
)} - {hasFetched ? this.renderTable() : } -
-
+ {hasFetched && this.renderTable()} + + + ); } } From d426981d1d20d9a302accd49cfda7fa908d48ca0 Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 14 Jan 2019 17:03:49 +0100 Subject: [PATCH 21/36] fix: Add Pages component to Plugins and TeamList --- .../app/features/plugins/PluginListPage.tsx | 37 +++++++++---------- public/app/features/teams/TeamList.tsx | 13 ++++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/public/app/features/plugins/PluginListPage.tsx b/public/app/features/plugins/PluginListPage.tsx index a2fcb90ce54..ba61f637609 100644 --- a/public/app/features/plugins/PluginListPage.tsx +++ b/public/app/features/plugins/PluginListPage.tsx @@ -1,9 +1,8 @@ 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'; @@ -48,23 +47,23 @@ export class PluginListPage extends PureComponent { }; return ( -
- -
- setPluginsLayoutMode(mode)} - setSearchQuery={query => setPluginsSearchQuery(query)} - linkButton={linkButton} - /> - {hasFetched ? ( - plugins && - ) : ( - - )} -
-
+ + + + <> + setPluginsLayoutMode(mode)} + setSearchQuery={query => setPluginsSearchQuery(query)} + linkButton={linkButton} + /> + {hasFetched && plugins && ( + plugins && + )} + + + ); } } diff --git a/public/app/features/teams/TeamList.tsx b/public/app/features/teams/TeamList.tsx index d1551d6baa6..8eac05be3bf 100644 --- a/public/app/features/teams/TeamList.tsx +++ b/public/app/features/teams/TeamList.tsx @@ -1,10 +1,9 @@ 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 { loadTeams, deleteTeam, setSearchQuery } from './state/actions'; import { getSearchQuery, getTeams, getTeamsCount } from './state/selectors'; @@ -141,10 +140,12 @@ export class TeamList extends PureComponent { const { hasFetched, navModel } = this.props; return ( -
- - {hasFetched ? this.renderList() : } -
+ + + + {hasFetched && this.renderList()} + + ); } } From 1e80bac2d226e8d62c53aa45c1209067a13711fb Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 14 Jan 2019 22:15:21 +0100 Subject: [PATCH 22/36] chore: Reactify footer --- public/app/core/components/Footer/Footer.tsx | 50 ++++++++++++++++++++ public/app/core/components/Page/Page.tsx | 21 ++++---- public/app/core/config.ts | 2 + 3 files changed, 63 insertions(+), 10 deletions(-) create mode 100644 public/app/core/components/Footer/Footer.tsx diff --git a/public/app/core/components/Footer/Footer.tsx b/public/app/core/components/Footer/Footer.tsx new file mode 100644 index 00000000000..01da74036b6 --- /dev/null +++ b/public/app/core/components/Footer/Footer.tsx @@ -0,0 +1,50 @@ +import React, { SFC } from 'react'; +import { Tooltip } from '@grafana/ui'; + +interface Props { + appName: string; + buildVersion: string; + buildCommit: string; + newGrafanaVersionExists: boolean; + newGrafanaVersion: string; +} + +export const Footer: SFC = ({appName, buildVersion, buildCommit, newGrafanaVersionExists, newGrafanaVersion}) => { + return ( + + ); +}; + +export default Footer; diff --git a/public/app/core/components/Page/Page.tsx b/public/app/core/components/Page/Page.tsx index eeba4b3037b..95345f250ed 100644 --- a/public/app/core/components/Page/Page.tsx +++ b/public/app/core/components/Page/Page.tsx @@ -1,11 +1,14 @@ // Libraries import React, { Component } from 'react'; +import config from 'app/core/config'; // 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; @@ -14,15 +17,11 @@ interface Props { class Page extends Component { private bodyClass = 'is-react'; private body = document.getElementsByTagName('body')[0]; - private footer = document.getElementsByClassName('footer')[0].cloneNode(true); - private scrollbarElementRef = React.createRef(); static Header = PageHeader; static Contents = PageContents; - componentDidMount() { this.body.classList.add(this.bodyClass); - this.copyFooter(); this.updateTitle(); } @@ -41,17 +40,19 @@ class Page extends Component { document.title = title ? title + ' - Grafana' : 'Grafana'; } - copyFooter = () => { - const c = this.scrollbarElementRef.current; - c.append(this.footer); - } - render() { + const { buildInfo } = config; return (
-
+
{this.props.children} +
diff --git a/public/app/core/config.ts b/public/app/core/config.ts index 13d84772ecf..0aa159af84d 100644 --- a/public/app/core/config.ts +++ b/public/app/core/config.ts @@ -6,6 +6,8 @@ export interface BuildInfo { commit: string; isEnterprise: boolean; env: string; + latestVersion: string; + hasUpdate: boolean; } export class Settings { From 6bd87098cf0d46953d7ab6cba805202775387a93 Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Mon, 14 Jan 2019 22:19:24 +0100 Subject: [PATCH 23/36] chore: Better way of getting the body node --- public/app/core/components/Page/Page.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/public/app/core/components/Page/Page.tsx b/public/app/core/components/Page/Page.tsx index 95345f250ed..0197076d150 100644 --- a/public/app/core/components/Page/Page.tsx +++ b/public/app/core/components/Page/Page.tsx @@ -8,7 +8,6 @@ import Footer from '../Footer/Footer'; import PageContents from './PageContents'; import { CustomScrollbar } from '@grafana/ui'; - interface Props { title?: string; children: JSX.Element[] | JSX.Element; @@ -16,7 +15,7 @@ interface Props { class Page extends Component { private bodyClass = 'is-react'; - private body = document.getElementsByTagName('body')[0]; + private body = document.body; static Header = PageHeader; static Contents = PageContents; From 25304629bdbc75b35865f15283f97dd9e7b3d4f2 Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Tue, 15 Jan 2019 08:27:07 +0100 Subject: [PATCH 24/36] test: Updated snapshots --- .../DataSourcesListPage.test.tsx.snap | 4 +- .../PluginListPage.test.tsx.snap | 27 +- .../__snapshots__/TeamList.test.tsx.snap | 578 +++++++++--------- .../__snapshots__/UsersListPage.test.tsx.snap | 27 +- 4 files changed, 323 insertions(+), 313 deletions(-) diff --git a/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap b/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap index e523816c021..145623bbad0 100644 --- a/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap +++ b/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap @@ -2,7 +2,7 @@ exports[`Render should render action bar and datasources 1`] = ` + -
- -
-
+ + `; exports[`Render should render list 1`] = ` -
+ -
-
-
+ + `; diff --git a/public/app/features/teams/__snapshots__/TeamList.test.tsx.snap b/public/app/features/teams/__snapshots__/TeamList.test.tsx.snap index ae94691df0e..d10a2fd2052 100644 --- a/public/app/features/teams/__snapshots__/TeamList.test.tsx.snap +++ b/public/app/features/teams/__snapshots__/TeamList.test.tsx.snap @@ -1,336 +1,344 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Render should render component 1`] = ` -
+ - -
+ `; exports[`Render should render teams table 1`] = ` -
+ -
- + +
+ -
- - - - - - - + + + + + - - - - - - - - - - - + - - + + + + + + + - + - - test-2 - - - + - + - - - - + + - + - - test-3 - - - + - + - - - - + + - + - - test-4 - - - + - + - - - - + + - + - - test-5 - - - + - + - - - -
- - Name - - Email - - Members - +
+ + Name + + Email + + Members + -
- - - - - - test-1 - - - - test-1@test.com - - - - 1 - - - -
+ +
+ + test-1 + + + + test-1@test.com + + + + 1 + + + - - +
- + + + - test-2@test.com - - - + test-2 + + - 2 - - - -
- + test-2@test.com + + - + 2 + + + - - +
- + + + - test-3@test.com - - - + test-3 + + - 3 - - - -
- + test-3@test.com + + - + 3 + + + - - +
- + + + - test-4@test.com - - - + test-4 + + - 4 - - - -
- + test-4@test.com + + - + 4 + + + - - +
- + + + - test-5@test.com - - - + test-5 + + - 5 - - - -
+ + test-5@test.com + + + + + 5 + + + + + + + + +
-
-
+ + `; diff --git a/public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap b/public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap index 429322eac98..a6c71f63d53 100644 --- a/public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap +++ b/public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap @@ -1,12 +1,14 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Render should render List page 1`] = ` -
+ -
-
-
+ + `; exports[`Render should render component 1`] = ` -
+ -
- -
-
+ + `; From feeb3ea56dae1cb3384466797dfda88de985925c Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Wed, 16 Jan 2019 15:59:05 +0100 Subject: [PATCH 25/36] feat: Generate page titles from navModel --- public/app/core/selectors/navModel.ts | 4 ++++ public/app/features/datasources/DataSourcesListPage.tsx | 5 +++-- public/app/features/plugins/PluginListPage.tsx | 6 +++--- public/app/features/teams/TeamList.tsx | 6 +++--- public/app/features/users/UsersListPage.tsx | 4 ++-- 5 files changed, 15 insertions(+), 10 deletions(-) diff --git a/public/app/core/selectors/navModel.ts b/public/app/core/selectors/navModel.ts index aa508616962..7d745b58002 100644 --- a/public/app/core/selectors/navModel.ts +++ b/public/app/core/selectors/navModel.ts @@ -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 : '' }`; +}; diff --git a/public/app/features/datasources/DataSourcesListPage.tsx b/public/app/features/datasources/DataSourcesListPage.tsx index 12eb49cb856..f1c1c45ded8 100644 --- a/public/app/features/datasources/DataSourcesListPage.tsx +++ b/public/app/features/datasources/DataSourcesListPage.tsx @@ -8,7 +8,8 @@ import DataSourcesList from './DataSourcesList'; 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 'app/core/selectors/navModel'; +import { getNavModel, getTitleFromNavModel } from 'app/core/selectors/navModel'; + import { getDataSources, getDataSourcesCount, @@ -66,7 +67,7 @@ export class DataSourcesListPage extends PureComponent { }; return ( - + <> diff --git a/public/app/features/plugins/PluginListPage.tsx b/public/app/features/plugins/PluginListPage.tsx index ba61f637609..14bd05f0537 100644 --- a/public/app/features/plugins/PluginListPage.tsx +++ b/public/app/features/plugins/PluginListPage.tsx @@ -6,9 +6,9 @@ import OrgActionBar from 'app/core/components/OrgActionBar/OrgActionBar'; 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, getTitleFromNavModel } 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; @@ -47,7 +47,7 @@ export class PluginListPage extends PureComponent { }; return ( - + <> diff --git a/public/app/features/teams/TeamList.tsx b/public/app/features/teams/TeamList.tsx index 8eac05be3bf..5dd83ca385c 100644 --- a/public/app/features/teams/TeamList.tsx +++ b/public/app/features/teams/TeamList.tsx @@ -4,10 +4,10 @@ import { hot } from 'react-hot-loader'; import Page from 'app/core/components/Page/Page'; import { DeleteButton } from '@grafana/ui'; import EmptyListCTA from 'app/core/components/EmptyListCTA/EmptyListCTA'; -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'; +import { getNavModel, getTitleFromNavModel } from 'app/core/selectors/navModel'; export interface Props { navModel: NavModel; @@ -140,7 +140,7 @@ export class TeamList extends PureComponent { const { hasFetched, navModel } = this.props; return ( - + {hasFetched && this.renderList()} diff --git a/public/app/features/users/UsersListPage.tsx b/public/app/features/users/UsersListPage.tsx index ece431158fd..43fcc67e470 100644 --- a/public/app/features/users/UsersListPage.tsx +++ b/public/app/features/users/UsersListPage.tsx @@ -9,7 +9,7 @@ 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, getTitleFromNavModel } from 'app/core/selectors/navModel'; import { getInvitees, getUsers, getUsersSearchQuery } from './state/selectors'; export interface Props { @@ -104,7 +104,7 @@ export class UsersListPage extends PureComponent { const externalUserMngInfoHtml = this.externalUserMngInfoHtml; return ( - + <> From 3ca7523a0207ad514692d4ae132fc543ac060a86 Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Wed, 16 Jan 2019 16:16:19 +0100 Subject: [PATCH 26/36] fix: Use Page component on "Api Keys" and "Preferences" under Configuration --- public/app/features/api-keys/ApiKeysPage.tsx | 29 ++++++++-------- public/app/features/org/OrgDetailsPage.tsx | 36 ++++++++++---------- 2 files changed, 32 insertions(+), 33 deletions(-) diff --git a/public/app/features/api-keys/ApiKeysPage.tsx b/public/app/features/api-keys/ApiKeysPage.tsx index e14873fa9f6..4cbd8ce4170 100644 --- a/public/app/features/api-keys/ApiKeysPage.tsx +++ b/public/app/features/api-keys/ApiKeysPage.tsx @@ -3,11 +3,10 @@ import ReactDOMServer from 'react-dom/server'; import { connect } from 'react-redux'; import { hot } from 'react-hot-loader'; import { NavModel, ApiKey, NewApiKey, OrgRole } from 'app/types'; -import { getNavModel } from 'app/core/selectors/navModel'; +import { getNavModel, getTitleFromNavModel } 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,18 @@ export class ApiKeysPage extends PureComponent { const { hasFetched, navModel, apiKeysCount } = this.props; return ( -
- - {hasFetched ? ( - apiKeysCount > 0 ? ( - this.renderApiKeyList() - ) : ( - this.renderEmptyList() - ) - ) : ( - - )} -
+ + + + {hasFetched && ( + apiKeysCount > 0 ? ( + this.renderApiKeyList() + ) : ( + this.renderEmptyList() + ) + )} + + ); } } diff --git a/public/app/features/org/OrgDetailsPage.tsx b/public/app/features/org/OrgDetailsPage.tsx index b011901aa71..ce84bdefafd 100644 --- a/public/app/features/org/OrgDetailsPage.tsx +++ b/public/app/features/org/OrgDetailsPage.tsx @@ -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, getTitleFromNavModel } from 'app/core/selectors/navModel'; export interface Props { navModel: NavModel; @@ -35,22 +34,23 @@ export class OrgDetailsPage extends PureComponent { const isLoading = Object.keys(organization).length === 0; return ( -
- -
- {isLoading && } - {!isLoading && ( -
- this.onOrgNameChange(name)} - onSubmit={this.onUpdateOrganization} - orgName={organization.name} - /> - + + + +
+ {!isLoading && ( +
+ this.onOrgNameChange(name)} + onSubmit={this.onUpdateOrganization} + orgName={organization.name} + /> + +
+ )}
- )} -
-
+ + ); } } From 234713466e655c1f4167fbede9ee4509f8c8456f Mon Sep 17 00:00:00 2001 From: Johannes Schill Date: Wed, 16 Jan 2019 16:29:07 +0100 Subject: [PATCH 27/36] test: Update snapshots and mocks --- .../CustomScrollbar.test.tsx.snap | 4 +- .../features/api-keys/ApiKeysPage.test.tsx | 9 +- .../__snapshots__/ApiKeysPage.test.tsx.snap | 242 ++++++++++-------- .../datasources/DataSourcesListPage.test.tsx | 9 +- .../DataSourcesListPage.test.tsx.snap | 22 +- .../app/features/org/OrgDetailsPage.test.tsx | 9 +- .../OrgDetailsPage.test.tsx.snap | 72 ++++-- .../features/plugins/PluginListPage.test.tsx | 9 +- .../PluginListPage.test.tsx.snap | 22 +- public/app/features/teams/TeamList.test.tsx | 9 +- .../__snapshots__/TeamList.test.tsx.snap | 26 +- .../app/features/users/UsersListPage.test.tsx | 9 +- .../__snapshots__/UsersListPage.test.tsx.snap | 22 +- 13 files changed, 315 insertions(+), 149 deletions(-) diff --git a/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap b/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap index 60b4a2e0aa5..aabe3dd98c5 100644 --- a/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap +++ b/packages/grafana-ui/src/components/CustomScrollbar/__snapshots__/CustomScrollbar.test.tsx.snap @@ -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, diff --git a/public/app/features/api-keys/ApiKeysPage.test.tsx b/public/app/features/api-keys/ApiKeysPage.test.tsx index 54200234ddc..cd640b5a357 100644 --- a/public/app/features/api-keys/ApiKeysPage.test.tsx +++ b/public/app/features/api-keys/ApiKeysPage.test.tsx @@ -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, diff --git a/public/app/features/api-keys/__snapshots__/ApiKeysPage.test.tsx.snap b/public/app/features/api-keys/__snapshots__/ApiKeysPage.test.tsx.snap index 7ede9618250..fd05b79da81 100644 --- a/public/app/features/api-keys/__snapshots__/ApiKeysPage.test.tsx.snap +++ b/public/app/features/api-keys/__snapshots__/ApiKeysPage.test.tsx.snap @@ -1,132 +1,158 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Render should render API keys table if there are any keys 1`] = ` -
+ - -
+ `; exports[`Render should render CTA if there are no API keys 1`] = ` -
+ -
- - + +
-
+ - -
- Add API Key -
-
-
+ + +
+ Add API Key +
+
- - Key name - - -
-
- - Role - - - +
+
+ + Role + + + - -
-
-
+
- Add - + +
-
- -
-
-
-
+ +
+ +
+ +
`; diff --git a/public/app/features/datasources/DataSourcesListPage.test.tsx b/public/app/features/datasources/DataSourcesListPage.test.tsx index 0ea716d62c9..33f5790978d 100644 --- a/public/app/features/datasources/DataSourcesListPage.test.tsx +++ b/public/app/features/datasources/DataSourcesListPage.test.tsx @@ -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(), diff --git a/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap b/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap index 145623bbad0..8c351d1dc2d 100644 --- a/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap +++ b/public/app/features/datasources/__snapshots__/DataSourcesListPage.test.tsx.snap @@ -5,7 +5,16 @@ exports[`Render should render action bar and datasources 1`] = ` title="Configuration: Data Sources" > { 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(), diff --git a/public/app/features/org/__snapshots__/OrgDetailsPage.test.tsx.snap b/public/app/features/org/__snapshots__/OrgDetailsPage.test.tsx.snap index 582d626d315..84c4f17fba8 100644 --- a/public/app/features/org/__snapshots__/OrgDetailsPage.test.tsx.snap +++ b/public/app/features/org/__snapshots__/OrgDetailsPage.test.tsx.snap @@ -1,38 +1,64 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Render should render component 1`] = ` -
+ -
- -
-
+
+
`; exports[`Render should render organization and preferences 1`] = ` -
+ -
-
- - +
+
+ + +
-
-
+ +
`; diff --git a/public/app/features/plugins/PluginListPage.test.tsx b/public/app/features/plugins/PluginListPage.test.tsx index 31b2f128436..31956f41cc1 100644 --- a/public/app/features/plugins/PluginListPage.test.tsx +++ b/public/app/features/plugins/PluginListPage.test.tsx @@ -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(), diff --git a/public/app/features/plugins/__snapshots__/PluginListPage.test.tsx.snap b/public/app/features/plugins/__snapshots__/PluginListPage.test.tsx.snap index 6444c0c82cc..48f7d638637 100644 --- a/public/app/features/plugins/__snapshots__/PluginListPage.test.tsx.snap +++ b/public/app/features/plugins/__snapshots__/PluginListPage.test.tsx.snap @@ -5,7 +5,16 @@ exports[`Render should render component 1`] = ` title="Configuration: Plugins" > { 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(), diff --git a/public/app/features/teams/__snapshots__/TeamList.test.tsx.snap b/public/app/features/teams/__snapshots__/TeamList.test.tsx.snap index d10a2fd2052..cfa9533e1b6 100644 --- a/public/app/features/teams/__snapshots__/TeamList.test.tsx.snap +++ b/public/app/features/teams/__snapshots__/TeamList.test.tsx.snap @@ -2,10 +2,19 @@ exports[`Render should render component 1`] = ` ({ 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: '', diff --git a/public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap b/public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap index a6c71f63d53..c6c02562115 100644 --- a/public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap +++ b/public/app/features/users/__snapshots__/UsersListPage.test.tsx.snap @@ -5,7 +5,16 @@ exports[`Render should render List page 1`] = ` title="Configuration: Users" > Date: Wed, 16 Jan 2019 18:02:27 +0000 Subject: [PATCH 28/36] removing Label and going with FormLabel --- .../src/components/FormField/FormField.tsx | 4 +-- .../src/components/FormLabel/FormLabel.tsx | 27 ++++++++++++++++--- .../grafana-ui/src/components/Label/Label.tsx | 25 ----------------- .../ValueMappingsEditor/MappingRow.tsx | 8 +++--- packages/grafana-ui/src/components/index.ts | 1 - .../SharedPreferences/SharedPreferences.tsx | 6 ++--- .../datasources/settings/BasicSettings.tsx | 6 ++--- public/app/features/teams/TeamSettings.tsx | 8 +++--- .../app/plugins/panel/gauge/ValueOptions.tsx | 6 ++--- 9 files changed, 42 insertions(+), 49 deletions(-) delete mode 100644 packages/grafana-ui/src/components/Label/Label.tsx diff --git a/packages/grafana-ui/src/components/FormField/FormField.tsx b/packages/grafana-ui/src/components/FormField/FormField.tsx index 14bec79b57f..593678c7383 100644 --- a/packages/grafana-ui/src/components/FormField/FormField.tsx +++ b/packages/grafana-ui/src/components/FormField/FormField.tsx @@ -1,5 +1,5 @@ import React, { InputHTMLAttributes, FunctionComponent } from 'react'; -import { Label } from '..'; +import { FormLabel } from '..'; export interface Props extends InputHTMLAttributes { label: string; @@ -15,7 +15,7 @@ const defaultProps = { const FormField: FunctionComponent = ({ label, labelWidth, inputWidth, ...inputProps }) => { return (
- + {label}
); diff --git a/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx b/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx index d6ac3da9394..2bd4fbc153b 100644 --- a/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx +++ b/packages/grafana-ui/src/components/FormLabel/FormLabel.tsx @@ -1,16 +1,28 @@ -import React, { SFC, ReactNode } from 'react'; +import React, { FunctionComponent, ReactNode } from 'react'; import classNames from 'classnames'; +import { Tooltip } from '..'; interface Props { children: ReactNode; - htmlFor?: string; className?: string; + htmlFor?: string; isFocused?: boolean; isInvalid?: boolean; + tooltip?: string; + width?: number; } -export const FormLabel: SFC = ({ children, isFocused, isInvalid, className, htmlFor, ...rest }) => { - const classes = classNames('gf-form-label', className, { +export const FormLabel: FunctionComponent = ({ + children, + isFocused, + isInvalid, + className, + htmlFor, + tooltip, + width, + ...rest +}) => { + const classes = classNames(`gf-form-label width-${width ? width : '10'}`, className, { 'gf-form-label--is-focused': isFocused, 'gf-form-label--is-invalid': isInvalid, }); @@ -18,6 +30,13 @@ export const FormLabel: SFC = ({ children, isFocused, isInvalid, classNam return ( ); }; diff --git a/packages/grafana-ui/src/components/Label/Label.tsx b/packages/grafana-ui/src/components/Label/Label.tsx deleted file mode 100644 index 270b0161226..00000000000 --- a/packages/grafana-ui/src/components/Label/Label.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React, { SFC, ReactNode } from 'react'; -import { Tooltip } from '../Tooltip/Tooltip'; - -interface Props { - tooltip?: string; - for?: string; - children: ReactNode; - width?: number; - className?: string; -} - -export const Label: SFC = props => { - return ( - - {props.children} - {props.tooltip && ( - -
- -
-
- )} -
- ); -}; diff --git a/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx b/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx index db970046fc4..deb73460354 100644 --- a/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx +++ b/packages/grafana-ui/src/components/ValueMappingsEditor/MappingRow.tsx @@ -1,7 +1,7 @@ import React, { ChangeEvent, PureComponent } from 'react'; import { MappingType, ValueMapping } from '../../types'; -import { FormField, Label, Select } from '..'; +import { FormField, FormLabel, Select } from '..'; export interface Props { valueMapping: ValueMapping; @@ -78,7 +78,7 @@ export default class MappingRow extends PureComponent { value={to} />
- + Text { inputWidth={8} />
- + Text { return (
- + Type dashboard.id === homeDashboardId)} getOptionValue={i => i.id} diff --git a/public/app/features/datasources/settings/BasicSettings.tsx b/public/app/features/datasources/settings/BasicSettings.tsx index 21a548a5045..56d4570e3a3 100644 --- a/public/app/features/datasources/settings/BasicSettings.tsx +++ b/public/app/features/datasources/settings/BasicSettings.tsx @@ -1,5 +1,5 @@ import React, { SFC } from 'react'; -import { Label } from '@grafana/ui'; +import { FormLabel } from '@grafana/ui'; import { Switch } from '../../../core/components/Switch/Switch'; export interface Props { @@ -14,14 +14,14 @@ const BasicSettings: SFC = ({ dataSourceName, isDefault, onDefaultChange,
- + {

Team Settings

- + Name {
- +
- + Stat