diff --git a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx index 2b8632dc57f..c9287df0b04 100644 --- a/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx +++ b/packages/compass-indexes/src/components/indexes-toolbar/indexes-toolbar.tsx @@ -189,7 +189,9 @@ export const IndexesToolbar: React.FunctionComponent = ({ warnings={['Readonly views may not contain indexes.']} /> ) : ( - !!errorMessage && + !!errorMessage && ( + + ) )} ); diff --git a/packages/compass-indexes/src/components/indexes/indexes.spec.tsx b/packages/compass-indexes/src/components/indexes/indexes.spec.tsx index d1ec4a6b5eb..4706d23a155 100644 --- a/packages/compass-indexes/src/components/indexes/indexes.spec.tsx +++ b/packages/compass-indexes/src/components/indexes/indexes.spec.tsx @@ -95,7 +95,9 @@ describe('Indexes Component', function () { }, }); expect(screen.getByTestId('indexes-toolbar')).to.exist; - // TODO: actually check for the error + expect(screen.getByTestId('indexes-error').textContent).to.equal( + 'Some random error' + ); }); it('renders indexes toolbar when there is a search indexes error', async function () { @@ -200,28 +202,20 @@ describe('Indexes Component', function () { ], usageCount: 20, }, + ], + inProgressIndexes: [ { - key: {}, - ns: 'db.coll', - cardinality: 'single', + id: 'test-inprogress-index', name: 'item', - size: 0, - relativeSize: 0, - type: 'hashed', - extra: { - status: 'inprogress', - }, - properties: [], fields: [ { field: 'item', value: 1, }, ], - usageCount: 0, + status: 'inprogress', }, ], - inProgressIndexes: [], error: undefined, status: 'READY', }, @@ -263,29 +257,21 @@ describe('Indexes Component', function () { ], usageCount: 20, }, + ], + inProgressIndexes: [ { - key: {}, - ns: 'db.coll', - cardinality: 'single', + id: 'test-inprogress-index', name: 'item', - size: 0, - relativeSize: 0, - type: 'hashed', - extra: { - status: 'failed', - regularError: 'regularError message', - }, - properties: [], fields: [ { field: 'item', value: 1, }, ], - usageCount: 0, + status: 'failed', + error: 'Error message', }, ], - inProgressIndexes: [], error: undefined, status: 'READY', }, diff --git a/packages/compass-indexes/src/components/regular-indexes-table/in-progress-index-actions.spec.tsx b/packages/compass-indexes/src/components/regular-indexes-table/in-progress-index-actions.spec.tsx new file mode 100644 index 00000000000..a9641c189de --- /dev/null +++ b/packages/compass-indexes/src/components/regular-indexes-table/in-progress-index-actions.spec.tsx @@ -0,0 +1,58 @@ +import React from 'react'; +import { + cleanup, + render, + screen, + userEvent, +} from '@mongodb-js/testing-library-compass'; +import { expect } from 'chai'; +import { spy } from 'sinon'; +import type { SinonSpy } from 'sinon'; + +import InProgressIndexActions from './in-progress-index-actions'; + +describe('IndexActions Component', function () { + let onDeleteSpy: SinonSpy; + + before(cleanup); + afterEach(cleanup); + beforeEach(function () { + onDeleteSpy = spy(); + }); + + it('does not render the delete button for an in progress index that is still in progress', function () { + render( + + ); + + const button = screen.queryByTestId('index-actions-delete-action'); + expect(button).to.not.exist; + }); + + it('renders delete button for an in progress index that has failed', function () { + render( + + ); + + const button = screen.getByTestId('index-actions-delete-action'); + expect(button).to.exist; + expect(button.getAttribute('aria-label')).to.equal( + 'Drop Index artist_id_index' + ); + expect(onDeleteSpy.callCount).to.equal(0); + userEvent.click(button); + expect(onDeleteSpy.callCount).to.equal(1); + }); +}); diff --git a/packages/compass-indexes/src/components/regular-indexes-table/in-progress-index-actions.tsx b/packages/compass-indexes/src/components/regular-indexes-table/in-progress-index-actions.tsx new file mode 100644 index 00000000000..1596a1e541c --- /dev/null +++ b/packages/compass-indexes/src/components/regular-indexes-table/in-progress-index-actions.tsx @@ -0,0 +1,55 @@ +import React, { useCallback, useMemo } from 'react'; +import type { GroupedItemAction } from '@mongodb-js/compass-components'; +import { ItemActionGroup } from '@mongodb-js/compass-components'; +import type { InProgressIndex } from '../../modules/regular-indexes'; + +type Index = { + name: string; + status: InProgressIndex['status']; +}; + +type IndexActionsProps = { + index: Index; + onDeleteFailedIndexClick: (name: string) => void; +}; + +type IndexAction = 'delete'; + +const IndexActions: React.FunctionComponent = ({ + index, + onDeleteFailedIndexClick, +}) => { + const indexActions: GroupedItemAction[] = useMemo(() => { + const actions: GroupedItemAction[] = []; + + // you can only drop regular indexes or failed inprogress indexes + if (index.status === 'failed') { + actions.push({ + action: 'delete', + label: `Drop Index ${index.name}`, + icon: 'Trash', + }); + } + + return actions; + }, [index]); + + const onAction = useCallback( + (action: IndexAction) => { + if (action === 'delete') { + onDeleteFailedIndexClick(index.name); + } + }, + [onDeleteFailedIndexClick, index] + ); + + return ( + + data-testid="index-actions" + actions={indexActions} + onAction={onAction} + > + ); +}; + +export default IndexActions; diff --git a/packages/compass-indexes/src/components/regular-indexes-table/index-actions.spec.tsx b/packages/compass-indexes/src/components/regular-indexes-table/index-actions.spec.tsx deleted file mode 100644 index 12c9dd55a8c..00000000000 --- a/packages/compass-indexes/src/components/regular-indexes-table/index-actions.spec.tsx +++ /dev/null @@ -1,94 +0,0 @@ -import React from 'react'; -import { - cleanup, - render, - screen, - userEvent, -} from '@mongodb-js/testing-library-compass'; -import { expect } from 'chai'; -import { spy } from 'sinon'; -import type { SinonSpy } from 'sinon'; - -import IndexActions from './index-actions'; - -describe('IndexActions Component', function () { - let onDeleteSpy: SinonSpy; - let onHideIndexSpy: SinonSpy; - let onUnhideIndexSpy: SinonSpy; - - before(cleanup); - afterEach(cleanup); - beforeEach(function () { - onDeleteSpy = spy(); - onHideIndexSpy = spy(); - onUnhideIndexSpy = spy(); - render( - - ); - }); - - it('renders delete button', function () { - const button = screen.getByTestId('index-actions-delete-action'); - expect(button).to.exist; - expect(button.getAttribute('aria-label')).to.equal( - 'Drop Index artist_id_index' - ); - expect(onDeleteSpy.callCount).to.equal(0); - userEvent.click(button); - expect(onDeleteSpy.callCount).to.equal(1); - }); - - context('when server version is >= 4.4.0', function () { - it('renders hide index button when index is not hidden', function () { - const button = screen.getByTestId('index-actions-hide-action'); - expect(button).to.exist; - expect(button.getAttribute('aria-label')).to.equal( - 'Hide Index artist_id_index' - ); - expect(onHideIndexSpy.callCount).to.equal(0); - userEvent.click(button); - expect(onHideIndexSpy.callCount).to.equal(1); - }); - - it('renders unhide index button when index is hidden', function () { - render( - - ); - const button = screen.getByTestId('index-actions-unhide-action'); - expect(button).to.exist; - expect(button.getAttribute('aria-label')).to.equal( - 'Unhide Index artist_id_index' - ); - expect(onUnhideIndexSpy.callCount).to.equal(0); - userEvent.click(button); - expect(onUnhideIndexSpy.callCount).to.equal(1); - }); - }); - - context('when server version is < 4.4.0', function () { - it('will not render hide index button', function () { - render( - - ); - expect(() => screen.getByTestId('index-actions-hide-action')).to.throw; - }); - }); -}); diff --git a/packages/compass-indexes/src/components/regular-indexes-table/property-field.spec.tsx b/packages/compass-indexes/src/components/regular-indexes-table/property-field.spec.tsx index 4bd91314221..a5fc8596218 100644 --- a/packages/compass-indexes/src/components/regular-indexes-table/property-field.spec.tsx +++ b/packages/compass-indexes/src/components/regular-indexes-table/property-field.spec.tsx @@ -9,6 +9,7 @@ import { expect } from 'chai'; import PropertyField, { getPropertyTooltip } from './property-field'; import getIndexHelpLink from '../../utils/index-link-helper'; +import type { HELP_URL_KEY } from '../../utils/index-link-helper'; describe('PropertyField', function () { before(cleanup); @@ -26,7 +27,8 @@ describe('PropertyField', function () { /> ); - ['ttl', 'partial'].forEach((type) => { + const helpFields = ['ttl', 'partial']; + for (const type of helpFields) { const badge = screen.getByTestId(`${type}-badge`); expect(badge).to.exist; expect(badge.textContent).to.equal(type); @@ -35,9 +37,9 @@ describe('PropertyField', function () { }); expect(infoIcon).to.exist; expect(infoIcon.closest('a')?.href).to.equal( - getIndexHelpLink(type.toUpperCase() as any) + getIndexHelpLink(type.toUpperCase() as HELP_URL_KEY) ); - }); + } }); it('does not render cardinality badge when its single', function () { @@ -69,7 +71,7 @@ describe('PropertyField', function () { render( ); diff --git a/packages/compass-indexes/src/components/regular-indexes-table/property-field.tsx b/packages/compass-indexes/src/components/regular-indexes-table/property-field.tsx index fe29fa9197c..2c09340139e 100644 --- a/packages/compass-indexes/src/components/regular-indexes-table/property-field.tsx +++ b/packages/compass-indexes/src/components/regular-indexes-table/property-field.tsx @@ -10,7 +10,10 @@ import { BadgeVariant, useDarkMode, } from '@mongodb-js/compass-components'; -import type { RegularIndex } from '../../modules/regular-indexes'; +import type { + InProgressIndex, + RegularIndex, +} from '../../modules/regular-indexes'; import BadgeWithIconLink from '../indexes-table/badge-with-icon-link'; const containerStyles = css({ @@ -24,19 +27,23 @@ const partialTooltip = (partialFilterExpression: unknown) => { return `partialFilterExpression: ${JSON.stringify(partialFilterExpression)}`; }; -const ttlTooltip = (expireAfterSeconds: number) => { +const ttlTooltip = (expireAfterSeconds: string) => { return `expireAfterSeconds: ${expireAfterSeconds}`; }; export const getPropertyTooltip = ( - property: string | undefined, + property: string, extra: RegularIndex['extra'] ): string | null => { - return property === 'ttl' - ? ttlTooltip(extra.expireAfterSeconds as number) - : property === 'partial' - ? partialTooltip(extra.partialFilterExpression) - : null; + if (property === 'ttl' && extra.expireAfterSeconds !== undefined) { + return ttlTooltip(extra.expireAfterSeconds as unknown as string); + } + + if (property === 'partial' && extra.partialFilterExpression !== undefined) { + return partialTooltip(extra.partialFilterExpression); + } + + return null; }; const PropertyBadgeWithTooltip: React.FunctionComponent<{ @@ -70,52 +77,59 @@ const ErrorBadgeWithTooltip: React.FunctionComponent<{ }; type PropertyFieldProps = { - extra: RegularIndex['extra']; + cardinality?: RegularIndex['cardinality']; + extra?: RegularIndex['extra']; properties: RegularIndex['properties']; - cardinality: RegularIndex['cardinality']; + + // TODO(COMPASS-8329): these belong in their own column + status?: InProgressIndex['status']; + error?: InProgressIndex['error']; }; const HIDDEN_INDEX_TEXT = 'HIDDEN'; const PropertyField: React.FunctionComponent = ({ + status, extra, properties, cardinality, + error, }) => { const darkMode = useDarkMode(); return (
- {properties?.map((property) => { - return ( - - ); - })} + {extra && + properties?.map((property) => { + return ( + + ); + })} {cardinality === 'compound' && ( )} - {extra.hidden && ( + {extra?.hidden && ( )} - {extra.status === 'inprogress' && ( + {status === 'inprogress' && ( In Progress ... )} - {extra.status === 'failed' && ( + {status === 'failed' && ( )} diff --git a/packages/compass-indexes/src/components/regular-indexes-table/regular-index-actions.spec.tsx b/packages/compass-indexes/src/components/regular-indexes-table/regular-index-actions.spec.tsx new file mode 100644 index 00000000000..f0606d5affa --- /dev/null +++ b/packages/compass-indexes/src/components/regular-indexes-table/regular-index-actions.spec.tsx @@ -0,0 +1,119 @@ +import React from 'react'; +import { + cleanup, + render, + screen, + userEvent, +} from '@mongodb-js/testing-library-compass'; +import { expect } from 'chai'; +import { spy } from 'sinon'; +import type { SinonSpy } from 'sinon'; + +import RegularIndexActions from './regular-index-actions'; + +describe('IndexActions Component', function () { + let onDeleteSpy: SinonSpy; + let onHideIndexSpy: SinonSpy; + let onUnhideIndexSpy: SinonSpy; + + before(cleanup); + afterEach(cleanup); + beforeEach(function () { + onDeleteSpy = spy(); + onHideIndexSpy = spy(); + onUnhideIndexSpy = spy(); + }); + + it('renders delete button for a regular index', function () { + render( + + ); + + const button = screen.getByTestId('index-actions-delete-action'); + expect(button).to.exist; + expect(button.getAttribute('aria-label')).to.equal( + 'Drop Index artist_id_index' + ); + expect(onDeleteSpy.callCount).to.equal(0); + userEvent.click(button); + expect(onDeleteSpy.callCount).to.equal(1); + }); + + context( + 'when server version is >= 4.4.0 and the index is a regular index', + function () { + it('renders hide index button when index is not hidden', function () { + render( + + ); + + const button = screen.getByTestId('index-actions-hide-action'); + expect(button).to.exist; + expect(button.getAttribute('aria-label')).to.equal( + 'Hide Index artist_id_index' + ); + expect(onHideIndexSpy.callCount).to.equal(0); + userEvent.click(button); + expect(onHideIndexSpy.callCount).to.equal(1); + }); + + it('renders unhide index button when index is hidden', function () { + render( + + ); + const button = screen.getByTestId('index-actions-unhide-action'); + expect(button).to.exist; + expect(button.getAttribute('aria-label')).to.equal( + 'Unhide Index artist_id_index' + ); + expect(onUnhideIndexSpy.callCount).to.equal(0); + userEvent.click(button); + expect(onUnhideIndexSpy.callCount).to.equal(1); + }); + } + ); + + context( + 'when server version is < 4.4.0 and the index is a regular index', + function () { + it('will not render hide index button', function () { + render( + + ); + expect(() => screen.getByTestId('index-actions-hide-action')).to.throw; + }); + } + ); +}); diff --git a/packages/compass-indexes/src/components/regular-indexes-table/index-actions.tsx b/packages/compass-indexes/src/components/regular-indexes-table/regular-index-actions.tsx similarity index 87% rename from packages/compass-indexes/src/components/regular-indexes-table/index-actions.tsx rename to packages/compass-indexes/src/components/regular-indexes-table/regular-index-actions.tsx index 93c73a7daa9..7de14ee4c59 100644 --- a/packages/compass-indexes/src/components/regular-indexes-table/index-actions.tsx +++ b/packages/compass-indexes/src/components/regular-indexes-table/regular-index-actions.tsx @@ -2,10 +2,16 @@ import semver from 'semver'; import React, { useCallback, useMemo } from 'react'; import type { GroupedItemAction } from '@mongodb-js/compass-components'; import { ItemActionGroup } from '@mongodb-js/compass-components'; -import type { RegularIndex } from '../../modules/regular-indexes'; + +type Index = { + name: string; + extra?: { + hidden?: boolean; + }; +}; type IndexActionsProps = { - index: RegularIndex; + index: Index; serverVersion: string; onDeleteIndexClick: (name: string) => void; onHideIndexClick: (name: string) => void; @@ -32,16 +38,10 @@ const IndexActions: React.FunctionComponent = ({ onUnhideIndexClick, }) => { const indexActions: GroupedItemAction[] = useMemo(() => { - const actions: GroupedItemAction[] = [ - { - action: 'delete', - label: `Drop Index ${index.name}`, - icon: 'Trash', - }, - ]; + const actions: GroupedItemAction[] = []; if (serverSupportsHideIndex(serverVersion)) { - actions.unshift( + actions.push( index.extra?.hidden ? { action: 'unhide', @@ -58,6 +58,12 @@ const IndexActions: React.FunctionComponent = ({ ); } + actions.push({ + action: 'delete', + label: `Drop Index ${index.name}`, + icon: 'Trash', + }); + return actions; }, [index, serverVersion]); diff --git a/packages/compass-indexes/src/components/regular-indexes-table/regular-indexes-table.spec.tsx b/packages/compass-indexes/src/components/regular-indexes-table/regular-indexes-table.spec.tsx index 4164b1e9e9a..48210c2ac1b 100644 --- a/packages/compass-indexes/src/components/regular-indexes-table/regular-indexes-table.spec.tsx +++ b/packages/compass-indexes/src/components/regular-indexes-table/regular-indexes-table.spec.tsx @@ -9,10 +9,13 @@ import { import { expect } from 'chai'; import { RegularIndexesTable } from './regular-indexes-table'; -import type { RegularIndex } from '../../modules/regular-indexes'; +import type { + RegularIndex, + InProgressIndex, +} from '../../modules/regular-indexes'; import { mockRegularIndex } from '../../../test/helpers'; -const indexes = [ +const indexes: RegularIndex[] = [ { ns: 'db.coll', cardinality: 'single', @@ -97,7 +100,37 @@ const indexes = [ ], usageCount: 25, }, -] as RegularIndex[]; +]; + +const inProgressIndexes: InProgressIndex[] = [ + { + id: 'in-progress-1', + name: 'AAAA', + fields: [ + { + field: 'a', + value: 1, + }, + { + field: 'b', + value: -1, + }, + ], + status: 'inprogress', + }, + { + id: 'in-progress-2', + name: 'z', + fields: [ + { + field: 'z', + value: 'text', + }, + ], + status: 'inprogress', + error: 'this is an error', + }, +]; const renderIndexList = ( props: Partial> = {} @@ -105,12 +138,14 @@ const renderIndexList = ( return render( {}} onUnhideIndexClick={() => {}} onDeleteIndexClick={() => {}} + onDeleteFailedIndexClick={() => {}} onRegularIndexesOpened={() => {}} onRegularIndexesClosed={() => {}} {...props} @@ -118,40 +153,113 @@ const renderIndexList = ( ); }; +const indexFields = [ + 'indexes-name-field', + 'indexes-type-field', + 'indexes-size-field', + 'indexes-usageCount-field', + 'indexes-properties-field', + 'indexes-actions-field', +]; + describe('RegularIndexesTable Component', function () { before(cleanup); afterEach(cleanup); - it('renders indexes list', function () { + it('renders regular indexes', function () { renderIndexList({ isWritable: true, readOnly: false, indexes: indexes }); const indexesList = screen.getByTestId('indexes-list'); expect(indexesList).to.exist; // Renders indexes list (table rows) - indexes.forEach((index) => { - const indexRow = screen.getByText(index.name).closest('tr')!; + for (const index of indexes) { + const indexRow = screen.getByTestId(`indexes-row-${index.name}`); expect(indexRow, 'it renders each index in a row').to.exist; // Renders index fields (table cells) - [ - 'indexes-name-field', - 'indexes-type-field', - 'indexes-size-field', - 'indexes-usage-field', - 'indexes-properties-field', - 'indexes-actions-field', - ].forEach((indexCell) => { - // For _id index we always hide drop index field - if (index.name !== '_id_' && indexCell !== 'indexes-actions-field') { + for (const indexCell of indexFields) { + let mustExist = true; + + // For _id index we always hide hide/drop index field buttons + if (index.name === '_id_' && indexCell === 'indexes-actions-field') { + mustExist = false; + } + + if (mustExist) { expect(within(indexRow).getByTestId(indexCell)).to.exist; } else { expect(() => { within(indexRow).getByTestId(indexCell); }).to.throw; } - }); + } + + if (index.name === '_id_') { + expect(() => { + within(indexRow).getByTestId('index-actions-hide-action'); + }).to.throw; + expect(() => { + within(indexRow).getByTestId('index-actions-delete-action'); + }).to.throw; + } else { + if (index.extra.hidden) { + expect(() => + within(indexRow).getByTestId('index-actions-hide-action') + ).to.throw; + expect(within(indexRow).getByTestId('index-actions-unhide-action')).to + .exist; + } else { + expect(within(indexRow).getByTestId('index-actions-hide-action')).to + .exist; + expect(() => + within(indexRow).getByTestId('index-actions-unhide-action') + ).to.throw; + } + expect(within(indexRow).getByTestId('index-actions-delete-action')).to + .exist; + } + + userEvent.click(within(indexRow).getByLabelText('Expand row')); + const detailsRow = indexRow.nextSibling as HTMLTableRowElement; + expect(detailsRow).to.exist; + + const details = within(detailsRow).getByTestId( + `indexes-details-${index.name}` + ); + expect(details).to.exist; + + for (const field of index.fields) { + expect(within(details).getByTestId(`${field.field}-key`)); + } + } + }); + + it('renders in-progress indexes', function () { + renderIndexList({ + isWritable: true, + readOnly: false, + inProgressIndexes: inProgressIndexes, }); + + for (const index of inProgressIndexes) { + const indexRow = screen.getByTestId(`indexes-row-${index.name}`); + + for (const indexCell of indexFields) { + expect(within(indexRow).getByTestId(indexCell)).to.exist; + } + + expect(() => within(indexRow).getByTestId('index-actions-hide-action')).to + .throw; + if (index.status === 'inprogress') { + expect(() => + within(indexRow).getByTestId('index-actions-delete-action') + ).to.throw; + } else { + expect(within(indexRow).getByTestId('index-actions-delete-action')).to + .exist; + } + } }); it('does not render the list if there is an error', function () { @@ -172,7 +280,7 @@ describe('RegularIndexesTable Component', function () { const indexesList = screen.getByTestId('indexes-list'); expect(indexesList).to.exist; indexes.forEach((index) => { - const indexRow = screen.getByText(index.name).closest('tr')!; + const indexRow = screen.getByTestId(`indexes-row-${index.name}`); expect(within(indexRow).getByTestId('indexes-actions-field')).to.exist; }); }); @@ -182,9 +290,9 @@ describe('RegularIndexesTable Component', function () { const indexesList = screen.getByTestId('indexes-list'); expect(indexesList).to.exist; indexes.forEach((index) => { - const indexRow = screen.getByText(index.name).closest('tr')!; + const indexRow = screen.getByTestId(`indexes-row-${index.name}`); expect(() => { - within(indexRow).getByTestId('indexes-actions-field'); + within(indexRow).queryByTestId('indexes-actions-field'); }).to.throw; }); }); @@ -194,7 +302,7 @@ describe('RegularIndexesTable Component', function () { const indexesList = screen.getByTestId('indexes-list'); expect(indexesList).to.exist; indexes.forEach((index) => { - const indexRow = screen.getByText(index.name).closest('tr')!; + const indexRow = screen.getByTestId(`indexes-row-${index.name}`); expect(() => { within(indexRow).getByTestId('indexes-actions-field'); }).to.throw; @@ -204,7 +312,7 @@ describe('RegularIndexesTable Component', function () { describe('sorting', function () { function getIndexNames() { return screen.getAllByTestId('indexes-name-field').map((el) => { - return el.textContent!.trim(); + return (el.textContent as string).trim(); }); } diff --git a/packages/compass-indexes/src/components/regular-indexes-table/regular-indexes-table.tsx b/packages/compass-indexes/src/components/regular-indexes-table/regular-indexes-table.tsx index 4325f27c3ad..c30158e6fa4 100644 --- a/packages/compass-indexes/src/components/regular-indexes-table/regular-indexes-table.tsx +++ b/packages/compass-indexes/src/components/regular-indexes-table/regular-indexes-table.tsx @@ -15,26 +15,33 @@ import TypeField from './type-field'; import SizeField from './size-field'; import UsageField from './usage-field'; import PropertyField from './property-field'; -import IndexActions from './index-actions'; +import RegularIndexActions from './regular-index-actions'; +import InProgressIndexActions from './in-progress-index-actions'; import { IndexesTable } from '../indexes-table'; import { dropIndex, + dropFailedIndex, hideIndex, unhideIndex, startPollingRegularIndexes, stopPollingRegularIndexes, } from '../../modules/regular-indexes'; -import { type RegularIndex } from '../../modules/regular-indexes'; +import type { + RegularIndex, + InProgressIndex, +} from '../../modules/regular-indexes'; type RegularIndexesTableProps = { indexes: RegularIndex[]; + inProgressIndexes: InProgressIndex[]; serverVersion: string; isWritable?: boolean; onHideIndexClick: (name: string) => void; onUnhideIndexClick: (name: string) => void; onDeleteIndexClick: (name: string) => void; + onDeleteFailedIndexClick: (name: string) => void; readOnly?: boolean; error?: string | null; onRegularIndexesOpened: (tabId: string) => void; @@ -44,20 +51,30 @@ type RegularIndexesTableProps = { type IndexInfo = { id: string; name: string; - indexInfo: RegularIndex; + indexInfo: MergedIndex; type: React.ReactNode; size: React.ReactNode; - usage: React.ReactNode; + usageCount: React.ReactNode; properties: React.ReactNode; actions: undefined | React.ReactNode; renderExpandedContent: React.ReactNode; }; -function sortByProperties(a: RegularIndex, b: RegularIndex) { - const aValue = - a.cardinality === 'compound' ? 'compound' : a.properties?.[0] || ''; - const bValue = - b.cardinality === 'compound' ? 'compound' : b.properties?.[0] || ''; +function mergedIndexPropertyValue(index: MergedIndex): string { + // TODO(COMPASS-8335): right now only regular indexes have properties & + // cardinality + if (index.compassIndexType !== 'regular-index') { + return ''; + } + + return index.cardinality === 'compound' + ? 'compound' + : index.properties?.[0] || ''; +} + +function sortByProperties(a: MergedIndex, b: MergedIndex) { + const aValue = mergedIndexPropertyValue(a); + const bValue = mergedIndexPropertyValue(b); if (aValue > bValue) { return -1; } @@ -67,11 +84,41 @@ function sortByProperties(a: RegularIndex, b: RegularIndex) { return 0; } +type SortableField = 'name' | 'type' | 'size' | 'usageCount'; + +function mergedIndexFieldValue( + index: MergedIndex, + field: SortableField +): string | number | undefined { + if (index.compassIndexType === 'in-progress-index') { + if (field === 'type') { + // TODO(COMPASS-8335): type should be supported by in-progress-index + return 'unknown'; + } + if (field === 'size' || field === 'usageCount') { + return 0; + } + return index[field]; + } + + return index[field]; +} + +function isSupportedSortField( + field: string +): field is 'name' | 'type' | 'size' | 'usageCount' | 'properties' { + return ['name', 'type', 'size', 'usageCount', 'properties'].includes(field); +} + function sortFn( rowA: LeafyGreenTableRow, rowB: LeafyGreenTableRow, field: string ) { + if (!isSupportedSortField(field)) { + return 0; + } + if (field === 'properties') { const propSort = sortByProperties( rowA.original.indexInfo, @@ -80,12 +127,12 @@ function sortFn( return propSort; } - if (field === 'usage') { - field = 'usageCount'; - } + const fieldA = mergedIndexFieldValue(rowA.original.indexInfo, field); + const fieldB = mergedIndexFieldValue(rowB.original.indexInfo, field); - const fieldA = rowA.original.indexInfo[field as keyof RegularIndex]!; - const fieldB = rowB.original.indexInfo[field as keyof RegularIndex]!; + if (fieldA === undefined || fieldB === undefined) { + return 0; + } if (fieldA > fieldB) return -1; if (fieldB > fieldA) return 1; @@ -113,7 +160,7 @@ const COLUMNS: LGColumnDef[] = [ sortingFn: sortFn, }, { - accessorKey: 'usage', + accessorKey: 'usageCount', header: 'Usage', cell: (info) => info.getValue(), sortingFn: sortFn, @@ -140,16 +187,117 @@ const COLUMNS_WITH_ACTIONS: LGColumnDef[] = [ }, ]; +// compassIndexType because type is taken by RegularIndex. indexType is taken by AtlasIndexStats. +type MappedRegularIndex = RegularIndex & { compassIndexType: 'regular-index' }; +type MappedInProgressIndex = InProgressIndex & { + compassIndexType: 'in-progress-index'; +}; + +type MergedIndex = MappedRegularIndex | MappedInProgressIndex; + +function mergeIndexes( + indexes: RegularIndex[], + inProgressIndexes: InProgressIndex[] +): MergedIndex[] { + const mappedIndexes: MappedRegularIndex[] = indexes.map((index) => { + return { ...index, compassIndexType: 'regular-index' }; + }); + + const mappedInProgressIndexes: MappedInProgressIndex[] = + inProgressIndexes.map((index) => { + return { ...index, compassIndexType: 'in-progress-index' }; + }); + + return [...mappedIndexes, ...mappedInProgressIndexes]; +} + +type CommonIndexInfo = Omit; + +function getInProgressIndexInfo( + index: MappedInProgressIndex, + { + onDeleteFailedIndexClick, + }: { + onDeleteFailedIndexClick: (indexName: string) => void; + } +): CommonIndexInfo { + return { + id: index.id, + name: index.name, + indexInfo: index, + type: , + size: , + usageCount: , + properties: ( + + ), + actions: ( + + ), + }; +} + +function getRegularIndexInfo( + index: MappedRegularIndex, + { + serverVersion, + onHideIndexClick, + onUnhideIndexClick, + onDeleteIndexClick, + }: { + serverVersion: string; + onHideIndexClick: (indexName: string) => void; + onUnhideIndexClick: (indexName: string) => void; + onDeleteIndexClick: (indexName: string) => void; + } +): CommonIndexInfo { + return { + id: index.name, + name: index.name, + indexInfo: index, + type: , + size: , + usageCount: ( + + ), + properties: ( + + ), + actions: index.name !== '_id_' && ( + + ), + }; +} + export const RegularIndexesTable: React.FunctionComponent< RegularIndexesTableProps > = ({ isWritable, readOnly, indexes, + inProgressIndexes, serverVersion, onHideIndexClick, onUnhideIndexClick, onDeleteIndexClick, + onDeleteFailedIndexClick, onRegularIndexesOpened, onRegularIndexesClosed, error, @@ -163,44 +311,41 @@ export const RegularIndexesTable: React.FunctionComponent< }; }, [tabId, onRegularIndexesOpened, onRegularIndexesClosed]); + const allIndexes: MergedIndex[] = mergeIndexes(indexes, inProgressIndexes); + const data = useMemo[]>( () => - indexes.map((index) => ({ - id: index.name, - name: index.name, - indexInfo: index, - type: , - size: , - usage: , - properties: ( - - ), - actions: index.name !== '_id_' && - index.extra.status !== 'inprogress' && ( - - ), - - // eslint-disable-next-line react/display-name - renderExpandedContent: () => ( - - ), - })), + allIndexes.map((index) => { + let indexData: CommonIndexInfo; + if (index.compassIndexType === 'in-progress-index') { + indexData = getInProgressIndexInfo(index, { + onDeleteFailedIndexClick, + }); + } else { + indexData = getRegularIndexInfo(index, { + serverVersion, + onDeleteIndexClick, + onHideIndexClick, + onUnhideIndexClick, + }); + } + + return { + ...indexData, + renderExpandedContent() { + return ( + + ); + }, + }; + }), [ - indexes, + allIndexes, onDeleteIndexClick, + onDeleteFailedIndexClick, onHideIndexClick, onUnhideIndexClick, serverVersion, @@ -233,11 +378,13 @@ const mapState = ({ isWritable, serverVersion, indexes: regularIndexes.indexes, + inProgressIndexes: regularIndexes.inProgressIndexes, error: regularIndexes.error, }); const mapDispatch = { onDeleteIndexClick: dropIndex, + onDeleteFailedIndexClick: dropFailedIndex, onHideIndexClick: hideIndex, onUnhideIndexClick: unhideIndex, onRegularIndexesOpened: startPollingRegularIndexes, diff --git a/packages/compass-indexes/src/components/regular-indexes-table/type-field.tsx b/packages/compass-indexes/src/components/regular-indexes-table/type-field.tsx index 851aa92e7d5..b8fd4b81c89 100644 --- a/packages/compass-indexes/src/components/regular-indexes-table/type-field.tsx +++ b/packages/compass-indexes/src/components/regular-indexes-table/type-field.tsx @@ -5,13 +5,16 @@ import { Tooltip, Body } from '@mongodb-js/compass-components'; import type { RegularIndex } from '../../modules/regular-indexes'; import BadgeWithIconLink from '../indexes-table/badge-with-icon-link'; -export const canRenderTooltip = (type: RegularIndex['type']) => { +export const canRenderTooltip = (type: string) => { return ['text', 'wildcard', 'columnstore'].indexOf(type ?? '') !== -1; }; type TypeFieldProps = { - type: RegularIndex['type']; - extra: RegularIndex['extra']; + // TODO(COMPASS-8335): we can remove unknown once we support type on + // in-progress indexes + type: RegularIndex['type'] | 'unknown'; + // in-progress and rolling indexes don't have extra + extra?: RegularIndex['extra']; }; export const IndexTypeTooltip: React.FunctionComponent<{ @@ -45,7 +48,7 @@ const TypeField: React.FunctionComponent = ({ } > - + {extra && } ); }; diff --git a/packages/compass-indexes/src/components/search-index-template-dropdown/index.spec.tsx b/packages/compass-indexes/src/components/search-index-template-dropdown/index.spec.tsx index f398cae55ec..c0498256616 100644 --- a/packages/compass-indexes/src/components/search-index-template-dropdown/index.spec.tsx +++ b/packages/compass-indexes/src/components/search-index-template-dropdown/index.spec.tsx @@ -39,7 +39,7 @@ describe('Search Index Template Dropdown', function () { it('notifies upwards with onTemplate when a new template is chosen', async function () { const dropDown = screen .getByText('Dynamic field mappings') - .closest('button')!; + .closest('button') as HTMLButtonElement; userEvent.click(dropDown); diff --git a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx index ebfd350b258..86cf6bcce31 100644 --- a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx +++ b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.spec.tsx @@ -52,7 +52,9 @@ describe('SearchIndexesTable Component', function () { // Renders indexes list (table rows) for (const index of indexes) { - const indexRow = screen.getByText(index.name).closest('tr')!; + const indexRow = screen + .getByText(index.name) + .closest('tr') as HTMLTableRowElement; expect(indexRow, 'it renders each index in a row').to.exist; // Renders index fields (table cells) @@ -160,7 +162,9 @@ describe('SearchIndexesTable Component', function () { indexes: vectorSearchIndexes, }); - const indexRow = screen.getByText('vectorSearching123').closest('tr')!; + const indexRow = screen + .getByText('vectorSearching123') + .closest('tr') as HTMLTableRowElement; const expandButton = within(indexRow).getByLabelText('Expand row'); expect(expandButton).to.exist; @@ -180,7 +184,7 @@ describe('SearchIndexesTable Component', function () { describe('sorting', function () { function getIndexNames() { return screen.getAllByTestId('search-indexes-name-field').map((el) => { - return el.textContent!.trim(); + return (el.textContent as string).trim(); }); } diff --git a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx index 6285951d677..ef369e8f207 100644 --- a/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx +++ b/packages/compass-indexes/src/components/search-indexes-table/search-indexes-table.tsx @@ -342,19 +342,22 @@ export const SearchIndexesTable: React.FunctionComponent< }} /> ), - // eslint-disable-next-line react/display-name - renderExpandedContent: () => ( -
- {isVectorSearchIndex ? ( - - ) : ( - - )} -
- ), + renderExpandedContent() { + return ( +
+ {isVectorSearchIndex ? ( + + ) : ( + + )} +
+ ); + }, }; }), [ diff --git a/packages/compass-indexes/src/modules/regular-indexes.spec.ts b/packages/compass-indexes/src/modules/regular-indexes.spec.ts index c138e14b411..6fa4cec9632 100644 --- a/packages/compass-indexes/src/modules/regular-indexes.spec.ts +++ b/packages/compass-indexes/src/modules/regular-indexes.spec.ts @@ -4,6 +4,7 @@ import { refreshRegularIndexes, pollRegularIndexes, dropIndex, + dropFailedIndex, hideIndex, unhideIndex, startPollingRegularIndexes, @@ -127,81 +128,6 @@ describe('regular-indexes module', function () { expect(state.status).to.equal('READY'); }); - it('merges with in progress indexes', async function () { - const store = await setupStoreAndWait( - {}, - { - indexes: () => Promise.resolve(indexesList), - } - ); - - Object.assign(store.getState(), { - regularIndexes: { - ...store.getState().regularIndexes, - inProgressIndexes: inProgressIndexes.slice(), - }, - }); - - await store.dispatch(refreshRegularIndexes()); - - const state = store.getState().regularIndexes; - - expect(state.indexes.length).to.equal( - defaultSortedIndexes.length + inProgressIndexes.length - ); - - const indexes = state.indexes.filter( - (index: any) => index.extra.status === 'inprogress' - ); - - expect(indexes).to.deep.equal([ - // NOTE: this one is a real index and an in-progress one - { - cardinality: 'single', - extra: { - status: 'inprogress', - }, - fields: [], - key: { - aaaa: -1, - }, - name: 'AAAA', - ns: 'foo', - properties: ['partial', 'ttl'], - relativeSize: 1, - size: 4096, - type: 'regular', - usageCount: 4, - usageHost: 'computername.local:27017', - usageSince: new Date('2019-02-08T14:39:56.285Z'), - version: 2, - }, - // NOTE: this one is only in progress, not also a real index - { - extra: { - status: 'inprogress', - }, - fields: [ - { - field: 'z', - value: 1, - }, - ], - key: { - z: 1, - }, - name: 'z', - ns: 'citibike.trips', - relativeSize: 0, - size: 0, - usageCount: 0, - }, - ]); - - expect(state.error).to.be.undefined; - expect(state.status).to.equal('READY'); - }); - it('sets status=FETCHING when indexes are being fetched and status is NOT_READY', async function () { let statusBeforeFetch: FetchStatus | undefined = undefined; @@ -359,10 +285,13 @@ describe('regular-indexes module', function () { describe('#dropIndex (thunk)', function () { it('removes a failed in-progress index', async function () { + const dropIndexSpy = sinon.spy(); + const store = await setupStoreAndWait( {}, { indexes: () => Promise.resolve(indexesList), + dropIndex: dropIndexSpy, } ); @@ -374,33 +303,22 @@ describe('regular-indexes module', function () { ..._index, }; if (index.name === 'AAAA') { - index.extra.status = 'failed'; + index.status = 'failed'; } return index; }), }, }); - // fetch first so it merges the in-progress ones - await store.dispatch(refreshRegularIndexes()); - - // one of the real indexes is also in progress, so gets merged together - const numOverlapping = 1; - - // sanity check let state = store.getState().regularIndexes; - expect(state.indexes.length).to.equal( - indexesList.length + inProgressIndexes.length - numOverlapping - ); expect(state.inProgressIndexes.length).to.equal(inProgressIndexes.length); - await store.dispatch(dropIndex('AAAA')); + store.dispatch(dropFailedIndex('AAAA')); + + expect(dropIndexSpy.callCount).to.equal(0); state = store.getState().regularIndexes; - expect(state.indexes.length).to.equal( - indexesList.length + inProgressIndexes.length - 1 - ); expect(state.inProgressIndexes.length).to.equal( inProgressIndexes.length - 1 ); @@ -409,10 +327,13 @@ describe('regular-indexes module', function () { }); it('removes a real index', async function () { + const dropIndexSpy = sinon.spy(); + const store = await setupStoreAndWait( {}, { indexes: () => Promise.resolve(indexesList), + dropIndex: dropIndexSpy, } ); @@ -428,33 +349,15 @@ describe('regular-indexes module', function () { }, }); - // fetch first so it merges the in-progress ones - await store.dispatch(refreshRegularIndexes()); - - // one of the real indexes is also in progress, so gets merged together - const numOverlapping = 1; - - // sanity check - let state = store.getState().regularIndexes; - expect(state.indexes.length).to.equal( - indexesList.length + inProgressIndexes.length - numOverlapping - ); - expect(state.inProgressIndexes.length).to.equal(inProgressIndexes.length); - + expect(dropIndexSpy.callCount).to.equal(0); await store.dispatch(dropIndex('BBBB')); // a real regular index. not in progress - - state = store.getState().regularIndexes; - - expect(state.indexes.length).to.equal( - indexesList.length + inProgressIndexes.length - 1 - ); - expect(state.inProgressIndexes.length).to.equal(inProgressIndexes.length); + expect(dropIndexSpy.args).to.deep.equal([['citibike.trips', 'BBBB']]); }); }); describe('#hideIndex (thunk)', function () { it('hides an index', async function () { - const updateCollection = sinon.stub().resolves({}); + const updateCollection = sinon.spy(); const store = await setupStoreAndWait( {}, { @@ -466,6 +369,7 @@ describe('regular-indexes module', function () { // fetch indexes so there's something to hide await store.dispatch(refreshRegularIndexes()); + expect(updateCollection.callCount).to.equal(0); await store.dispatch(hideIndex('BBBB')); expect(updateCollection.args).to.deep.equal([ diff --git a/packages/compass-indexes/src/modules/regular-indexes.ts b/packages/compass-indexes/src/modules/regular-indexes.ts index 042dc2775a1..0b71b617b97 100644 --- a/packages/compass-indexes/src/modules/regular-indexes.ts +++ b/packages/compass-indexes/src/modules/regular-indexes.ts @@ -1,4 +1,4 @@ -import { cloneDeep, isEqual, pick } from 'lodash'; +import { isEqual, pick } from 'lodash'; import type { IndexDefinition } from 'mongodb-data-service'; import type { AnyAction } from 'redux'; import { @@ -20,35 +20,34 @@ import { import type { IndexSpecification, CreateIndexesOptions } from 'mongodb'; import { hasColumnstoreIndex } from '../utils/columnstore-indexes'; -export type RegularIndex = Omit< - IndexDefinition, - 'type' | 'cardinality' | 'properties' | 'version' -> & - Partial; - -export type InProgressIndex = { +export type RegularIndex = Partial & + Pick< + IndexDefinition, + // These are the only ones we're treating as required because they are the + // ones we use. Everything else is treated as optional. + | 'name' + | 'type' + | 'cardinality' + | 'properties' + | 'fields' + | 'extra' + | 'size' + | 'relativeSize' + | 'usageCount' + >; + +export type InProgressIndex = Pick & { id: string; - key: CreateIndexSpec; - fields: { field: string; value: string | number }[]; - name: string; - ns: string; - size: number; - relativeSize: number; - usageCount: number; - extra: { - status: 'inprogress' | 'failed'; - error?: string; - }; + status: 'inprogress' | 'failed'; + error?: string; }; const prepareInProgressIndex = ( id: string, { - ns, name, spec, }: { - ns: string; name?: string; spec: CreateIndexSpec; } @@ -66,16 +65,13 @@ const prepareInProgressIndex = ( }, ''); return { id, - extra: { - status: 'inprogress', - }, - key: spec, + // TODO(COMPASS-8335): we need the type because it shows in the table + // TODO(COMPASS-8335): the table can also use cardinality + status: 'inprogress', fields: inProgressIndexFields, name: inProgressIndexName, - ns, - size: 0, - relativeSize: 0, - usageCount: 0, + // TODO(COMPASS-8335): we never mapped properties and the table does have + // room to display them }; }; @@ -142,8 +138,8 @@ type FailedIndexRemovedAction = { }; export type State = { - indexes: RegularIndex[]; status: FetchStatus; + indexes: RegularIndex[]; inProgressIndexes: InProgressIndex[]; error?: string; }; @@ -191,16 +187,9 @@ export default function reducer( ActionTypes.FetchIndexesSucceeded ) ) { - // Merge the newly fetched indexes and the existing in-progress ones. - const inProgressIndexes = state.inProgressIndexes; - const allIndexes = _mergeInProgressIndexes( - action.indexes, - cloneDeep(inProgressIndexes) - ); - return { ...state, - indexes: allIndexes, + indexes: action.indexes, status: FetchStatuses.READY, }; } @@ -234,16 +223,9 @@ export default function reducer( action.inProgressIndex, ]; - // Merge the in-progress indexes into the existing indexes. - const allIndexes = _mergeInProgressIndexes( - state.indexes, - cloneDeep(inProgressIndexes) - ); - return { ...state, inProgressIndexes, - indexes: allIndexes, }; } @@ -256,9 +238,6 @@ export default function reducer( ) { return { ...state, - // NOTE: the index is still in indexes because it would have been merged - // in there, so it will only be gone from the list once fetchIndexes() - // is dispatched and finishes. inProgressIndexes: state.inProgressIndexes.filter( (x) => x.id !== action.inProgressIndexId ), @@ -275,23 +254,13 @@ export default function reducer( const newInProgressIndexes = state.inProgressIndexes; newInProgressIndexes[idx] = { ...newInProgressIndexes[idx], - extra: { - ...newInProgressIndexes[idx].extra, - status: 'failed', - error: action.error, - }, + status: 'failed', + error: action.error, }; - // When an inprogress index fails to create, we also have to update it in - // the state.indexes list to correctly update the UI with error state. - const newIndexes = _mergeInProgressIndexes( - state.indexes, - newInProgressIndexes - ); return { ...state, inProgressIndexes: newInProgressIndexes, - indexes: newIndexes, }; } @@ -474,7 +443,6 @@ export function createRegularIndex( ) => { const ns = getState().namespace; const inProgressIndex = prepareInProgressIndex(inProgressIndexId, { - ns, name: options.name, spec, }); @@ -528,36 +496,37 @@ const failedIndexRemoved = ( // its value. This enables to test dropIndex action. export const showConfirmation = showConfirmationModal; +export const dropFailedIndex = ( + indexName: string +): IndexesThunkAction => { + return (dispatch, getState) => { + const { regularIndexes } = getState(); + const { inProgressIndexes } = regularIndexes; + + const inProgressIndex = inProgressIndexes.find((x) => x.name === indexName); + if (inProgressIndex && inProgressIndex.status === 'failed') { + // This really just removes the (failed) in-progress index + dispatch(failedIndexRemoved(String(inProgressIndex.id))); + } + }; +}; + export const dropIndex = ( indexName: string -): IndexesThunkAction< - Promise, - FailedIndexRemovedAction | FetchIndexesActions -> => { +): IndexesThunkAction, FetchIndexesActions> => { return async ( dispatch, getState, { connectionInfoRef, dataService, track } ) => { const { namespace, regularIndexes } = getState(); - const { indexes, inProgressIndexes } = regularIndexes; - const index = indexes.find((x) => x.name === indexName); + const { indexes } = regularIndexes; + const index = indexes.find((x) => x.name === indexName); if (!index) { return; } - const inProgressIndex = inProgressIndexes.find((x) => x.name === indexName); - if (inProgressIndex && inProgressIndex.extra.status === 'failed') { - // This really just removes the (failed) in-progress index - dispatch(failedIndexRemoved(String(inProgressIndex.id))); - - // By fetching the indexes again we make sure the merged list doesn't have - // it either. - await dispatch(fetchIndexes(FetchReasons.REFRESH)); - return; - } - try { const connectionInfo = connectionInfoRef.current; track('Screen', { name: 'drop_index_modal' }, connectionInfo); @@ -658,29 +627,3 @@ export const unhideIndex = ( } }; }; - -function _mergeInProgressIndexes( - _indexes: RegularIndex[], - inProgressIndexes: InProgressIndex[] -) { - const indexes = cloneDeep(_indexes); - - for (const inProgressIndex of inProgressIndexes) { - const index = indexes.find((index) => index.name === inProgressIndex.name); - - if (index) { - index.extra = index.extra ?? {}; - index.extra.status = inProgressIndex.extra.status; - if (inProgressIndex.extra.error) { - index.extra.error = inProgressIndex.extra.error; - } - } else { - // in-progress indexes also have ids which regular indexes don't - const index: RegularIndex = { ...inProgressIndex }; - delete (index as RegularIndex & { id?: any }).id; - indexes.push(index); - } - } - - return indexes; -} diff --git a/packages/compass-indexes/src/utils/index-link-helper.ts b/packages/compass-indexes/src/utils/index-link-helper.ts index 07f88f8f30f..50c896dce7c 100644 --- a/packages/compass-indexes/src/utils/index-link-helper.ts +++ b/packages/compass-indexes/src/utils/index-link-helper.ts @@ -25,7 +25,7 @@ const HELP_URLS = { UNKNOWN: null, }; -type HELP_URL_KEY = +export type HELP_URL_KEY = | Uppercase | Lowercase; diff --git a/packages/compass-indexes/test/fixtures/regular-indexes.ts b/packages/compass-indexes/test/fixtures/regular-indexes.ts index 7c663826ce1..e29bc223a7c 100644 --- a/packages/compass-indexes/test/fixtures/regular-indexes.ts +++ b/packages/compass-indexes/test/fixtures/regular-indexes.ts @@ -242,37 +242,18 @@ export const inProgressIndexes: InProgressIndex[] = [ id: 'in-progress-1', name: 'AAAA', //version: 2, - extra: { - status: 'inprogress', - }, - key: { - aaaa: -1, - }, - usageCount: 4, - size: 4096, - fields: [], - ns: 'foo', - relativeSize: 1, + status: 'inprogress', }, { id: 'in-progress-2', - extra: { - status: 'inprogress', - }, - key: { - z: 1, - }, + name: 'z', fields: [ { field: 'z', value: 1, }, ], - name: 'z', - ns: 'citibike.trips', - size: 0, - relativeSize: 0, - usageCount: 0, + status: 'inprogress', }, ]; diff --git a/packages/compass-indexes/test/helpers.ts b/packages/compass-indexes/test/helpers.ts index 2866bcbe7ba..4857ca8dbee 100644 --- a/packages/compass-indexes/test/helpers.ts +++ b/packages/compass-indexes/test/helpers.ts @@ -5,10 +5,13 @@ export function mockRegularIndex(info: Partial): RegularIndex { return { ns: 'test.test', name: '_id_1', + type: 'regular', key: {}, fields: [], size: 0, relativeSize: 0, + cardinality: 'single', + properties: [], ...info, extra: { ...info.extra, diff --git a/packages/data-service/src/index-detail-helper.ts b/packages/data-service/src/index-detail-helper.ts index 6674319c03d..3264e0b3a49 100644 --- a/packages/data-service/src/index-detail-helper.ts +++ b/packages/data-service/src/index-detail-helper.ts @@ -32,7 +32,7 @@ export type IndexDefinition = { | 'columnstore'; cardinality: 'single' | 'compound'; properties: ('unique' | 'sparse' | 'partial' | 'ttl' | 'collation')[]; - extra: Record>; + extra: Record>; size: IndexSize; relativeSize: number; } & IndexStats;