Skip to content

Commit 370b972

Browse files
mabaasitgribnoysup
andauthored
feat(guide-cue): component implementation COMPASS-6334 (#4524)
Co-authored-by: Sergey Petushkov <[email protected]>
1 parent dbd3cbc commit 370b972

File tree

18 files changed

+1605
-285
lines changed

18 files changed

+1605
-285
lines changed

package-lock.json

Lines changed: 0 additions & 18 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/compass-aggregations/package.json

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@
4848
"@mongodb-js/mongodb-redux-common": "^2.0.8",
4949
"bson": "^5.2.0",
5050
"compass-preferences-model": "^2.10.0",
51-
"hadron-type-checker": "^7.0.3",
5251
"hadron-document": "^8.2.1",
52+
"hadron-type-checker": "^7.0.3",
5353
"react": "^17.0.2"
5454
},
5555
"devDependencies": {
@@ -94,8 +94,7 @@
9494
"redux-thunk": "^2.4.1",
9595
"semver": "^5.7.1",
9696
"sinon": "^9.2.3",
97-
"xvfb-maybe": "^0.2.1",
98-
"react-intersection-observer": "^8.34.0"
97+
"xvfb-maybe": "^0.2.1"
9998
},
10099
"dependencies": {
101100
"@mongodb-js/compass-components": "^1.10.0",
@@ -108,8 +107,8 @@
108107
"@mongodb-js/mongodb-redux-common": "^2.0.8",
109108
"bson": "^5.2.0",
110109
"compass-preferences-model": "^2.10.0",
111-
"hadron-type-checker": "^7.0.3",
112-
"hadron-document": "^8.2.1"
110+
"hadron-document": "^8.2.1",
111+
"hadron-type-checker": "^7.0.3"
113112
},
114113
"homepage": "https://github.com/mongodb-js/compass",
115114
"bugs": {

packages/compass-aggregations/src/components/aggregation-side-panel/index.spec.tsx

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import configureStore from '../../../test/configure-store';
99
import { Provider } from 'react-redux';
1010
import sinon from 'sinon';
1111
import { STAGE_WIZARD_USE_CASES } from './stage-wizard-use-cases';
12-
import * as guideCueHook from '../use-guide-cue';
1312

1413
const renderAggregationSidePanel = (
1514
props: Partial<ComponentProps<typeof AggregationSidePanel>> = {}
@@ -102,44 +101,4 @@ describe('aggregation side panel', function () {
102101
screen.getByTestId('use-case-sort').click();
103102
expect(onSelectUseCase).to.have.been.calledOnceWith('sort', '$sort');
104103
});
105-
106-
context('guide cue', function () {
107-
const guideCueSandbox: sinon.SinonSandbox = sinon.createSandbox();
108-
afterEach(function () {
109-
guideCueSandbox.restore();
110-
});
111-
112-
context('shows guide cue', function () {
113-
let markCueVisitedSpy: sinon.SinonSpy;
114-
beforeEach(function () {
115-
markCueVisitedSpy = sinon.spy();
116-
guideCueSandbox.stub(guideCueHook, 'useGuideCue').returns({
117-
isCueVisible: true,
118-
markCueVisited: markCueVisitedSpy,
119-
cueRefEl: React.createRef(),
120-
} as any);
121-
renderAggregationSidePanel();
122-
});
123-
it('shows guide cue first time', function () {
124-
expect(
125-
screen.getByTestId('stage-wizard-use-case-list-guide-cue')
126-
).to.exist;
127-
});
128-
it('marks cue visited when use case is clicked', function () {
129-
expect(markCueVisitedSpy.callCount).to.equal(0);
130-
screen.getByTestId('use-case-sort').click();
131-
expect(markCueVisitedSpy.callCount).to.equal(1);
132-
});
133-
});
134-
135-
it('does not show guide cue when its already shown', function () {
136-
guideCueSandbox
137-
.stub(guideCueHook, 'useGuideCue')
138-
.returns({ isCueVisible: false, cueRefEl: React.createRef() } as any);
139-
renderAggregationSidePanel();
140-
expect(() =>
141-
screen.getByTestId('stage-wizard-use-case-list-guide-cue')
142-
).to.throw;
143-
});
144-
});
145104
});

packages/compass-aggregations/src/components/aggregation-side-panel/index.tsx

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,12 @@ import {
1414
} from '@mongodb-js/compass-components';
1515
import { connect } from 'react-redux';
1616
import { createLoggerAndTelemetry } from '@mongodb-js/compass-logging';
17-
import { useDndMonitor } from '@dnd-kit/core';
1817

1918
import { toggleSidePanel } from '../../modules/side-panel';
2019
import { STAGE_WIZARD_USE_CASES } from './stage-wizard-use-cases';
2120
import { FeedbackLink } from './feedback-link';
2221
import { addWizard } from '../../modules/pipeline-builder/stage-editor';
2322
import { UseCaseCard } from './stage-wizard-use-cases';
24-
import { useGuideCue, GuideCueStorageKeys } from '../use-guide-cue';
2523

2624
const { track } = createLoggerAndTelemetry('COMPASS-AGGREGATIONS-UI');
2725

@@ -80,13 +78,10 @@ export const AggregationSidePanel = ({
8078
const [searchText, setSearchText] = useState<string>('');
8179
const darkMode = useDarkMode();
8280

83-
const { cueIntersectingRef, cueRefEl, isCueVisible, markCueVisited } =
84-
useGuideCue(GuideCueStorageKeys.STAGE_WIZARD_LIST);
85-
8681
const filteredUseCases = useMemo(() => {
8782
return STAGE_WIZARD_USE_CASES.filter(({ title, stageOperator }) => {
8883
return title.includes(searchText) || stageOperator.includes(searchText);
89-
});
84+
}).map(({ id, title, stageOperator }) => ({ id, title, stageOperator }));
9085
}, [searchText]);
9186

9287
const handleSearchTextChange = useCallback(
@@ -109,23 +104,12 @@ export const AggregationSidePanel = ({
109104
drag_and_drop: false,
110105
stage_name: useCase.stageOperator,
111106
});
112-
markCueVisited();
113107
},
114-
[onSelectUseCase, markCueVisited]
108+
[onSelectUseCase]
115109
);
116110

117-
// Hide guide cue when use-case card is dragged from the list
118-
useDndMonitor({
119-
onDragStart(event) {
120-
if (event.active.data.current?.type === 'use-case') {
121-
markCueVisited();
122-
}
123-
},
124-
});
125-
126111
return (
127112
<KeylineCard
128-
ref={cueIntersectingRef}
129113
data-testid="aggregation-side-panel"
130114
className={cx(containerStyles, darkMode && darkModeContainerStyles)}
131115
>
@@ -152,39 +136,37 @@ export const AggregationSidePanel = ({
152136
aria-label="How can we help?"
153137
/>
154138
<div className={contentStyles} data-testid="side-panel-content">
155-
{filteredUseCases.map((useCase, index) => (
156-
<div key={index}>
157-
<GuideCue
158-
data-testid="stage-wizard-use-case-list-guide-cue"
159-
open={isCueVisible && index === 0}
160-
setOpen={markCueVisited}
161-
refEl={cueRefEl}
162-
numberOfSteps={1}
163-
popoverZIndex={2}
164-
title="Quick access to the stages"
165-
tooltipJustify="end"
166-
tooltipAlign="left"
167-
>
168-
Choose from the list and use our easy drag & drop functionality to
169-
add it in the pipeline overview.
170-
</GuideCue>
171-
<div
172-
ref={(r) => {
173-
if (index === 0) {
174-
cueRefEl.current = r;
175-
}
176-
}}
177-
>
139+
{filteredUseCases.map((useCase, index) => {
140+
if (index !== 0) {
141+
return (
178142
<UseCaseCard
143+
{...useCase}
179144
key={useCase.id}
180-
id={useCase.id}
181-
title={useCase.title}
182-
stageOperator={useCase.stageOperator}
183145
onSelect={() => onSelect(useCase.id)}
184146
/>
185-
</div>
186-
</div>
187-
))}
147+
);
148+
}
149+
150+
return (
151+
<GuideCue<HTMLDivElement>
152+
key={useCase.id}
153+
cueId="aggregation-sidebar-wizard-use-case"
154+
title="Quick access to the stages"
155+
description={
156+
'Choose from the list and use our easy drag & drop functionality to add it in the pipeline overview.'
157+
}
158+
tooltipAlign="left"
159+
trigger={({ ref }) => (
160+
<div ref={ref}>
161+
<UseCaseCard
162+
{...useCase}
163+
onSelect={() => onSelect(useCase.id)}
164+
/>
165+
</div>
166+
)}
167+
/>
168+
);
169+
})}
188170
<FeedbackLink />
189171
</div>
190172
</KeylineCard>

packages/compass-aggregations/src/components/pipeline-toolbar/pipeline-settings/pipeline-extra-settings.spec.tsx

Lines changed: 2 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import React from 'react';
22
import type { ComponentProps } from 'react';
3-
import { render, screen, within } from '@testing-library/react';
3+
import { cleanup, render, screen, within } from '@testing-library/react';
44
import userEvent from '@testing-library/user-event';
55
import { expect } from 'chai';
66
import type { SinonSandbox } from 'sinon';
77
import { spy, createSandbox } from 'sinon';
8-
import * as guideCueHook from '../../use-guide-cue';
98

109
import { PipelineExtraSettings } from './pipeline-extra-settings';
1110
import preferences from 'compass-preferences-model';
@@ -80,6 +79,7 @@ describe('PipelineExtraSettings', function () {
8079
});
8180
afterEach(function () {
8281
sandbox.restore();
82+
cleanup();
8383
});
8484

8585
it('calls onToggleSidePanel when clicked', function () {
@@ -105,57 +105,5 @@ describe('PipelineExtraSettings', function () {
105105
.getAttribute('aria-disabled')
106106
).to.equal('true');
107107
});
108-
109-
context('guide cue', function () {
110-
const guideCueSandbox: sinon.SinonSandbox = sinon.createSandbox();
111-
112-
afterEach(function () {
113-
guideCueSandbox.restore();
114-
});
115-
116-
context('shows guide cue', function () {
117-
let markCueVisitedSpy: sinon.SinonSpy;
118-
beforeEach(function () {
119-
markCueVisitedSpy = sinon.spy();
120-
guideCueSandbox.stub(guideCueHook, 'useGuideCue').returns({
121-
isCueVisible: true,
122-
markCueVisited: markCueVisitedSpy,
123-
} as any);
124-
renderPipelineExtraSettings({
125-
pipelineMode: 'builder-ui',
126-
});
127-
});
128-
it('shows guide cue first time', function () {
129-
expect(screen.getByTestId('stage-wizard-guide-cue')).to.exist;
130-
});
131-
it('marks cue visited when stage wizard button is clicked', function () {
132-
expect(markCueVisitedSpy.callCount).to.equal(0);
133-
screen.getByTestId('pipeline-toolbar-side-panel-button').click();
134-
expect(markCueVisitedSpy.callCount).to.equal(1);
135-
});
136-
});
137-
138-
context('does not show guide cue', function () {
139-
it('when its already shown', function () {
140-
guideCueSandbox
141-
.stub(guideCueHook, 'useGuideCue')
142-
.returns({ isCueVisible: false } as any);
143-
renderPipelineExtraSettings({
144-
pipelineMode: 'builder-ui',
145-
});
146-
expect(() => screen.getByTestId('stage-wizard-guide-cue')).to.throw;
147-
});
148-
149-
it('in text mode', function () {
150-
guideCueSandbox
151-
.stub(guideCueHook, 'useGuideCue')
152-
.returns({ isCueVisible: true } as any);
153-
renderPipelineExtraSettings({
154-
pipelineMode: 'as-text',
155-
});
156-
expect(() => screen.getByTestId('stage-wizard-guide-cue')).to.throw;
157-
});
158-
});
159-
});
160108
});
161109
});

0 commit comments

Comments
 (0)