Skip to content

Commit

Permalink
feat(compass-global-writes): incomplete sharding setup COMPASS-8372 (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
paula-stacho authored Nov 6, 2024
1 parent 89f803c commit 29ee428
Show file tree
Hide file tree
Showing 15 changed files with 723 additions and 190 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import { renderWithStore } from '../../tests/create-store';
import { expect } from 'chai';
import { screen } from '@mongodb-js/testing-library-compass';
import ExampleCommandsMarkup, {
type ExampleCommandsMarkupProps,
} from './example-commands-markup';
import { type ShardKey } from '../store/reducer';

describe('ExampleCommandsMarkup', function () {
const db = 'db1';
const coll = 'coll1';
const namespace = `${db}.${coll}`;
const shardKey: ShardKey = {
fields: [
{ type: 'RANGE', name: 'location' },
{ type: 'HASHED', name: 'secondary' },
],
isUnique: false,
};

function renderWithProps(props?: Partial<ExampleCommandsMarkupProps>) {
return renderWithStore(
<ExampleCommandsMarkup
namespace={namespace}
shardKey={shardKey}
{...props}
/>
);
}

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>})`
);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import {
Body,
Code,
css,
Label,
Link,
spacing,
Subtitle,
} from '@mongodb-js/compass-components';
import React, { useMemo } from 'react';
import type { ShardKey } from '../store/reducer';
import toNS from 'mongodb-ns';

const codeBlockContainerStyles = css({
display: 'flex',
flexDirection: 'column',
gap: spacing[100],
});

export interface ExampleCommandsMarkupProps {
shardKey: ShardKey;
namespace: string;
showMetaData?: boolean;
type?: 'requested' | 'existing';
}

const paragraphStyles = css({
display: 'flex',
flexDirection: 'column',
gap: spacing[100],
});

export function ExampleCommandsMarkup({
namespace,
shardKey,
}: ExampleCommandsMarkupProps) {
const customShardKeyField = useMemo(() => {
return shardKey.fields[1].name;
}, [shardKey]);

const sampleCodes = useMemo(() => {
const { collection, database } = toNS(namespace);
return {
findingDocuments: `use ${database}\ndb[${JSON.stringify(
collection
)}].find({"location": "US-NY", "${customShardKeyField}": "<id_value>"})`,
insertingDocuments: `use ${database}\ndb[${JSON.stringify(
collection
)}].insertOne({"location": "US-NY", "${customShardKeyField}": "<id_value>",...<other fields>})`,
};
}, [namespace, customShardKeyField]);

return (
<>
<Subtitle>Example commands</Subtitle>
<div className={paragraphStyles}>
<Body>
Start querying your database with some of the most{' '}
<Link
href="https://www.mongodb.com/docs/atlas/global-clusters"
hideExternalIcon
>
common commands
</Link>{' '}
for Global Writes.
</Body>
<Body>
Replace the text to perform operations on different documents. US-NY
is an ISO 3166 location code referring to New York, United States. You
can look up other ISO 3166 location codes below.
</Body>
</div>

<div className={codeBlockContainerStyles}>
<Label htmlFor="finding-documents">Finding documents</Label>
<Code
language="js"
data-testid="sample-finding-documents"
id="finding-documents"
>
{sampleCodes.findingDocuments}
</Code>
</div>

<div className={codeBlockContainerStyles}>
<Label htmlFor="inserting-documents">Inserting documents</Label>
<Code
language="js"
data-testid="sample-inserting-documents"
id="inserting-documents"
>
{sampleCodes.insertingDocuments}
</Code>
</div>
</>
);
}

export default ExampleCommandsMarkup;
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 @@ -15,6 +15,7 @@ import ShardKeyCorrect from './states/shard-key-correct';
import ShardKeyInvalid from './states/shard-key-invalid';
import ShardKeyMismatch from './states/shard-key-mismatch';
import ShardingError from './states/sharding-error';
import IncompleteShardingSetup from './states/incomplete-sharding-setup';

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

if (
shardingStatus === ShardingStatuses.INCOMPLETE_SHARDING_SETUP ||
shardingStatus === ShardingStatuses.SUBMITTING_FOR_SHARDING_INCOMPLETE
) {
return <IncompleteShardingSetup />;
}

return null;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
Body,
css,
Link,
spacing,
Subtitle,
} from '@mongodb-js/compass-components';
import { useConnectionInfo } from '@mongodb-js/compass-connections/provider';
import React from 'react';

const paragraphStyles = css({
display: 'flex',
flexDirection: 'column',
gap: spacing[100],
});

export function ShardZonesDescription() {
const { atlasMetadata } = useConnectionInfo();
return (
<>
<Subtitle>Location Codes</Subtitle>
<div className={paragraphStyles}>
<Body>
Each document’s first field should include an ISO 3166-1 Alpha-2 code
for the location it belongs to.
</Body>
<Body>
We also support ISO 3166-2 subdivision codes for countries containing
a cloud provider data center (both ISO 3166-1 and ISO 3166-2 codes may
be used for these countries). All valid country codes and the zones to
which they map are listed in the table below. Additionally, you can
view a list of all location codes{' '}
<Link href="/static/atlas/country_iso_codes.txt">here</Link>.
</Body>
<Body>
{atlasMetadata?.projectId && atlasMetadata?.clusterName && (
<>
Locations’ zone mapping can be changed by navigating to this
clusters{' '}
<Link
href={`/v2/${atlasMetadata?.projectId}#/clusters/edit/${atlasMetadata?.clusterName}`}
>
Edit Configuration
</Link>{' '}
page and clicking the Configure Location Mappings’ link above the
map.
</>
)}
</Body>
</div>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import { expect } from 'chai';
import { screen } from '@mongodb-js/testing-library-compass';
import type { ConnectionInfo } from '@mongodb-js/compass-connections/provider';
import { renderWithStore } from '../../tests/create-store';
import { ShardZonesDescription } from './shard-zones-description';

describe('ShardZonesDescription', () => {
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 renderWithStore(<ShardZonesDescription />, {
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);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
type LgTableRowType,
} from '@mongodb-js/compass-components';
import type { ShardZoneData } from '../store/reducer';
import { ShardZonesDescription } from './shard-zones-description';

const containerStyles = css({
height: '400px',
Expand Down Expand Up @@ -131,6 +132,7 @@ export function ShardZonesTable({

return (
<>
<ShardZonesDescription />
<SearchInput
value={searchText}
onChange={handleSearchTextChange}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
import React from 'react';
import { expect } from 'chai';
import { screen, userEvent } from '@mongodb-js/testing-library-compass';
import {
IncompleteShardingSetup,
type IncompleteShardingSetupProps,
} from './incomplete-sharding-setup';
import Sinon from 'sinon';
import { renderWithStore } from '../../../tests/create-store';
import { type ConnectionInfo } from '@mongodb-js/compass-connections/provider';
import { type ShardZoneData } from '../../store/reducer';

describe('IncompleteShardingSetup', function () {
const shardZones: ShardZoneData[] = [
{
zoneId: '45893084',
country: 'Germany',
readableName: 'Germany',
isoCode: 'DE',
typeOneIsoCode: 'DE',
zoneName: 'EMEA',
zoneLocations: ['Frankfurt'],
},
];
const baseProps: IncompleteShardingSetupProps = {
namespace: 'db1.coll1',
shardZones,
shardKey: {
fields: [
{ type: 'RANGE', name: 'location' },
{ type: 'HASHED', name: 'secondary' },
],
isUnique: false,
},
isSubmittingForSharding: false,
onResume: () => {},
};

const connectionInfo = {
id: 'testConnection',
connectionOptions: {
connectionString: 'mongodb://test',
},
atlasMetadata: {
projectId: 'project1',
clusterName: 'myCluster',
} as ConnectionInfo['atlasMetadata'],
};

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

it('Shows description', async function () {
await renderWithProps();

expect(screen.findByText(/your configuration is incomplete/)).to.be.exist;
expect(screen.findByText(/Please enable Global Writes/)).to.be.exist;
});

it('Provides button to resume managed namespace', async function () {
const onResume = Sinon.spy();
await renderWithProps({ onResume });

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

userEvent.click(btn);

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

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

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

userEvent.click(btn);

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

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

const title = await screen.findByTestId(
'existing-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(
'existing-shardkey-description-content'
);
expect(list).to.be.visible;
expect(list.textContent).to.contain(`"location", "secondary"`);
});

it('Includes code examples', async function () {
await renderWithProps();

const example = await screen.findByText(/Example commands/);
expect(example).to.be.visible;
});
});
Loading

0 comments on commit 29ee428

Please sign in to comment.