Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 9624da6

Browse files
Drill down metrics (#200)
* multiple dashboards on same page * fix * time range selector fix
1 parent 0ffaebc commit 9624da6

File tree

20 files changed

+412
-151
lines changed

20 files changed

+412
-151
lines changed

‎packages/grafana-ui/src/components/Button/Button.tsx

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import { PopoverContent, Tooltip, TooltipPlacement } from '../Tooltip';
1414

1515
export type ButtonVariant = 'primary' | 'secondary' | 'destructive' | 'success';
1616
export const allButtonVariants: ButtonVariant[] = ['primary', 'secondary', 'destructive'];
17-
export type ButtonFill = 'solid' | 'outline' | 'text';
17+
export type ButtonFill = 'solid' | 'outline' | 'text'|'ghost';
1818
export const allButtonFills: ButtonFill[] = ['solid', 'outline', 'text'];
1919

2020
type CommonProps = {
@@ -319,6 +319,17 @@ function getButtonVariantStyles(theme: GrafanaTheme2, color: ThemeRichColor, fil
319319
};
320320
}
321321

322+
if (fill === 'ghost') {
323+
return {
324+
background: '#5d5a5990',
325+
color: color.text,
326+
border: `1px solid ${borderColor}`,
327+
transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color', 'color'], {
328+
duration: theme.transitions.duration.short,
329+
}),
330+
};
331+
}
332+
322333
return {
323334
background: color.main,
324335
color: color.contrastText,

‎packages/grafana-ui/src/components/DateTimePickers/TimeRangePicker/TimeRangeContent.tsx

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export const TimeRangeContent = (props: Props) => {
5858
onApply: onApplyFromProps,
5959
isReversed,
6060
fiscalYearStartMonth,
61-
onError,
61+
// onError,
6262
weekStart,
6363
} = props;
6464
const [fromValue, toValue] = valueToState(value.raw.from, value.raw.to, timeZone);
@@ -112,28 +112,28 @@ export const TimeRangeContent = (props: Props) => {
112112
}
113113
};
114114

115-
const onCopy = () => {
116-
const raw: RawTimeRange = { from: from.value, to: to.value };
117-
navigator.clipboard.writeText(JSON.stringify(raw));
118-
};
119-
120-
const onPaste = async () => {
121-
const raw = await navigator.clipboard.readText();
122-
let range;
123-
124-
try {
125-
range = JSON.parse(raw);
126-
} catch (error) {
127-
if (onError) {
128-
onError(raw);
129-
}
130-
return;
131-
}
132-
133-
const [fromValue, toValue] = valueToState(range.from, range.to, timeZone);
134-
setFrom(fromValue);
135-
setTo(toValue);
136-
};
115+
// const onCopy = () => {
116+
// const raw: RawTimeRange = { from: from.value, to: to.value };
117+
// navigator.clipboard.writeText(JSON.stringify(raw));
118+
// };
119+
120+
// const onPaste = async () => {
121+
// const raw = await navigator.clipboard.readText();
122+
// let range;
123+
124+
// try {
125+
// range = JSON.parse(raw);
126+
// } catch (error) {
127+
// if (onError) {
128+
// onError(raw);
129+
// }
130+
// return;
131+
// }
132+
133+
// const [fromValue, toValue] = valueToState(range.from, range.to, timeZone);
134+
// setFrom(fromValue);
135+
// setTo(toValue);
136+
// };
137137

138138
const fiscalYear = rangeUtil.convertRawToRange({ from: 'now/fy', to: 'now/fy' }, timeZone, fiscalYearStartMonth);
139139
const fiscalYearMessage = t('time-picker.range-content.fiscal-year', 'Fiscal year');
@@ -197,7 +197,7 @@ export const TimeRangeContent = (props: Props) => {
197197
</div>
198198

199199
<div className={style.buttonsContainer}>
200-
<Button
200+
{/* <Button
201201
data-testid={selectors.components.TimePicker.copyTimeRange}
202202
icon="copy"
203203
variant="secondary"
@@ -212,13 +212,13 @@ export const TimeRangeContent = (props: Props) => {
212212
tooltip={t('time-picker.copy-paste.tooltip-paste', 'Paste time range')}
213213
type="button"
214214
onClick={onPaste}
215-
/>
215+
/> */}
216216
<Button
217217
data-testid={selectors.components.TimePicker.applyTimeRange}
218218
type="button"
219219
onClick={onApply}
220220
style={{
221-
width: 193,
221+
width: 205,
222222
textAlign: 'center',
223223
paddingLeft: 45,
224224
}}

‎packages/grafana-ui/src/components/Pagination/Pagination.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ export const Pagination = ({
3434
const pages = [...new Array(numberOfPages).keys()];
3535

3636
const condensePages = numberOfPages > pageLengthToCondense;
37-
const getListItem = (page: number, fill?: 'outline') => (
37+
const getListItem = (page: number, fill?: 'outline'|'ghost') => (
3838
<li key={page} className={styles.item}>
3939
<Button size="sm" onClick={() => onNavigate(page)} fill={fill}>
4040
{page}
@@ -44,7 +44,7 @@ export const Pagination = ({
4444

4545
return pages.reduce<JSX.Element[]>((pagesToRender, pageIndex) => {
4646
const page = pageIndex + 1;
47-
const fill: 'outline' | undefined = page === currentPage ? undefined : 'outline';
47+
const fill: 'outline' | 'ghost' = page === currentPage ? 'ghost' : 'outline';
4848

4949
// The indexes at which to start and stop condensing pages
5050
const lowerBoundIndex = pageLengthToCondense;

‎packages/grafana-ui/src/components/Table/RowsList.tsx

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ interface RowsListProps {
5353
initialRowIndex?: number;
5454
headerGroups: HeaderGroup[];
5555
longestField?: Field;
56+
onClickRow?: (row: Record<string, string | number>) => void;
5657
}
5758

5859
export const RowsList = (props: RowsListProps) => {
@@ -78,6 +79,7 @@ export const RowsList = (props: RowsListProps) => {
7879
initialRowIndex = undefined,
7980
headerGroups,
8081
longestField,
82+
onClickRow,
8183
} = props;
8284

8385
const [rowHighlightIndex, setRowHighlightIndex] = useState<number | undefined>(initialRowIndex);
@@ -303,13 +305,44 @@ export const RowsList = (props: RowsListProps) => {
303305
}
304306
const { key, ...rowProps } = row.getRowProps({ style, ...additionalProps });
305307

308+
const mapRowValues = () => {
309+
const rowValues: Record<string, string | number> = {};
310+
for (const [key, val] of Object.entries(row.values)) {
311+
const k = (row.cells[Number(key)].column as unknown as { field?: { name: string | undefined } })?.field?.name;
312+
if (k === undefined) {
313+
continue;
314+
}
315+
const camelCaseKey = k
316+
.replace(/(?:^\w|[A-Z]|\b\w)/g, (word, index) => (index === 0 ? word.toLowerCase() : word.toUpperCase()))
317+
.replace(/\s+/g, '');
318+
rowValues[camelCaseKey] = val;
319+
}
320+
return rowValues;
321+
};
322+
306323
return (
307324
<div
308325
key={key}
309326
{...rowProps}
310327
className={cx(tableStyles.row, expandedRowStyle)}
311328
onMouseEnter={() => onRowHover(index, data)}
312329
onMouseLeave={onRowLeave}
330+
onClick={() => {
331+
if (onClickRow) {
332+
onClickRow(mapRowValues());
333+
}
334+
}}
335+
role={onClickRow ? 'button' : undefined}
336+
tabIndex={onClickRow ? 0 : undefined}
337+
onKeyDown={
338+
onClickRow
339+
? (e) => {
340+
if (e.key === 'Enter' || e.key === ' ') {
341+
e.preventDefault();
342+
}
343+
}
344+
: undefined
345+
}
313346
>
314347
{/*add the nested data to the DOM first to prevent a 1px border CSS issue on the last cell of the row*/}
315348
{rowExpanded && (
@@ -343,6 +376,7 @@ export const RowsList = (props: RowsListProps) => {
343376
);
344377
},
345378
[
379+
onClickRow,
346380
cellHeight,
347381
data,
348382
nestedDataField,

‎packages/grafana-ui/src/components/Table/Table.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ export const Table = memo((props: Props) => {
5858
enableSharedCrosshair = false,
5959
initialRowIndex = undefined,
6060
fieldConfig,
61+
onClickRow,
6162
} = props;
6263

6364
const listRef = useRef<VariableSizeList>(null);
@@ -334,6 +335,7 @@ export const Table = memo((props: Props) => {
334335
enableSharedCrosshair={enableSharedCrosshair}
335336
initialRowIndex={initialRowIndex}
336337
longestField={longestField}
338+
onClickRow={onClickRow}
337339
/>
338340
</div>
339341
) : (

‎packages/grafana-ui/src/components/Table/styles.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@ export function useTableStyles(theme: GrafanaTheme2, cellHeightOption: TableCell
5959
minHeight: `${rowHeight - 1}px`,
6060
wordBreak: textShouldWrap ? 'break-word' : undefined,
6161
whiteSpace: textShouldWrap && overflowOnHover ? 'normal' : 'nowrap',
62-
boxShadow: overflowOnHover ? `0 0 2px ${theme.colors.primary.main}` : undefined,
63-
background: rowStyled ? 'inherit': (backgroundHover ?? theme.colors.background.primary),
62+
//boxShadow: overflowOnHover ? `0 0 2px ${theme.colors.primary.main}` : undefined,
63+
// background: 'inherit', //: (backgroundHover ?? theme.colors.background.primary),
6464
zIndex: 1,
6565
'.cellActions': {
6666
color: '#FFF',

‎packages/grafana-ui/src/components/Table/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export interface Props {
100100
// The index of the field value that the table will initialize scrolled to
101101
initialRowIndex?: number;
102102
fieldConfig?: FieldConfigSource;
103+
onClickRow?: (row: Record<string, string | number>) => void;
103104
}
104105

105106
/**

‎public/app/core/components/Page/usePageTitle.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { useEffect } from 'react';
22

33
import { NavModel, NavModelItem } from '@grafana/data';
4-
import { FnGlobalState } from 'app/core/reducers/fn-slice';
54
import { HOME_NAV_ID } from 'app/core/reducers/navModel';
65
import { useSelector } from 'app/types';
76

@@ -10,7 +9,7 @@ import { buildBreadcrumbs } from '../Breadcrumbs/utils';
109

1110
export function usePageTitle(navModel?: NavModel, pageNav?: NavModelItem) {
1211
const homeNav = useSelector((state) => state.navIndex)[HOME_NAV_ID];
13-
const { FNDashboard, pageTitle } = useSelector<FnGlobalState>((state) => state.fnGlobalState);
12+
const { FNDashboard, pageTitle } = useSelector((state) => state.fnGlobalState);
1413

1514
useEffect(() => {
1615
const sectionNav = (navModel?.node !== navModel?.main ? navModel?.node : navModel?.main) ?? { text: 'Grafana' };

‎public/app/core/components/TimePicker/TimePickerWithHistory.tsx

Lines changed: 4 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
1-
import { isEqual, uniqBy } from 'lodash';
2-
import { CSSProperties, FC, useEffect, useRef } from 'react';
3-
// eslint-disable-next-line no-restricted-imports
4-
import { useDispatch, useSelector } from 'react-redux';
1+
import { uniqBy } from 'lodash';
2+
import { CSSProperties, FC } from 'react';
53

64
import { TimeRange, isDateTime, rangeUtil } from '@grafana/data';
75
import { TimeRangePickerProps, TimeRangePicker, useTheme2 } from '@grafana/ui';
8-
import { FnGlobalState, updatePartialFnStates } from 'app/core/reducers/fn-slice';
9-
import { StoreState } from 'app/types';
6+
import { useSelector } from 'app/types';
107

118
import { LocalStorageValueProvider } from '../LocalStorageValueProvider';
129

@@ -24,7 +21,7 @@ interface TimePickerHistoryItem {
2421
type LSTimePickerHistoryItem = TimePickerHistoryItem | TimeRange;
2522

2623
const FnText: React.FC = () => {
27-
const { FNDashboard } = useSelector<StoreState,FnGlobalState>(({ fnGlobalState }) => fnGlobalState);
24+
const { FNDashboard } = useSelector(({ fnGlobalState }) => fnGlobalState);
2825
const theme = useTheme2();
2926

3027
const FN_TEXT_STYLE: CSSProperties = { fontWeight: 700, fontSize: 14, marginLeft: 8 };
@@ -47,32 +44,9 @@ export interface PickerProps {
4744
}
4845

4946
export const Picker: FC<PickerProps> = ({ rawValues, onSaveToStore, pickerProps }) => {
50-
const { fnGlobalTimeRange } = useSelector<StoreState, FnGlobalState>(({ fnGlobalState }) => fnGlobalState);
51-
const dispatch = useDispatch();
52-
5347
const values = migrateHistory(rawValues);
5448
const history = deserializeHistory(values);
5549

56-
const didMountRef = useRef(false);
57-
useEffect(() => {
58-
/* The condition below skips the first run of useeffect that happens when this component gets mounted */
59-
if (didMountRef.current) {
60-
/* If the current timerange value has changed, update fnGlobalTimeRange */
61-
if (!isEqual(fnGlobalTimeRange?.raw, pickerProps.value.raw)) {
62-
dispatch(
63-
updatePartialFnStates({
64-
fnGlobalTimeRange: pickerProps.value,
65-
})
66-
);
67-
}
68-
} else if (fnGlobalTimeRange && !isEqual(fnGlobalTimeRange.raw, pickerProps.value.raw)) {
69-
/* If fnGlobalTimeRange exists in the initial render, set the time as that */
70-
pickerProps.onChange(fnGlobalTimeRange);
71-
}
72-
73-
didMountRef.current = true;
74-
}, [dispatch, fnGlobalTimeRange, pickerProps]);
75-
7650
return (
7751
<TimeRangePicker
7852
{...pickerProps}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /