import {Fragment} from 'react'; import {useTheme} from '@emotion/react'; import styled from '@emotion/styled'; import {Location} from 'history'; import moment from 'moment'; import {CompactSelect} from 'sentry/components/compactSelect'; import {t} from 'sentry/locale'; import {space} from 'sentry/styles/space'; import {Series} from 'sentry/types/echarts'; import {getDuration} from 'sentry/utils/formatters'; import usePageFilters from 'sentry/utils/usePageFilters'; import Chart, {useSynchronizeCharts} from 'sentry/views/starfish/components/chart'; import ChartPanel from 'sentry/views/starfish/components/chartPanel'; import { useQueryDbTables, useQueryTopDbOperationsChart, useQueryTopTablesChart, } from 'sentry/views/starfish/modules/databaseModule/queries'; import {datetimeToClickhouseFilterTimestamps} from 'sentry/views/starfish/utils/dates'; import {zeroFillSeries} from 'sentry/views/starfish/utils/zeroFillSeries'; const INTERVAL = 12; type Props = { location: Location; onChange: (value: string) => void; table: string; }; function parseOptions(options, label) { const prefix = {t('Operation')}; return [ { value: 'ALL', prefix, label: `ALL`, }, ...options.map(action => { return { value: action.key, prefix, label: `${action.key || 'null'} - ${getDuration( action.value / 1000, 2, true )} ${label}`, }; }), ]; } export default function DatabaseChartView({table, onChange}: Props) { const pageFilter = usePageFilters(); const theme = useTheme(); const {start_timestamp, end_timestamp} = datetimeToClickhouseFilterTimestamps( pageFilter.selection.datetime ); const {data: tableData} = useQueryDbTables(); const {isLoading: isTopGraphLoading, data: topGraphData} = useQueryTopDbOperationsChart(INTERVAL); const {isLoading: tableGraphLoading, data: tableGraphData} = useQueryTopTablesChart(INTERVAL); const seriesByDomain: {[action: string]: Series} = {}; const tpmByDomain: {[action: string]: Series} = {}; if (!tableGraphLoading) { tableGraphData.forEach(datum => { seriesByDomain[datum.domain] = { seriesName: datum.domain, data: [], }; tpmByDomain[datum.domain] = { seriesName: datum.domain, data: [], }; }); tableGraphData.forEach(datum => { seriesByDomain[datum.domain].data.push({ value: datum.p50, name: datum.interval, }); tpmByDomain[datum.domain].data.push({ value: datum.count, name: datum.interval, }); }); } const topDomains = Object.values(seriesByDomain).map(series => zeroFillSeries( series, moment.duration(INTERVAL, 'hours'), moment(start_timestamp), moment(end_timestamp) ) ); const tpmDomains = Object.values(tpmByDomain).map(series => zeroFillSeries( series, moment.duration(INTERVAL, 'hours'), moment(start_timestamp), moment(end_timestamp) ) ); const tpmByQuery: {[query: string]: Series} = {}; const seriesByQuery: {[action: string]: Series} = {}; if (!isTopGraphLoading) { topGraphData.forEach(datum => { seriesByQuery[datum.action] = { seriesName: datum.action, data: [], }; tpmByQuery[datum.action] = { seriesName: datum.action, data: [], }; }); topGraphData.forEach(datum => { seriesByQuery[datum.action].data.push({ value: datum.p50, name: datum.interval, }); tpmByQuery[datum.action].data.push({ value: datum.count, name: datum.interval, }); }); } const chartColors = [...theme.charts.getColorPalette(6).slice(2, 7), theme.gray300]; useSynchronizeCharts([!tableGraphLoading]); return ( {tableData.length === 1 && tableData[0].key === '' ? ( ) : ( onChange(opt.value)} /> )} ); } const Selectors = styled(`div`)` display: flex; margin-bottom: ${space(2)}; `; const ChartsContainer = styled('div')` display: flex; flex-direction: row; flex-wrap: wrap; gap: ${space(2)}; `; const ChartsContainerItem = styled('div')` flex: 1; `;