Skip to content

Commit

Permalink
feat: [M3-7011] - Add databases to search result queries (#11059)
Browse files Browse the repository at this point in the history
* Add databases to search result queries

* Update getDatabasesDescription

* Added changeset: Databases to search result queries

* Add shouldMakeDBRequests flag for db enabled or not enabled users

* Some cleanup...

* Add TODO note
  • Loading branch information
pmakode-akamai authored Oct 9, 2024
1 parent 194d9d4 commit 7da635d
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 13 deletions.
5 changes: 5 additions & 0 deletions packages/manager/.changeset/pr-11059-added-1728379220045.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@linode/manager": Added
---

Databases to search result queries ([#11059](https://github.com/linode/manager/pull/11059))
Original file line number Diff line number Diff line change
@@ -1,10 +1,3 @@
import { Region } from '@linode/api-v4';
import {
Database,
DatabaseInstance,
DatabaseType,
} from '@linode/api-v4/lib/databases/types';
import { Theme } from '@mui/material/styles';
import * as React from 'react';
import { makeStyles } from 'tss-react/mui';

Expand All @@ -20,6 +13,14 @@ import { convertMegabytesTo } from 'src/utilities/unitConversions';
import { databaseEngineMap } from '../../DatabaseLanding/DatabaseRow';
import { DatabaseStatusDisplay } from '../DatabaseStatusDisplay';

import type { Region } from '@linode/api-v4';
import type {
Database,
DatabaseInstance,
DatabaseType,
} from '@linode/api-v4/lib/databases/types';
import type { Theme } from '@mui/material/styles';

const useStyles = makeStyles()((theme: Theme) => ({
configs: {
fontSize: '0.875rem',
Expand Down
8 changes: 8 additions & 0 deletions packages/manager/src/features/Databases/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ import { useAccount } from 'src/queries/account/account';
import { useDatabaseEnginesQuery } from 'src/queries/databases/databases';
import { isFeatureEnabledV2 } from 'src/utilities/accountCapabilities';

import { databaseEngineMap } from './DatabaseLanding/DatabaseRow';

import type { DatabaseInstance } from '@linode/api-v4';

/**
* A hook to determine if Databases should be visible to the user.
*
Expand Down Expand Up @@ -180,3 +184,7 @@ export const toDatabaseFork = (
}
return fork;
};

export const getDatabasesDescription = (database: DatabaseInstance) => {
return `${databaseEngineMap[database.engine]} v${database.version}`;
};
25 changes: 23 additions & 2 deletions packages/manager/src/features/Search/SearchLanding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Notice } from 'src/components/Notice/Notice';
import { Typography } from 'src/components/Typography';
import { useAPISearch } from 'src/features/Search/useAPISearch';
import { useIsLargeAccount } from 'src/hooks/useIsLargeAccount';
import { useAllDatabasesQuery } from 'src/queries/databases/databases';
import { useAllDomainsQuery } from 'src/queries/domains';
import { useAllFirewallsQuery } from 'src/queries/firewalls';
import { useAllImagesQuery } from 'src/queries/images';
Expand Down Expand Up @@ -42,9 +43,11 @@ import withStoreSearch from './withStoreSearch';

import type { SearchProps } from './withStoreSearch';
import type { RouteComponentProps } from 'react-router-dom';
import { useIsDatabasesEnabled } from '../Databases/utilities';

const displayMap = {
buckets: 'Buckets',
databases: 'Databases',
domains: 'Domains',
firewalls: 'Firewalls',
images: 'Images',
Expand All @@ -63,12 +66,16 @@ export const SearchLanding = (props: SearchLandingProps) => {
const { data: regions } = useRegionsQuery();

const isLargeAccount = useIsLargeAccount();
const { isDatabasesEnabled } = useIsDatabasesEnabled();

// We only want to fetch all entities if we know they
// are not a large account. We do this rather than `!isLargeAccount`
// because we don't want to fetch all entities if isLargeAccount is loading (undefined).
const shouldFetchAllEntities = isLargeAccount === false;

const shouldMakeDBRequests =
shouldFetchAllEntities && Boolean(isDatabasesEnabled);

/*
@TODO OBJ Multicluster:'region' will become required, and the
'cluster' field will be deprecated once the feature is fully rolled out in production.
Expand All @@ -81,6 +88,16 @@ export const SearchLanding = (props: SearchLandingProps) => {
isLoading: areBucketsLoading,
} = useObjectStorageBuckets(shouldFetchAllEntities);

/*
@TODO DBaaS: Change the passed argument to 'shouldFetchAllEntities' and
remove 'isDatabasesEnabled' once DBaaS V2 is fully rolled out.
*/
const {
data: databases,
error: databasesError,
isLoading: areDatabasesLoading,
} = useAllDatabasesQuery(shouldMakeDBRequests);

const {
data: domains,
error: domainsError,
Expand Down Expand Up @@ -186,7 +203,8 @@ export const SearchLanding = (props: SearchLandingProps) => {
regions ?? [],
searchableLinodes ?? [],
nodebalancers ?? [],
firewalls ?? []
firewalls ?? [],
databases ?? []
);
}
}, [
Expand All @@ -204,6 +222,7 @@ export const SearchLanding = (props: SearchLandingProps) => {
nodebalancers,
linodes,
firewalls,
databases,
]);

const getErrorMessage = () => {
Expand All @@ -216,6 +235,7 @@ export const SearchLanding = (props: SearchLandingProps) => {
[nodebalancersError, 'NodeBalancers'],
[kubernetesClustersError, 'Kubernetes'],
[firewallsError, 'Firewalls'],
[databasesError, 'Databases'],
[
objectStorageBuckets && objectStorageBuckets.errors.length > 0,
`Object Storage in ${objectStorageBuckets?.errors
Expand Down Expand Up @@ -250,7 +270,8 @@ export const SearchLanding = (props: SearchLandingProps) => {
areKubernetesClustersLoading ||
areImagesLoading ||
areNodeBalancersLoading ||
areFirewallsLoading;
areFirewallsLoading ||
areDatabasesLoading;

const errorMessage = getErrorMessage();

Expand Down
2 changes: 1 addition & 1 deletion packages/manager/src/features/Search/refinedSearch.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import logicQueryParser from 'logic-query-parser';
import { all, any, equals, isEmpty } from 'ramda';
import searchString from 'search-string';

import { SearchField, SearchableItem } from './search.interfaces';
import type { SearchField, SearchableItem } from './search.interfaces';

export const COMPRESSED_IPV6_REGEX = /^([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,7})?::([0-9A-Fa-f]{1,4}(:[0-9A-Fa-f]{1,4}){0,7})?$/;
const DEFAULT_SEARCH_FIELDS = ['label', 'tags', 'ips'];
Expand Down
2 changes: 2 additions & 0 deletions packages/manager/src/features/Search/search.interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export interface SearchableItem<T = number | string> {

export type SearchableEntityType =
| 'bucket'
| 'database'
| 'domain'
| 'firewall'
| 'image'
Expand All @@ -25,6 +26,7 @@ export type SearchField = 'ips' | 'label' | 'tags' | 'type';

export interface SearchResultsByEntity {
buckets: SearchableItem[];
databases: SearchableItem[];
domains: SearchableItem[];
firewalls: SearchableItem[];
images: SearchableItem[];
Expand Down
3 changes: 3 additions & 0 deletions packages/manager/src/features/Search/utils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ describe('separate results by entity', () => {
expect(results).toHaveProperty('kubernetesClusters');
expect(results).toHaveProperty('buckets');
expect(results).toHaveProperty('firewalls');
expect(results).toHaveProperty('databases');
});

it('the value of each entity type is an array', () => {
Expand All @@ -28,12 +29,14 @@ describe('separate results by entity', () => {
expect(results.kubernetesClusters).toBeInstanceOf(Array);
expect(results.buckets).toBeInstanceOf(Array);
expect(results.firewalls).toBeInstanceOf(Array);
expect(results.databases).toBeInstanceOf(Array);
});

it('returns empty results if there is no data', () => {
const newResults = separateResultsByEntity([]);
expect(newResults).toEqual({
buckets: [],
databases: [],
domains: [],
firewalls: [],
images: [],
Expand Down
2 changes: 2 additions & 0 deletions packages/manager/src/features/Search/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {

export const emptyResults: SearchResultsByEntity = {
buckets: [],
databases: [],
domains: [],
firewalls: [],
images: [],
Expand All @@ -19,6 +20,7 @@ export const separateResultsByEntity = (
): SearchResultsByEntity => {
const separatedResults: SearchResultsByEntity = {
buckets: [],
databases: [],
domains: [],
firewalls: [],
images: [],
Expand Down
12 changes: 10 additions & 2 deletions packages/manager/src/features/Search/withStoreSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { compose, withStateHandlers } from 'recompose';

import {
bucketToSearchableItem,
databaseToSearchableItem,
domainToSearchableItem,
firewallToSearchableItem,
imageToSearchableItem,
Expand All @@ -20,6 +21,7 @@ import type {
SearchableItem,
} from './search.interfaces';
import type {
DatabaseInstance,
Firewall,
Image,
KubernetesCluster,
Expand All @@ -41,7 +43,8 @@ interface HandlerProps {
regions: Region[],
searchableLinodes: SearchableItem<number | string>[],
nodebalancers: NodeBalancer[],
firewalls: Firewall[]
firewalls: Firewall[],
databases: DatabaseInstance[]
) => SearchResults;
}
export interface SearchProps extends HandlerProps {
Expand Down Expand Up @@ -88,7 +91,8 @@ export default () => (Component: React.ComponentType<any>) => {
regions: Region[],
searchableLinodes: SearchableItem<number | string>[],
nodebalancers: NodeBalancer[],
firewalls: Firewall[]
firewalls: Firewall[],
databases: DatabaseInstance[]
) => {
const searchableBuckets = objectStorageBuckets.map((bucket) =>
bucketToSearchableItem(bucket)
Expand All @@ -111,6 +115,9 @@ export default () => (Component: React.ComponentType<any>) => {
const searchableFirewalls = firewalls.map((firewall) =>
firewallToSearchableItem(firewall)
);
const searchableDatabases = databases.map((database) =>
databaseToSearchableItem(database)
);
const results = search(
[
...searchableLinodes,
Expand All @@ -121,6 +128,7 @@ export default () => (Component: React.ComponentType<any>) => {
...searchableClusters,
...searchableNodebalancers,
...searchableFirewalls,
...searchableDatabases,
],
query
);
Expand Down
17 changes: 16 additions & 1 deletion packages/manager/src/features/TopMenu/SearchBar/SearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import { components } from 'react-select';
import { debounce } from 'throttle-debounce';

import EnhancedSelect from 'src/components/EnhancedSelect/Select';
import { useIsDatabasesEnabled } from 'src/features/Databases/utilities';
import { getImageLabelForLinode } from 'src/features/Images/utils';
import { useAPISearch } from 'src/features/Search/useAPISearch';
import withStoreSearch from 'src/features/Search/withStoreSearch';
import { useIsLargeAccount } from 'src/hooks/useIsLargeAccount';
import { useAllDatabasesQuery } from 'src/queries/databases/databases';
import { useAllDomainsQuery } from 'src/queries/domains';
import { useAllFirewallsQuery } from 'src/queries/firewalls';
import { useAllImagesQuery } from 'src/queries/images';
Expand Down Expand Up @@ -86,12 +88,16 @@ const SearchBar = (props: SearchProps) => {
const [apiSearchLoading, setAPILoading] = React.useState<boolean>(false);
const history = useHistory();
const isLargeAccount = useIsLargeAccount(searchActive);
const { isDatabasesEnabled } = useIsDatabasesEnabled();

// Only request things if the search bar is open/active and we
// know if the account is large or not
const shouldMakeRequests =
searchActive && isLargeAccount !== undefined && !isLargeAccount;

const shouldMakeDBRequests =
shouldMakeRequests && Boolean(isDatabasesEnabled);

const { data: regions } = useRegionsQuery();

const { data: objectStorageBuckets } = useObjectStorageBuckets(
Expand All @@ -103,6 +109,13 @@ const SearchBar = (props: SearchProps) => {
const { data: volumes } = useAllVolumesQuery({}, {}, shouldMakeRequests);
const { data: nodebalancers } = useAllNodeBalancersQuery(shouldMakeRequests);
const { data: firewalls } = useAllFirewallsQuery(shouldMakeRequests);

/*
@TODO DBaaS: Change the passed argument to 'shouldMakeRequests' and
remove 'isDatabasesEnabled' once DBaaS V2 is fully rolled out.
*/
const { data: databases } = useAllDatabasesQuery(shouldMakeDBRequests);

const { data: _privateImages, isLoading: imagesLoading } = useAllImagesQuery(
{},
{ is_public: false }, // We want to display private images (i.e., not Debian, Ubuntu, etc. distros)
Expand Down Expand Up @@ -186,7 +199,8 @@ const SearchBar = (props: SearchProps) => {
regions ?? [],
searchableLinodes ?? [],
nodebalancers ?? [],
firewalls ?? []
firewalls ?? [],
databases ?? []
);
}
}, [
Expand All @@ -202,6 +216,7 @@ const SearchBar = (props: SearchProps) => {
regions,
nodebalancers,
firewalls,
databases,
]);

const handleSearchChange = (_searchText: string): void => {
Expand Down
18 changes: 18 additions & 0 deletions packages/manager/src/store/selectors/getSearchEntities.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { getDatabasesDescription } from 'src/features/Databases/utilities';
import { getFirewallDescription } from 'src/features/Firewalls/shared';
import { getDescriptionForCluster } from 'src/features/Kubernetes/kubeUtils';
import { displayType } from 'src/features/Linodes/presentation';
import { getLinodeDescription } from 'src/utilities/getLinodeDescription';
import { readableBytes } from 'src/utilities/unitConversions';

import type {
DatabaseInstance,
Domain,
Firewall,
Image,
Expand Down Expand Up @@ -179,3 +181,19 @@ export const firewallToSearchableItem = (
label: firewall.label,
value: firewall.id,
});

export const databaseToSearchableItem = (
database: DatabaseInstance
): SearchableItem => ({
data: {
created: database.created,
description: getDatabasesDescription(database),
icon: 'database',
path: `/databases/${database.engine}/${database.id}`,
region: database.region,
status: database.status,
},
entityType: 'database',
label: database.label,
value: `${database.engine}/${database.id}`,
});

0 comments on commit 7da635d

Please sign in to comment.