Commit 56fb04e9 by Ivana Huckova Committed by GitHub

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
parent 7562c674
......@@ -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};
`,
};
......
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};
`,
};
});
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';
......
$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 {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment