diff --git a/package-lock.json b/package-lock.json
index 882d17093..13116ae8c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -121,6 +121,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz",
"integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/code-frame": "^7.29.7",
"@babel/generator": "^7.29.7",
@@ -314,6 +315,7 @@
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz",
"integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=6.9.0"
}
@@ -420,6 +422,7 @@
"node_modules/@emotion/react": {
"version": "11.14.0",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -457,6 +460,7 @@
"node_modules/@emotion/styled": {
"version": "11.14.1",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -1322,6 +1326,7 @@
"node_modules/@mui/icons-material": {
"version": "7.2.0",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.27.6"
},
@@ -1346,6 +1351,7 @@
"node_modules/@mui/material": {
"version": "7.2.0",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.27.6",
"@mui/core-downloads-tracker": "^7.2.0",
@@ -1450,6 +1456,7 @@
"node_modules/@mui/system": {
"version": "7.2.0",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@babel/runtime": "^7.27.6",
"@mui/private-theming": "^7.2.0",
@@ -2987,8 +2994,7 @@
},
"node_modules/@types/aria-query": {
"version": "5.0.4",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
@@ -3169,6 +3175,7 @@
"node_modules/@types/react": {
"version": "18.3.23",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.0.2"
@@ -3303,6 +3310,7 @@
"node_modules/@uppy/core": {
"version": "4.4.7",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@transloadit/prettier-bytes": "^0.3.4",
"@uppy/store-default": "^4.2.0",
@@ -3317,6 +3325,7 @@
"node_modules/@uppy/dashboard": {
"version": "4.3.4",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@transloadit/prettier-bytes": "^0.3.4",
"@uppy/informer": "^4.2.1",
@@ -3338,6 +3347,7 @@
"node_modules/@uppy/drag-drop": {
"version": "4.1.3",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@uppy/utils": "^6.1.4",
"preact": "^10.5.13"
@@ -3360,6 +3370,7 @@
"node_modules/@uppy/progress-bar": {
"version": "4.2.1",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@uppy/utils": "^6.1.1",
"preact": "^10.5.13"
@@ -3493,15 +3504,15 @@
}
},
"node_modules/@vitest/expect": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.6.tgz",
- "integrity": "sha512-1+7q9BtaKzEmO+fmNT3kYvoNn5Y71XWAx2Q5HRim4tTVRQVRv4uJFAQ5FbK0OPUeNP/WmVCpxYxoJdvuHVjzBQ==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.2.7.tgz",
+ "integrity": "sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/chai": "^5.2.2",
- "@vitest/spy": "3.2.6",
- "@vitest/utils": "3.2.6",
+ "@vitest/spy": "3.2.7",
+ "@vitest/utils": "3.2.7",
"chai": "^5.2.0",
"tinyrainbow": "^2.0.0"
},
@@ -3510,13 +3521,13 @@
}
},
"node_modules/@vitest/mocker": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.6.tgz",
- "integrity": "sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.2.7.tgz",
+ "integrity": "sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/spy": "3.2.6",
+ "@vitest/spy": "3.2.7",
"estree-walker": "^3.0.3",
"magic-string": "^0.30.17"
},
@@ -3537,9 +3548,9 @@
}
},
"node_modules/@vitest/pretty-format": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.6.tgz",
- "integrity": "sha512-lb7XXXzmm2h2ASzFnRvQpDo6onT1NmMJA3tkGTWiBFtRJ9lxGY3d3mm/Apt36gej2bkkOVLL/yTOtufDaFa/jA==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.2.7.tgz",
+ "integrity": "sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3550,13 +3561,13 @@
}
},
"node_modules/@vitest/runner": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.6.tgz",
- "integrity": "sha512-HYcoSj1w5tcgUnzoF0HcyaAQjpA1gj9ftUJ7iSJSuipc02jW9gKkigwZbjFldAfYHA1fa8UZVRftdMY5msWM9Q==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.2.7.tgz",
+ "integrity": "sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/utils": "3.2.6",
+ "@vitest/utils": "3.2.7",
"pathe": "^2.0.3",
"strip-literal": "^3.0.0"
},
@@ -3565,13 +3576,13 @@
}
},
"node_modules/@vitest/snapshot": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.6.tgz",
- "integrity": "sha512-H+ZjNTWGpObenh0YnlBctAPnJSI20P81PL8BPzWpx54YXLLTm8hEsWawtcYLMrwvpK48hGxLLbCS+1KRXhsKhw==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.2.7.tgz",
+ "integrity": "sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "3.2.6",
+ "@vitest/pretty-format": "3.2.7",
"magic-string": "^0.30.17",
"pathe": "^2.0.3"
},
@@ -3580,9 +3591,9 @@
}
},
"node_modules/@vitest/spy": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.6.tgz",
- "integrity": "sha512-oq6BbH68WzcWmwtBrU9nqLeaXTR4XwJF7FSLkKEZo4i6eoXcrxjcwSuTvWBIRUTC6VC72nXYunzqgZA+IKdtxg==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.2.7.tgz",
+ "integrity": "sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -3593,13 +3604,13 @@
}
},
"node_modules/@vitest/utils": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.6.tgz",
- "integrity": "sha512-lI23nIs4bnT3T8NIoh+vFaz5s2/DdP0Jgt2jxwgWljvwn82cLJtyi/If+fjFyoLMGIOz0U/fKvWE0d4jsNQEfg==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.2.7.tgz",
+ "integrity": "sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==",
"dev": true,
"license": "MIT",
"dependencies": {
- "@vitest/pretty-format": "3.2.6",
+ "@vitest/pretty-format": "3.2.7",
"loupe": "^3.1.4",
"tinyrainbow": "^2.0.0"
},
@@ -3629,6 +3640,7 @@
"node_modules/acorn": {
"version": "8.15.0",
"license": "MIT",
+ "peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3877,6 +3889,7 @@
"resolved": "https://registry.npmjs.org/axios/-/axios-1.19.0.tgz",
"integrity": "sha512-ht/iuYZXEjFxLH/Hkezgd7m6JKlHHXEUSneaDz8uZe1Gj5QZtCnpyDsckvAiEnT89OEbCLmnte4R4sn7P0EKFw==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"follow-redirects": "^1.16.0",
"form-data": "^4.0.6",
@@ -3974,6 +3987,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.11.12",
"caniuse-lite": "^1.0.30001809",
@@ -4323,7 +4337,7 @@
},
"node_modules/create-collection-form": {
"version": "0.0.0",
- "resolved": "git+ssh://git@github.com/qdrant/create-collection-form.git#07bb75aa55d01ed06797586a165d1543325e89b8",
+ "resolved": "git+ssh://git@github.com/qdrant/create-collection-form.git#df676404330e11e7512711c0ad9bcef65da527e4",
"dependencies": {
"jtd": "^0.1.1"
},
@@ -4333,7 +4347,8 @@
"@mui/icons-material": "^7.0.2",
"@mui/material": "^7.0.2",
"lucide-react": "^0.545.0",
- "prop-types": "^15.8.1"
+ "prop-types": "^15.8.1",
+ "react": "^18.3.1 || ^19.0.0"
}
},
"node_modules/cross-spawn": {
@@ -4366,7 +4381,8 @@
},
"node_modules/csstype": {
"version": "3.1.3",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/d3-array": {
"version": "3.2.4",
@@ -4484,6 +4500,7 @@
"node_modules/d3-selection": {
"version": "3.0.0",
"license": "ISC",
+ "peer": true,
"engines": {
"node": ">=12"
}
@@ -5043,6 +5060,7 @@
"version": "8.57.1",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
@@ -6755,9 +6773,9 @@
"license": "MIT"
},
"node_modules/js-yaml": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz",
- "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==",
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz",
+ "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==",
"funding": [
{
"type": "github",
@@ -6769,6 +6787,7 @@
}
],
"license": "MIT",
+ "peer": true,
"dependencies": {
"argparse": "^2.0.1"
},
@@ -6780,6 +6799,7 @@
"version": "22.1.0",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"abab": "^2.0.6",
"cssstyle": "^3.0.0",
@@ -7225,6 +7245,7 @@
"node_modules/lucide-react": {
"version": "0.545.0",
"license": "ISC",
+ "peer": true,
"peerDependencies": {
"react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
@@ -7232,7 +7253,6 @@
"node_modules/lz-string": {
"version": "1.5.0",
"license": "MIT",
- "peer": true,
"bin": {
"lz-string": "bin/bin.js"
}
@@ -8126,7 +8146,8 @@
},
"node_modules/monaco-editor": {
"version": "0.44.0",
- "license": "MIT"
+ "license": "MIT",
+ "peer": true
},
"node_modules/mri": {
"version": "1.2.0",
@@ -8783,7 +8804,6 @@
"node_modules/pretty-format": {
"version": "27.5.1",
"license": "MIT",
- "peer": true,
"dependencies": {
"ansi-regex": "^5.0.1",
"ansi-styles": "^5.0.0",
@@ -8796,7 +8816,6 @@
"node_modules/pretty-format/node_modules/ansi-styles": {
"version": "5.2.0",
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=10"
},
@@ -8806,8 +8825,7 @@
},
"node_modules/pretty-format/node_modules/react-is": {
"version": "17.0.2",
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/prism-react-renderer": {
"version": "2.4.1",
@@ -8830,6 +8848,7 @@
"node_modules/prop-types": {
"version": "15.8.1",
"license": "MIT",
+ "peer": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -8904,6 +8923,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz",
"integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -8973,6 +8993,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz",
"integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"scheduler": "^0.27.0"
},
@@ -9261,6 +9282,7 @@
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz",
"integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"@types/estree": "1.0.8"
},
@@ -9977,9 +9999,9 @@
}
},
"node_modules/tinyspy": {
- "version": "4.0.4",
- "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.4.tgz",
- "integrity": "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==",
+ "version": "4.0.6",
+ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-4.0.6.tgz",
+ "integrity": "sha512-u8KszXvGfU68hVcZpRHKG28T0krMuv2G5nDhiHaMLen/gIuFEgIJhaJuO69qjnXg5paSrbPMFfx3brNuN8eVSg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -10477,6 +10499,7 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.3.tgz",
"integrity": "sha512-NTKlcQjlAK7MlQoyb6LgaqHc8sso/pVyUJYWMws3jg21uTJw/LddqIFPcPqP6PzpgbIcZyKI85sFE4HBrQDA8A==",
"license": "MIT",
+ "peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
@@ -10642,20 +10665,20 @@
}
},
"node_modules/vitest": {
- "version": "3.2.6",
- "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.6.tgz",
- "integrity": "sha512-xejya+bT/j/+R/AGa1XOfRxLmNUlLtlwjRsFUILF+xHfzElmGcmFydy2gqqIrd62ptIEfwVMofd19uNWD9L7Nw==",
+ "version": "3.2.7",
+ "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.2.7.tgz",
+ "integrity": "sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/chai": "^5.2.2",
- "@vitest/expect": "3.2.6",
- "@vitest/mocker": "3.2.6",
- "@vitest/pretty-format": "^3.2.6",
- "@vitest/runner": "3.2.6",
- "@vitest/snapshot": "3.2.6",
- "@vitest/spy": "3.2.6",
- "@vitest/utils": "3.2.6",
+ "@vitest/expect": "3.2.7",
+ "@vitest/mocker": "3.2.7",
+ "@vitest/pretty-format": "^3.2.7",
+ "@vitest/runner": "3.2.7",
+ "@vitest/snapshot": "3.2.7",
+ "@vitest/spy": "3.2.7",
+ "@vitest/utils": "3.2.7",
"chai": "^5.2.0",
"debug": "^4.4.1",
"expect-type": "^1.2.1",
@@ -10685,8 +10708,8 @@
"@edge-runtime/vm": "*",
"@types/debug": "^4.1.12",
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
- "@vitest/browser": "3.2.6",
- "@vitest/ui": "3.2.6",
+ "@vitest/browser": "3.2.7",
+ "@vitest/ui": "3.2.7",
"happy-dom": "*",
"jsdom": "*"
},
diff --git a/src/components/Points/PayloadIndexDialog.jsx b/src/components/Points/PayloadIndexDialog.jsx
index 04d8de787..33bf79906 100644
--- a/src/components/Points/PayloadIndexDialog.jsx
+++ b/src/components/Points/PayloadIndexDialog.jsx
@@ -18,7 +18,10 @@ import {
TextField,
InputLabel,
FormControl,
+ Collapse,
+ Link,
} from '@mui/material';
+import { ChevronDown, ChevronRight } from 'lucide-react';
import JsonView from '../Common/JsonViewBase';
import { useTheme } from '@mui/material/styles';
import { useJsonViewerTheme } from '../../theme/json-viewer-theme';
@@ -34,14 +37,78 @@ const FIELD_TYPES = ['keyword', 'integer', 'float', 'uuid', 'datetime', 'text',
const TEXT_TOKENIZERS = ['prefix', 'whitespace', 'word', 'multilingual'];
+// Snowball stemmer languages supported by Qdrant.
+const STEMMER_LANGUAGES = [
+ 'none',
+ 'arabic',
+ 'armenian',
+ 'danish',
+ 'dutch',
+ 'english',
+ 'finnish',
+ 'french',
+ 'german',
+ 'greek',
+ 'hungarian',
+ 'italian',
+ 'norwegian',
+ 'portuguese',
+ 'romanian',
+ 'russian',
+ 'spanish',
+ 'swedish',
+ 'tamil',
+ 'turkish',
+];
+
+// Stopword languages supported by Qdrant.
+const STOPWORDS_LANGUAGES = [
+ 'none',
+ 'arabic',
+ 'azerbaijani',
+ 'basque',
+ 'bengali',
+ 'catalan',
+ 'chinese',
+ 'danish',
+ 'dutch',
+ 'english',
+ 'finnish',
+ 'french',
+ 'german',
+ 'greek',
+ 'hebrew',
+ 'hinglish',
+ 'hungarian',
+ 'indonesian',
+ 'italian',
+ 'japanese',
+ 'kazakh',
+ 'nepali',
+ 'norwegian',
+ 'portuguese',
+ 'romanian',
+ 'russian',
+ 'slovene',
+ 'spanish',
+ 'swedish',
+ 'tajik',
+ 'turkish',
+];
+
const DEFAULT_STATE = {
// integer
range: true,
lookup: true,
+ // keyword
+ prefix: false,
// text
tokenizer: 'whitespace',
lowercase: true,
phrase_matching: true,
+ ascii_folding: false,
+ stemmer_language: 'none',
+ stopwords: 'none',
min_token_len: '',
max_token_len: '',
};
@@ -60,16 +127,40 @@ function paramsFromSchema(indexInfo) {
state.range = params.range ?? true;
state.lookup = params.lookup ?? true;
}
+ if (indexInfo?.data_type === 'keyword') {
+ state.prefix = params.prefix ?? false;
+ }
if (indexInfo?.data_type === 'text') {
state.tokenizer = params.tokenizer || 'whitespace';
state.lowercase = params.lowercase ?? true;
state.phrase_matching = params.phrase_matching ?? true;
+ state.ascii_folding = params.ascii_folding ?? false;
+ state.stemmer_language = params.stemmer?.language ?? 'none';
+ state.stopwords = typeof params.stopwords === 'string' ? params.stopwords : 'none';
state.min_token_len = params.min_token_len ?? '';
state.max_token_len = params.max_token_len ?? '';
}
return state;
}
+/**
+ * Whether a text params state uses any of the advanced options (kept collapsed
+ * by default). Used to auto-expand the advanced section when editing an index
+ * that already relies on them, so no active setting stays hidden.
+ *
+ * @param {Object} state - params state
+ * @return {boolean} true when an advanced option is set
+ */
+function hasAdvancedTextParams(state) {
+ return (
+ !!state.ascii_folding ||
+ (state.stemmer_language && state.stemmer_language !== 'none') ||
+ (state.stopwords && state.stopwords !== 'none') ||
+ state.min_token_len !== '' ||
+ state.max_token_len !== ''
+ );
+}
+
const PayloadIndexDialog = ({
open,
onClose,
@@ -88,6 +179,7 @@ const PayloadIndexDialog = ({
const [params, setParams] = useState(DEFAULT_STATE);
const [loading, setLoading] = useState(false);
const [confirmDelete, setConfirmDelete] = useState(false);
+ const [showAdvanced, setShowAdvanced] = useState(false);
const indexInfo = selectedField ? payloadSchema?.[selectedField] : null;
const isEditing = !!indexInfo;
@@ -103,8 +195,11 @@ const PayloadIndexDialog = ({
if (!open) return;
const info = selectedField ? payloadSchema?.[selectedField] : null;
if (info) {
+ const presetParams = paramsFromSchema(info);
setSelectedType(info.data_type);
- setParams(paramsFromSchema(info));
+ setParams(presetParams);
+ // Reveal advanced options up front when the existing index already uses them.
+ setShowAdvanced(info.data_type === 'text' && hasAdvancedTextParams(presetParams));
} else {
const sample =
selectedField && selectedField === fieldName
@@ -112,6 +207,7 @@ const PayloadIndexDialog = ({
: availableFields?.find((field) => field.name === selectedField)?.value;
setSelectedType(suggestFieldType(sample));
setParams(DEFAULT_STATE);
+ setShowAdvanced(false);
}
}, [open, selectedField]);
@@ -126,6 +222,7 @@ const PayloadIndexDialog = ({
setSelectedField(null);
setSelectedType(null);
setParams(DEFAULT_STATE);
+ setShowAdvanced(false);
onClose();
};
@@ -237,6 +334,17 @@ const PayloadIndexDialog = ({
))}
+ {selectedType === 'keyword' && (
+
+ set('prefix', e.target.checked)} size="small" />
+ }
+ label={Prefix matching}
+ />
+
+ )}
+
{selectedType === 'integer' && (
-
+
Phrase matching}
/>
-
- set('min_token_len', e.target.value)}
- inputProps={{ min: 1 }}
- />
- set('max_token_len', e.target.value)}
- inputProps={{ min: 1 }}
- />
-
+
+ setShowAdvanced((prev) => !prev)}
+ sx={{
+ display: 'inline-flex',
+ alignItems: 'center',
+ gap: 0.5,
+ alignSelf: 'flex-start',
+ color: 'text.secondary',
+ }}
+ >
+ {showAdvanced ? : }
+ Advanced options
+
+
+
+
+ set('ascii_folding', e.target.checked)}
+ size="small"
+ />
+ }
+ label={ASCII folding}
+ />
+
+
+ Stemmer
+
+
+
+ Stopwords
+
+
+
+
+ set('min_token_len', e.target.value)}
+ inputProps={{ min: 1 }}
+ />
+ set('max_token_len', e.target.value)}
+ inputProps={{ min: 1 }}
+ />
+
+
+
)}
diff --git a/src/lib/payload-index-helpers.js b/src/lib/payload-index-helpers.js
index f8ad0f300..6d22a962e 100644
--- a/src/lib/payload-index-helpers.js
+++ b/src/lib/payload-index-helpers.js
@@ -25,6 +25,7 @@ export function payloadFieldFormToIndexConfig(fieldName, fieldFormData) {
params.lowercase = fieldFormData?.lowercase ?? true;
params.tokenizer = fieldFormData?.tokenizer || 'whitespace';
params.phrase_matching = fieldFormData?.phrase_matching ?? true;
+ params.ascii_folding = fieldFormData?.ascii_folding ?? false;
const minLength = fieldFormData?.min_token_len;
const maxLength = fieldFormData?.max_token_len;
@@ -37,9 +38,21 @@ export function payloadFieldFormToIndexConfig(fieldName, fieldFormData) {
const value = typeof maxLength === 'number' ? maxLength : parseInt(maxLength, 10);
if (!isNaN(value) && value >= 0) params.max_token_len = value;
}
+
+ const stemmerLanguage = fieldFormData?.stemmer_language;
+ if (stemmerLanguage && stemmerLanguage !== 'none') {
+ params.stemmer = { type: 'snowball', language: stemmerLanguage };
+ }
+
+ const stopwords = fieldFormData?.stopwords;
+ if (stopwords && stopwords !== 'none') {
+ params.stopwords = stopwords;
+ }
} else if (type === 'integer') {
params.range = fieldFormData?.range ?? true;
params.lookup = fieldFormData?.lookup ?? true;
+ } else if (type === 'keyword') {
+ params.prefix = fieldFormData?.prefix ?? false;
}
return { name: fieldName, type, params };
diff --git a/src/lib/tests/payload-index-helpers.test.js b/src/lib/tests/payload-index-helpers.test.js
index 969e680a1..8fd906bab 100644
--- a/src/lib/tests/payload-index-helpers.test.js
+++ b/src/lib/tests/payload-index-helpers.test.js
@@ -8,9 +8,14 @@ import {
import { createPayloadIndexParams } from '../../components/Collections/CreateCollection/create-collection';
describe('payloadFieldFormToIndexConfig', () => {
- it('converts keyword type with no extra params', () => {
+ it('converts keyword type with prefix defaulting to false', () => {
const result = payloadFieldFormToIndexConfig('color', { field_config_enum: 'keyword' });
- expect(result).toEqual({ name: 'color', type: 'keyword', params: {} });
+ expect(result).toEqual({ name: 'color', type: 'keyword', params: { prefix: false } });
+ });
+
+ it('converts keyword type with prefix matching enabled', () => {
+ const result = payloadFieldFormToIndexConfig('color', { field_config_enum: 'keyword', prefix: true });
+ expect(result).toEqual({ name: 'color', type: 'keyword', params: { prefix: true } });
});
it('converts integer type with range and lookup', () => {
@@ -33,6 +38,9 @@ describe('payloadFieldFormToIndexConfig', () => {
lowercase: false,
tokenizer: 'word',
phrase_matching: false,
+ ascii_folding: true,
+ stemmer_language: 'english',
+ stopwords: 'english',
min_token_len: 2,
max_token_len: 10,
});
@@ -43,6 +51,9 @@ describe('payloadFieldFormToIndexConfig', () => {
lowercase: false,
tokenizer: 'word',
phrase_matching: false,
+ ascii_folding: true,
+ stemmer: { type: 'snowball', language: 'english' },
+ stopwords: 'english',
min_token_len: 2,
max_token_len: 10,
},
@@ -55,11 +66,22 @@ describe('payloadFieldFormToIndexConfig', () => {
lowercase: true,
tokenizer: 'whitespace',
phrase_matching: true,
+ ascii_folding: false,
});
expect(result.params.min_token_len).toBeUndefined();
expect(result.params.max_token_len).toBeUndefined();
});
+ it('omits stemmer and stopwords when set to "none"', () => {
+ const result = payloadFieldFormToIndexConfig('body', {
+ field_config_enum: 'text',
+ stemmer_language: 'none',
+ stopwords: 'none',
+ });
+ expect(result.params.stemmer).toBeUndefined();
+ expect(result.params.stopwords).toBeUndefined();
+ });
+
it('ignores blank min/max token length values', () => {
const result = payloadFieldFormToIndexConfig('body', {
field_config_enum: 'text',