grafana/public/app/plugins/datasource/graphite/components/MetricTankMetaInspector.tsx
Piotr Jamróz d93d989a5a
Graphite: Migrate to React (part 4 & 5: group all components) (#37590)
* Add UMLs

* Add rendered diagrams

* Move QueryCtrl to flux

* Remove redundant param in the reducer

* Use named imports for lodash and fix typing for GraphiteTagOperator

* Add missing async/await

* Extract providers to a separate file

* Clean up async await

* Rename controller functions back to main

* Simplify creating actions

* Re-order controller functions

* Separate helpers from actions

* Rename vars

* Simplify helpers

* Move controller methods to state reducers

* Remove docs (they are added in design doc)

* Move actions.ts to state folder

* Add docs

* Add old methods stubs for easier review

* Check how state dependencies will be mapped

* Rename state to store

* Rename state to store

* Rewrite spec tests for Graphite Query Controller

* Update docs

* Update docs

* Add GraphiteTextEditor

* Add play button

* Add AddGraphiteFunction

* Use Segment to simplify AddGraphiteFunction

* Memoize function defs

* Fix useCallback deps

* Update public/app/plugins/datasource/graphite/state/helpers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Update public/app/plugins/datasource/graphite/state/helpers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Update public/app/plugins/datasource/graphite/state/helpers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Update public/app/plugins/datasource/graphite/state/providers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Update public/app/plugins/datasource/graphite/state/providers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Update public/app/plugins/datasource/graphite/state/providers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Update public/app/plugins/datasource/graphite/state/providers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Update public/app/plugins/datasource/graphite/state/providers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Update public/app/plugins/datasource/graphite/state/providers.ts

Co-authored-by: Giordano Ricci <me@giordanoricci.com>

* Add more type definitions

* Remove submitOnClickAwayOption

This behavior is actually needed to remove parameters in functions

* Load function definitions before parsing the target on initial load

* Add button padding

* Fix loading function definitions

* Change targetChanged to updateQuery to avoid mutating state directly

It's also needed for extra refresh/runQuery execution as handleTargetChanged doesn't handle changing the raw query

* Fix updating query after adding a function

* Simplify updating function params

* Migrate function editor to react

* Simplify setting Segment Select min width

* Remove unnecessary changes to SegmentInput

* Extract view logic to a helper and update types definitions

* Clean up types

* Update FuncDef types and add tests

* Show red border for unknown functions

* Autofocus on new params

* Extract params mapping to a helper

* Split code between params and function editor

* Focus on the first param when a function is added even if it's an optional argument

* Add function editor tests

* Remove todo marker

* Fix adding new functions

* Allow empty value in selects for removing function params

* Add placeholders and fix styling

* Add more docs

* Create basic implementation for metrics and tags

* Post merge fixes

These files are not .ts

* Remove mapping to Angular dropdowns

* Simplify mapping tag names, values and operators

* Simplify mapping metrics

* Fix removing tags and autocomplete

* Simplify debouncing providers

* Ensure options are loaded twice and segment is opened

* Remove focusing new segments logic (not supported by React's segment)

* Clean up

* Move debouncing to components

* Simplify mapping to selectable options

* Add docs

* Group all components

* Remove unused controller methods

* Create Dispatch context

* Group Series and Tags Sections

* Create Functions section

* Create Section component

* use getStyles

* remove redundant async/await

* Remove

* remove redundant async/await

* Remove console.log and silent test console output

* Do not display the name of the selected dropdown option

* Move Section to grafana-ui

* Update storybook

* Simplify SectionLabel

* Fix Influx tests

* Fix API Extractor warnings

* Fix API Extractor warnings

* Do not show hidden functions

* Use block docs for better doc generation

* Handle undefined values provided for autocomplete

* Section -> SegmentSection

* Simplify section styling

* Remove redundant div

* Simplify SegmentSection component

* Use theme.spacing

* Use empty label instead of a single space label

Co-authored-by: Giordano Ricci <me@giordanoricci.com>
2021-08-17 18:50:31 +02:00

182 lines
6.3 KiB
TypeScript

import { css, cx } from '@emotion/css';
import React, { PureComponent } from 'react';
import { MetadataInspectorProps, rangeUtil } from '@grafana/data';
import { GraphiteDatasource } from '../datasource';
import { GraphiteQuery, GraphiteOptions, MetricTankSeriesMeta } from '../types';
import { parseSchemaRetentions, getRollupNotice, getRuntimeConsolidationNotice } from '../meta';
import { stylesFactory } from '@grafana/ui';
import { config } from 'app/core/config';
export type Props = MetadataInspectorProps<GraphiteDatasource, GraphiteQuery, GraphiteOptions>;
export interface State {
index: number;
}
export class MetricTankMetaInspector extends PureComponent<Props, State> {
renderMeta(meta: MetricTankSeriesMeta, key: string) {
const styles = getStyles();
const buckets = parseSchemaRetentions(meta['schema-retentions']);
const rollupNotice = getRollupNotice([meta]);
const runtimeNotice = getRuntimeConsolidationNotice([meta]);
const normFunc = (meta['consolidator-normfetch'] ?? '').replace('Consolidator', '');
const totalSeconds = buckets.reduce(
(acc, bucket) => acc + (bucket.retention ? rangeUtil.intervalToSeconds(bucket.retention) : 0),
0
);
return (
<div className={styles.metaItem} key={key}>
<div className={styles.metaItemHeader}>
Schema: {meta['schema-name']}
<div className="small muted">Series count: {meta.count}</div>
</div>
<div className={styles.metaItemBody}>
<div className={styles.step}>
<div className={styles.stepHeading}>Step 1: Fetch</div>
<div className={styles.stepDescription}>
First data is fetched, either from raw data archive or a rollup archive
</div>
{rollupNotice && <p>{rollupNotice.text}</p>}
{!rollupNotice && <p>No rollup archive was used</p>}
<div>
{buckets.map((bucket, index) => {
const bucketLength = bucket.retention ? rangeUtil.intervalToSeconds(bucket.retention) : 0;
const lengthPercent = (bucketLength / totalSeconds) * 100;
const isActive = index === meta['archive-read'];
return (
<div key={bucket.retention} className={styles.bucket}>
<div className={styles.bucketInterval}>{bucket.interval}</div>
<div
className={cx(styles.bucketRetention, { [styles.bucketRetentionActive]: isActive })}
style={{ flexGrow: lengthPercent }}
/>
<div style={{ flexGrow: 100 - lengthPercent }}>{bucket.retention}</div>
</div>
);
})}
</div>
</div>
<div className={styles.step}>
<div className={styles.stepHeading}>Step 2: Normalization</div>
<div className={styles.stepDescription}>
Normalization happens when series with different intervals between points are combined.
</div>
{meta['aggnum-norm'] > 1 && <p>Normalization did occur using {normFunc}</p>}
{meta['aggnum-norm'] === 1 && <p>No normalization was needed</p>}
</div>
<div className={styles.step}>
<div className={styles.stepHeading}>Step 3: Runtime consolidation</div>
<div className={styles.stepDescription}>
If there are too many data points at this point Metrictank will consolidate them down to below max data
points (set in queries tab).
</div>
{runtimeNotice && <p>{runtimeNotice.text}</p>}
{!runtimeNotice && <p>No runtime consolidation</p>}
</div>
</div>
</div>
);
}
render() {
const { data } = this.props;
// away to dedupe them
const seriesMetas: Record<string, MetricTankSeriesMeta> = {};
for (const series of data) {
if (series.meta && series.meta.custom) {
for (const metaItem of series.meta.custom.seriesMetaList as MetricTankSeriesMeta[]) {
// key is to dedupe as many series will have identitical meta
const key = `${JSON.stringify(metaItem)}`;
if (seriesMetas[key]) {
seriesMetas[key].count += metaItem.count;
} else {
seriesMetas[key] = metaItem;
}
}
}
}
if (Object.keys(seriesMetas).length === 0) {
return <div>No response meta data</div>;
}
return (
<div>
<h2 className="page-heading">Metrictank Lineage</h2>
{Object.keys(seriesMetas).map((key) => this.renderMeta(seriesMetas[key], key))}
</div>
);
}
}
const getStyles = stylesFactory(() => {
const { theme } = config;
const borderColor = theme.isDark ? theme.palette.gray25 : theme.palette.gray85;
const background = theme.isDark ? theme.palette.dark1 : theme.palette.white;
const headerBg = theme.isDark ? theme.palette.gray15 : theme.palette.gray85;
return {
metaItem: css`
background: ${background};
border: 1px solid ${borderColor};
margin-bottom: ${theme.spacing.md};
`,
metaItemHeader: css`
background: ${headerBg};
padding: ${theme.spacing.xs} ${theme.spacing.md};
font-size: ${theme.typography.size.md};
display: flex;
justify-content: space-between;
`,
metaItemBody: css`
padding: ${theme.spacing.md};
`,
stepHeading: css`
font-size: ${theme.typography.size.md};
`,
stepDescription: css`
font-size: ${theme.typography.size.sm};
color: ${theme.colors.textWeak};
margin-bottom: ${theme.spacing.sm};
`,
step: css`
margin-bottom: ${theme.spacing.lg};
&:last-child {
margin-bottom: 0;
}
`,
bucket: css`
display: flex;
margin-bottom: ${theme.spacing.sm};
border-radius: ${theme.border.radius.md};
`,
bucketInterval: css`
flex-grow: 0;
width: 60px;
`,
bucketRetention: css`
background: linear-gradient(0deg, ${theme.palette.blue85}, ${theme.palette.blue95});
text-align: center;
color: ${theme.palette.white};
margin-right: ${theme.spacing.md};
border-radius: ${theme.border.radius.md};
`,
bucketRetentionActive: css`
background: linear-gradient(0deg, ${theme.palette.greenBase}, ${theme.palette.greenShade});
`,
};
});