mirror of
https://github.com/grafana/grafana.git
synced 2024-11-25 18:30:41 -06:00
parent
1aae808723
commit
4d564f8b0a
@ -272,7 +272,7 @@
|
||||
"@grafana/schema": "workspace:*",
|
||||
"@grafana/ui": "workspace:*",
|
||||
"@kusto/monaco-kusto": "5.3.6",
|
||||
"@leeoniya/ufuzzy": "0.9.1",
|
||||
"@leeoniya/ufuzzy": "1.0.2",
|
||||
"@lezer/common": "1.0.1",
|
||||
"@lezer/highlight": "1.1.2",
|
||||
"@lezer/lr": "1.3.1",
|
||||
|
@ -52,7 +52,7 @@
|
||||
"@grafana/data": "9.4.0-pre",
|
||||
"@grafana/e2e-selectors": "9.4.0-pre",
|
||||
"@grafana/schema": "9.4.0-pre",
|
||||
"@leeoniya/ufuzzy": "0.9.0",
|
||||
"@leeoniya/ufuzzy": "1.0.2",
|
||||
"@monaco-editor/react": "4.4.6",
|
||||
"@popperjs/core": "2.11.6",
|
||||
"@react-aria/button": "3.6.1",
|
||||
|
@ -186,8 +186,8 @@ function useInternalMatches(filtered: ActionImpl[], search: string): Match[] {
|
||||
return throttledFiltered.map((action) => ({ score: 0, action }));
|
||||
}
|
||||
|
||||
const haystack = throttledFiltered.map((action) =>
|
||||
[action.name, action.keywords, action.subtitle].join(' ').toLowerCase()
|
||||
const haystack = throttledFiltered.map(({ name, keywords, subtitle }) =>
|
||||
`${name} ${keywords ?? ''} ${subtitle ?? ''}`.toLowerCase()
|
||||
);
|
||||
|
||||
const results: Match[] = [];
|
||||
@ -201,35 +201,27 @@ function useInternalMatches(filtered: ActionImpl[], search: string): Match[] {
|
||||
const haystackItem = haystack[haystackIndex];
|
||||
|
||||
// Use the position of the match as a stand-in for score
|
||||
const substringPosition = haystackItem.toLowerCase().indexOf(query);
|
||||
const substringPosition = haystackItem.indexOf(query);
|
||||
|
||||
if (substringPosition > -1) {
|
||||
const score = haystack.length - substringPosition;
|
||||
const score = substringPosition * -1; // lower position of the match should be a higher priority score
|
||||
const action = throttledFiltered[haystackIndex];
|
||||
results.push({ score, action });
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const allMatchedIndexes = new Set<number>();
|
||||
const termCount = ufuzzy.split(throttledSearch).length;
|
||||
const infoThresh = Infinity;
|
||||
const oooSearch = termCount < 5;
|
||||
|
||||
const queryWords = ufuzzy.split(throttledSearch);
|
||||
const queryPermutations =
|
||||
queryWords.length < 5 ? uFuzzy.permute(queryWords).map((terms) => terms.join(' ')) : [throttledSearch];
|
||||
|
||||
for (const permutedSearchTerm of queryPermutations) {
|
||||
const indexes = ufuzzy.filter(haystack, permutedSearchTerm);
|
||||
const info = ufuzzy.info(indexes, haystack, permutedSearchTerm);
|
||||
const order = ufuzzy.sort(info, haystack, permutedSearchTerm);
|
||||
const [, info, order] = ufuzzy.search(haystack, throttledSearch, oooSearch, infoThresh);
|
||||
|
||||
if (info && order) {
|
||||
for (let orderIndex = 0; orderIndex < order.length; orderIndex++) {
|
||||
const actionIndex = order[orderIndex];
|
||||
|
||||
if (!allMatchedIndexes.has(actionIndex)) {
|
||||
allMatchedIndexes.add(actionIndex);
|
||||
const score = order.length - orderIndex;
|
||||
const action = throttledFiltered[info.idx[actionIndex]];
|
||||
results.push({ score, action });
|
||||
}
|
||||
const score = order.length - orderIndex;
|
||||
const action = throttledFiltered[info.idx[actionIndex]];
|
||||
results.push({ score, action });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -116,28 +116,27 @@ class FullResultCache {
|
||||
// eslint-disable-next-line
|
||||
const values = allFields.map((v) => [] as any[]); // empty value for each field
|
||||
|
||||
// out-of-order terms
|
||||
const oooIdxs = new Set<number>();
|
||||
const queryTerms = this.ufuzzy.split(query);
|
||||
const oooNeedles = uFuzzy.permute(queryTerms).map((terms) => terms.join(' '));
|
||||
let [idxs, info, order] = this.ufuzzy.search(haystack, query, true);
|
||||
|
||||
oooNeedles.forEach((needle) => {
|
||||
let idxs = this.ufuzzy.filter(haystack, needle);
|
||||
let info = this.ufuzzy.info(idxs, haystack, needle);
|
||||
let order = this.ufuzzy.sort(info, haystack, needle);
|
||||
for (let c = 0; c < allFields.length; c++) {
|
||||
let src = allFields[c].values.toArray();
|
||||
let dst = values[c];
|
||||
|
||||
for (let i = 0; i < order.length; i++) {
|
||||
let haystackIdx = info.idx[order[i]];
|
||||
|
||||
if (!oooIdxs.has(haystackIdx)) {
|
||||
oooIdxs.add(haystackIdx);
|
||||
|
||||
for (let c = 0; c < allFields.length; c++) {
|
||||
values[c].push(allFields[c].values.get(haystackIdx));
|
||||
}
|
||||
// <= 1000 matches (ranked)
|
||||
if (info && order) {
|
||||
for (let i = 0; i < order.length; i++) {
|
||||
let haystackIdx = info.idx[order[i]];
|
||||
dst.push(src[haystackIdx]);
|
||||
}
|
||||
}
|
||||
});
|
||||
// > 1000 matches (unranked)
|
||||
else {
|
||||
for (let i = 0; i < idxs.length; i++) {
|
||||
let haystackIdx = idxs[i];
|
||||
dst.push(src[haystackIdx]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mutates the search object
|
||||
this.empty.dataFrame.fields.forEach((f, idx) => {
|
||||
|
@ -18,7 +18,7 @@
|
||||
// THIS SOFTWARE.
|
||||
import { css } from '@emotion/css';
|
||||
import uFuzzy from '@leeoniya/ufuzzy';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { useMeasure } from 'react-use';
|
||||
|
||||
import { CoreApp, createTheme, DataFrame, FieldType, getDisplayProcessor } from '@grafana/data';
|
||||
@ -90,6 +90,26 @@ const FlameGraph = ({
|
||||
[levels, totalTicks, rangeMin]
|
||||
);
|
||||
|
||||
const [ufuzzy] = useState(() => {
|
||||
return new uFuzzy();
|
||||
});
|
||||
|
||||
const uniqueLabels = useMemo(() => {
|
||||
return [...new Set<string>(data.fields.find((f) => f.name === 'label')?.values.toArray())];
|
||||
}, [data]);
|
||||
|
||||
const foundLabels = useMemo(() => {
|
||||
const foundLabels = new Set<string>();
|
||||
|
||||
if (search) {
|
||||
for (let idx of ufuzzy.filter(uniqueLabels, search)) {
|
||||
foundLabels.add(uniqueLabels[idx]);
|
||||
}
|
||||
}
|
||||
|
||||
return foundLabels;
|
||||
}, [ufuzzy, search, uniqueLabels]);
|
||||
|
||||
const render = useCallback(
|
||||
(pixelsPerTick: number) => {
|
||||
if (!levels.length) {
|
||||
@ -113,11 +133,6 @@ const FlameGraph = ({
|
||||
theme: createTheme() /* theme does not matter for us here */,
|
||||
});
|
||||
|
||||
const ufuzzy = new uFuzzy({
|
||||
intraMode: 0,
|
||||
intraIns: 0,
|
||||
});
|
||||
|
||||
for (let levelIndex = 0; levelIndex < levels.length; levelIndex++) {
|
||||
const level = levels[levelIndex];
|
||||
// Get all the dimensions of the rectangles for the level. We do this by level instead of per rectangle, because
|
||||
@ -125,11 +140,11 @@ const FlameGraph = ({
|
||||
const dimensions = getRectDimensionsForLevel(level, levelIndex, totalTicks, rangeMin, pixelsPerTick, processor);
|
||||
for (const rect of dimensions) {
|
||||
// Render each rectangle based on the computed dimensions
|
||||
renderRect(ctx, rect, totalTicks, rangeMin, rangeMax, search, levelIndex, topLevelIndex, ufuzzy);
|
||||
renderRect(ctx, rect, totalTicks, rangeMin, rangeMax, search, levelIndex, topLevelIndex, foundLabels);
|
||||
}
|
||||
}
|
||||
},
|
||||
[levels, wrapperWidth, valueField, totalTicks, rangeMin, rangeMax, search, topLevelIndex]
|
||||
[levels, wrapperWidth, valueField, totalTicks, rangeMin, rangeMax, search, topLevelIndex, foundLabels]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
|
@ -86,7 +86,7 @@ export function renderRect(
|
||||
query: string,
|
||||
levelIndex: number,
|
||||
topLevelIndex: number,
|
||||
ufuzzy: uFuzzy
|
||||
foundNames: Set<string>
|
||||
) {
|
||||
if (rect.width < HIDE_THRESHOLD) {
|
||||
return;
|
||||
@ -101,19 +101,17 @@ export function renderRect(
|
||||
const l = 65 + 7 * intensity;
|
||||
|
||||
const name = rect.label;
|
||||
const idxs = ufuzzy.filter([name], query);
|
||||
const queryResult = query && idxs.length > 0;
|
||||
|
||||
if (!rect.collapsed) {
|
||||
ctx.stroke();
|
||||
|
||||
if (query) {
|
||||
ctx.fillStyle = queryResult ? getBarColor(h, l) : colors[55];
|
||||
ctx.fillStyle = foundNames.has(name) ? getBarColor(h, l) : colors[55];
|
||||
} else {
|
||||
ctx.fillStyle = levelIndex > topLevelIndex - 1 ? getBarColor(h, l) : getBarColor(h, l + 15);
|
||||
}
|
||||
} else {
|
||||
ctx.fillStyle = queryResult ? getBarColor(h, l) : colors[55];
|
||||
ctx.fillStyle = foundNames.has(name) ? getBarColor(h, l) : colors[55];
|
||||
}
|
||||
ctx.fill();
|
||||
|
||||
|
19
yarn.lock
19
yarn.lock
@ -5302,7 +5302,7 @@ __metadata:
|
||||
"@grafana/e2e-selectors": 9.4.0-pre
|
||||
"@grafana/schema": 9.4.0-pre
|
||||
"@grafana/tsconfig": ^1.2.0-rc1
|
||||
"@leeoniya/ufuzzy": 0.9.0
|
||||
"@leeoniya/ufuzzy": 1.0.2
|
||||
"@mdx-js/react": 1.6.22
|
||||
"@monaco-editor/react": 4.4.6
|
||||
"@popperjs/core": 2.11.6
|
||||
@ -6246,17 +6246,10 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@leeoniya/ufuzzy@npm:0.9.0":
|
||||
version: 0.9.0
|
||||
resolution: "@leeoniya/ufuzzy@npm:0.9.0"
|
||||
checksum: ee1b781530b3dbddd44eb0923f576028829209648c7b7283e5981f89527ac029c034d234ac2e98c9c25e99fe1d97e524d1e3ee0a79f5cbb92230d36e9cfa69d5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@leeoniya/ufuzzy@npm:0.9.1":
|
||||
version: 0.9.1
|
||||
resolution: "@leeoniya/ufuzzy@npm:0.9.1"
|
||||
checksum: 27750dff2e754ec3729937abce7c36b87917325e934cef7b1bb54a2310fd1e497dcb725397abee8c714f24a84da155120177a93da8f9706eefe32a8a1bb66945
|
||||
"@leeoniya/ufuzzy@npm:1.0.2":
|
||||
version: 1.0.2
|
||||
resolution: "@leeoniya/ufuzzy@npm:1.0.2"
|
||||
checksum: 5460378a8c32d121b0bc7c8e95cde995316516655528e248051b1bf360cdca0311ef3275de14b802587748231333cee6183c931b3abba26f9e4236ecc4959aa3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
@ -22083,7 +22076,7 @@ __metadata:
|
||||
"@grafana/tsconfig": ^1.2.0-rc1
|
||||
"@grafana/ui": "workspace:*"
|
||||
"@kusto/monaco-kusto": 5.3.6
|
||||
"@leeoniya/ufuzzy": 0.9.1
|
||||
"@leeoniya/ufuzzy": 1.0.2
|
||||
"@lezer/common": 1.0.1
|
||||
"@lezer/highlight": 1.1.2
|
||||
"@lezer/lr": 1.3.1
|
||||
|
Loading…
Reference in New Issue
Block a user