mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Explore: Update styling of buttons (#30493)
* Switch deprecared toggle group for radio buttons * Create transparent version of field, label and witch * Replace divs wiith components * Move styling from scss to js * Update buttons * Remove log generating file * Update level button
This commit is contained in:
parent
7562c6749d
commit
56fb04e94c
@ -13,6 +13,8 @@ export interface Props extends Omit<FieldProps, 'css' | 'horizontal' | 'descript
|
||||
labelWidth?: number | 'auto';
|
||||
/** Make the field's child to fill the width of the row. Equivalent to setting `flex-grow:1` on the field */
|
||||
grow?: boolean;
|
||||
/** Make field's background transparent */
|
||||
transparent?: boolean;
|
||||
}
|
||||
|
||||
export const InlineField: FC<Props> = ({
|
||||
@ -25,6 +27,7 @@ export const InlineField: FC<Props> = ({
|
||||
disabled,
|
||||
className,
|
||||
grow,
|
||||
transparent,
|
||||
...htmlProps
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
@ -37,7 +40,7 @@ export const InlineField: FC<Props> = ({
|
||||
}
|
||||
const labelElement =
|
||||
typeof label === 'string' ? (
|
||||
<InlineLabel width={labelWidth} tooltip={tooltip} htmlFor={inputId}>
|
||||
<InlineLabel width={labelWidth} tooltip={tooltip} htmlFor={inputId} transparent={transparent}>
|
||||
{label}
|
||||
</InlineLabel>
|
||||
) : (
|
||||
|
@ -12,6 +12,8 @@ export interface Props extends Omit<LabelProps, 'css' | 'description' | 'categor
|
||||
tooltip?: PopoverContent;
|
||||
/** Custom width for the label */
|
||||
width?: number | 'auto';
|
||||
/** Make labels's background transparent */
|
||||
transparent?: boolean;
|
||||
/** @deprecated */
|
||||
/** This prop is deprecated and is not used anymore */
|
||||
isFocused?: boolean;
|
||||
@ -28,12 +30,12 @@ export const InlineLabel: FunctionComponent<Props> = ({
|
||||
className,
|
||||
tooltip,
|
||||
width,
|
||||
transparent,
|
||||
as: Component = 'label',
|
||||
...rest
|
||||
}) => {
|
||||
const theme = useTheme();
|
||||
const styles = getInlineLabelStyles(theme, width);
|
||||
|
||||
const styles = getInlineLabelStyles(theme, transparent, width);
|
||||
return (
|
||||
<Component className={cx(styles.label, className)} {...rest}>
|
||||
{children}
|
||||
@ -46,7 +48,7 @@ export const InlineLabel: FunctionComponent<Props> = ({
|
||||
);
|
||||
};
|
||||
|
||||
export const getInlineLabelStyles = (theme: GrafanaTheme, width?: number | 'auto') => {
|
||||
export const getInlineLabelStyles = (theme: GrafanaTheme, transparent = false, width?: number | 'auto') => {
|
||||
return {
|
||||
label: css`
|
||||
display: flex;
|
||||
@ -56,7 +58,7 @@ export const getInlineLabelStyles = (theme: GrafanaTheme, width?: number | 'auto
|
||||
padding: 0 ${theme.spacing.sm};
|
||||
font-weight: ${theme.typography.weight.semibold};
|
||||
font-size: ${theme.typography.size.sm};
|
||||
background-color: ${theme.colors.bg2};
|
||||
background-color: ${transparent ? 'transparent' : theme.colors.bg2};
|
||||
height: ${theme.height.md}px;
|
||||
line-height: ${theme.height.md}px;
|
||||
margin-right: ${theme.spacing.xs};
|
||||
|
@ -7,6 +7,8 @@ import { focusCss } from '../../themes/mixins';
|
||||
|
||||
export interface Props extends Omit<HTMLProps<HTMLInputElement>, 'value'> {
|
||||
value?: boolean;
|
||||
/** Make switch's background and border transparent */
|
||||
transparent?: boolean;
|
||||
}
|
||||
|
||||
export const Switch = React.forwardRef<HTMLInputElement, Props>(
|
||||
@ -40,9 +42,9 @@ export const Switch = React.forwardRef<HTMLInputElement, Props>(
|
||||
|
||||
Switch.displayName = 'Switch';
|
||||
|
||||
export const InlineSwitch = React.forwardRef<HTMLInputElement, Props>((props, ref) => {
|
||||
export const InlineSwitch = React.forwardRef<HTMLInputElement, Props>(({ transparent, ...props }, ref) => {
|
||||
const theme = useTheme();
|
||||
const styles = getSwitchStyles(theme);
|
||||
const styles = getSwitchStyles(theme, transparent);
|
||||
|
||||
return (
|
||||
<div className={styles.inlineContainer}>
|
||||
@ -53,7 +55,7 @@ export const InlineSwitch = React.forwardRef<HTMLInputElement, Props>((props, re
|
||||
|
||||
InlineSwitch.displayName = 'Switch';
|
||||
|
||||
const getSwitchStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
const getSwitchStyles = stylesFactory((theme: GrafanaTheme, transparent?: boolean) => {
|
||||
return {
|
||||
switch: css`
|
||||
width: 32px;
|
||||
@ -120,8 +122,8 @@ const getSwitchStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
height: ${theme.spacing.formInputHeight}px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: ${theme.colors.formInputBg};
|
||||
border: 1px solid ${theme.colors.formInputBorder};
|
||||
background: ${transparent ? 'transparent' : theme.colors.formInputBg};
|
||||
border: 1px solid ${transparent ? 'transparent' : theme.colors.formInputBorder};
|
||||
border-radius: ${theme.border.radius.md};
|
||||
`,
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
import { css } from 'emotion';
|
||||
import { capitalize } from 'lodash';
|
||||
|
||||
import {
|
||||
@ -17,11 +17,20 @@ import {
|
||||
GraphSeriesXY,
|
||||
LinkModel,
|
||||
Field,
|
||||
GrafanaTheme,
|
||||
} from '@grafana/data';
|
||||
import { LegacyForms, LogLabels, ToggleButtonGroup, ToggleButton, LogRows, Button } from '@grafana/ui';
|
||||
const { Switch } = LegacyForms;
|
||||
import {
|
||||
LogLabels,
|
||||
RadioButtonGroup,
|
||||
LogRows,
|
||||
Button,
|
||||
InlineField,
|
||||
InlineFieldRow,
|
||||
InlineSwitch,
|
||||
withTheme,
|
||||
stylesFactory,
|
||||
} from '@grafana/ui';
|
||||
import store from 'app/core/store';
|
||||
|
||||
import { ExploreGraphPanel } from './ExploreGraphPanel';
|
||||
import { MetaInfoText } from './MetaInfoText';
|
||||
import { RowContextOptions } from '@grafana/ui/src/components/Logs/LogRowContextProvider';
|
||||
@ -52,8 +61,8 @@ interface Props {
|
||||
logsSeries?: GraphSeriesXY[];
|
||||
dedupedRows?: LogRowModel[];
|
||||
visibleRange?: AbsoluteTimeRange;
|
||||
|
||||
width: number;
|
||||
theme: GrafanaTheme;
|
||||
highlighterExpressions?: string[];
|
||||
loading: boolean;
|
||||
absoluteRange: AbsoluteTimeRange;
|
||||
@ -82,7 +91,7 @@ interface State {
|
||||
showDetectedFields: string[];
|
||||
}
|
||||
|
||||
export class Logs extends PureComponent<Props, State> {
|
||||
export class UnthemedLogs extends PureComponent<Props, State> {
|
||||
flipOrderTimer: NodeJS.Timeout;
|
||||
cancelFlippingTimer: NodeJS.Timeout;
|
||||
|
||||
@ -224,14 +233,16 @@ export class Logs extends PureComponent<Props, State> {
|
||||
absoluteRange,
|
||||
onChangeTime,
|
||||
getFieldLinks,
|
||||
dedupStrategy,
|
||||
theme,
|
||||
} = this.props;
|
||||
|
||||
const { showLabels, showTime, wrapLogMessage, logsSortOrder, isFlipping, showDetectedFields } = this.state;
|
||||
|
||||
if (!logRows) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { showLabels, showTime, wrapLogMessage, logsSortOrder, isFlipping, showDetectedFields } = this.state;
|
||||
const { dedupStrategy } = this.props;
|
||||
const hasData = logRows && logRows.length > 0;
|
||||
const dedupCount = dedupedRows
|
||||
? dedupedRows.reduce((sum, row) => (row.duplicates ? sum + row.duplicates : sum), 0)
|
||||
@ -256,10 +267,10 @@ export class Logs extends PureComponent<Props, State> {
|
||||
|
||||
const scanText = scanRange ? `Scanning ${rangeUtil.describeTimeRange(scanRange)}` : 'Scanning...';
|
||||
const series = logsSeries ? logsSeries : [];
|
||||
const styles = getStyles(theme);
|
||||
|
||||
return (
|
||||
<div className="logs-panel">
|
||||
<div className="logs-panel-graph">
|
||||
<>
|
||||
<ExploreGraphPanel
|
||||
series={series}
|
||||
width={width}
|
||||
@ -273,43 +284,40 @@ export class Logs extends PureComponent<Props, State> {
|
||||
showLines={false}
|
||||
onUpdateTimeRange={onChangeTime}
|
||||
/>
|
||||
</div>
|
||||
<div className="logs-panel-options">
|
||||
<div className="logs-panel-controls">
|
||||
<div className="logs-panel-controls-main">
|
||||
<Switch label="Time" checked={showTime} onChange={this.onChangeTime} transparent />
|
||||
<Switch label="Unique labels" checked={showLabels} onChange={this.onChangeLabels} transparent />
|
||||
<Switch label="Wrap lines" checked={wrapLogMessage} onChange={this.onChangewrapLogMessage} transparent />
|
||||
<ToggleButtonGroup label="Dedup" transparent={true}>
|
||||
{Object.keys(LogsDedupStrategy).map((dedupType: string, i) => (
|
||||
<ToggleButton
|
||||
key={i}
|
||||
value={dedupType}
|
||||
<div className={styles.logOptions}>
|
||||
<InlineFieldRow>
|
||||
<InlineField label="Time" transparent>
|
||||
<InlineSwitch value={showTime} onChange={this.onChangeTime} transparent />
|
||||
</InlineField>
|
||||
<InlineField label="Unique labels" transparent>
|
||||
<InlineSwitch value={showLabels} onChange={this.onChangeLabels} transparent />
|
||||
</InlineField>
|
||||
<InlineField label="Wrap lines" transparent>
|
||||
<InlineSwitch value={wrapLogMessage} onChange={this.onChangewrapLogMessage} transparent />
|
||||
</InlineField>
|
||||
<InlineField label="Dedup" transparent>
|
||||
<RadioButtonGroup
|
||||
options={Object.keys(LogsDedupStrategy).map((dedupType: LogsDedupStrategy) => ({
|
||||
label: capitalize(dedupType),
|
||||
value: dedupType,
|
||||
description: LogsDedupDescription[dedupType],
|
||||
}))}
|
||||
value={dedupStrategy}
|
||||
onChange={this.onChangeDedup}
|
||||
selected={dedupStrategy === dedupType}
|
||||
// @ts-ignore
|
||||
tooltip={LogsDedupDescription[dedupType]}
|
||||
>
|
||||
{capitalize(dedupType)}
|
||||
</ToggleButton>
|
||||
))}
|
||||
</ToggleButtonGroup>
|
||||
</div>
|
||||
<button
|
||||
className={styles.radioButtons}
|
||||
/>
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
<Button
|
||||
variant="secondary"
|
||||
disabled={isFlipping}
|
||||
title={logsSortOrder === LogsSortOrder.Ascending ? 'Change to newest first' : 'Change to oldest first'}
|
||||
aria-label="Flip results order"
|
||||
className={cx(
|
||||
'gf-form-label gf-form-label--btn',
|
||||
css`
|
||||
margin-top: 4px;
|
||||
`
|
||||
)}
|
||||
className={styles.flipButton}
|
||||
onClick={this.onChangeLogsSortOrder}
|
||||
>
|
||||
<span className="btn-title">{isFlipping ? 'Flipping...' : 'Flip results order'}</span>
|
||||
</button>
|
||||
</div>
|
||||
{isFlipping ? 'Flipping...' : 'Flip results order'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{meta && (
|
||||
@ -323,7 +331,7 @@ export class Logs extends PureComponent<Props, State> {
|
||||
/>
|
||||
)}
|
||||
|
||||
{showDetectedFields && showDetectedFields.length > 0 && (
|
||||
{showDetectedFields?.length > 0 && (
|
||||
<MetaInfoText
|
||||
metaItems={[
|
||||
{
|
||||
@ -364,7 +372,7 @@ export class Logs extends PureComponent<Props, State> {
|
||||
/>
|
||||
|
||||
{!loading && !hasData && !scanning && (
|
||||
<div className="logs-panel-nodata">
|
||||
<div className={styles.noData}>
|
||||
No logs found.
|
||||
<Button size="xs" variant="link" onClick={this.onClickScan}>
|
||||
Scan for older logs
|
||||
@ -373,14 +381,43 @@ export class Logs extends PureComponent<Props, State> {
|
||||
)}
|
||||
|
||||
{scanning && (
|
||||
<div className="logs-panel-nodata">
|
||||
<div className={styles.noData}>
|
||||
<span>{scanText}</span>
|
||||
<Button size="xs" variant="link" onClick={this.onClickStopScan}>
|
||||
Stop scan
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export const Logs = withTheme(UnthemedLogs);
|
||||
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
return {
|
||||
noData: css`
|
||||
> * {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
`,
|
||||
logOptions: css`
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
background-color: ${theme.colors.bg1};
|
||||
padding: ${theme.spacing.sm} ${theme.spacing.md};
|
||||
border-radius: ${theme.border.radius.md};
|
||||
margin: ${theme.spacing.md} 0 ${theme.spacing.sm};
|
||||
border: 1px solid ${theme.colors.panelBorder};
|
||||
`,
|
||||
flipButton: css`
|
||||
margin: ${theme.spacing.xs} 0 0 ${theme.spacing.sm};
|
||||
`,
|
||||
radioButtons: css`
|
||||
margin: 0 ${theme.spacing.sm};
|
||||
`,
|
||||
};
|
||||
});
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React from 'react';
|
||||
import { css, cx } from 'emotion';
|
||||
import { stylesFactory, Icon } from '@grafana/ui';
|
||||
import { GrafanaTheme } from '@grafana/data';
|
||||
import { stylesFactory, Button, HorizontalGroup, useTheme } from '@grafana/ui';
|
||||
|
||||
type Props = {
|
||||
addQueryRowButtonDisabled?: boolean;
|
||||
@ -13,48 +14,49 @@ type Props = {
|
||||
onClickQueryInspectorButton: () => void;
|
||||
};
|
||||
|
||||
const getStyles = stylesFactory(() => {
|
||||
const getStyles = stylesFactory((theme: GrafanaTheme) => {
|
||||
return {
|
||||
button: css`
|
||||
margin: 1em 4px 0 0;
|
||||
containerMargin: css`
|
||||
margin-top: ${theme.spacing.md};
|
||||
`,
|
||||
};
|
||||
});
|
||||
export function SecondaryActions(props: Props) {
|
||||
const styles = getStyles();
|
||||
const theme = useTheme();
|
||||
const styles = getStyles(theme);
|
||||
return (
|
||||
<div className="gf-form">
|
||||
<div className={styles.containerMargin}>
|
||||
<HorizontalGroup>
|
||||
{!props.addQueryRowButtonHidden && (
|
||||
<button
|
||||
<Button
|
||||
variant="secondary"
|
||||
aria-label="Add row button"
|
||||
className={`gf-form-label gf-form-label--btn ${styles.button}`}
|
||||
onClick={props.onClickAddQueryRowButton}
|
||||
disabled={props.addQueryRowButtonDisabled}
|
||||
icon="plus"
|
||||
>
|
||||
<Icon className="icon-margin-right" name="plus" size="sm" />
|
||||
<span className="btn-title">{'\xA0' + 'Add query'}</span>
|
||||
</button>
|
||||
Add query
|
||||
</Button>
|
||||
)}
|
||||
<button
|
||||
<Button
|
||||
variant="secondary"
|
||||
aria-label="Rich history button"
|
||||
className={cx(`gf-form-label gf-form-label--btn ${styles.button}`, {
|
||||
['explore-active-button']: props.richHistoryButtonActive,
|
||||
})}
|
||||
className={cx({ ['explore-active-button']: props.richHistoryButtonActive })}
|
||||
onClick={props.onClickRichHistoryButton}
|
||||
icon="history"
|
||||
>
|
||||
<Icon className="icon-margin-right" name="history" size="sm" />
|
||||
<span className="btn-title">{'\xA0' + 'Query history'}</span>
|
||||
</button>
|
||||
<button
|
||||
Query history
|
||||
</Button>
|
||||
<Button
|
||||
variant="secondary"
|
||||
aria-label="Query inspector button"
|
||||
className={cx(`gf-form-label gf-form-label--btn ${styles.button}`, {
|
||||
['explore-active-button']: props.queryInspectorButtonActive,
|
||||
})}
|
||||
className={cx({ ['explore-active-button']: props.queryInspectorButtonActive })}
|
||||
onClick={props.onClickQueryInspectorButton}
|
||||
icon="info-circle"
|
||||
>
|
||||
<Icon className="icon-margin-right" name="info-circle" size="sm" />
|
||||
<span className="btn-title">{'\xA0' + 'Query inspector'}</span>
|
||||
</button>
|
||||
Query inspector
|
||||
</Button>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
@ -4,7 +4,7 @@ import { useAsync } from 'react-use';
|
||||
|
||||
// Components
|
||||
import { selectors as editorSelectors } from '@grafana/e2e-selectors';
|
||||
import { Input, InlineFieldRow, InlineField, Select, TextArea, Switch } from '@grafana/ui';
|
||||
import { Input, InlineFieldRow, InlineField, Select, TextArea, InlineSwitch } from '@grafana/ui';
|
||||
import { QueryEditorProps, SelectableValue } from '@grafana/data';
|
||||
import { StreamingClientEditor, ManualEntryEditor, RandomWalkEditor } from './components';
|
||||
|
||||
@ -205,7 +205,7 @@ export const QueryEditor = ({ query, datasource, onChange, onRunQuery }: Props)
|
||||
/>
|
||||
</InlineField>
|
||||
<InlineField label="Level" labelWidth={14}>
|
||||
<Switch onChange={onInputChange} name="levelColumn" value={!!query.levelColumn} />
|
||||
<InlineSwitch onChange={onInputChange} name="levelColumn" value={!!query.levelColumn} />
|
||||
</InlineField>
|
||||
</InlineFieldRow>
|
||||
)}
|
||||
|
@ -53,7 +53,6 @@
|
||||
@import 'components/panel_table';
|
||||
@import 'components/panel_text';
|
||||
@import 'components/panel_heatmap';
|
||||
@import 'components/panel_logs';
|
||||
@import 'components/tagsinput';
|
||||
@import 'components/tables_lists';
|
||||
@import 'components/search';
|
||||
|
@ -1,34 +0,0 @@
|
||||
$column-horizontal-spacing: 10px;
|
||||
|
||||
.logs-panel-options {
|
||||
display: flex;
|
||||
background-color: $page-bg;
|
||||
padding: $space-sm $space-md $space-sm $space-md;
|
||||
border-radius: $border-radius;
|
||||
margin: $space-md 0 $space-sm;
|
||||
border: $panel-border;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.logs-panel-controls {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
.logs-panel-controls-main {
|
||||
display: flex;
|
||||
justify-items: flex-start;
|
||||
align-items: center;
|
||||
flex-wrap: wrap;
|
||||
|
||||
> * {
|
||||
margin-right: $spacer * 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.logs-panel-nodata {
|
||||
> * {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
@ -20,22 +20,8 @@
|
||||
|
||||
.explore-active-button {
|
||||
box-shadow: $btn-active-box-shadow;
|
||||
border: 1px solid $orange-dark;
|
||||
background-image: none;
|
||||
background-color: transparent;
|
||||
border: 1px solid $orange-dark !important;
|
||||
color: $orange-dark !important;
|
||||
|
||||
&:focus {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
i {
|
||||
text-shadow: none;
|
||||
background: linear-gradient(180deg, #f05a28 30%, #fbca0a 100%);
|
||||
background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
-moz-text-fill-color: transparent;
|
||||
}
|
||||
}
|
||||
|
||||
.explore-ds-picker {
|
||||
|
Loading…
Reference in New Issue
Block a user