mirror of https://github.com/grafana/grafana
Prometheus: Metric encyclopedia ux collab design (#68421)
* add class for full story click event on open modal * move feedback link to modal top under header * move results amount to bottom left * move settings into modal, change language from exclude to include * add metadata to backend search, use toggletip for settings, clean code * style input row, remove labels and update settings button design * remove alphabet search as requested by design * display selected metric * update style warning message for labels filtered metrics * organize results footer * update table design w fixed width and sticky header * allow focus row on tab and use key Enter to select metric on keydown * add rudderstack event for disable text wrap * add messages for no metrics found, labels, search and none in data source. * filter by type placeholder * add min width to custom select option * add text wrap for long metric names * Have 4px margin b/w the search row and the 'currently selected' text. 16px between 'currently selected text' and the table * Add some padding inside the first table header row (8 pixels on all sides) * font-size of 12px for additional settings text * 4px padding between additional settings text * 24px margin between the last table cell and the pagination row * # of Results per page font size 0.85rem * 8px margin b/w the '# of results per page' and the dropdown * fix test * add infer type setting for testing * use title on icon instead of wrapping in tooltip to fix test * fix icon issue * italicize inferred types, update setting text and add icon * add space for label filters alert message * make open button style consistent with advanced datasource picker * keep copy for open modal button * refactor rudderstack interactions and add inferType * add event tracking for opening the modal * galen's feedback, fix select horizontal scroll and results perpg bug * ismail's feedback for metric types * revert button in option for accessibility(galen) and style button with ghost mode * change name to Metrics explorer * fix hover/focus styles * ismail's feedbcak, refactor hints, return empty string, remove @return * Fix icon hovering: put tooltips back in over titles on icon * make results not expand to fill table space and fix width for modal open option buttonpull/68638/head
parent
effe21fb65
commit
2e6c71fd39
@ -0,0 +1,100 @@ |
|||||||
|
import { css } from '@emotion/css'; |
||||||
|
import React from 'react'; |
||||||
|
|
||||||
|
import { GrafanaTheme2 } from '@grafana/data'; |
||||||
|
import { Icon, Switch, Tooltip, useTheme2 } from '@grafana/ui'; |
||||||
|
|
||||||
|
import { testIds } from './MetricsModal'; |
||||||
|
import { placeholders } from './state/helpers'; |
||||||
|
import { MetricsModalState } from './state/state'; |
||||||
|
|
||||||
|
type AdditionalSettingsProps = { |
||||||
|
state: MetricsModalState; |
||||||
|
onChangeFullMetaSearch: () => void; |
||||||
|
onChangeIncludeNullMetadata: () => void; |
||||||
|
onChangeDisableTextWrap: () => void; |
||||||
|
onChangeUseBackend: () => void; |
||||||
|
onChangeInferType: () => void; |
||||||
|
}; |
||||||
|
|
||||||
|
export function AdditionalSettings(props: AdditionalSettingsProps) { |
||||||
|
const { |
||||||
|
state, |
||||||
|
onChangeFullMetaSearch, |
||||||
|
onChangeIncludeNullMetadata, |
||||||
|
onChangeDisableTextWrap, |
||||||
|
onChangeUseBackend, |
||||||
|
onChangeInferType, |
||||||
|
} = props; |
||||||
|
|
||||||
|
const theme = useTheme2(); |
||||||
|
const styles = getStyles(theme); |
||||||
|
|
||||||
|
return ( |
||||||
|
<> |
||||||
|
<div className={styles.selectItem}> |
||||||
|
<Switch |
||||||
|
data-testid={testIds.searchWithMetadata} |
||||||
|
value={state.fullMetaSearch} |
||||||
|
disabled={state.useBackend || !state.hasMetadata} |
||||||
|
onChange={() => onChangeFullMetaSearch()} |
||||||
|
/> |
||||||
|
<div className={styles.selectItemLabel}>{placeholders.metadataSearchSwitch}</div> |
||||||
|
</div> |
||||||
|
<div className={styles.selectItem}> |
||||||
|
<Switch |
||||||
|
value={state.includeNullMetadata} |
||||||
|
disabled={!state.hasMetadata} |
||||||
|
onChange={() => onChangeIncludeNullMetadata()} |
||||||
|
/> |
||||||
|
<div className={styles.selectItemLabel}>{placeholders.includeNullMetadata}</div> |
||||||
|
</div> |
||||||
|
<div className={styles.selectItem}> |
||||||
|
<Switch value={state.disableTextWrap} onChange={() => onChangeDisableTextWrap()} /> |
||||||
|
<div className={styles.selectItemLabel}>Disable text wrap</div> |
||||||
|
</div> |
||||||
|
<div className={styles.selectItem}> |
||||||
|
<Switch data-testid={testIds.setUseBackend} value={state.useBackend} onChange={() => onChangeUseBackend()} /> |
||||||
|
<div className={styles.selectItemLabel}>{placeholders.setUseBackend} </div> |
||||||
|
<Tooltip |
||||||
|
content={'Filter metric names by regex search, using an additional call on the Prometheus API.'} |
||||||
|
placement="bottom-end" |
||||||
|
> |
||||||
|
<Icon name="info-circle" size="xs" className={styles.settingsIcon} /> |
||||||
|
</Tooltip> |
||||||
|
</div> |
||||||
|
<div className={styles.selectItem}> |
||||||
|
<Switch data-testid={testIds.inferType} value={state.inferType} onChange={() => onChangeInferType()} /> |
||||||
|
<div className={styles.selectItemLabel}>{placeholders.inferType} </div> |
||||||
|
<Tooltip |
||||||
|
content={ |
||||||
|
'For example, metrics ending in _sum, _count, will be given an inferred type of counter. Metrics ending in _bucket with be given a type of histogram.' |
||||||
|
} |
||||||
|
placement="bottom-end" |
||||||
|
> |
||||||
|
<Icon name="info-circle" size="xs" className={styles.settingsIcon} /> |
||||||
|
</Tooltip> |
||||||
|
</div> |
||||||
|
</> |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
function getStyles(theme: GrafanaTheme2) { |
||||||
|
return { |
||||||
|
settingsIcon: css` |
||||||
|
color: ${theme.colors.text.secondary}; |
||||||
|
`,
|
||||||
|
selectItem: css` |
||||||
|
display: flex; |
||||||
|
flex-direction: row; |
||||||
|
align-items: center; |
||||||
|
padding: 4px 0; |
||||||
|
`,
|
||||||
|
selectItemLabel: css` |
||||||
|
margin: 0 0 0 ${theme.spacing(1)}; |
||||||
|
align-self: center; |
||||||
|
color: ${theme.colors.text.secondary}; |
||||||
|
font-size: 12px; |
||||||
|
`,
|
||||||
|
}; |
||||||
|
} |
||||||
@ -1,71 +0,0 @@ |
|||||||
import React from 'react'; |
|
||||||
|
|
||||||
import { useTheme2 } from '@grafana/ui'; |
|
||||||
|
|
||||||
import { getStyles } from './styles'; |
|
||||||
import { MetricData, MetricsData } from './types'; |
|
||||||
|
|
||||||
export type LetterSearchProps = { |
|
||||||
filteredMetrics: MetricsData; |
|
||||||
disableTextWrap: boolean; |
|
||||||
updateLetterSearch: (letter: string) => void; |
|
||||||
letterSearch: string | null; |
|
||||||
}; |
|
||||||
|
|
||||||
export function LetterSearch(props: LetterSearchProps) { |
|
||||||
const { filteredMetrics, disableTextWrap, updateLetterSearch, letterSearch } = props; |
|
||||||
|
|
||||||
const alphabetDictionary = alphabetCheck(); |
|
||||||
|
|
||||||
const theme = useTheme2(); |
|
||||||
const styles = getStyles(theme, disableTextWrap); |
|
||||||
|
|
||||||
filteredMetrics.forEach((m: MetricData, idx: number) => { |
|
||||||
const metricFirstLetter = m.value[0].toUpperCase(); |
|
||||||
|
|
||||||
if (alphabet.includes(metricFirstLetter) && !alphabetDictionary[metricFirstLetter]) { |
|
||||||
alphabetDictionary[metricFirstLetter] += 1; |
|
||||||
} |
|
||||||
}); |
|
||||||
|
|
||||||
// return the alphabet components with the correct style and behavior
|
|
||||||
return ( |
|
||||||
<div> |
|
||||||
{Object.keys(alphabetDictionary).map((letter: string) => { |
|
||||||
const active: boolean = alphabetDictionary[letter] > 0; |
|
||||||
// starts with letter search
|
|
||||||
// filter by starts with letter
|
|
||||||
// if same letter searched null out remove letter search
|
|
||||||
function setLetterSearch() { |
|
||||||
updateLetterSearch(letter); |
|
||||||
} |
|
||||||
// selected letter to filter by
|
|
||||||
const selectedClass: string = letterSearch === letter ? styles.selAlpha : ''; |
|
||||||
// these letters are represented in the list of metrics
|
|
||||||
const activeClass: string = active ? styles.active : styles.gray; |
|
||||||
|
|
||||||
return ( |
|
||||||
<span |
|
||||||
onClick={active ? setLetterSearch : () => {}} |
|
||||||
className={`${selectedClass} ${activeClass}`} |
|
||||||
key={letter} |
|
||||||
data-testid={'letter-' + letter} |
|
||||||
> |
|
||||||
{letter + ' '} |
|
||||||
{/* {idx !== coll.length - 1 ? '|': ''} */} |
|
||||||
</span> |
|
||||||
); |
|
||||||
})} |
|
||||||
</div> |
|
||||||
); |
|
||||||
} |
|
||||||
|
|
||||||
export const alphabet = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZ']; |
|
||||||
|
|
||||||
function alphabetCheck(): { [char: string]: number } { |
|
||||||
const check: { [char: string]: number } = {}; |
|
||||||
|
|
||||||
alphabet.forEach((char) => (check[char] = 0)); |
|
||||||
|
|
||||||
return check; |
|
||||||
} |
|
||||||
Loading…
Reference in new issue