Skip to content

Commit

Permalink
Improve performance of fields list rendering and application as a who…
Browse files Browse the repository at this point in the history
…le (#42)

Optimized the fields list rendering and the app as a whole
  • Loading branch information
kyle-sammons authored Dec 1, 2023
1 parent 006ba0c commit 1b1b847
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 122 deletions.
14 changes: 14 additions & 0 deletions .config/webpack/webpack.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@ import path from 'path';
import ReplaceInFileWebpackPlugin from 'replace-in-file-webpack-plugin';
import { Configuration } from 'webpack';


import { getPackageJson, getPluginJson, hasReadme, getEntries } from './utils';
import { SOURCE_DIR, DIST_DIR } from './constants';

const pluginJson = getPluginJson();
const TerserPlugin = require("terser-webpack-plugin");


const config = async (env): Promise<Configuration> => ({
cache: {
Expand Down Expand Up @@ -196,6 +199,17 @@ const config = async (env): Promise<Configuration> => ({
modules: [path.resolve(process.cwd(), 'src'), 'node_modules'],
unsafeCache: true,
},

optimization: {
minimize: true,
usedExports: true,
minimizer: [new TerserPlugin({
terserOptions: {
sourceMap: true,
compress: true
}
})]
}
});

export default config;
1 change: 1 addition & 0 deletions docker-compose.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ services:
GF_AUTH_ANONYMOUS_ORG_ROLE: "Admin"
GF_PATHS_PLUGINS: "/var/lib/grafana/plugins"
GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: "slack-kaldb-app,slack-kaldb-app-backend-datasource"
GF_SERVER_ENABLE_GZIP: "true"
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@
"react-dom": "17.0.2",
"react-use": "17.4.0",
"react-virtualized-auto-sizer": "1.0.2",
"react-window": "^1.8.10",
"rxjs": "7.8.0",
"semver": "7.3.7",
"tslib": "2.5.3",
Expand All @@ -100,5 +101,6 @@
"engines": {
"node": ">=16"
},
"packageManager": "[email protected]"
"packageManager": "[email protected]",
"sideEffects": false
}
54 changes: 48 additions & 6 deletions src/datasource/components/FieldValueFrequency.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { Field } from 'datasource/types';
import { Field, ValueFrequency } from 'datasource/types';
import { Toggletip } from './Toggletip';
import { HorizontalGroup, VerticalGroup, Button } from '@grafana/ui';

Expand All @@ -10,6 +10,45 @@ interface Props {
onMinusClick?: (field: Field, value: string) => void;
}


/*
* Calculates the frequency map for a list of values.
* The map returned is in sorted descending order
*/
function getFrequencyMap<T>(values: T[]): Map<string, number> {
let frequencyMap = new Map<string, number>();
for (let value of values) {
if (value === undefined) {
continue;
}

let stringValue = JSON.stringify(value);

let currentCount = frequencyMap.has(stringValue) ? frequencyMap.get(stringValue) : 0;
frequencyMap.set(stringValue, currentCount + 1);
}
return new Map([...frequencyMap].sort((a, b) => (a[1] >= b[1] ? -1 : 0)));
}

function getValueCountsForField(unmappedFieldValuesArray: any): ValueFrequency[] {
let frequencyMapForField = getFrequencyMap(unmappedFieldValuesArray);
let topFiveMostPopularValues: ValueFrequency[] = [];
let i = 0;
for (let [value, _count] of frequencyMapForField) {
if (i === 5) {
break;
}
let definedCount = unmappedFieldValuesArray.filter((value) => value !== undefined).length;
let valueFreq: ValueFrequency = {
value: value,
frequency: _count / definedCount,
};
topFiveMostPopularValues.push(valueFreq);
i++;
}
return topFiveMostPopularValues;
}

const InnerTitle = (field: Field) => {
return (
<div>
Expand All @@ -31,14 +70,15 @@ const InnerContent = (
onPlusClick?: (field: Field, value: string) => void,
onMinusClick?: (field: Field, value: string) => void
) => {
let mostCommonValues = getValueCountsForField(field.unmappedFieldValuesArray)
return (
<div>
<span>
<b>
Top {field.mostCommonValues.length} {field.mostCommonValues.length > 1 ? 'values' : 'value'}
Top {mostCommonValues.length} {mostCommonValues.length > 1 ? 'values' : 'value'}
</b>
</span>
{field.mostCommonValues.map((valueFreq) => {
{mostCommonValues.map((valueFreq) => {
return (
<VerticalGroup key={valueFreq.value}>
<HorizontalGroup spacing={'lg'} justify={'space-between'}>
Expand Down Expand Up @@ -84,15 +124,15 @@ const InnerContent = (
const InnerFooter = (field: Field) => {
return (
<span>
Exists in {field.numberOfLogsFieldIsIn} / {field.totalNumberOfLogs} records
Exists in {field.numberOfLogsFieldIsIn} / {field.unmappedFieldValuesArray.values.length} records
</span>
);
};

/**
* A component to show the FieldValueFrequency for a given field value in the app UI.
*/
export const FieldValueFrequency = ({ field, children, onMinusClick, onPlusClick }: Props) => {
const FieldValueFrequency = ({ field, children, onMinusClick, onPlusClick }: Props) => {
// This doesn't make sense for this field
if (field.name === '_source') {
return <div></div>;
Expand All @@ -101,7 +141,7 @@ export const FieldValueFrequency = ({ field, children, onMinusClick, onPlusClick
return (
<Toggletip
title={InnerTitle(field)}
content={InnerContent(field, onPlusClick, onMinusClick)}
content={() => InnerContent(field, onPlusClick, onMinusClick)}
footer={InnerFooter(field)}
closeButton={false}
placement={'right'}
Expand All @@ -110,3 +150,5 @@ export const FieldValueFrequency = ({ field, children, onMinusClick, onPlusClick
</Toggletip>
);
};

export default FieldValueFrequency;
8 changes: 4 additions & 4 deletions src/datasource/components/Toggletip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ export interface ToggletipContentProps {
update?: () => void;
}

export type ToggletipContent = string | React.ReactElement | ((props: ToggletipContentProps) => JSX.Element);
export type ToggletipContent = string | React.ReactElement | (() => React.ReactElement);

export interface ToggletipProps {
/** The theme used to display the toggletip */
Expand Down Expand Up @@ -243,7 +243,7 @@ export const Toggletip = React.memo(
return undefined;
}, [controlledVisible, closeToggletip]);

const { getArrowProps, getTooltipProps, setTooltipRef, setTriggerRef, visible, update } = usePopperTooltip({
const { getArrowProps, getTooltipProps, setTooltipRef, setTriggerRef, visible } = usePopperTooltip({
visible: controlledVisible,
placement: placement,
interactive: true,
Expand All @@ -257,6 +257,7 @@ export const Toggletip = React.memo(
},
});


return (
<>
{React.cloneElement(children, {
Expand All @@ -283,8 +284,7 @@ export const Toggletip = React.memo(
)}
<div ref={contentRef} {...getArrowProps({ className: style.arrow })} />
<div className={style.body}>
{(typeof content === 'string' || React.isValidElement(content)) && content}
{typeof content === 'function' && update && content({ update })}
{(typeof content === 'function' && React.isValidElement(content())) && content()}
</div>
{Boolean(footer) && <div className={style.footer}>{footer}</div>}
</div>
Expand Down
3 changes: 1 addition & 2 deletions src/datasource/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,6 @@ export interface ValueFrequency {
export interface Field {
name: string;
type: string;
mostCommonValues: ValueFrequency[];
numberOfLogsFieldIsIn: number;
totalNumberOfLogs: number;
unmappedFieldValuesArray: any[];
}
Loading

0 comments on commit 1b1b847

Please sign in to comment.