Merge branch 'ifrost/graphite-on-react-4' into ifrost/graphite-on-react-6

This commit is contained in:
Piotr Jamróz
2021-08-16 14:48:48 +02:00
16 changed files with 85 additions and 83 deletions
@@ -1,25 +0,0 @@
import React from 'react';
import { SectionFill } from './SectionFill';
import { SectionLabel } from './SectionLabel';
/**
* @alpha
*/
export const Section = ({
label,
children,
fill,
}: {
label: string;
children: React.ReactNode;
inline?: boolean;
fill?: boolean;
}) => (
<div className="gf-form-inline">
<div className="gf-form">
<SectionLabel name={label} className="width-7" />
{children}
</div>
{fill && <SectionFill />}
</div>
);
@@ -1,2 +0,0 @@
export { Section } from './Section';
export { SectionLabel } from './SectionLabel';
@@ -1,6 +1,6 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { Segment, Icon, Section } from '@grafana/ui'; import { Segment, Icon, SegmentSection } from '@grafana/ui';
const AddButton = ( const AddButton = (
<a className="gf-form-label query-part"> <a className="gf-form-label query-part">
@@ -17,10 +17,10 @@ const groupedOptions = [
const SegmentFrame = ({ options, children }: any) => ( const SegmentFrame = ({ options, children }: any) => (
<> <>
<Section label="Segment Name"> <SegmentSection label="Segment Name">
{children} {children}
<Segment Component={AddButton} onChange={({ value }) => action('New value added')(value)} options={options} /> <Segment Component={AddButton} onChange={({ value }) => action('New value added')(value)} options={options} />
</Section> </SegmentSection>
</> </>
); );
@@ -2,7 +2,7 @@ import React, { useState } from 'react';
import { AsyncState } from 'react-use/lib/useAsync'; import { AsyncState } from 'react-use/lib/useAsync';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { SelectableValue } from '@grafana/data'; import { SelectableValue } from '@grafana/data';
import { SegmentAsync, Icon, Section } from '@grafana/ui'; import { SegmentAsync, Icon, SegmentSection } from '@grafana/ui';
const AddButton = ( const AddButton = (
<a className="gf-form-label query-part"> <a className="gf-form-label query-part">
@@ -21,14 +21,14 @@ const loadOptionsErr = (): Promise<Array<SelectableValue<string>>> =>
const SegmentFrame = ({ loadOptions, children }: any) => ( const SegmentFrame = ({ loadOptions, children }: any) => (
<> <>
<Section label="Segment Name"> <SegmentSection label="Segment Name">
{children} {children}
<SegmentAsync <SegmentAsync
Component={AddButton} Component={AddButton}
onChange={(value) => action('New value added')(value)} onChange={(value) => action('New value added')(value)}
loadOptions={() => loadOptions(options)} loadOptions={() => loadOptions(options)}
/> />
</Section> </SegmentSection>
</> </>
); );
@@ -1,10 +1,10 @@
import React, { useState } from 'react'; import React, { useState } from 'react';
import { action } from '@storybook/addon-actions'; import { action } from '@storybook/addon-actions';
import { SegmentInput, Icon, Section } from '@grafana/ui'; import { SegmentInput, Icon, SegmentSection } from '@grafana/ui';
const SegmentFrame = ({ children }: any) => ( const SegmentFrame = ({ children }: any) => (
<> <>
<Section label="Section Name">{children}</Section> <SegmentSection label="Segment Name">{children}</SegmentSection>
</> </>
); );
@@ -0,0 +1,44 @@
import React from 'react';
import { css } from '@emotion/css';
import { GrafanaTheme2 } from '@grafana/data';
import { SegmentSectionFill } from './SegmentSectionFill';
import { SegmentSectionLabel } from './SegmentSectionLabel';
import { useStyles2 } from '../../themes';
/**
* Horizontal section for editor components.
*
* @alpha
*/
export const SegmentSection = ({
label,
children,
fill,
}: {
// Name of the section
label: string;
// List of components in the section
children: React.ReactNode;
// Fill the space at the end
fill?: boolean;
}) => {
const styles = useStyles2(getStyles);
return (
<>
<div className={styles.container}>
<SegmentSectionLabel name={label} className="width-7" />
{children}
{fill && <SegmentSectionFill />}
</div>
</>
);
};
const getStyles = (theme: GrafanaTheme2) => ({
container: css`
display: flex;
flex-wrap: wrap;
row-gap: ${theme.spacing(0.5)};
align-content: flex-start;
`,
});
@@ -3,7 +3,7 @@ import React from 'react';
/** /**
* @alpha * @alpha
*/ */
export const SectionFill = () => ( export const SegmentSectionFill = () => (
<div className="gf-form gf-form--grow"> <div className="gf-form gf-form--grow">
<label className="gf-form-label gf-form-label--grow" /> <label className="gf-form-label gf-form-label--grow" />
</div> </div>
@@ -4,6 +4,6 @@ import { cx } from '@emotion/css';
/** /**
* @alpha * @alpha
*/ */
export const SectionLabel = ({ name, className }: { name: string; className?: string }) => ( export const SegmentSectionLabel = ({ name, className }: { name: string; className?: string }) => (
<label className={cx('gf-form-label query-keyword', className)}>{name}</label> <label className={cx('gf-form-label query-keyword', className)}>{name}</label>
); );
@@ -2,5 +2,7 @@ export { Segment } from './Segment';
export { SegmentAsync } from './SegmentAsync'; export { SegmentAsync } from './SegmentAsync';
export { SegmentSelect } from './SegmentSelect'; export { SegmentSelect } from './SegmentSelect';
export { SegmentInput } from './SegmentInput'; export { SegmentInput } from './SegmentInput';
export { SegmentSection } from './SegmentSection';
export { SegmentSectionLabel } from './SegmentSectionLabel';
export { SegmentProps } from './types'; export { SegmentProps } from './types';
export { useExpandableLabel } from './useExpandableLabel'; export { useExpandableLabel } from './useExpandableLabel';
+1 -2
View File
@@ -152,8 +152,7 @@ export { CertificationKey } from './DataSourceSettings/CertificationKey';
export { Spinner } from './Spinner/Spinner'; export { Spinner } from './Spinner/Spinner';
export { FadeTransition } from './transitions/FadeTransition'; export { FadeTransition } from './transitions/FadeTransition';
export { SlideOutTransition } from './transitions/SlideOutTransition'; export { SlideOutTransition } from './transitions/SlideOutTransition';
export { Segment, SegmentAsync, SegmentInput, SegmentSelect } from './Segment/'; export { Segment, SegmentAsync, SegmentInput, SegmentSelect, SegmentSection, SegmentSectionLabel } from './Segment/';
export { Section, SectionLabel } from './Section/';
export { Drawer } from './Drawer/Drawer'; export { Drawer } from './Drawer/Drawer';
export { Slider } from './Slider/Slider'; export { Slider } from './Slider/Slider';
export { RangeSlider } from './Slider/RangeSlider'; export { RangeSlider } from './Slider/RangeSlider';
@@ -2,7 +2,7 @@ import React from 'react';
import { FuncDefs, FuncInstance } from '../gfunc'; import { FuncDefs, FuncInstance } from '../gfunc';
import { GraphiteFunctionEditor } from './GraphiteFunctionEditor'; import { GraphiteFunctionEditor } from './GraphiteFunctionEditor';
import { AddGraphiteFunction } from './AddGraphiteFunction'; import { AddGraphiteFunction } from './AddGraphiteFunction';
import { Section } from '@grafana/ui'; import { SegmentSection } from '@grafana/ui';
type Props = { type Props = {
functions: FuncInstance[]; functions: FuncInstance[];
@@ -11,11 +11,11 @@ type Props = {
export function FunctionsSection({ functions = [], funcDefs }: Props) { export function FunctionsSection({ functions = [], funcDefs }: Props) {
return ( return (
<Section label="Functions" fill={true}> <SegmentSection label="Functions" fill={true}>
{functions.map((func: FuncInstance, index: number) => { {functions.map((func: FuncInstance, index: number) => {
return !func.hidden && <GraphiteFunctionEditor key={index} func={func} />; return !func.hidden && <GraphiteFunctionEditor key={index} func={func} />;
})} })}
<AddGraphiteFunction funcDefs={funcDefs} /> <AddGraphiteFunction funcDefs={funcDefs} />
</Section> </SegmentSection>
); );
} }
@@ -82,6 +82,7 @@ const getStyles = (theme: GrafanaTheme2) => ({
borderRadius: theme.shape.borderRadius(), borderRadius: theme.shape.borderRadius(),
marginRight: theme.spacing(0.5), marginRight: theme.spacing(0.5),
padding: `0 ${theme.spacing(1)}`, padding: `0 ${theme.spacing(1)}`,
height: `${theme.v1.spacing.formInputHeight}px`,
}), }),
error: css` error: css`
border: 1px solid ${theme.colors.error.main}; border: 1px solid ${theme.colors.error.main};
@@ -2,8 +2,6 @@ import React from 'react';
import { GraphiteSegment } from '../types'; import { GraphiteSegment } from '../types';
import { GraphiteQueryEditorState } from '../state/store'; import { GraphiteQueryEditorState } from '../state/store';
import { MetricSegment } from './MetricSegment'; import { MetricSegment } from './MetricSegment';
import { css } from '@emotion/css';
import { useStyles2 } from '@grafana/ui';
type Props = { type Props = {
segments: GraphiteSegment[]; segments: GraphiteSegment[];
@@ -11,22 +9,11 @@ type Props = {
}; };
export function MetricsSection({ segments = [], state }: Props) { export function MetricsSection({ segments = [], state }: Props) {
const styles = useStyles2(getStyles);
return ( return (
<div className={styles.container}> <>
{segments.map((segment, index) => { {segments.map((segment, index) => {
return <MetricSegment segment={segment} metricIndex={index} key={index} state={state} />; return <MetricSegment segment={segment} metricIndex={index} key={index} state={state} />;
})} })}
</div> </>
); );
} }
function getStyles() {
return {
container: css`
display: flex;
flex-direction: row;
`,
};
}
@@ -2,7 +2,7 @@ import React from 'react';
import { GraphiteQueryEditorState } from '../state/store'; import { GraphiteQueryEditorState } from '../state/store';
import { TagsSection } from './TagsSection'; import { TagsSection } from './TagsSection';
import { MetricsSection } from './MetricsSection'; import { MetricsSection } from './MetricsSection';
import { Section } from '@grafana/ui'; import { SegmentSection } from '@grafana/ui';
type Props = { type Props = {
state: GraphiteQueryEditorState; state: GraphiteQueryEditorState;
@@ -16,8 +16,8 @@ export function SeriesSection({ state }: Props) {
); );
return ( return (
<Section label="Series" fill={true}> <SegmentSection label="Series" fill={true}>
{sectionContent} {sectionContent}
</Section> </SegmentSection>
); );
} }
@@ -40,7 +40,7 @@ export function TagsSection({ tags, state }: Props) {
]); ]);
return ( return (
<div className={styles.container}> <>
{tags.map((tag, index) => { {tags.map((tag, index) => {
return <TagEditor key={index} tagIndex={index} tag={tag} state={state} />; return <TagEditor key={index} tagIndex={index} tag={tag} state={state} />;
})} })}
@@ -56,16 +56,12 @@ export function TagsSection({ tags, state }: Props) {
/> />
)} )}
{state.paused && <PlayButton />} {state.paused && <PlayButton />}
</div> </>
); );
} }
function getStyles(theme: GrafanaTheme2) { function getStyles(theme: GrafanaTheme2) {
return { return {
container: css`
display: flex;
flex-direction: row;
`,
button: css` button: css`
margin-right: ${theme.spacing(0.5)}; margin-right: ${theme.spacing(0.5)};
`, `,
@@ -26,7 +26,7 @@ import {
import { FormatAsSection } from './FormatAsSection'; import { FormatAsSection } from './FormatAsSection';
import { DEFAULT_RESULT_FORMAT } from '../constants'; import { DEFAULT_RESULT_FORMAT } from '../constants';
import { getNewSelectPartOptions, getNewGroupByPartOptions, makePartList } from './partListUtils'; import { getNewSelectPartOptions, getNewGroupByPartOptions, makePartList } from './partListUtils';
import { Section, SectionLabel } from '@grafana/ui'; import { SegmentSection, SegmentSectionLabel } from '@grafana/ui';
type Props = { type Props = {
query: InfluxQuery; query: InfluxQuery;
@@ -103,7 +103,7 @@ export const Editor = (props: Props): JSX.Element => {
return ( return (
<div> <div>
<Section label="FROM" fill={true}> <SegmentSection label="FROM" fill={true}>
<FromSection <FromSection
policy={policy} policy={policy}
measurement={measurement} measurement={measurement}
@@ -115,7 +115,7 @@ export const Editor = (props: Props): JSX.Element => {
} }
onChange={handleFromSectionChange} onChange={handleFromSectionChange}
/> />
<SectionLabel name="WHERE" /> <SegmentSectionLabel name="WHERE" />
<TagsSection <TagsSection
tags={query.tags ?? []} tags={query.tags ?? []}
onChange={handleTagsSectionChange} onChange={handleTagsSectionChange}
@@ -124,9 +124,9 @@ export const Editor = (props: Props): JSX.Element => {
withTemplateVariableOptions(getTagValues(key, measurement, policy, query.tags ?? [], datasource)) withTemplateVariableOptions(getTagValues(key, measurement, policy, query.tags ?? [], datasource))
} }
/> />
</Section> </SegmentSection>
{selectLists.map((sel, index) => ( {selectLists.map((sel, index) => (
<Section key={index} label={index === 0 ? 'SELECT' : ''} fill={true}> <SegmentSection key={index} label={index === 0 ? 'SELECT' : ''} fill={true}>
<PartListSection <PartListSection
parts={sel} parts={sel}
getNewPartOptions={() => Promise.resolve(getNewSelectPartOptions())} getNewPartOptions={() => Promise.resolve(getNewSelectPartOptions())}
@@ -141,9 +141,9 @@ export const Editor = (props: Props): JSX.Element => {
onAppliedChange(removeSelectPart(query, partIndex, index)); onAppliedChange(removeSelectPart(query, partIndex, index));
}} }}
/> />
</Section> </SegmentSection>
))} ))}
<Section label="GROUP BY" fill={true}> <SegmentSection label="GROUP BY" fill={true}>
<PartListSection <PartListSection
parts={groupByList} parts={groupByList}
getNewPartOptions={() => getNewGroupByPartOptions(query, getTagKeys)} getNewPartOptions={() => getNewGroupByPartOptions(query, getTagKeys)}
@@ -158,8 +158,8 @@ export const Editor = (props: Props): JSX.Element => {
onAppliedChange(removeGroupByPart(query, partIndex)); onAppliedChange(removeGroupByPart(query, partIndex));
}} }}
/> />
</Section> </SegmentSection>
<Section label="TIMEZONE" fill={true}> <SegmentSection label="TIMEZONE" fill={true}>
<InputSection <InputSection
placeholder="(optional)" placeholder="(optional)"
value={query.tz} value={query.tz}
@@ -167,20 +167,20 @@ export const Editor = (props: Props): JSX.Element => {
onAppliedChange({ ...query, tz }); onAppliedChange({ ...query, tz });
}} }}
/> />
<SectionLabel name="ORDER BY TIME" /> <SegmentSectionLabel name="ORDER BY TIME" />
<OrderByTimeSection <OrderByTimeSection
value={query.orderByTime === 'DESC' ? 'DESC' : 'ASC' /* FIXME: make this shared with influx_query_model */} value={query.orderByTime === 'DESC' ? 'DESC' : 'ASC' /* FIXME: make this shared with influx_query_model */}
onChange={(v) => { onChange={(v) => {
onAppliedChange({ ...query, orderByTime: v }); onAppliedChange({ ...query, orderByTime: v });
}} }}
/> />
</Section> </SegmentSection>
{/* query.fill is ignored in the query-editor, and it is deleted whenever {/* query.fill is ignored in the query-editor, and it is deleted whenever
query-editor changes. the influx_query_model still handles it, but the new query-editor changes. the influx_query_model still handles it, but the new
approach seem to be to handle "fill" inside query.groupBy. so, if you approach seem to be to handle "fill" inside query.groupBy. so, if you
have a panel where in the json you have query.fill, it will be applied, have a panel where in the json you have query.fill, it will be applied,
as long as you do not edit that query. */} as long as you do not edit that query. */}
<Section label="LIMIT" fill={true}> <SegmentSection label="LIMIT" fill={true}>
<InputSection <InputSection
placeholder="(optional)" placeholder="(optional)"
value={query.limit?.toString()} value={query.limit?.toString()}
@@ -188,7 +188,7 @@ export const Editor = (props: Props): JSX.Element => {
onAppliedChange({ ...query, limit }); onAppliedChange({ ...query, limit });
}} }}
/> />
<SectionLabel name="SLIMIT" /> <SegmentSectionLabel name="SLIMIT" />
<InputSection <InputSection
placeholder="(optional)" placeholder="(optional)"
value={query.slimit?.toString()} value={query.slimit?.toString()}
@@ -196,8 +196,8 @@ export const Editor = (props: Props): JSX.Element => {
onAppliedChange({ ...query, slimit }); onAppliedChange({ ...query, slimit });
}} }}
/> />
</Section> </SegmentSection>
<Section label="FORMAT AS" fill={true}> <SegmentSection label="FORMAT AS" fill={true}>
<FormatAsSection <FormatAsSection
format={query.resultFormat ?? DEFAULT_RESULT_FORMAT} format={query.resultFormat ?? DEFAULT_RESULT_FORMAT}
onChange={(format) => { onChange={(format) => {
@@ -206,7 +206,7 @@ export const Editor = (props: Props): JSX.Element => {
/> />
{query.resultFormat !== 'table' && ( {query.resultFormat !== 'table' && (
<> <>
<SectionLabel name="ALIAS" /> <SegmentSectionLabel name="ALIAS" />
<InputSection <InputSection
isWide isWide
placeholder="Naming pattern" placeholder="Naming pattern"
@@ -217,7 +217,7 @@ export const Editor = (props: Props): JSX.Element => {
/> />
</> </>
)} )}
</Section> </SegmentSection>
</div> </div>
); );
}; };