Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ describe('Indexes Component', function () {
},
],
usageCount: 20,
buildProgress: 0,
},
],
inProgressIndexes: [
Expand All @@ -203,6 +204,7 @@ describe('Indexes Component', function () {
},
],
status: 'inprogress',
buildProgress: 0,
},
],
error: undefined,
Expand Down Expand Up @@ -245,6 +247,7 @@ describe('Indexes Component', function () {
},
],
usageCount: 20,
buildProgress: 0,
},
],
inProgressIndexes: [
Expand All @@ -259,6 +262,7 @@ describe('Indexes Component', function () {
],
status: 'failed',
error: 'Error message',
buildProgress: 0,
},
],
error: undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ describe('IndexActions Component', function () {
index={{
name: 'artist_id_index',
status: 'inprogress',
buildProgress: 0,
}}
onDeleteFailedIndexClick={onDeleteSpy}
/>
Expand All @@ -41,6 +42,7 @@ describe('IndexActions Component', function () {
index={{
name: 'artist_id_index',
status: 'failed',
buildProgress: 0,
}}
onDeleteFailedIndexClick={onDeleteSpy}
/>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
import React, { useCallback, useMemo } from 'react';
import type { GroupedItemAction } from '@mongodb-js/compass-components';
import { ItemActionGroup } from '@mongodb-js/compass-components';
import { ItemActionGroup, css, spacing } from '@mongodb-js/compass-components';
import type { InProgressIndex } from '../../modules/regular-indexes';

type Index = {
name: string;
status: InProgressIndex['status'];
buildProgress: number;
};

const indexActionsContainerStyles = css({
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
gap: spacing[200],
});

type IndexActionsProps = {
index: Index;
onDeleteFailedIndexClick: (name: string) => void;
Expand Down Expand Up @@ -44,11 +52,13 @@ const IndexActions: React.FunctionComponent<IndexActionsProps> = ({
);

return (
<ItemActionGroup<IndexAction>
data-testid="index-actions"
actions={indexActions}
onAction={onAction}
></ItemActionGroup>
<div className={indexActionsContainerStyles}>
<ItemActionGroup<IndexAction>
data-testid="index-actions"
actions={indexActions}
onAction={onAction}
/>
</div>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,20 @@ import { spy } from 'sinon';
import type { SinonSpy } from 'sinon';

import RegularIndexActions from './regular-index-actions';
import type { RegularIndex } from '../../modules/regular-indexes';

const commonIndexProperties: RegularIndex = {
name: 'artist_id_index',
type: 'regular',
cardinality: 'compound',
properties: [],
fields: [],
extra: {},
size: 0,
relativeSize: 0,
usageCount: 0,
buildProgress: 0,
};

describe('IndexActions Component', function () {
let onDeleteSpy: SinonSpy;
Expand All @@ -24,10 +38,100 @@ describe('IndexActions Component', function () {
onUnhideIndexSpy = spy();
});

describe('build progress display', function () {
it('does not display progress percentage when buildProgress is 0', function () {
render(
<RegularIndexActions
index={{
...commonIndexProperties,
name: 'test_index',
buildProgress: 0,
}}
serverVersion={'4.4.0'}
onDeleteIndexClick={onDeleteSpy}
onHideIndexClick={onHideIndexSpy}
onUnhideIndexClick={onUnhideIndexSpy}
/>
);

// Should not show building spinner or percentage
expect(() => screen.getByTestId('index-building-spinner')).to.throw;
expect(() => screen.getByText(/Building\.\.\. \d+%/)).to.throw;
});

it('displays progress percentage when buildProgress is 50% (0.5)', function () {
render(
<RegularIndexActions
index={{
...commonIndexProperties,
name: 'test_index',
buildProgress: 0.5,
}}
serverVersion={'4.4.0'}
onDeleteIndexClick={onDeleteSpy}
onHideIndexClick={onHideIndexSpy}
onUnhideIndexClick={onUnhideIndexSpy}
/>
);

// Should show building spinner and percentage
const buildingSpinner = screen.getByTestId('index-building-spinner');
expect(buildingSpinner).to.exist;

const progressText = screen.getByText('Building... 50%');
expect(progressText).to.exist;
});

it('does not display progress percentage when buildProgress is 100% (1.0)', function () {
render(
<RegularIndexActions
index={{
...commonIndexProperties,
name: 'test_index',
buildProgress: 1.0,
}}
serverVersion={'4.4.0'}
onDeleteIndexClick={onDeleteSpy}
onHideIndexClick={onHideIndexSpy}
onUnhideIndexClick={onUnhideIndexSpy}
/>
);

// Should not show building spinner or percentage when complete
expect(() => screen.getByTestId('index-building-spinner')).to.throw;
expect(() => screen.getByText(/Building\.\.\. \d+%/)).to.throw;
});

it('displays cancel button when index is building', function () {
render(
<RegularIndexActions
index={{
...commonIndexProperties,
name: 'building_index',
buildProgress: 0.3,
}}
serverVersion={'4.4.0'}
onDeleteIndexClick={onDeleteSpy}
onHideIndexClick={onHideIndexSpy}
onUnhideIndexClick={onUnhideIndexSpy}
/>
);

const cancelButton = screen.getByLabelText('Cancel Index building_index');
expect(cancelButton).to.exist;
expect(onDeleteSpy.callCount).to.equal(0);
userEvent.click(cancelButton);
expect(onDeleteSpy.callCount).to.equal(1);
});
});

it('renders delete button for a regular index', function () {
render(
<RegularIndexActions
index={{ name: 'artist_id_index' }}
index={{
...commonIndexProperties,
name: 'artist_id_index',
}}
serverVersion={'4.4.0'}
onDeleteIndexClick={onDeleteSpy}
onHideIndexClick={onHideIndexSpy}
Expand All @@ -52,6 +156,7 @@ describe('IndexActions Component', function () {
render(
<RegularIndexActions
index={{
...commonIndexProperties,
name: 'artist_id_index',
}}
serverVersion={'4.4.0'}
Expand All @@ -75,6 +180,7 @@ describe('IndexActions Component', function () {
render(
<RegularIndexActions
index={{
...commonIndexProperties,
name: 'artist_id_index',
extra: { hidden: true },
}}
Expand Down Expand Up @@ -103,6 +209,7 @@ describe('IndexActions Component', function () {
render(
<RegularIndexActions
index={{
...commonIndexProperties,
name: 'artist_id_index',
extra: { hidden: true },
}}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,22 +1,29 @@
import semver from 'semver';
import React, { useCallback, useMemo } from 'react';
import type { GroupedItemAction } from '@mongodb-js/compass-components';
import { css, ItemActionGroup } from '@mongodb-js/compass-components';
import {
css,
ItemActionGroup,
SpinLoader,
Body,
spacing,
} from '@mongodb-js/compass-components';
import type { RegularIndex } from '../../modules/regular-indexes';

const styles = css({
// Align actions with the end of the table
justifyContent: 'flex-end',
});

type Index = {
name: string;
extra?: {
hidden?: boolean;
};
};
const buildProgressStyles = css({
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
gap: spacing[200],
});

type IndexActionsProps = {
index: Index;
index: RegularIndex;
serverVersion: string;
onDeleteIndexClick: (name: string) => void;
onHideIndexClick: (name: string) => void;
Expand Down Expand Up @@ -44,33 +51,46 @@ const IndexActions: React.FunctionComponent<IndexActionsProps> = ({
}) => {
const indexActions: GroupedItemAction<IndexAction>[] = useMemo(() => {
const actions: GroupedItemAction<IndexAction>[] = [];
const buildProgress = index.buildProgress;
const isBuilding = buildProgress > 0 && buildProgress < 1;

if (serverSupportsHideIndex(serverVersion)) {
actions.push(
index.extra?.hidden
? {
action: 'unhide',
label: `Unhide Index ${index.name}`,
tooltip: `Unhide Index`,
icon: 'Visibility',
}
: {
action: 'hide',
label: `Hide Index ${index.name}`,
tooltip: `Hide Index`,
icon: 'VisibilityOff',
}
);
}
if (isBuilding) {
// partially built
actions.push({
action: 'delete',
label: `Cancel Index ${index.name}`,
icon: 'XWithCircle',
variant: 'destructive',
});
} else {
// completed
if (serverSupportsHideIndex(serverVersion)) {
actions.push(
index.extra?.hidden
? {
action: 'unhide',
label: `Unhide Index ${index.name}`,
tooltip: `Unhide Index`,
icon: 'Visibility',
}
: {
action: 'hide',
label: `Hide Index ${index.name}`,
tooltip: `Hide Index`,
icon: 'VisibilityOff',
}
);
}

actions.push({
action: 'delete',
label: `Drop Index ${index.name}`,
icon: 'Trash',
});
actions.push({
action: 'delete',
label: `Drop Index ${index.name}`,
icon: 'Trash',
});
}

return actions;
}, [index, serverVersion]);
}, [index.name, index.extra?.hidden, index.buildProgress, serverVersion]);

const onAction = useCallback(
(action: IndexAction) => {
Expand All @@ -85,6 +105,21 @@ const IndexActions: React.FunctionComponent<IndexActionsProps> = ({
[onDeleteIndexClick, onHideIndexClick, onUnhideIndexClick, index]
);

const buildProgress = index.buildProgress;
if (buildProgress > 0 && buildProgress < 1) {
return (
<div className={buildProgressStyles} data-testid="index-building-spinner">
<Body>Building... {(buildProgress * 100) | 0}%</Body>
<SpinLoader size={16} title="Index build in progress" />
<ItemActionGroup<IndexAction>
data-testid="index-actions"
actions={indexActions}
onAction={onAction}
/>
</div>
);
}

return (
<ItemActionGroup<IndexAction>
data-testid="index-actions"
Expand Down
Loading
Loading