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
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import type { RootState } from '../../../modules';
import { collationChanged } from '../../../modules/collation';
import { collationStringChanged } from '../../../modules/collation-string';
import { openLink } from '../../../modules/link';
import { maxTimeMSChanged } from '../../../modules/max-time-ms';

import LegacyPipelineCollation from '../../pipeline/collation-toolbar';

Expand All @@ -15,25 +16,36 @@ const PipelineCollation: React.FunctionComponent<PipelineCollationProps> = ({
collationChanged,
collationStringChanged,
openLink,
maxTimeMS,
maxTimeMSChanged,
}) => {
const props = {
collation,
collationString,
collationChanged,
maxTimeMS,
collationStringChanged,
openLink,
maxTimeMSChanged,
};
return <LegacyPipelineCollation {...props} />;
};

const mapState = ({ collation, collationString }: RootState) => ({
const mapState = ({
collation,
collationString,
settings: { maxTimeMS: defaultMaxTimeMS, isDirty },
maxTimeMS,
}: RootState) => ({
collation,
collationString,
maxTimeMS: isDirty ? defaultMaxTimeMS : maxTimeMS,
});
const mapDispatch = {
collationChanged,
collationStringChanged,
openLink,
maxTimeMSChanged,
};
const connector = connect(mapState, mapDispatch);
type PipelineCollationProps = ConnectedProps<typeof connector>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ import classnames from 'classnames';

import styles from './collation-toolbar.module.less';

import { DEFAULT_MAX_TIME_MS } from '../../constants';

/**
* The help URL for collation.
*/
const HELP_URL_COLLATION = 'https://docs.mongodb.com/master/reference/collation/';
const HELP_URL_MAX_TIME_MS = 'https://www.mongodb.com/docs/manual/reference/method/cursor.maxTimeMS/';

/**
* The collation toolbar component.
Expand All @@ -20,8 +23,10 @@ class CollationToolbar extends PureComponent {
collation: PropTypes.oneOfType([PropTypes.bool, PropTypes.object]),
collationChanged: PropTypes.func.isRequired,
collationString: PropTypes.string,
maxTimeMS: PropTypes.number,
collationStringChanged: PropTypes.func.isRequired,
openLink: PropTypes.func.isRequired
openLink: PropTypes.func.isRequired,
maxTimeMSChanged: PropTypes.func,
};

static defaultProps = { collation: {}, collationString: ''};
Expand All @@ -38,6 +43,12 @@ class CollationToolbar extends PureComponent {
this.props.collationChanged(evt.target.value);
};

onMaxTimeMsChanged = (evt) => {
if (this.props.maxTimeMSChanged) {
this.props.maxTimeMSChanged(parseInt(evt.currentTarget.value, 10));
}
};

/**
* Sets collation input focus
*/
Expand All @@ -58,38 +69,63 @@ class CollationToolbar extends PureComponent {
* @returns {React.Component} The component.
*/
render() {
const isNewToolbar =
global?.process?.env?.COMPASS_SHOW_NEW_AGGREGATION_TOOLBAR === 'true';
return (
<div
data-testid="legacy-collation-toolbar"
className={classnames(styles['collation-toolbar'], {
[styles['collation-toolbar-in-new-toolbar']]:
global?.process?.env?.COMPASS_SHOW_NEW_AGGREGATION_TOOLBAR ===
'true',
[styles['collation-toolbar-in-new-toolbar']]: isNewToolbar,
})}
>
<div
onBlur={this._onBlur}
onFocus={this._onFocus}
className={classnames(
styles['collation-toolbar-input-wrapper'],
styles['toolbar-input-wrapper'],
{ [ styles['has-focus'] ]: this.state.hasFocus }
)}
>
<div
className={classnames(
styles['collation-toolbar-input-label'],
styles['toolbar-input-label'],
{ [ styles['has-error'] ]: (this.props.collation === false) }
)}
data-testid="collation-toolbar-input-label">
<InfoSprinkle helpLink={HELP_URL_COLLATION} onClickHandler={this.props.openLink} />
Collation
</div>
<input
data-test-id="collation-string"
data-testid="collation-string"
placeholder="{ locale: 'simple' }"
type="text"
onChange={this.onCollationChange}
value={this.props.collationString} />
value={this.props.collationString}
/>
{isNewToolbar && (
<div className={classnames(styles['max-time-ms'])}>
<div
className={classnames(styles['toolbar-input-label'])}
data-testid="maxtimems-toolbar-input-label"
>
<InfoSprinkle
helpLink={HELP_URL_MAX_TIME_MS}
onClickHandler={this.props.openLink}
/>
Max Time MS
</div>
<input
data-testid="max-time-ms"
id="max-time-limit"
aria-describedby="max-time-limit"
type="number"
min="0"
placeholder={DEFAULT_MAX_TIME_MS}
value={this.props.maxTimeMS}
onChange={this.onMaxTimeMsChanged}
/>
</div>
)}
</div>
</div>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
border: none,
}

.collation-toolbar-input-wrapper {
.toolbar-input-wrapper {
width: 100%;
height: 30px;
position: relative;
Expand All @@ -29,22 +29,22 @@
padding: 4px;
margin-right: 5px;

.collation-toolbar-input-label {
.toolbar-input-label {
background: @gray5;
color: @pw;
white-space: nowrap;
border-radius: 14px;
padding: 2px 1px;
padding: 2px 8px 2px 4px;
margin-right: 5px;
text-transform: uppercase;
font-weight: bold;
font-family: "Akzidenz", "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 11px;
flex-grow: 0;
width: 117px;

i {
margin-right: 3px;
margin-left: 0px;
}
}

Expand All @@ -60,6 +60,18 @@
input:focus {
outline-width: 0;
}

.max-time-ms {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe we can hide the arrow buttons here to make it more like the one in the query bar

display: flex;
min-width: 170px;

input[type=number]::-webkit-inner-spin-button,
input[type=number]::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
}

}

.has-focus {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,12 +37,66 @@ describe('CollationToolbar [Component]', function() {
expect(component.find(`.${styles['collation-toolbar']}`)).to.be.present();
});

it('renders the collation lable', function() {
expect(component.find(`.${styles['collation-toolbar-input-label']}`)).
to.be.present();
it('renders the collation label', function() {
expect(
component.find('[data-testid="collation-toolbar-input-label"]')
).to.be.present();
});

it('renders the collation tooltip', function() {
expect(component.find('.info-sprinkle')).to.be.present();
});

it('renders the collation input', function() {
expect(
component.find('[data-testid="collation-string"]')
).to.be.present();
});

it('does not render the maxTimeMS label by default', function() {
expect(
component.find('[data-testid="maxtimems-toolbar-input-label"]')
).not.be.present();
});

it('does not render the maxTimeMS input by default', function() {
expect(
component.find('[data-testid="max-time-ms"]')
).not.be.present();
});

describe('CollationToolbar [Component] with maxTimeMS', function() {
const showNewAggregationInitialValue = process.env.COMPASS_SHOW_NEW_AGGREGATION_TOOLBAR;
let component;
beforeEach(function() {
process.env.COMPASS_SHOW_NEW_AGGREGATION_TOOLBAR = 'true';
component = mount(
<CollationToolbar
maxTimeMS={1000}
maxTimeMSChanged={() => {}}
collation={{ locale: 'simple' }}
collationChanged={() => {}}
collationString="{locale: 'simple' }"
collationStringChanged={() => {}}
openLink={() => {}} />
);
});

afterEach(function() {
component = null;
process.env.COMPASS_SHOW_NEW_AGGREGATION_TOOLBAR = showNewAggregationInitialValue;
});

it('renders the maxTimeMS label', function() {
expect(
component.find('[data-testid="maxtimems-toolbar-input-label"]')
).to.be.present();
});

it('renders the maxTimeMS input', function() {
expect(
component.find('[data-testid="max-time-ms"]')
).to.be.present();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -98,15 +98,49 @@ class Settings extends PureComponent {
}
}

renderMaxTimeMs() {
const isNewToolbar =
global?.process?.env?.COMPASS_SHOW_NEW_AGGREGATION_TOOLBAR === 'true';
if (isNewToolbar) {
return null;
}

const maxTimeMS = this.props.settings.isDirty
? this.props.settings.maxTimeMS
: this.props.maxTimeMS;

return (
<div className={classnames(styles['input-group'])}>
<div className={classnames(styles['input-meta'])}>
<Label htmlFor="aggregation-max-time-ms">Max Time</Label>
<Description id="aggregation-max-time-ms-description">
Specifies a cumulative time limit in milliseconds for processing
operations on a cursor. Max timeout prevents long hang times.
</Description>
</div>
<div className={classnames(styles['input-control'])}>
<input
id="aggregation-max-time-ms"
aria-describedby="aggregation-max-time-ms-description"
type="number"
placeholder={DEFAULT_MAX_TIME_MS}
min="0"
step="1000"
value={maxTimeMS}
onChange={this.onMaxTimeoutChanged.bind(this)}
/>
</div>
</div>
);
}

renderFields() {
let commentModeChecked = this.props.isCommenting;
let sampleSize = this.props.limit;
let maxTimeMS = this.props.maxTimeMS;

if (this.props.settings.isDirty) {
commentModeChecked = this.props.settings.isCommentMode;
sampleSize = this.props.settings.sampleSize;
maxTimeMS = this.props.settings.maxTimeMS;
}

return (
Expand Down Expand Up @@ -146,27 +180,7 @@ class Settings extends PureComponent {
/>
</div>
</div>
<div className={classnames(styles['input-group'])}>
<div className={classnames(styles['input-meta'])}>
<Label htmlFor="aggregation-max-time-ms">Max Time</Label>
<Description id="aggregation-max-time-ms-description">
Specifies a cumulative time limit in milliseconds for processing
operations on a cursor. Max timeout prevents long hang times.
</Description>
</div>
<div className={classnames(styles['input-control'])}>
<input
id="aggregation-max-time-ms"
aria-describedby="aggregation-max-time-ms-description"
type="number"
placeholder={DEFAULT_MAX_TIME_MS}
min="0"
step="1000"
value={maxTimeMS}
onChange={this.onMaxTimeoutChanged.bind(this)}
/>
</div>
</div>
{this.renderMaxTimeMs()}
{this.renderLargeLimit()}
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion packages/compass-e2e-tests/helpers/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ export const MyQueriesList = '[data-testid="my-queries-list"]';
export const StageContainer = '[data-test-id="stage-container"]';
export const CreateNewPipelineButton = 'button#create-new-pipeline';
export const ToggleAggregationCollation = '[data-test-id="toggle-collation"]';
export const AggregationCollationInput = '[data-test-id="collation-string"]';
export const AggregationCollationInput = '[data-testid="collation-string"]';
export const AggregationSettingsButton =
'[data-test-id="aggregation-settings"]';
export const AggregationCommentModeCheckbox = '#aggregation-comment-mode';
Expand Down