Skip to content
Open
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
d3ca101
feat(vector-search): allow index creation when no data exists
dantovska Jul 10, 2026
638ce9c
fix(vector-search): reliably detect existing keys for the create inde…
dantovska Jul 10, 2026
39d89a7
fix(vector-search): enable index creation without a prefix in manual …
dantovska Jul 10, 2026
10900ea
refactor(vector-search): lean on backend scan defaults in existing-ke…
dantovska Jul 13, 2026
e5473b2
chore(vector-search): trim comments in create-index flow
dantovska Jul 13, 2026
7080f95
chore(vector-search): restore i18n welcome constants lost in rebase
dantovska Jul 13, 2026
fd14f16
chore(vector-search): trim comments
dantovska Jul 13, 2026
da36ff6
chore(vector-search): add Bulgarian translations for manual index cre…
dantovska Jul 13, 2026
d4ba0f7
fix(vector-search): fall back to browse mode when the keys check fails
dantovska Jul 13, 2026
192e940
fix(vector-search): keep create page mounted during keys re-checks
dantovska Jul 13, 2026
106e410
feat(vector-search): key type selector for manual index creation
dantovska Jul 13, 2026
5a46c92
fix(vector-search): disable view toggle until manual creation has fields
dantovska Jul 13, 2026
160c920
fix(vector-search): show empty command view in manual creation
dantovska Jul 13, 2026
aa4354a
fix(vector-search): detect existing keys on any cluster node
dantovska Jul 13, 2026
32df6e2
fix(vector-search): keep last probe error during silent re-checks
dantovska Jul 13, 2026
17f782c
refactor(vector-search): run the existing-keys probe only on the crea…
dantovska Jul 13, 2026
d11ef7f
refactor(vector-search): simplify keys probe lifecycle to one check p…
dantovska Jul 13, 2026
caf7762
fix(vector-search): treat an incomplete keys scan as inconclusive
dantovska Jul 13, 2026
1056166
perf(vector-search): scan for existing keys only in the browse create…
dantovska Jul 13, 2026
04a5dcd
fix(vector-search): run the keys probe exactly once per page mount
dantovska Jul 14, 2026
eeba2f7
fix(vector-search): re-arm the keys probe when the database changes
dantovska Jul 14, 2026
686989c
fix(vector-search): resolve the keys probe when no instance is connected
dantovska Jul 14, 2026
a5c761c
refactor(vector-search): key the keys probe by the route database id
dantovska Jul 14, 2026
a939755
refactor(vector-search): derive showBrowser inside the create-index p…
dantovska Jul 14, 2026
eb1478c
refactor(vector-search): flatten the keys probe into a plain effect
dantovska Jul 14, 2026
ebf5577
refactor(vector-search): reduce the keys probe to minimal changes ove…
dantovska Jul 14, 2026
5ea9df7
test(vector-search): dedupe create-index page spec
dantovska Jul 14, 2026
96f8b9d
fix(vector-search): fall back to browse mode on failed/ignored keys p…
dantovska Jul 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions redisinsight/ui/src/i18n/locales/bg.json
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,9 @@
"vectorSearch.createIndex.confirmKeyChange.keepEditing": "Продължи редактирането",
"vectorSearch.createIndex.confirmKeyChange.title": "Незапазени промени",
"vectorSearch.createIndex.content.emptyState": "Схемата на индексиране ще се появи тук, след като\nизберете ключ от браузъра вляво.",
"vectorSearch.createIndex.content.emptyStateManual": "Изградете своя индекс за търсене, като ръчно добавите полетата, които искате да индексирате.\nЩе трябва да зададете име на индекса и префикс, за да определите кои ключове да бъдат включени.",
"vectorSearch.createIndex.createDisabledReason": "Изберете ключ и поне едно поле за индексиране.",
"vectorSearch.createIndex.createDisabledReasonManual": "Добавете поне едно поле за индексиране.",
"vectorSearch.createIndex.displayNameFallback": "съществуващи данни",
"vectorSearch.createIndex.footer.cancel": "Отказ",
"vectorSearch.createIndex.footer.createIndex": "Създай индекс",
Expand All @@ -447,6 +449,7 @@
"vectorSearch.createIndex.toolbar.addField": "+ Добави поле",
"vectorSearch.createIndex.toolbar.commandView": "Изглед за напреднали",
"vectorSearch.createIndex.toolbar.indexPrefix": "Префикс на индекса:",
"vectorSearch.createIndex.toolbar.keyType": "Тип на ключа:",
"vectorSearch.createIndex.toolbar.tableView": "Табличен изглед",
"vectorSearch.fallback.getStarted": "Започнете безплатно",
"vectorSearch.fallback.learnMore": "Научете повече",
Expand Down Expand Up @@ -547,10 +550,8 @@
"vectorSearch.list.column.records": "Записи",
"vectorSearch.list.column.terms": "Термини",
"vectorSearch.list.column.types": "Типове на индекс",
"vectorSearch.list.createMenu.checkingKeys": "Проверка за съществуващи ключове…",
"vectorSearch.list.createMenu.create": "+ Създай индекс за търсене",
"vectorSearch.list.createMenu.existingData": "Използвай съществуващи данни",
"vectorSearch.list.createMenu.noKeys": "Няма намерени Hash или JSON ключове във вашата база данни",
"vectorSearch.list.createMenu.sampleData": "Използвай примерни данни",
"vectorSearch.list.delete.cancel": "Запази индекса",
"vectorSearch.list.delete.confirm": "Изтрий индекса",
Expand Down Expand Up @@ -674,7 +675,6 @@
"vectorSearch.versionNotSupported.ctaText": "Създайте безплатна база данни Redis Cloud, за да започнете да използвате тези функционалности.",
"vectorSearch.versionNotSupported.description": "Тази функционалност изисква Redis Search 2.0 или по-нова версия (включена в Redis 6+). По-старите версии на Redis Search не са съвместими с командите, използвани тук.",
"vectorSearch.versionNotSupported.title": "Изисква се Redis Search 2.0+",
"vectorSearch.welcome.checkingKeys": "Проверка за съществуващи ключове…",
"vectorSearch.welcome.feature.fullText.description": "Намирайте и филтрирайте данните си мигновено чрез мощни заявки по ключови думи и полета.",
"vectorSearch.welcome.feature.fullText.title": "Пълнотекстово търсене",
"vectorSearch.welcome.feature.hybrid.description": "Комбинирайте векторно търсене и търсене по ключови думи за по-висока точност и по-добри резултати.",
Expand All @@ -683,11 +683,10 @@
"vectorSearch.welcome.feature.performance.title": "Висока производителност, малко усилия",
"vectorSearch.welcome.feature.vector.description": "Извличайте резултати по смисъл, а не само по думи. Идеално за AI, семантични и припоръчващи приложения.",
"vectorSearch.welcome.feature.vector.title": "Векторно търсене",
"vectorSearch.welcome.noKeysFound": "Не са намерени Hash или JSON ключове във вашата база данни",
"vectorSearch.welcome.subtitle": "Вижте как Redis позволява пълнотекстовото и векторното търсене. Бързо, лесно и ефективно.",
"vectorSearch.welcome.title": "Търсете със скоростта на светлината",
"vectorSearch.welcome.trySampleData": "Опитайте с примерни данни",
"vectorSearch.welcome.useMyDatabase": "Използвайте данни от моята база данни",
"vectorSearch.welcome.useMyDatabase": "Създай индекс",
"whatsNew.button.gotIt": "Разбрах",
"whatsNew.card.comingSoon": "Очаквайте скоро",
"whatsNew.card.locationLabel": "Къде да го намерите:",
Expand Down
9 changes: 4 additions & 5 deletions redisinsight/ui/src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,9 @@
"vectorSearch.createIndex.confirmKeyChange.keepEditing": "Keep editing",
"vectorSearch.createIndex.confirmKeyChange.title": "Unsaved changes",
"vectorSearch.createIndex.content.emptyState": "The indexing schema will appear here once you\nselect a key from the browser on the left.",
"vectorSearch.createIndex.content.emptyStateManual": "Build your search index by manually adding the fields you want to index.\nYou'll need to provide an index name and a prefix to define which keys are included.",
"vectorSearch.createIndex.createDisabledReason": "Select a key and at least one field to index.",
"vectorSearch.createIndex.createDisabledReasonManual": "Add at least one field to index.",
"vectorSearch.createIndex.displayNameFallback": "existing data",
"vectorSearch.createIndex.footer.cancel": "Cancel",
"vectorSearch.createIndex.footer.createIndex": "Create index",
Expand All @@ -447,6 +449,7 @@
"vectorSearch.createIndex.toolbar.addField": "+ Add field",
"vectorSearch.createIndex.toolbar.commandView": "Command view",
"vectorSearch.createIndex.toolbar.indexPrefix": "Index prefix:",
"vectorSearch.createIndex.toolbar.keyType": "Key type:",
"vectorSearch.createIndex.toolbar.tableView": "Table view",
"vectorSearch.fallback.getStarted": "Get started for free",
"vectorSearch.fallback.learnMore": "Learn more",
Expand Down Expand Up @@ -547,10 +550,8 @@
"vectorSearch.list.column.records": "Records",
"vectorSearch.list.column.terms": "Terms",
"vectorSearch.list.column.types": "Index types",
"vectorSearch.list.createMenu.checkingKeys": "Checking for existing keys…",
"vectorSearch.list.createMenu.create": "+ Create search index",
"vectorSearch.list.createMenu.existingData": "Use existing data",
"vectorSearch.list.createMenu.noKeys": "No Hash or JSON keys found in your database",
"vectorSearch.list.createMenu.sampleData": "Use sample data",
"vectorSearch.list.delete.cancel": "Keep index",
"vectorSearch.list.delete.confirm": "Delete index",
Expand Down Expand Up @@ -674,7 +675,6 @@
"vectorSearch.versionNotSupported.ctaText": "Create a free Redis Cloud database to start exploring these capabilities.",
"vectorSearch.versionNotSupported.description": "This page requires Redis Search 2.0 or later (included with Redis 6+). Older versions of Redis Search are not compatible with the commands used here.",
"vectorSearch.versionNotSupported.title": "Redis Search 2.0+ required",
"vectorSearch.welcome.checkingKeys": "Checking for existing keys…",
"vectorSearch.welcome.feature.fullText.description": "Find and filter your data instantly using powerful keyword and field-based queries.",
"vectorSearch.welcome.feature.fullText.title": "Full-text search",
"vectorSearch.welcome.feature.hybrid.description": "Combine vector and keyword search for higher accuracy and more relevant results.",
Expand All @@ -683,11 +683,10 @@
"vectorSearch.welcome.feature.performance.title": "High performance, low effort",
"vectorSearch.welcome.feature.vector.description": "Retrieve results by meaning, not just words. Ideal for AI, semantic, and recommendation apps.",
"vectorSearch.welcome.feature.vector.title": "Vector search",
"vectorSearch.welcome.noKeysFound": "No Hash or JSON keys found in your database",
"vectorSearch.welcome.subtitle": "Discover how Redis enables full-text and vector search. Fast, simple, and production-ready.",
"vectorSearch.welcome.title": "Search your data at in-memory speed",
"vectorSearch.welcome.trySampleData": "Try with sample data",
"vectorSearch.welcome.useMyDatabase": "Use data from my database",
"vectorSearch.welcome.useMyDatabase": "Create index",
"whatsNew.button.gotIt": "Got it",
"whatsNew.card.comingSoon": "Coming soon",
"whatsNew.card.locationLabel": "Where to find it:",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import React from 'react'
import { act } from '@testing-library/react'
import {
fireEvent,
render,
screen,
waitForRiTooltipVisible,
} from 'uiSrc/utils/test-utils'
import { fireEvent, render, screen } from 'uiSrc/utils/test-utils'

import i18n from 'uiSrc/i18n'
import { WelcomeScreen } from './WelcomeScreen'
Expand Down Expand Up @@ -54,6 +48,10 @@ describe('WelcomeScreen', () => {
'welcome-screen--use-my-database-btn',
)
expect(useMyDatabaseBtn).toBeInTheDocument()
expect(useMyDatabaseBtn).toHaveTextContent(
i18n.t('vectorSearch.welcome.useMyDatabase'),
)
expect(useMyDatabaseBtn).toBeEnabled()

const background = screen.getByTestId('welcome-screen--background')
expect(background).toBeInTheDocument()
Expand Down Expand Up @@ -82,26 +80,4 @@ describe('WelcomeScreen', () => {

expect(onUseMyDatabaseClick).toHaveBeenCalledTimes(1)
})

it('should disable secondary button when useMyDatabaseDisabled is provided', async () => {
const onUseMyDatabaseClick = jest.fn()
renderComponent({
onUseMyDatabaseClick,
useMyDatabaseDisabled: { tooltip: 'Feature disabled' },
})

const button = screen.getByTestId('welcome-screen--use-my-database-btn')
expect(button).toBeDisabled()

fireEvent.click(button)
expect(onUseMyDatabaseClick).not.toHaveBeenCalled()

await act(async () => {
fireEvent.focus(button)
})
await waitForRiTooltipVisible()

const tooltipText = screen.getAllByText('Feature disabled')[0]
expect(tooltipText).toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,6 @@ export const Default: Story = {
// eslint-disable-next-line no-alert
onTrySampleDataClick: () => alert('Try with sample data clicked!'),
// eslint-disable-next-line no-alert
onUseMyDatabaseClick: () => alert('Use data from my database clicked!'),
},
}

export const UseMyDatabaseDisabled: Story = {
name: '"Use data from my database" disabled',
args: {
// eslint-disable-next-line no-alert
onTrySampleDataClick: () => alert('Try with sample data clicked!'),
useMyDatabaseDisabled: {
tooltip: "You don't have any data in your database yet",
},
onUseMyDatabaseClick: () => alert('Create index clicked!'),
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
PrimaryButton,
SecondaryButton,
} from 'uiSrc/components/base/forms/buttons'
import { RiTooltip } from 'uiSrc/components/base/tooltip'
import { useTranslation } from 'uiSrc/i18n'

import { getFeatures } from './WelcomeScreen.constants'
Expand All @@ -18,11 +17,8 @@ import * as S from './WelcomeScreen.styles'
export const WelcomeScreen = ({
onTrySampleDataClick,
onUseMyDatabaseClick,
useMyDatabaseDisabled,
}: WelcomeScreenProps) => {
const { t } = useTranslation()
const isUseMyDatabaseDisabled = !!useMyDatabaseDisabled
const useMyDatabaseTooltip = useMyDatabaseDisabled?.tooltip
const features = getFeatures()

return (
Expand Down Expand Up @@ -86,20 +82,14 @@ export const WelcomeScreen = ({
{t('vectorSearch.welcome.trySampleData')}
</PrimaryButton>

<RiTooltip
content={isUseMyDatabaseDisabled ? useMyDatabaseTooltip : null}
anchorClassName="euiToolTip__btn-disabled"
<SecondaryButton
filled
size="l"
onClick={onUseMyDatabaseClick}
data-testid="welcome-screen--use-my-database-btn"
>
<SecondaryButton
filled
size="l"
onClick={onUseMyDatabaseClick}
disabled={isUseMyDatabaseDisabled}
data-testid="welcome-screen--use-my-database-btn"
>
{t('vectorSearch.welcome.useMyDatabase')}
</SecondaryButton>
</RiTooltip>
{t('vectorSearch.welcome.useMyDatabase')}
</SecondaryButton>
</Row>
</S.Content>
</S.ScrollArea>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,9 @@ export interface WelcomeScreenProps {
onTrySampleDataClick?: () => void

/**
* Callback when "Use data from my database" button is clicked.
* Callback when "Create index" button is clicked.
*/
onUseMyDatabaseClick?: () => void

/**
* Disable "Use data from my database" button and show tooltip.
* Tooltip text is required when button is disabled.
*/
useMyDatabaseDisabled?: {
tooltip: string
}
}

export interface Feature {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ export interface CreateIndexPageContextValue {
/** Whether the KeysBrowser panel should be shown (browse mode). */
showBrowser: boolean

/** Whether the index is defined manually (no keys in the database). */
isManualCreation: boolean

/** Pre-selected key from navigation (triggers auto-selection on mount). */
initialKey?: RedisResponseBuffer

Expand Down Expand Up @@ -101,7 +104,7 @@ export interface CreateIndexPageProviderProps {
instanceId: string
mode?: CreateIndexMode
sampleData?: SampleDataContent
showBrowser?: boolean
isManualCreation?: boolean
initialKey?: RedisResponseBuffer
initialKeyType?: RedisearchIndexKeyType
initialPrefix?: string
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export const CreateIndexPageProvider = ({
instanceId,
sampleData,
mode: modeProp,
showBrowser: showBrowserProp = true,
isManualCreation: isManualCreationProp = false,
initialKey: initialKeyProp,
initialKeyType: initialKeyTypeProp,
initialPrefix: initialPrefixProp,
Expand All @@ -70,6 +70,7 @@ export const CreateIndexPageProvider = ({
const { t } = useTranslation()
const mode = modeProp ?? CreateIndexMode.SampleData
const isSampleData = mode === CreateIndexMode.SampleData
const isManualCreation = !isSampleData && isManualCreationProp

const [activeTab, setActiveTab] = useState<CreateIndexTab>(
CreateIndexTab.Table,
Expand Down Expand Up @@ -177,7 +178,7 @@ export const CreateIndexPageProvider = ({
return t('vectorSearch.createIndex.displayNameFallback')
}, [isSampleData, sampleData, t])

const showBrowser = !isSampleData && showBrowserProp
const showBrowser = !isSampleData && !initialKeyProp && !isManualCreation

const selectedFields = useMemo(() => {
if (isSampleData) return fields
Expand Down Expand Up @@ -205,10 +206,12 @@ export const CreateIndexPageProvider = ({
const createDisabledReason = useMemo((): string | null => {
if (isSampleData) return null
if (selectedFields.length === 0)
return t('vectorSearch.createIndex.createDisabledReason')
return isManualCreation
? t('vectorSearch.createIndex.createDisabledReasonManual')
: t('vectorSearch.createIndex.createDisabledReason')
if (indexNameError !== null) return indexNameError
return null
}, [isSampleData, indexNameError, selectedFields, t])
}, [isSampleData, isManualCreation, indexNameError, selectedFields, t])

const isCreateDisabled = createDisabledReason !== null

Expand Down Expand Up @@ -426,6 +429,7 @@ export const CreateIndexPageProvider = ({
setActiveTab: changeActiveTab,
isReadonly,
showBrowser,
isManualCreation,
initialKey: initialKeyProp,
initialKeyType: initialKeyTypeProp,
displayName,
Expand Down Expand Up @@ -461,6 +465,7 @@ export const CreateIndexPageProvider = ({
changeActiveTab,
isReadonly,
showBrowser,
isManualCreation,
initialKeyProp,
initialKeyTypeProp,
displayName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ import { SearchTelemetrySource } from '../../telemetry.constants'
export interface VectorSearchContextValue {
openPickSampleDataModal: (source: SearchTelemetrySource) => void
navigateToExistingDataFlow: (source: SearchTelemetrySource) => void
hasExistingKeys: boolean
hasExistingKeysLoading: boolean
}

export interface VectorSearchProviderProps {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { IndexField } from '../../components/index-details/IndexDetails.types'
import { PickSampleDataModal } from '../../components/pick-sample-data-modal'
import { SampleDataContent } from '../../components/pick-sample-data-modal/PickSampleDataModal.types'
import { useCreateIndexFlow, useHasExistingKeys } from '../../hooks'
import { useCreateIndexFlow } from '../../hooks'
import { CreateIndexMode } from '../../pages/VectorSearchCreateIndexPage/VectorSearchCreateIndexPage.types'
import {
SearchTelemetryCancelStep,
Expand All @@ -31,8 +31,6 @@

const { run: createIndexFlow, loading: createIndexLoading } =
useCreateIndexFlow()
const { hasKeys: hasExistingKeys, loading: hasExistingKeysLoading } =
useHasExistingKeys()

const openPickSampleDataModal = useCallback(
(source: SearchTelemetrySource) => {
Expand Down Expand Up @@ -162,20 +160,13 @@
[history, instanceId],
)

const contextValue = useMemo(
() => ({
openPickSampleDataModal,
navigateToExistingDataFlow,
hasExistingKeys,
hasExistingKeysLoading,
}),
[
openPickSampleDataModal,
navigateToExistingDataFlow,
hasExistingKeys,
hasExistingKeysLoading,
],
[openPickSampleDataModal, navigateToExistingDataFlow],
)

Check warning on line 169 in redisinsight/ui/src/pages/vector-search/context/vector-search/VectorSearchProvider.tsx

View workflow job for this annotation

GitHub Actions / Coverage annotations (🧪 jest-coverage-report-action)

🧾 Statement is not covered

Warning! Not covered statement

return (
<VectorSearchContext.Provider value={contextValue}>
Expand Down
Loading
Loading