Skip to content

Commit

Permalink
feat: add sharded state COMPASS-8279 (#6304)
Browse files Browse the repository at this point in the history
  • Loading branch information
paula-stacho authored Oct 9, 2024
1 parent 2c24180 commit 58fb9f5
Show file tree
Hide file tree
Showing 16 changed files with 1,314 additions and 231 deletions.
2 changes: 2 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/compass-global-writes/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@mongodb-js/compass-logging": "^1.4.8",
"@mongodb-js/compass-telemetry": "^1.2.0",
"hadron-app-registry": "^9.2.7",
"lodash": "^4.17.21",
"@mongodb-js/compass-field-store": "^9.18.1",
"mongodb-ns": "^2.4.2",
"react": "^17.0.2",
Expand Down
16 changes: 8 additions & 8 deletions packages/compass-global-writes/src/components/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,25 @@ import { GlobalWrites } from './index';
import { renderWithStore } from './../../tests/create-store';

describe('Compass GlobalWrites Plugin', function () {
it('renders plugin in NOT_READY state', function () {
renderWithStore(<GlobalWrites shardingStatus={'NOT_READY'} />);
it('renders plugin in NOT_READY state', async function () {
await renderWithStore(<GlobalWrites shardingStatus={'NOT_READY'} />);
expect(screen.getByText(/loading/i)).to.exist;
});

it('renders plugin in UNSHARDED state', function () {
renderWithStore(<GlobalWrites shardingStatus={'UNSHARDED'} />);
it('renders plugin in UNSHARDED state', async function () {
await renderWithStore(<GlobalWrites shardingStatus={'UNSHARDED'} />);
expect(screen.getByTestId('shard-collection-button')).to.exist;
});

it('renders plugin in SUBMITTING_FOR_SHARDING state', function () {
renderWithStore(
it('renders plugin in SUBMITTING_FOR_SHARDING state', async function () {
await renderWithStore(
<GlobalWrites shardingStatus={'SUBMITTING_FOR_SHARDING'} />
);
expect(screen.getByTestId('shard-collection-button')).to.exist;
});

it('renders plugin in SHARDING state', function () {
renderWithStore(<GlobalWrites shardingStatus={'SHARDING'} />);
it('renders plugin in SHARDING state', async function () {
await renderWithStore(<GlobalWrites shardingStatus={'SHARDING'} />);
expect(screen.getByText(/sharding your collection/i)).to.exist;
});
});
8 changes: 8 additions & 0 deletions packages/compass-global-writes/src/components/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import type { RootState, ShardingStatus } from '../store/reducer';
import { ShardingStatuses } from '../store/reducer';
import UnshardedState from './states/unsharded';
import ShardingState from './states/sharding';
import ShardKeyCorrect from './states/shard-key-correct';

const containerStyles = css({
paddingLeft: spacing[400],
Expand Down Expand Up @@ -58,6 +59,13 @@ function ShardingStateView({
return <ShardingState />;
}

if (
shardingStatus === ShardingStatuses.SHARD_KEY_CORRECT ||
shardingStatus === ShardingStatuses.UNMANAGING_NAMESPACE
) {
return <ShardKeyCorrect />;
}

return null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import React from 'react';
import { expect } from 'chai';
import { render, screen, within } from '@mongodb-js/testing-library-compass';
import { ShardZonesTable } from './shard-zones-table';
import { type ShardZoneData } from '../store/reducer';

describe('Compass GlobalWrites Plugin', function () {
const shardZones: ShardZoneData[] = [
{
zoneId: '45893084',
country: 'Germany',
readableName: 'Germany',
isoCode: 'DE',
typeOneIsoCode: 'DE',
zoneName: 'EMEA',
zoneLocations: ['Frankfurt'],
},
{
zoneId: '43829408',
country: 'Germany',
readableName: 'Germany - Berlin',
isoCode: 'DE-BE',
typeOneIsoCode: 'DE',
zoneName: 'EMEA',
zoneLocations: ['Frankfurt'],
},
];

it('renders the Location name & Zone for all items', function () {
render(<ShardZonesTable shardZones={shardZones} />);

const rows = screen.getAllByRole('row');
expect(rows).to.have.lengthOf(3); // 1 header, 2 items
expect(within(rows[1]).getByText('Germany (DE)')).to.be.visible;
expect(within(rows[1]).getByText('EMEA (Frankfurt)')).to.be.visible;
expect(within(rows[2]).getByText('Germany - Berlin (DE-BE)')).to.be.visible;
expect(within(rows[2]).getByText('EMEA (Frankfurt)')).to.be.visible;
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React from 'react';
import {
Table,
TableBody,
TableHead,
HeaderRow,
HeaderCell,
Row,
Cell,
css,
} from '@mongodb-js/compass-components';
import type { ShardZoneData } from '../store/reducer';

const containerStyles = css({
maxWidth: '700px',
height: '400px',
});

export function ShardZonesTable({
shardZones,
}: {
shardZones: ShardZoneData[];
}) {
return (
// TODO(COMPASS-8336):
// Add search
// group zones by ShardZoneData.typeOneIsoCode
// and display them in a single row that can be expanded
<Table className={containerStyles} title="Zone Mapping">
<TableHead isSticky>
<HeaderRow>
<HeaderCell>Location Name</HeaderCell>
<HeaderCell>Zone</HeaderCell>
</HeaderRow>
</TableHead>
<TableBody>
{shardZones.map(
({ readableName, zoneName, zoneLocations, isoCode }, index) => {
return (
<Row key={index}>
<Cell>
{readableName} ({isoCode})
</Cell>
<Cell>
{zoneName} ({zoneLocations.join(', ')})
</Cell>
</Row>
);
}
)}
</TableBody>
</Table>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import React from 'react';
import { expect } from 'chai';
import { screen, userEvent } from '@mongodb-js/testing-library-compass';
import {
ShardKeyCorrect,
type ShardKeyCorrectProps,
} from './shard-key-correct';
import { type ShardZoneData } from '../../store/reducer';
import Sinon from 'sinon';
import { renderWithStore } from '../../../tests/create-store';
import { type ConnectionInfo } from '@mongodb-js/compass-connections/provider';

describe('Compass GlobalWrites Plugin', function () {
const shardZones: ShardZoneData[] = [
{
zoneId: '45893084',
country: 'Germany',
readableName: 'Germany',
isoCode: 'DE',
typeOneIsoCode: 'DE',
zoneName: 'EMEA',
zoneLocations: ['Frankfurt'],
},
];

const baseProps: ShardKeyCorrectProps = {
shardZones,
namespace: 'db1.coll1',
shardKey: {
fields: [
{ type: 'HASHED', name: 'location' },
{ type: 'RANGE', name: 'secondary' },
],
isUnique: false,
},
isUnmanagingNamespace: false,
onUnmanageNamespace: () => {},
};

function renderWithProps(
props?: Partial<ShardKeyCorrectProps>,
options?: Parameters<typeof renderWithStore>[1]
) {
return renderWithStore(
<ShardKeyCorrect {...baseProps} {...props} />,
options
);
}

it('Provides button to unmanage', async function () {
const onUnmanageNamespace = Sinon.spy();
await renderWithProps({ onUnmanageNamespace });

const btn = await screen.findByRole<HTMLButtonElement>('button', {
name: /Unmanage collection/,
});
expect(btn).to.be.visible;

userEvent.click(btn);

expect(onUnmanageNamespace).to.have.been.calledOnce;
});

it('Unmanage btn is disabled when the action is in progress', async function () {
const onUnmanageNamespace = Sinon.spy();
await renderWithProps({ onUnmanageNamespace, isUnmanagingNamespace: true });

const btn = await screen.findByTestId<HTMLButtonElement>(
'shard-collection-button'
);
expect(btn).to.be.visible;
expect(btn.getAttribute('aria-disabled')).to.equal('true');

userEvent.click(btn);

expect(onUnmanageNamespace).not.to.have.been.called;
});

it('Provides link to Edit Configuration', async function () {
const connectionInfo = {
id: 'testConnection',
connectionOptions: {
connectionString: 'mongodb://test',
},
atlasMetadata: {
projectId: 'project1',
clusterName: 'myCluster',
} as ConnectionInfo['atlasMetadata'],
};
await renderWithProps(undefined, {
connectionInfo,
});

const link = await screen.findByRole('link', {
name: /Edit Configuration/,
});
const expectedHref = `/v2/${connectionInfo.atlasMetadata?.projectId}#/clusters/edit/${connectionInfo.atlasMetadata?.clusterName}`;

expect(link).to.be.visible;
expect(link).to.have.attribute('href', expectedHref);
});

it('Describes the shardKey', async function () {
await renderWithProps();

const title = await screen.findByTestId('shardkey-description-title');
expect(title).to.be.visible;
expect(title.textContent).to.equal(
`${baseProps.namespace} is configured with the following shard key:`
);
const list = await screen.findByTestId('shardkey-description-content');
expect(list).to.be.visible;
expect(list.textContent).to.contain(`"location", "secondary"`);
});

it('Contains sample codes', async function () {
await renderWithProps();

const findingDocumentsSample = await screen.findByTestId(
'sample-finding-documents'
);
expect(findingDocumentsSample).to.be.visible;
expect(findingDocumentsSample.textContent).to.contain(
`use db1db["coll1"].find({"location": "US-NY", "secondary": "<id_value>"})`
);

const insertingDocumentsSample = await screen.findByTestId(
'sample-inserting-documents'
);
expect(insertingDocumentsSample).to.be.visible;
expect(insertingDocumentsSample.textContent).to.contain(
`use db1db["coll1"].insertOne({"location": "US-NY", "secondary": "<id_value>",...<other fields>})`
);
});
});
Loading

0 comments on commit 58fb9f5

Please sign in to comment.