Skip to content

Commit

Permalink
WIP feat: add fuzzy search to popup menu and search pad
Browse files Browse the repository at this point in the history
  • Loading branch information
philippfromme committed Nov 22, 2024
1 parent 99c1ad7 commit 7a7eb7f
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 1 deletion.
5 changes: 4 additions & 1 deletion lib/base/Modeler.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
BpmnPropertiesProviderModule as bpmnPropertiesProviderModule
} from 'bpmn-js-properties-panel';

import fuzzySearchModule from './features/fuzzy-search';

/**
* @typedef {import('bpmn-js/lib/BaseViewer').BaseViewerOptions} BaseViewerOptions
*
Expand Down Expand Up @@ -57,7 +59,8 @@ Modeler.prototype._extensionModules = [
minimapModule,
executableFixModule,
propertiesPanelModule,
bpmnPropertiesProviderModule
bpmnPropertiesProviderModule,
fuzzySearchModule
];

Modeler.prototype._modules = [].concat(
Expand Down
120 changes: 120 additions & 0 deletions lib/base/features/fuzzy-search/fuzzySearch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
import Fuse from 'fuse.js/basic';

/**
* @typedef { {
* index: number;
* match: boolean;
* value: string;
* } } Token
*
* @typedef {Token[]} Tokens
*/

/**
* @template R
*
* @typedef { {
* item: R,
* tokens: Record<string, Tokens>
* } } SearchResult
*/

/**
* Search items using fuzzy search.
*
* @template T
*
* @param {T[]} items
* @param {string} pattern
* @param { {
* keys: string[];
* } } options
*
* @returns {SearchResult<T>[]}
*/
export default function fuzzySearch(items, pattern, options) {
const fuse = new Fuse(items, {

Check warning on line 36 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L36

Added line #L36 was not covered by tests
includeScore: true,
ignoreLocation: true,
includeMatches: true,
threshold: 0.25,
keys: options.keys
});

const result = fuse.search(pattern);

Check warning on line 44 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L44

Added line #L44 was not covered by tests

console.log(result);

Check warning on line 46 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L46

Added line #L46 was not covered by tests

return result.map(({ item, matches }) => {
let tokens = {};

Check warning on line 49 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L48-L49

Added lines #L48 - L49 were not covered by tests

for (const key of options.keys) {

Check warning on line 51 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L51

Added line #L51 was not covered by tests

if (item[key] && item[key].length) {
tokens = {

Check warning on line 54 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L53-L54

Added lines #L53 - L54 were not covered by tests
...tokens,
[key]: matchesToTokens(matches, key, item[key])
};
} else {
tokens = {

Check warning on line 59 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L59

Added line #L59 was not covered by tests
...tokens,
[key]: []
};
}
}

return {

Check warning on line 66 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L66

Added line #L66 was not covered by tests
item,
tokens
};
});
};

function matchesToTokens(matches, key, value) {
const match = matches.find((match) => match.key === key);

Check warning on line 74 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L74

Added line #L74 was not covered by tests

if (!match) {
return [

Check warning on line 77 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L76-L77

Added lines #L76 - L77 were not covered by tests
{
index: 0,
value
}
];
}

const { indices } = match;

Check warning on line 85 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L85

Added line #L85 was not covered by tests

const tokensMatch = indices.map(([ start, end ]) => {
return {

Check warning on line 88 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L87-L88

Added lines #L87 - L88 were not covered by tests
index: start,
match: true,
value: match.value.slice(start, end + 1)
};
});

const tokens = [];

Check warning on line 95 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L95

Added line #L95 was not covered by tests

let lastIndex = 0;

Check warning on line 97 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L97

Added line #L97 was not covered by tests

tokensMatch.forEach((token, index) => {
if (token.index !== lastIndex) {
tokens.push({

Check warning on line 101 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L99-L101

Added lines #L99 - L101 were not covered by tests
index: lastIndex,
value: match.value.slice(lastIndex, token.index)
});
}

tokens.push(token);

Check warning on line 107 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L107

Added line #L107 was not covered by tests

lastIndex = token.index + token.value.length;

Check warning on line 109 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L109

Added line #L109 was not covered by tests

if (index === tokensMatch.length - 1 && lastIndex !== match.value.length) {
tokens.push({

Check warning on line 112 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L111-L112

Added lines #L111 - L112 were not covered by tests
index: lastIndex,
value: match.value.slice(lastIndex)
});
}
});

return tokens;

Check warning on line 119 in lib/base/features/fuzzy-search/fuzzySearch.js

View check run for this annotation

Codecov / codecov/patch

lib/base/features/fuzzy-search/fuzzySearch.js#L119

Added line #L119 was not covered by tests
}
5 changes: 5 additions & 0 deletions lib/base/features/fuzzy-search/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import fuzzySearch from './fuzzySearch';

export default {
search: [ 'value', fuzzySearch ]
};
14 changes: 14 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"diagram-js-grid": "^1.1.0",
"diagram-js-minimap": "^5.2.0",
"diagram-js-origin": "^1.4.0",
"fuse.js": "^7.0.0",
"inherits-browser": "^0.1.0",
"min-dash": "^4.2.2",
"zeebe-bpmn-moddle": "^1.7.0"
Expand Down

0 comments on commit 7a7eb7f

Please sign in to comment.