From 495a3d96fd11b16b0d80997c9e8a26207918f3c1 Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Mon, 4 Nov 2024 15:16:08 -0500 Subject: [PATCH] [5.x] Improved fieldtype search using keywords (#11053) --- package-lock.json | 11 ++++++----- package.json | 2 +- resources/js/components/data-list/DataList.vue | 2 +- resources/js/components/fields/FieldtypeSelector.vue | 11 +++++++---- src/Dictionaries/Countries.php | 1 + src/Dictionaries/Currencies.php | 1 + src/Dictionaries/Dictionary.php | 6 ++++++ src/Dictionaries/File.php | 2 ++ src/Dictionaries/Timezones.php | 1 + src/Fields/Fieldtype.php | 7 +++++++ src/Fieldtypes/Assets/Assets.php | 1 + src/Fieldtypes/Bard.php | 1 + src/Fieldtypes/Collections.php | 1 + src/Fieldtypes/Color.php | 1 + src/Fieldtypes/Date.php | 1 + src/Fieldtypes/Dictionary.php | 11 +++++++++++ src/Fieldtypes/Entries.php | 1 + src/Fieldtypes/Markdown.php | 1 + src/Fieldtypes/Replicator.php | 1 + src/Fieldtypes/Select.php | 1 + src/Fieldtypes/Toggle.php | 1 + src/Fieldtypes/Yaml.php | 1 + tests/Fields/FieldtypeTest.php | 1 + 23 files changed, 56 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index f3356f8f5f..cb4fd1f3bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,7 +47,7 @@ "codemirror": "^5.58.2", "cookies-js": "^1.2.2", "floating-vue": "^1.0.0-beta.19", - "fuse.js": "^3.4.6", + "fuse.js": "^7.0.0", "highlight.js": "^11.7.0", "imask": "^6.6.0-alpha.0", "laravel-echo": "^1.16.0", @@ -5333,11 +5333,12 @@ "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/fuse.js": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-3.6.1.tgz", - "integrity": "sha512-hT9yh/tiinkmirKrlv4KWOjztdoZo1mx9Qh4KvWqC7isoXwdUY3PNWUxceF4/qO9R6riA2C29jdTOeQOIROjgw==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz", + "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==", + "license": "Apache-2.0", "engines": { - "node": ">=6" + "node": ">=10" } }, "node_modules/gensync": { diff --git a/package.json b/package.json index b898d87d3f..7abe2d80ab 100644 --- a/package.json +++ b/package.json @@ -52,7 +52,7 @@ "codemirror": "^5.58.2", "cookies-js": "^1.2.2", "floating-vue": "^1.0.0-beta.19", - "fuse.js": "^3.4.6", + "fuse.js": "^7.0.0", "highlight.js": "^11.7.0", "imask": "^6.6.0-alpha.0", "laravel-echo": "^1.16.0", diff --git a/resources/js/components/data-list/DataList.vue b/resources/js/components/data-list/DataList.vue index c40d42ee02..eed59d6e7d 100644 --- a/resources/js/components/data-list/DataList.vue +++ b/resources/js/components/data-list/DataList.vue @@ -135,7 +135,7 @@ export default { keys: this.searchableColumns, }); - return fuse.search(this.searchQuery); + return fuse.search(this.searchQuery).map(result => result.item); }, sortRows(rows) { diff --git a/resources/js/components/fields/FieldtypeSelector.vue b/resources/js/components/fields/FieldtypeSelector.vue index 37ae0717bb..7a0abbff0f 100644 --- a/resources/js/components/fields/FieldtypeSelector.vue +++ b/resources/js/components/fields/FieldtypeSelector.vue @@ -99,7 +99,7 @@ export default { if (!this.fieldtypesLoaded) return []; let options = this.fieldtypes.map(fieldtype => { - return {text: fieldtype.title, value: fieldtype.handle, categories: fieldtype.categories, icon: fieldtype.icon}; + return {text: fieldtype.title, value: fieldtype.handle, categories: fieldtype.categories, keywords: fieldtype.keywords, icon: fieldtype.icon}; }); if (this.allowDate) options.unshift({text: __('Publish Date'), value: 'date', categories: ['system'], isMeta: true, icon: 'date'}); @@ -131,11 +131,14 @@ export default { const fuse = new Fuse(options, { findAllMatches: true, threshold: 0.1, - minMatchCharLength: 2, - keys: ['text'], + keys: [ + {name: 'text', weight: 1}, + {name: 'categories', weight: 0.1}, + {name: 'keywords', weight: 0.4}, + ], }); - options = fuse.search(this.search); + options = fuse.search(this.search).map(result => result.item); } return options; diff --git a/src/Dictionaries/Countries.php b/src/Dictionaries/Countries.php index 651543d473..b0476a43df 100644 --- a/src/Dictionaries/Countries.php +++ b/src/Dictionaries/Countries.php @@ -8,6 +8,7 @@ class Countries extends BasicDictionary { protected string $valueKey = 'iso3'; protected array $searchable = ['name', 'iso3']; + protected array $keywords = ['countries', 'country']; private array $regions; private array $subregions; diff --git a/src/Dictionaries/Currencies.php b/src/Dictionaries/Currencies.php index ba528b07e0..f18918ab1b 100644 --- a/src/Dictionaries/Currencies.php +++ b/src/Dictionaries/Currencies.php @@ -5,6 +5,7 @@ class Currencies extends BasicDictionary { protected string $valueKey = 'code'; + protected array $keywords = ['currencies', 'currency', 'money', 'dollar']; protected function getItemLabel(array $item): string { diff --git a/src/Dictionaries/Dictionary.php b/src/Dictionaries/Dictionary.php index dd704bc380..269b00d04f 100644 --- a/src/Dictionaries/Dictionary.php +++ b/src/Dictionaries/Dictionary.php @@ -15,6 +15,7 @@ abstract class Dictionary protected array $fields = []; protected array $config = []; + protected array $keywords = []; abstract public function options(?string $search = null): array; @@ -75,4 +76,9 @@ public function optionItems(?string $search = null): array ->map(fn ($label, $value) => new Item($value, $label, $this->get($value)->extra())) ->all(); } + + public function keywords(): array + { + return $this->keywords; + } } diff --git a/src/Dictionaries/File.php b/src/Dictionaries/File.php index 57bdc173b6..62765f74b9 100644 --- a/src/Dictionaries/File.php +++ b/src/Dictionaries/File.php @@ -7,6 +7,8 @@ class File extends BasicDictionary { + protected array $keywords = ['files', 'file', 'json', 'csv', 'yaml', 'yml']; + protected function fieldItems() { return [ diff --git a/src/Dictionaries/Timezones.php b/src/Dictionaries/Timezones.php index 8a4e9420d0..d333633b54 100644 --- a/src/Dictionaries/Timezones.php +++ b/src/Dictionaries/Timezones.php @@ -8,6 +8,7 @@ class Timezones extends BasicDictionary { protected string $valueKey = 'name'; + protected array $keywords = ['timezone', 'tz', 'zone', 'time', 'date']; protected function getItemLabel(array $item): string { diff --git a/src/Fields/Fieldtype.php b/src/Fields/Fieldtype.php index bdf18fa9ba..7fd86d79bf 100644 --- a/src/Fields/Fieldtype.php +++ b/src/Fields/Fieldtype.php @@ -29,6 +29,7 @@ abstract class Fieldtype implements Arrayable protected $selectableInForms = false; protected $relationship = false; protected $categories = []; + protected $keywords = []; protected $rules = []; protected $extraRules = []; protected $defaultValue; @@ -113,6 +114,11 @@ public function categories(): array return $this->categories; } + public function keywords(): array + { + return $this->keywords; + } + public function filter() { return new FieldtypeFilter($this); @@ -167,6 +173,7 @@ public function toArray(): array 'validatable' => $this->validatable(), 'defaultable' => $this->defaultable(), 'categories' => $this->categories(), + 'keywords' => $this->keywords(), 'icon' => $this->icon(), 'config' => $this->configFields()->toPublishArray(), ]; diff --git a/src/Fieldtypes/Assets/Assets.php b/src/Fieldtypes/Assets/Assets.php index f44d58b305..e60f1b31cb 100644 --- a/src/Fieldtypes/Assets/Assets.php +++ b/src/Fieldtypes/Assets/Assets.php @@ -24,6 +24,7 @@ class Assets extends Fieldtype { protected $categories = ['media', 'relationship']; + protected $keywords = ['file', 'files', 'image', 'images', 'video', 'videos', 'audio', 'upload']; protected $selectableInForms = true; protected function configFieldItems(): array diff --git a/src/Fieldtypes/Bard.php b/src/Fieldtypes/Bard.php index 13dd1ed1c8..ab8b2f958c 100644 --- a/src/Fieldtypes/Bard.php +++ b/src/Fieldtypes/Bard.php @@ -38,6 +38,7 @@ class Bard extends Replicator ]; protected $categories = ['text', 'structured']; + protected $keywords = ['rich', 'richtext', 'rich text', 'editor', 'wysiwg', 'builder', 'page builder', 'gutenberg', 'content']; protected $rules = []; protected function configFieldItems(): array diff --git a/src/Fieldtypes/Collections.php b/src/Fieldtypes/Collections.php index 4cbc6bc85b..8f8754b634 100644 --- a/src/Fieldtypes/Collections.php +++ b/src/Fieldtypes/Collections.php @@ -10,6 +10,7 @@ class Collections extends Relationship { protected $categories = ['relationship']; + protected $keywords = ['entries']; protected $canEdit = false; protected $canCreate = false; protected $canSearch = false; diff --git a/src/Fieldtypes/Color.php b/src/Fieldtypes/Color.php index b67325930e..aed0956f72 100644 --- a/src/Fieldtypes/Color.php +++ b/src/Fieldtypes/Color.php @@ -7,6 +7,7 @@ class Color extends Fieldtype { protected $categories = ['special']; + protected $keywords = ['rgb', 'hex', 'colour']; protected function configFieldItems(): array { diff --git a/src/Fieldtypes/Date.php b/src/Fieldtypes/Date.php index c362a4bb58..d9aba7a16c 100644 --- a/src/Fieldtypes/Date.php +++ b/src/Fieldtypes/Date.php @@ -18,6 +18,7 @@ class Date extends Fieldtype { protected $categories = ['special']; + protected $keywords = ['datetime', 'time']; const DEFAULT_DATE_FORMAT = 'Y-m-d'; const DEFAULT_DATETIME_FORMAT = 'Y-m-d H:i'; diff --git a/src/Fieldtypes/Dictionary.php b/src/Fieldtypes/Dictionary.php index 5d7bbcddae..c74cf9b564 100644 --- a/src/Fieldtypes/Dictionary.php +++ b/src/Fieldtypes/Dictionary.php @@ -170,4 +170,15 @@ public function addGqlTypes() { GraphQL::addType($this->dictionary()->getGqlType()); } + + public function keywords(): array + { + return \Statamic\Facades\Dictionary::all() + ->flatMap(fn ($dictionary) => [ + str($dictionary->handle())->replace('_', ' ')->toString(), + ...$dictionary->keywords(), + ]) + ->merge(['select', 'option', 'choice', 'dropdown', 'list']) + ->unique()->values()->all(); + } } diff --git a/src/Fieldtypes/Entries.php b/src/Fieldtypes/Entries.php index 48b2795c9d..cae2ffc025 100644 --- a/src/Fieldtypes/Entries.php +++ b/src/Fieldtypes/Entries.php @@ -32,6 +32,7 @@ class Entries extends Relationship use QueriesFilters; protected $categories = ['relationship']; + protected $keywords = ['entry']; protected $canEdit = true; protected $canCreate = true; protected $canSearch = true; diff --git a/src/Fieldtypes/Markdown.php b/src/Fieldtypes/Markdown.php index 19d8df30e6..4acc544a94 100644 --- a/src/Fieldtypes/Markdown.php +++ b/src/Fieldtypes/Markdown.php @@ -10,6 +10,7 @@ class Markdown extends Fieldtype { protected $categories = ['text']; + protected $keywords = ['md', 'content', 'html']; use Concerns\ResolvesStatamicUrls; diff --git a/src/Fieldtypes/Replicator.php b/src/Fieldtypes/Replicator.php index 96f06fb69a..117ec1f5ee 100644 --- a/src/Fieldtypes/Replicator.php +++ b/src/Fieldtypes/Replicator.php @@ -17,6 +17,7 @@ class Replicator extends Fieldtype { protected $categories = ['structured']; + protected $keywords = ['builder', 'page builder', 'content']; protected $rules = ['array']; protected function configFieldItems(): array diff --git a/src/Fieldtypes/Select.php b/src/Fieldtypes/Select.php index dc3b215a85..55813533f5 100644 --- a/src/Fieldtypes/Select.php +++ b/src/Fieldtypes/Select.php @@ -9,6 +9,7 @@ class Select extends Fieldtype use HasSelectOptions; protected $categories = ['controls']; + protected $keywords = ['select', 'option', 'choice', 'dropdown', 'list']; protected $selectableInForms = true; protected $indexComponent = 'tags'; diff --git a/src/Fieldtypes/Toggle.php b/src/Fieldtypes/Toggle.php index 5198040ac7..a689de319d 100644 --- a/src/Fieldtypes/Toggle.php +++ b/src/Fieldtypes/Toggle.php @@ -9,6 +9,7 @@ class Toggle extends Fieldtype { protected $categories = ['controls']; + protected $keywords = ['checkbox', 'bool', 'boolean']; protected $selectableInForms = true; protected $defaultValue = false; diff --git a/src/Fieldtypes/Yaml.php b/src/Fieldtypes/Yaml.php index 3079d68fb9..facbb4e866 100644 --- a/src/Fieldtypes/Yaml.php +++ b/src/Fieldtypes/Yaml.php @@ -9,6 +9,7 @@ class Yaml extends Fieldtype { protected $categories = ['special']; + protected $keywords = ['yml']; protected function configFieldItems(): array { diff --git a/tests/Fields/FieldtypeTest.php b/tests/Fields/FieldtypeTest.php index 730942b2bc..8ff3ca73e8 100644 --- a/tests/Fields/FieldtypeTest.php +++ b/tests/Fields/FieldtypeTest.php @@ -157,6 +157,7 @@ public function converts_to_an_array() 'validatable' => true, 'defaultable' => true, 'categories' => [], + 'keywords' => [], 'icon' => 'test', 'config' => [], ], $fieldtype->toArray());