Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
17 changes: 17 additions & 0 deletions packages/atlas-service/src/make-automation-agent-op-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ export type AutomationAgentRequestTypes = {
collection: string;
name: string;
};
getShardKey: ClusterOrServerlessId & {
db: string;
collection: string;
};
};

type AutomationAgentRequestOpTypes = keyof AutomationAgentRequestTypes;
Expand Down Expand Up @@ -60,6 +64,11 @@ export type AutomationAgentAwaitResponseTypes = {
status: 'rolling build' | 'building' | 'exists';
}[];
dropIndex: never[];
getShardKey: Array<{
_id: string;
unique: boolean;
key: Record<string, unknown>;
}>;
};

type AutomationAgentAwaitOpTypes = keyof AutomationAgentAwaitResponseTypes;
Expand Down Expand Up @@ -121,6 +130,10 @@ function unwrapAutomationAgentAwaitResponse(
json: any,
opType: 'dropIndex'
): UnwrappedAutomationAgentAwaitResponse<'dropIndex'>;
function unwrapAutomationAgentAwaitResponse(
json: any,
opType: 'getShardKey'
): UnwrappedAutomationAgentAwaitResponse<'getShardKey'>;
function unwrapAutomationAgentAwaitResponse(json: any, opType: string): never;
function unwrapAutomationAgentAwaitResponse(
json: any,
Expand All @@ -136,6 +149,10 @@ function unwrapAutomationAgentAwaitResponse(
assertAutomationAgentAwaitResponse(json, opType);
return json.response;
}
if (opType === 'getShardKey') {
assertAutomationAgentAwaitResponse(json, opType);
return json.response;
}
throw new Error(`Unsupported await response type: ${opType}`);
}

Expand Down
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,48 @@
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: Add option to search and group zones by ShardZoneData.typeOneIsoCode
// and display them in nested row
<Table className={containerStyles} title="Zone Mapping">
<TableHead isSticky>
<HeaderRow>
<HeaderCell>Location Name</HeaderCell>
<HeaderCell>Zone</HeaderCell>
</HeaderRow>
</TableHead>
<TableBody>
{shardZones.map((shardZone, index) => {
return (
<Row key={index}>
<Cell>{shardZone.country}</Cell>
<Cell>
{shardZone.zoneName}({shardZone.zoneLocations.join(', ')})
</Cell>
</Row>
);
})}
</TableBody>
</Table>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
import React, { useMemo } from 'react';
import {
Banner,
BannerVariant,
Body,
css,
Link,
spacing,
Code,
Subtitle,
Label,
SpinLoader,
Button,
} from '@mongodb-js/compass-components';
import { connect } from 'react-redux';
import {
ShardingStatuses,
unmanageNamespace,
type RootState,
type ShardKey,
type ShardZoneData,
} from '../../store/reducer';
import toNS from 'mongodb-ns';
import { ShardZonesTable } from '../shard-zones-table';

const nbsp = '\u00a0';

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

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

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

type ShardKeyCorrectProps = {
namespace: string;
shardKey: ShardKey;
shardZones: ShardZoneData[];
isUnmanagingNamespace: boolean;
onUnmanageNamespace: () => void;
};

export function ShardKeyCorrect({
namespace,
shardKey,
shardZones,
isUnmanagingNamespace,
onUnmanageNamespace,
}: ShardKeyCorrectProps) {
const customShardKeyField = useMemo(() => {
return shardKey.fields[1].name;
}, [shardKey]);

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

return (
<div className={containerStyles}>
<Banner variant={BannerVariant.Info}>
<strong>
All documents in your collection should contain both the ‘location’
field (with a ISO country or subdivision code) and your{' '}
{customShardKeyField} field at insert time.
</strong>
{nbsp}We have included a table for reference below.
</Banner>

<div className={codeBlockContainerStyles}>
<Body>
<strong>{namespace}</strong> is configured with the following shard
key:
</Body>
<Code language="js">{namespace}</Code>
</div>

<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">{sampleCodes.findingDocuments}</Code>
</div>

<div className={codeBlockContainerStyles}>
<Label htmlFor="inserting-documents">Inserting documents</Label>
<Code language="js">{sampleCodes.insertingDocuments}</Code>
</div>

<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="https://cloud-dev.mongodb.com/static/atlas/country_iso_codes.txt"
hideExternalIcon
>
here
</Link>
.
</Body>
<Body>
Locations’ zone mapping can be changed by navigating to this clusters{' '}
<Link
hideExternalIcon
href="https://cloud-dev.mongodb.com/v2/66bb81dafe547055785904a3#/clusters/edit/Cluster0"
>
Edit Configuration
</Link>{' '}
page and clicking the Configure Location Mappings’ link above the map.
</Body>
</div>

<ShardZonesTable shardZones={shardZones} />

<Subtitle>Unmanage this collection</Subtitle>
<Body>
Documents belonging to this collection will no longer be distributed
across the shards of your global clusters.
</Body>
<div>
<Button
data-testid="shard-collection-button"
onClick={onUnmanageNamespace}
disabled={isUnmanagingNamespace}
variant="primary"
leftGlyph={
isUnmanagingNamespace ? (
<SpinLoader title="Unmanaging collection" />
) : undefined
}
>
Unmanage collection
</Button>
</div>
</div>
);
}

export default connect(
(state: RootState) => ({
namespace: state.namespace,
// For this view, sharKey is always defined
shardKey: state.shardKey as ShardKey,
shardZones: state.shardZones,
isUnmanagingNamespace:
state.status === ShardingStatuses.UNMANAGING_NAMESPACE,
}),
{
onUnmanageNamespace: unmanageNamespace,
}
)(ShardKeyCorrect);
4 changes: 2 additions & 2 deletions packages/compass-global-writes/src/plugin-title.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ const PluginTitle = ({ showWarning }: { showWarning: boolean }) => {
};

export const GlobalWritesTabTitle = connect(
({ isNamespaceSharded, status }: RootState) => ({
showWarning: !isNamespaceSharded && status !== ShardingStatuses.NOT_READY,
({ managedNamespace, status }: RootState) => ({
showWarning: !managedNamespace && status !== ShardingStatuses.NOT_READY,
})
)(PluginTitle);
Loading