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