Skip to content

Commit c0832c6

Browse files
authored
chore(collection-header): collection action buttons (#5515)
* breadcrumbs ui * refactor * undo unwanted change * depcheck * fix workspace tab tests * unit test * fix e2e tests * todo * pr feedback * remove due to connection title * make text bold * better if * collection actions ux * fix css * remove irrelevant tests * reduce padding
1 parent e975995 commit c0832c6

File tree

7 files changed

+147
-191
lines changed

7 files changed

+147
-191
lines changed
Lines changed: 80 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,43 @@
11
import { expect } from 'chai';
2-
import React from 'react';
2+
import React, { type ComponentProps } from 'react';
33
import { render, screen, cleanup } from '@testing-library/react';
4-
4+
import sinon from 'sinon';
5+
import {
6+
WorkspacesServiceProvider,
7+
type WorkspacesService,
8+
} from '@mongodb-js/compass-workspaces/provider';
59
import CollectionHeaderActions from '../collection-header-actions';
610

11+
function renderCollectionHeaderActions(
12+
props: Partial<ComponentProps<typeof CollectionHeaderActions>> = {},
13+
workspaceService: Partial<WorkspacesService> = {}
14+
) {
15+
return render(
16+
<WorkspacesServiceProvider value={workspaceService as WorkspacesService}>
17+
<CollectionHeaderActions
18+
namespace="test.test"
19+
isReadonly={false}
20+
{...props}
21+
/>
22+
</WorkspacesServiceProvider>
23+
);
24+
}
25+
726
describe('CollectionHeaderActions [Component]', function () {
27+
let sandbox: sinon.SinonSandbox;
28+
beforeEach(function () {
29+
sandbox = sinon.createSandbox();
30+
});
31+
this.afterEach(function () {
32+
sandbox.restore();
33+
});
834
context('when the collection is not readonly', function () {
935
beforeEach(function () {
10-
render(
11-
<CollectionHeaderActions
12-
isReadonly={false}
13-
onEditViewClicked={() => {}}
14-
onReturnToViewClicked={() => {}}
15-
sourceName="db.coll"
16-
/>
17-
);
36+
renderCollectionHeaderActions({
37+
isReadonly: false,
38+
namespace: 'db.coll2',
39+
sourceName: 'db.coll',
40+
});
1841
});
1942

2043
afterEach(cleanup);
@@ -29,54 +52,20 @@ describe('CollectionHeaderActions [Component]', function () {
2952
});
3053
});
3154

32-
context('when the collection is readonly', function () {
33-
beforeEach(function () {
34-
render(
35-
<CollectionHeaderActions
36-
isReadonly={true}
37-
onEditViewClicked={() => {}}
38-
onReturnToViewClicked={() => {}}
39-
sourceName="orig.coll"
40-
/>
41-
);
42-
});
43-
44-
afterEach(cleanup);
45-
46-
it('renders the source collection', function () {
47-
const label = screen.getByTestId('collection-view-on');
48-
expect(label).to.have.text('view on: orig.coll');
49-
expect(label).to.be.visible;
50-
});
51-
});
52-
53-
context('when the collection is readonly but not a view', function () {
54-
beforeEach(function () {
55-
render(
56-
<CollectionHeaderActions
57-
isReadonly={true}
58-
onEditViewClicked={() => {}}
59-
onReturnToViewClicked={() => {}}
60-
/>
61-
);
62-
});
63-
64-
afterEach(cleanup);
65-
66-
it('does not render view information', function () {
67-
expect(screen.queryByTestId('collection-badge-view')).to.not.exist;
68-
});
69-
});
70-
7155
context('when the collection is a view', function () {
56+
let openEditViewWorkspaceStub: sinon.SinonStub;
7257
beforeEach(function () {
73-
render(
74-
<CollectionHeaderActions
75-
isReadonly={true}
76-
onEditViewClicked={() => {}}
77-
onReturnToViewClicked={() => {}}
78-
sourceName="db.someSource"
79-
/>
58+
openEditViewWorkspaceStub = sandbox.stub();
59+
renderCollectionHeaderActions(
60+
{
61+
isReadonly: true,
62+
namespace: 'db.coll2',
63+
sourceName: 'db.someSource',
64+
sourcePipeline: [{ $match: { a: 1 } }],
65+
},
66+
{
67+
openEditViewWorkspace: openEditViewWorkspaceStub,
68+
}
8069
);
8170
});
8271

@@ -87,17 +76,35 @@ describe('CollectionHeaderActions [Component]', function () {
8776
screen.getByTestId('collection-header-actions-edit-button')
8877
).to.exist;
8978
});
79+
it('calls openEditViewWorkspace when the edit button is clicked', function () {
80+
expect(openEditViewWorkspaceStub).to.not.have.been.called;
81+
const button = screen.getByTestId(
82+
'collection-header-actions-edit-button'
83+
);
84+
button.click();
85+
expect(openEditViewWorkspaceStub).to.have.been.calledOnceWith(
86+
'db.coll2',
87+
{
88+
sourceName: 'db.someSource',
89+
sourcePipeline: [{ $match: { a: 1 } }],
90+
}
91+
);
92+
});
9093
});
9194

9295
context('when the collection is editing a view', function () {
96+
let openCollectionWorkspaceStub: sinon.SinonStub;
9397
beforeEach(function () {
94-
render(
95-
<CollectionHeaderActions
96-
isReadonly={false}
97-
onEditViewClicked={() => {}}
98-
onReturnToViewClicked={() => {}}
99-
editViewName="db.editing"
100-
/>
98+
openCollectionWorkspaceStub = sandbox.stub();
99+
renderCollectionHeaderActions(
100+
{
101+
isReadonly: false,
102+
namespace: 'db.coll2',
103+
editViewName: 'db.editing',
104+
},
105+
{
106+
openCollectionWorkspace: openCollectionWorkspaceStub,
107+
}
101108
);
102109
});
103110

@@ -108,5 +115,15 @@ describe('CollectionHeaderActions [Component]', function () {
108115
screen.getByTestId('collection-header-actions-return-to-view-button')
109116
).to.exist;
110117
});
118+
it('calls openCollectionWorkspace when the return to view button is clicked', function () {
119+
expect(openCollectionWorkspaceStub).to.not.have.been.called;
120+
const button = screen.getByTestId(
121+
'collection-header-actions-return-to-view-button'
122+
);
123+
button.click();
124+
expect(openCollectionWorkspaceStub).to.have.been.calledOnceWith(
125+
'db.editing'
126+
);
127+
});
111128
});
112129
});

packages/compass-collection/src/components/collection-header-actions/collection-header-actions.tsx

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,71 +1,72 @@
11
import {
22
Button,
33
ButtonSize,
4+
Icon,
45
css,
56
spacing,
67
} from '@mongodb-js/compass-components';
8+
import { useOpenWorkspace } from '@mongodb-js/compass-workspaces/provider';
79
import React from 'react';
810

9-
import ViewInformation from './view-information';
10-
11-
const editViewButtonStyles = css({
12-
flex: 'none',
13-
});
14-
1511
const collectionHeaderActionsStyles = css({
1612
display: 'flex',
17-
marginLeft: 'auto',
1813
alignItems: 'center',
1914
overflow: 'hidden',
2015
gap: spacing[2],
2116
});
2217

23-
const collectionHeaderActionsReadonlyStyles = css({
24-
alignItems: 'center',
25-
flex: 'none',
26-
});
27-
2818
type CollectionHeaderActionsProps = {
29-
editViewName?: string;
19+
namespace: string;
3020
isReadonly: boolean;
31-
onEditViewClicked: () => void;
32-
onReturnToViewClicked: () => void;
21+
editViewName?: string;
3322
sourceName?: string;
23+
sourcePipeline?: unknown[];
3424
};
3525

3626
const CollectionHeaderActions: React.FunctionComponent<
3727
CollectionHeaderActionsProps
3828
> = ({
39-
editViewName,
29+
namespace,
4030
isReadonly,
41-
onEditViewClicked,
42-
onReturnToViewClicked,
31+
editViewName,
4332
sourceName,
33+
sourcePipeline,
4434
}: CollectionHeaderActionsProps) => {
35+
const { openCollectionWorkspace, openEditViewWorkspace } = useOpenWorkspace();
4536
return (
4637
<div
4738
className={collectionHeaderActionsStyles}
4839
data-testid="collection-header-actions"
4940
>
50-
{isReadonly && sourceName && <ViewInformation sourceName={sourceName} />}
5141
{isReadonly && sourceName && !editViewName && (
5242
<Button
5343
data-testid="collection-header-actions-edit-button"
54-
className={editViewButtonStyles}
55-
size={ButtonSize.XSmall}
56-
onClick={onEditViewClicked}
44+
size={ButtonSize.Small}
45+
onClick={() => {
46+
if (sourceName && sourcePipeline) {
47+
openEditViewWorkspace(namespace, {
48+
sourceName,
49+
sourcePipeline,
50+
});
51+
}
52+
}}
5753
>
58-
EDIT VIEW
54+
<Icon glyph="Edit" />
55+
Edit Pipeline
5956
</Button>
6057
)}
6158
{editViewName && (
6259
<Button
6360
data-testid="collection-header-actions-return-to-view-button"
64-
className={collectionHeaderActionsReadonlyStyles}
65-
size={ButtonSize.XSmall}
66-
onClick={onReturnToViewClicked}
61+
size={ButtonSize.Small}
62+
onClick={() => {
63+
if (editViewName) {
64+
openCollectionWorkspace(editViewName);
65+
}
66+
}}
6767
>
68-
&lt; Return to View
68+
<Icon glyph="ArrowLeft" />
69+
Return to View
6970
</Button>
7071
)}
7172
</div>

packages/compass-collection/src/components/collection-header-actions/view-information.tsx

Lines changed: 0 additions & 51 deletions
This file was deleted.

packages/compass-collection/src/components/collection-header/collection-header.spec.tsx

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -77,12 +77,6 @@ describe('CollectionHeader [Component]', function () {
7777
expect(screen.getByTestId('breadcrumbs')).to.exist;
7878
});
7979

80-
it('renders the source collection', function () {
81-
const label = screen.getByTestId('collection-view-on');
82-
expect(label).to.have.text('view on: orig.coll');
83-
expect(label).to.be.visible;
84-
});
85-
8680
it('renders the readonly badge', function () {
8781
expect(screen.getByTestId('collection-badge-readonly')).to.exist;
8882
});
@@ -97,10 +91,6 @@ describe('CollectionHeader [Component]', function () {
9791
renderCollectionHeader({ isReadonly: true, sourceName: undefined });
9892
});
9993

100-
it('does not render the source collection', function () {
101-
expect(screen.queryByTestId('collection-view-on')).to.not.exist;
102-
});
103-
10494
it('renders the readonly badge', function () {
10595
expect(screen.getByTestId('collection-badge-readonly')).to.exist;
10696
});
@@ -115,10 +105,6 @@ describe('CollectionHeader [Component]', function () {
115105
renderCollectionHeader({ isTimeSeries: true });
116106
});
117107

118-
it('does not render the source collection', function () {
119-
expect(screen.queryByTestId('collection-view-on')).to.not.exist;
120-
});
121-
122108
it('does not render the readonly badge', function () {
123109
expect(screen.queryByTestId('collection-badge-readonly')).to.not.exist;
124110
});
@@ -133,10 +119,6 @@ describe('CollectionHeader [Component]', function () {
133119
renderCollectionHeader({ isClustered: true });
134120
});
135121

136-
it('does not render the source collection', function () {
137-
expect(screen.queryByTestId('collection-view-on')).to.not.exist;
138-
});
139-
140122
it('does not render the readonly badge', function () {
141123
expect(screen.queryByTestId('collection-badge-readonly')).to.not.exist;
142124
});

0 commit comments

Comments
 (0)