-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
b91b488
commit e4511d9
Showing
8 changed files
with
462 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
import React from 'react'; | ||
|
||
import { DataFrame } from '@grafana/data'; | ||
import { | ||
SceneObjectState, | ||
SceneObjectBase, | ||
SceneComponentProps, | ||
sceneGraph, | ||
AdHocFiltersVariable, | ||
} from '@grafana/scenes'; | ||
import { Button } from '@grafana/ui'; | ||
|
||
export interface AddToFiltersGraphActionState extends SceneObjectState { | ||
frame: DataFrame; | ||
variableName: string; | ||
} | ||
|
||
export class AddToFiltersGraphAction extends SceneObjectBase<AddToFiltersGraphActionState> { | ||
public onClick = () => { | ||
const variable = sceneGraph.lookupVariable(this.state.variableName, this); | ||
if (!(variable instanceof AdHocFiltersVariable)) { | ||
return; | ||
} | ||
|
||
const labels = this.state.frame.fields[1]?.labels ?? {}; | ||
if (Object.keys(labels).length !== 1) { | ||
return; | ||
} | ||
|
||
const labelName = Object.keys(labels)[0]; | ||
|
||
variable.setState({ | ||
filters: [ | ||
...variable.state.filters, | ||
{ | ||
key: labelName, | ||
operator: '=', | ||
value: labels[labelName], | ||
}, | ||
], | ||
}); | ||
}; | ||
|
||
public static Component = ({ model }: SceneComponentProps<AddToFiltersGraphAction>) => { | ||
return ( | ||
<Button variant="primary" size="sm" fill="text" onClick={model.onClick}> | ||
Add to filters | ||
</Button> | ||
); | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import { css } from '@emotion/css'; | ||
import { useResizeObserver } from '@react-aria/utils'; | ||
import React, { useEffect, useRef, useState } from 'react'; | ||
|
||
import { GrafanaTheme2, SelectableValue } from '@grafana/data'; | ||
import { Select, RadioButtonGroup, useStyles2, useTheme2, measureText } from '@grafana/ui'; | ||
|
||
type Props = { | ||
options: Array<SelectableValue<string>>; | ||
value?: string; | ||
onChange: (label: string | undefined) => void; | ||
}; | ||
|
||
const mainAttributes = ['name', 'rootName', 'rootServiceName', 'status', 'span.http.status_code']; | ||
|
||
export function BreakdownLabelSelector({ options, value, onChange }: Props) { | ||
const styles = useStyles2(getStyles); | ||
const theme = useTheme2(); | ||
|
||
const [labelSelectorRequiredWidth, setLabelSelectorRequiredWidth] = useState<number>(0); | ||
const [availableWidth, setAvailableWidth] = useState<number>(0); | ||
|
||
const useHorizontalLabelSelector = availableWidth > labelSelectorRequiredWidth; | ||
|
||
const controlsContainer = useRef<HTMLDivElement>(null); | ||
|
||
useResizeObserver({ | ||
ref: controlsContainer, | ||
onResize: () => { | ||
const element = controlsContainer.current; | ||
if (element) { | ||
setAvailableWidth(element.clientWidth); | ||
} | ||
}, | ||
}); | ||
|
||
const mainOptions = mainAttributes | ||
.filter((at) => !!options.find((op) => op.value === at)) | ||
.map((attribute) => ({ label: attribute, text: attribute, value: attribute })); | ||
|
||
const otherOptions = options.filter((op) => !mainAttributes.includes(op.value?.toString()!)); | ||
|
||
useEffect(() => { | ||
const { fontSize } = theme.typography; | ||
const text = mainOptions.map((option) => option.label || option.text || '').join(' '); | ||
const textWidth = measureText(text, fontSize).width; | ||
const additionalWidthPerItem = 70; | ||
setLabelSelectorRequiredWidth(textWidth + additionalWidthPerItem * mainOptions.length); | ||
}, [mainOptions, theme]); | ||
|
||
return ( | ||
<div ref={controlsContainer} className={styles.container}> | ||
{useHorizontalLabelSelector ? ( | ||
<> | ||
<RadioButtonGroup {...{ options: mainOptions, value, onChange }} /> | ||
<Select | ||
{...{ value }} | ||
placeholder={'Other attributes'} | ||
options={otherOptions} | ||
onChange={(selected) => onChange(selected.value)} | ||
className={styles.select} | ||
/> | ||
</> | ||
) : ( | ||
<Select | ||
{...{ value }} | ||
placeholder={'Select attribute'} | ||
options={options} | ||
onChange={(selected) => onChange(selected.value)} | ||
className={styles.select} | ||
/> | ||
)} | ||
</div> | ||
); | ||
} | ||
|
||
function getStyles(theme: GrafanaTheme2) { | ||
return { | ||
select: css({ | ||
maxWidth: theme.spacing(22), | ||
}), | ||
container: css({ | ||
display: 'flex', | ||
gap: theme.spacing(1), | ||
}), | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React from 'react'; | ||
|
||
import { SelectableValue } from '@grafana/data'; | ||
import { SceneComponentProps, SceneObject, SceneObjectBase, SceneObjectState } from '@grafana/scenes'; | ||
import { Field, RadioButtonGroup } from '@grafana/ui'; | ||
|
||
export interface LayoutSwitcherState extends SceneObjectState { | ||
active: LayoutType; | ||
layouts: SceneObject[]; | ||
options: Array<SelectableValue<LayoutType>>; | ||
} | ||
|
||
export type LayoutType = 'single' | 'grid' | 'rows'; | ||
|
||
export class LayoutSwitcher extends SceneObjectBase<LayoutSwitcherState> { | ||
public Selector({ model }: { model: LayoutSwitcher }) { | ||
const { active, options } = model.useState(); | ||
|
||
return ( | ||
<Field label="View"> | ||
<RadioButtonGroup options={options} value={active} onChange={model.onLayoutChange} /> | ||
</Field> | ||
); | ||
} | ||
|
||
public onLayoutChange = (active: LayoutType) => { | ||
this.setState({ active }); | ||
}; | ||
|
||
public static Component = ({ model }: SceneComponentProps<LayoutSwitcher>) => { | ||
const { layouts, options, active } = model.useState(); | ||
|
||
const index = options.findIndex((o) => o.value === active); | ||
if (index === -1) { | ||
return null; | ||
} | ||
|
||
const layout = layouts[index]; | ||
|
||
return <layout.Component model={layout} />; | ||
}; | ||
} |
Oops, something went wrong.