Skip to content
Merged
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
11 changes: 10 additions & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,35 +9,44 @@
NOTE: use `feat`, `fix` and `perf` for user facing changes that will be part of
release notes.
-->

## Description

<!--- Describe your changes in detail -->
<!--- If applicable, describe (or illustrate) architecture flow -->
<!--- If the UI changes in a non-trivial way, consider adding screenshots/video illustrating the new flows -->

### Checklist

- [ ] New tests and/or benchmarks are included
- [ ] Documentation is changed or added
- [ ] If this change updates the UI, screenshots/videos are added and a design review is requested
- [ ] If this change could impact the load on the MongoDB cluster, please describe the expected and worst case impact
- [ ] I have signed the MongoDB Contributor License Agreement (https://www.mongodb.com/legal/contributor-agreement)

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->
<!--- If it's updating a dependency, link to the Pull Request that originally introduced the fix -->

- [ ] Bugfix
- [ ] New feature
- [ ] Dependency update
- [ ] Misc

## Open Questions

<!--- Any particular areas you'd like reviewers to pay attention to? -->

## Dependents

<!--- If applicable, link PRs/commits that this PR is dependent on or is a dependency of. -->

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [ ] *Backport Needed*

- [ ] _Backport Needed_
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These changes started to show up when I merged the main in my branch. I think these are due to precommit hook, where prettier reformatted the file.

- [ ] Patch (non-breaking change which fixes an issue)
- [ ] Minor (non-breaking change which adds functionality)
- [ ] Major (fix or feature that would cause existing functionality to change)
507 changes: 85 additions & 422 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion packages/compass-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
"@lg-chat/suggestions": "^0.2.3",
"@lg-chat/title-bar": "^4.0.7",
"@mongodb-js/compass-context-menu": "^0.3.0",
"@mongodb-js/diagramming": "^2.2.0",
"@mongodb-js/diagramming": "^2.2.1",
"@react-aria/interactions": "^3.9.1",
"@react-aria/utils": "^3.13.1",
"@react-aria/visually-hidden": "^3.3.1",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ import {
relationshipToDiagramEdge,
} from '../utils/nodes-and-edges';
import toNS from 'mongodb-ns';
import { getNamespaceRelationships } from '../utils/utils';
import { usePreference } from 'compass-preferences-model/provider';

const loadingContainerStyles = css({
Expand Down Expand Up @@ -236,6 +237,10 @@ const DiagramContent: React.FunctionComponent<{
!!selectedItems &&
selectedItems.type === 'collection' &&
selectedItems.id === coll.ns;
const relationships = getNamespaceRelationships(
coll.ns,
model?.relationships
);
return collectionToDiagramNode({
...coll,
highlightedFields,
Expand All @@ -245,6 +250,7 @@ const DiagramContent: React.FunctionComponent<{
: undefined,
selected,
isInRelationshipDrawingMode,
relationships,
isExpanded: coll.isExpanded,
});
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
} from './drawer-section-components';
import { useChangeOnBlur } from './use-change-on-blur';
import { RelationshipsSection } from './relationships-section';
import { getNamespaceRelationships } from '../../utils/utils';

type CollectionDrawerContentProps = {
namespace: string;
Expand Down Expand Up @@ -170,12 +171,10 @@ export default connect(
namespace: collection.ns,
isDraftCollection: state.diagram?.draftCollection === ownProps.namespace,
collections: model.collections,
relationships: model.relationships.filter((r) => {
const [local, foreign] = r.relationship;
return (
local.ns === ownProps.namespace || foreign.ns === ownProps.namespace
);
}),
relationships: getNamespaceRelationships(
ownProps.namespace,
model.relationships
),
};
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,17 @@ import {
Badge,
Button,
css,
cx,
Icon,
IconButton,
palette,
spacing,
Tooltip,
useDarkMode,
} from '@mongodb-js/compass-components';
import type { Relationship } from '../../services/data-model-storage';
import { getDefaultRelationshipName } from '../../utils';
import { isRelationshipValid } from '../../utils/utils';

const titleBtnStyles = css({
marginLeft: 'auto',
Expand All @@ -35,13 +39,28 @@ const relationshipItemStyles = css({
alignItems: 'center',
});

const relationshipNameStyles = css({
const relationshipNameWrapperStyles = css({
flexGrow: 1,
minWidth: 0,
display: 'flex',
alignItems: 'center',
gap: spacing[100],
paddingRight: spacing[200],
});

const relationshipNameStyles = css({
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
minWidth: 0,
paddingRight: spacing[200],
});

const warnIconWrapperStyles = css({
display: 'flex',
color: palette.yellow.dark2,
});

const warnIconWrapperDarkStyles = css({
color: palette.yellow.light2,
});

const relationshipContentStyles = css({
Expand All @@ -65,6 +84,7 @@ export const RelationshipsSection: React.FunctionComponent<
onEditRelationshipClick,
onDeleteRelationshipClick,
}) => {
const darkmode = useDarkMode();
return (
<DMDrawerSection
label={
Expand Down Expand Up @@ -97,12 +117,31 @@ export const RelationshipsSection: React.FunctionComponent<
data-relationship-id={r.id}
className={relationshipItemStyles}
>
<span
className={relationshipNameStyles}
title={relationshipLabel}
>
{relationshipLabel}
</span>
<div className={relationshipNameWrapperStyles}>
<span
className={relationshipNameStyles}
title={relationshipLabel}
>
{relationshipLabel}
</span>
{!isRelationshipValid(r) && (
<Tooltip
trigger={
<div
className={cx(
warnIconWrapperStyles,
darkmode && warnIconWrapperDarkStyles
)}
>
<Icon glyph="Warning" />
</div>
}
>
Cannot resolve the relationship - please verify the
linked fields and namespace.
</Tooltip>
)}
</div>
<IconButton
aria-label="Edit relationship"
title="Edit relationship"
Expand Down
12 changes: 11 additions & 1 deletion packages/compass-data-modeling/src/utils/nodes-and-edges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import type {
Relationship,
} from '../services/data-model-storage';
import { traverseSchema } from './schema-traversal';
import { areFieldPathsEqual, isIdField } from './utils';
import { areFieldPathsEqual, isIdField, isRelationshipValid } from './utils';

const NO_HIGHLIGHTED_FIELDS = {};

Expand Down Expand Up @@ -156,6 +156,7 @@ type CollectionWithRenderOptions = Pick<
selectedField?: FieldPath;
selected: boolean;
isInRelationshipDrawingMode: boolean;
relationships: Relationship[];
};

export function collectionToDiagramNode({
Expand All @@ -166,8 +167,16 @@ export function collectionToDiagramNode({
highlightedFields,
selected,
isInRelationshipDrawingMode,
relationships,
isExpanded,
}: CollectionWithRenderOptions): NodeProps {
let variant: NodeProps['variant'] = undefined;
if (relationships.some((r) => !isRelationshipValid(r))) {
variant = {
type: 'warn' as const,
warnMessage: 'One or more relationships cannot be resolved.',
};
}
return {
id: ns,
type: 'collection',
Expand All @@ -185,6 +194,7 @@ export function collectionToDiagramNode({
selected,
connectable: isInRelationshipDrawingMode,
draggable: !isInRelationshipDrawingMode,
variant,
};
}

Expand Down
40 changes: 40 additions & 0 deletions packages/compass-data-modeling/src/utils/utils.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
isRelationshipOfAField,
isSameFieldOrAncestor,
dualSourceHandlerDebounce,
isRelationshipValid,
} from './utils';
import type { Relationship } from '../services/data-model-storage';

Expand Down Expand Up @@ -135,3 +136,42 @@ describe('dualSourceHandlerDebounce', function () {
expect(invocationCount).to.equal(3);
});
});

describe('isRelationshipValid', function () {
it('should return false for relationships with missing namespaces', function () {
const relationship = {
relationship: [
{ ns: '', fields: ['a'], cardinality: 1 },
{ ns: 'db.coll2', fields: ['b'], cardinality: 1 },
],
} as any;
expect(isRelationshipValid(relationship)).to.be.false;
});
it('should return false for relationships with no fields', function () {
const relationship = {
relationship: [
{ ns: 'db.coll1', fields: undefined, cardinality: 1 },
{ ns: 'db.coll2', cardinality: 1 },
],
} as any;
expect(isRelationshipValid(relationship)).to.be.false;
});
it('should return false for relationships with empty fields', function () {
const relationship = {
relationship: [
{ ns: 'db.coll1', fields: [], cardinality: 1 },
{ ns: 'db.coll2', fields: [], cardinality: 1 },
],
} as any;
expect(isRelationshipValid(relationship)).to.be.false;
});
it('should return true for relationships with correct namespaces and fields', function () {
const relationship = {
relationship: [
{ ns: 'db.coll1', fields: ['_id'], cardinality: 1 },
{ ns: 'db.coll2', fields: ['order_id'], cardinality: 1 },
],
} as any;
expect(isRelationshipValid(relationship)).to.be.true;
});
});
26 changes: 26 additions & 0 deletions packages/compass-data-modeling/src/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,3 +84,29 @@ export function dualSourceHandlerDebounce(
};
return Array.from({ length: count }, (_, i) => makeHandler(i));
}

export function getNamespaceRelationships(
namespace: string,
relationships: Relationship[] = []
): Relationship[] {
return relationships.filter((r) => {
const [local, foreign] = r.relationship;
return local.ns === namespace || foreign.ns === namespace;
});
}

export function isRelationshipValid(relationship: Relationship): boolean {
const [source, target] = relationship.relationship;
if (
!source.ns ||
!target.ns ||
!source.fields ||
!target.fields ||
source.fields.length === 0 ||
target.fields.length === 0
) {
return false;
}

return true;
}
Loading