diff --git a/src/browser/modules/DBMSInfo/DBMSInfo.tsx b/src/browser/modules/DBMSInfo/DBMSInfo.tsx index 39cbf33c98d..50ae64085fa 100644 --- a/src/browser/modules/DBMSInfo/DBMSInfo.tsx +++ b/src/browser/modules/DBMSInfo/DBMSInfo.tsx @@ -42,7 +42,8 @@ import { forceCount, getCountAutomaticRefreshLoading, getCountAutomaticRefreshEnabled, - getUniqueDatbases + getUniqueDatabases, + getAliases } from 'shared/modules/dbMeta/dbMetaDuck' import { getGraphStyleData } from 'shared/modules/grass/grassDuck' import { Button } from '@neo4j-ndl/react' @@ -73,7 +74,14 @@ export function DBMSInfo(props: any): JSX.Element { nodes, relationships } = props.meta - const { user, onItemClick, onDbSelect, useDb, uniqueDatabases = [] } = props + const { + user, + onItemClick, + onDbSelect, + useDb, + uniqueDatabases = [], + aliases + } = props return ( @@ -81,6 +89,7 @@ export function DBMSInfo(props: any): JSX.Element { @@ -141,7 +150,8 @@ const mapStateToProps = (state: any) => { const countAutoRefreshing = getCountAutomaticRefreshEnabled(state) const countLoading = getCountAutomaticRefreshLoading(state) - const uniqueDatabases = getUniqueDatbases(state) + const uniqueDatabases = getUniqueDatabases(state) + const aliases = getAliases(state) return { graphStyleData: getGraphStyleData(state), @@ -149,6 +159,7 @@ const mapStateToProps = (state: any) => { user: getCurrentUser(state), useDb, uniqueDatabases, + aliases, countAutoRefreshing, countLoading } diff --git a/src/browser/modules/DBMSInfo/DatabaseSelector.tsx b/src/browser/modules/DBMSInfo/DatabaseSelector.tsx index 9939c4d1a65..55848da2fe7 100644 --- a/src/browser/modules/DBMSInfo/DatabaseSelector.tsx +++ b/src/browser/modules/DBMSInfo/DatabaseSelector.tsx @@ -26,7 +26,7 @@ import { DrawerSubHeader } from 'browser-components/drawer/drawer-styled' import { escapeCypherIdentifier } from 'services/utils' -import { Database } from 'shared/modules/dbMeta/dbMetaDuck' +import { Alias, Database } from 'shared/modules/dbMeta/dbMetaDuck' const Select = styled.select` width: 100%; @@ -43,10 +43,12 @@ type DatabaseSelectorProps = { uniqueDatabases?: Database[] selectedDb: string onChange?: (dbName: string) => void + aliases: Alias[] } export const DatabaseSelector = ({ uniqueDatabases = [], selectedDb, + aliases, onChange = () => undefined }: DatabaseSelectorProps): JSX.Element | null => { if (uniqueDatabases.length === 0) { @@ -64,15 +66,23 @@ export const DatabaseSelector = ({ uniqueDatabases.find(db => db.home) || uniqueDatabases.find(db => db.default) - const aliasList = uniqueDatabases.flatMap(db => - db.aliases - ? db.aliases.map(alias => ({ - databaseName: db.name, - name: alias, - status: db.status - })) - : [] - ) + const aliasList = aliases.flatMap(alias => { + const aliasedDb = uniqueDatabases.find(db => db.name === alias.database) + + // Don't show composite aliases since they can't be queried directly + if (alias.composite) { + return [] + } + + if (aliasedDb === undefined) { + return [] + } + + return { + name: alias.name, + status: aliasedDb.status + } + }) const databasesAndAliases = [...aliasList, ...uniqueDatabases].sort((a, b) => a.name.localeCompare(b.name) diff --git a/src/shared/modules/dbMeta/dbMetaDuck.ts b/src/shared/modules/dbMeta/dbMetaDuck.ts index 395ee158db5..1746b3af7c8 100644 --- a/src/shared/modules/dbMeta/dbMetaDuck.ts +++ b/src/shared/modules/dbMeta/dbMetaDuck.ts @@ -206,6 +206,7 @@ export const initialState = { storeSize: null }, databases: [], + aliases: null, serverConfigDone: false, settings: initialClientSettings, countAutomaticRefresh: { @@ -229,6 +230,14 @@ export type Database = { status: string } +export const ALIAS_COMPOSITE_FIELD_FIRST_VERSION = '5.11.0' +export type Alias = { + name: string + database: string + location: string + composite?: boolean // introduced in neo4j 5.11 +} + // Selectors export function findDatabaseByNameOrAlias( state: GlobalState, @@ -249,7 +258,7 @@ export function findDatabaseByNameOrAlias( ) } -export function getUniqueDatbases(state: GlobalState): Database[] { +export function getUniqueDatabases(state: GlobalState): Database[] { const uniqueDatabaseNames = uniq( state[NAME].databases.map((db: Database) => db.name) ) @@ -335,6 +344,10 @@ export const getMetricsPrefix = (state: GlobalState): string => export const getDatabases = (state: any): Database[] => (state[NAME] || initialState).databases + +export const getAliases = (state: any): null | Alias[] => + (state[NAME] || initialState).aliases + export const getActiveDbName = (state: any) => ((state[NAME] || {}).settings || {})['dbms.active_database'] diff --git a/src/shared/modules/dbMeta/dbMetaEpics.ts b/src/shared/modules/dbMeta/dbMetaEpics.ts index 3bfeaf7472f..144422ae23a 100644 --- a/src/shared/modules/dbMeta/dbMetaEpics.ts +++ b/src/shared/modules/dbMeta/dbMetaEpics.ts @@ -135,6 +135,27 @@ async function databaseList(store: any) { } catch {} } +async function aliasList(store: any) { + try { + const hasMultidb = supportsMultiDb(store.getState()) + if (!hasMultidb) { + return + } + + const res = await bolt.backgroundWorkerlessRoutedRead( + 'SHOW ALIASES FOR DATABASE', + { useDb: SYSTEM_DB }, + store + ) + + if (!res) return + + const aliases = res.records.map((record: any) => record.toObject()) + + store.dispatch(update({ aliases })) + } catch {} +} + async function getLabelsAndTypes(store: any) { const db = getCurrentDatabase(store.getState()) @@ -395,7 +416,8 @@ async function pollDbMeta(store: any) { await Promise.all([ getFunctionsAndProcedures(store), clusterRole(store), - databaseList(store) + databaseList(store), + aliasList(store) ]) }