Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(schema-validation): add confirmation modal when applying rules, add explicit editing state COMPASS-8861 #6766

Merged
merged 2 commits into from
Mar 5, 2025
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
3 changes: 3 additions & 0 deletions packages/compass-e2e-tests/helpers/commands/set-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export async function setValidation(

await browser.clickVisible(Selectors.UpdateValidationButton);

// Confirm in the confirmation modal.
await browser.clickVisible(Selectors.confirmationModalConfirmButton());

// both buttons should become hidden if it succeeds
await validationActionMessageElement.waitForDisplayed({
reverse: true,
Expand Down
2 changes: 2 additions & 0 deletions packages/compass-e2e-tests/helpers/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,8 @@ export const UnhideIndexButton = '[data-testid="index-actions-unhide-action"]';

// Validation tab
export const AddRuleButton = '[data-testid="add-rule-button"]';
export const EnableEditValidationButton =
'[data-testid="enable-edit-validation-button"]';
export const ValidationEditor = '[data-testid="validation-editor"]';
export const ValidationActionMessage =
'[data-testid="validation-action-message"]';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,14 @@ describe('Collection validation tab', function () {
);
});

// Reset the validation again to make everything valid for future tests
const enableUpdateValidationButtonElement = browser.$(
Selectors.EnableEditValidationButton
);
// Enable the editing mode and wait for it to be enabled.
await browser.clickVisible(enableUpdateValidationButtonElement);
await enableUpdateValidationButtonElement.waitForDisplayed({
reverse: true,
});

// the automatic indentation and brackets makes multi-line values very fiddly here
await browser.setValidation(PASSING_VALIDATOR);
Expand Down
9 changes: 9 additions & 0 deletions packages/compass-editor/src/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ const disabledContainerDarkModeStyles = css({
boxShadow: `0 0 0 1px ${palette.gray.dark2}`,
});

const readOnlyStyle = css({
// We hide the blinking cursor in read only mode
// as it can appear to users like the editor is editable.
'& .cm-cursor': {
display: 'none !important',
},
});

const hiddenScrollStyle = css({
'& .cm-scroller': {
overflow: '-moz-scrollbars-none',
Expand Down Expand Up @@ -1204,6 +1212,7 @@ const BaseEditor = React.forwardRef<EditorRef, EditorProps>(function BaseEditor(
className={cx(
disabled && disabledContainerStyles,
disabled && darkMode && disabledContainerDarkModeStyles,
readOnly && readOnlyStyle,
className
)}
style={{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,88 +1,94 @@
import React from 'react';
import { render, screen } from '@mongodb-js/testing-library-compass';
import { render, screen, userEvent } from '@mongodb-js/testing-library-compass';
import { expect } from 'chai';
import sinon from 'sinon';
import { ValidationEditor } from './validation-editor';

function renderValidationEditor(
props: Partial<React.ComponentProps<typeof ValidationEditor>>
) {
const validation = {
validator: '',
validationAction: 'warn',
validationLevel: 'moderate',
isChanged: false,
syntaxError: null,
error: null,
} as const;

return render(
<ValidationEditor
namespace="test.test"
validatorChanged={() => {}}
validationActionChanged={() => {}}
validationLevelChanged={() => {}}
cancelValidation={() => {}}
saveValidation={() => {}}
clearSampleDocuments={() => {}}
serverVersion="8.0.5"
onClickEnableEditRules={() => {}}
validation={validation}
isEditable
isEditingEnabled
{...props}
/>
);
}

describe('ValidationEditor [Component]', function () {
context('when it is an editable mode', function () {
const setValidatorChangedSpy = sinon.spy();
const setValidationActionChangedSpy = sinon.spy();
const setValidationLevelChangedSpy = sinon.spy();
const setCancelValidationSpy = sinon.spy();
const saveValidationSpy = sinon.spy();
const clearSampleDocumentsSpy = sinon.spy();
const serverVersion = '3.6.0';
const validation = {
validator: '',
validationAction: 'warn',
validationLevel: 'moderate',
isChanged: false,
syntaxError: null,
error: null,
} as const;
const isEditable = true;
context(
'when it is an editable mode but editing is not yet enabled',
function () {
let onClickEnableEditRulesSpy: sinon.SinonSpy;
beforeEach(function () {
onClickEnableEditRulesSpy = sinon.spy();
renderValidationEditor({
onClickEnableEditRules: onClickEnableEditRulesSpy,
isEditingEnabled: false,
isEditable: true,
});
});

it('does not allow to edit the editor', function () {
expect(screen.getByTestId('validation-editor')).to.exist;
expect(screen.getByRole('textbox').ariaReadOnly).to.eq('true');
expect(screen.getByTestId('enable-edit-validation-button')).to.be
.visible;
expect(onClickEnableEditRulesSpy).to.not.have.been.called;
userEvent.click(screen.getByTestId('enable-edit-validation-button'));
expect(onClickEnableEditRulesSpy).to.have.been.calledOnce;
});
}
);

context('when it is an editable mode and editing is enabled', function () {
beforeEach(function () {
render(
<ValidationEditor
namespace="test.test"
validatorChanged={setValidatorChangedSpy}
validationActionChanged={setValidationActionChangedSpy}
validationLevelChanged={setValidationLevelChangedSpy}
cancelValidation={setCancelValidationSpy}
saveValidation={saveValidationSpy}
clearSampleDocuments={clearSampleDocumentsSpy}
serverVersion={serverVersion}
validation={validation}
isEditable={isEditable}
/>
);
renderValidationEditor({
isEditable: true,
isEditingEnabled: true,
});
});

it('allows to edit the editor', function () {
expect(screen.getByTestId('validation-editor')).to.exist;
expect(screen.getByRole('textbox').ariaReadOnly).to.eq(null);
expect(
screen.queryByTestId('enable-edit-validation-button')
).to.not.exist;
});
});

context('when it is a not editable mode', function () {
const setValidatorChangedSpy = sinon.spy();
const setValidationActionChangedSpy = sinon.spy();
const setValidationLevelChangedSpy = sinon.spy();
const setCancelValidationSpy = sinon.spy();
const saveValidationSpy = sinon.spy();
const clearSampleDocumentsSpy = sinon.spy();
const serverVersion = '3.6.0';
const validation = {
validator: '',
validationAction: 'warn',
validationLevel: 'moderate',
isChanged: false,
syntaxError: null,
error: null,
} as const;
const isEditable = false;

beforeEach(function () {
render(
<ValidationEditor
namespace="test.test"
validatorChanged={setValidatorChangedSpy}
validationActionChanged={setValidationActionChangedSpy}
validationLevelChanged={setValidationLevelChangedSpy}
cancelValidation={setCancelValidationSpy}
saveValidation={saveValidationSpy}
clearSampleDocuments={clearSampleDocumentsSpy}
serverVersion={serverVersion}
validation={validation}
isEditable={isEditable}
/>
);
renderValidationEditor({
isEditable: false,
});
});

it('sets editor into readonly mode', function () {
expect(screen.getByRole('textbox').ariaReadOnly).to.eq('true');
expect(
screen.queryByTestId('enable-edit-validation-button')
).to.not.exist;
});
});
});
Loading
Loading