[MM-61716][MM-62643] Introduce Modal component, remove bootstrap and react-bootstrap from most modals, update styles (#3317)

* Introduce Modal, add some styles from the webapp

* Remove bootstrap from LoadingScreen/WelcomeScreen

* Migrate add/edit server modal to Modal, remove bootstrap

* Migrate remove server modal to Modal, remove bootstrap

* Migrate certificate modal to Modal, remove bootstrap

* Migrate login and permission modals to Modal, remove Bootstrap

* Misc fixes

* E2E tests for current modals

* Update src/renderer/components/Modal.tsx

Co-authored-by: Daniel Espino García <larkox@gmail.com>

* Update src/renderer/components/Modal.tsx

Co-authored-by: Daniel Espino García <larkox@gmail.com>

* PR feedback

---------

Co-authored-by: Daniel Espino García <larkox@gmail.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Devin Binnie
2025-02-18 10:58:28 -05:00
committed by GitHub
parent 34963cbaa8
commit 4d754efdd7
44 changed files with 1854 additions and 927 deletions

View File

@@ -99,8 +99,8 @@ describe('focus', function desc() {
const newServerView = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('newServer'),
});
await newServerView.waitForSelector('#cancelNewServerModal');
await newServerView.click('#cancelNewServerModal');
await newServerView.waitForSelector('#newServerModal_cancel');
await newServerView.click('#newServerModal_cancel');
const isTextboxFocused = await firstServer.$eval('#post_textbox', (el) => el === document.activeElement);
isTextboxFocused.should.be.true;

View File

@@ -80,7 +80,7 @@ describe('menu_bar/dropdown', function desc() {
const newServerModal = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('newServer'),
});
const modalTitle = await newServerModal.innerText('#newServerModal .modal-title');
const modalTitle = await newServerModal.innerText('#newServerModal .Modal__header__text_container');
modalTitle.should.equal('Add Server');
await afterFunc();

View File

@@ -46,7 +46,7 @@ describe('Add Server Modal', function desc() {
});
it('MM-T4388 should close the window after clicking cancel', async () => {
await newServerView.click('#cancelNewServerModal');
await newServerView.click('#newServerModal_cancel');
await asyncSleep(1000);
const existing = Boolean(this.app.windows().find((window) => window.url().includes('newServer')));
existing.should.be.false;
@@ -54,19 +54,17 @@ describe('Add Server Modal', function desc() {
describe('MM-T4389 Invalid messages', () => {
it('MM-T4389_1 should not be valid and save should be disabled if no server name or URL has been set', async () => {
const existing = await newServerView.isVisible('#nameValidation.error');
existing.should.be.true;
const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled');
const disabled = await newServerView.getAttribute('#newServerModal_confirm', 'disabled');
(disabled === '').should.be.true;
});
it('should warn the user if a server with the same URL exists, but still allow them to save', async () => {
await newServerView.type('#serverNameInput', 'some-new-server');
await newServerView.type('#serverUrlInput', config.teams[0].url);
await newServerView.waitForSelector('#urlValidation.warning');
const existing = await newServerView.isVisible('#urlValidation.warning');
await newServerView.waitForSelector('#customMessage_url.Input___warning');
const existing = await newServerView.isVisible('#customMessage_url.Input___warning');
existing.should.be.true;
const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled');
const disabled = await newServerView.getAttribute('#newServerModal_confirm', 'disabled');
(disabled === '').should.be.false;
});
@@ -76,8 +74,8 @@ describe('Add Server Modal', function desc() {
});
it('MM-T4389_2 Name should not be marked invalid, but should not be able to save', async () => {
await newServerView.waitForSelector('#nameValidation.error', {state: 'detached'});
const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled');
await newServerView.waitForSelector('#customMessage_name.Input___error', {state: 'detached'});
const disabled = await newServerView.getAttribute('#newServerModal_confirm', 'disabled');
(disabled === '').should.be.true;
});
});
@@ -88,9 +86,10 @@ describe('Add Server Modal', function desc() {
});
it('MM-T4389_3 URL should not be marked invalid, name should be marked invalid', async () => {
const existingUrl = await newServerView.isVisible('#urlValidation.error');
const existingName = await newServerView.isVisible('#nameValidation.error');
const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled');
await newServerView.waitForSelector('#customMessage_name.Input___error');
const existingUrl = await newServerView.isVisible('#customMessage_url.Input___error');
const existingName = await newServerView.isVisible('#customMessage_name.Input___error');
const disabled = await newServerView.getAttribute('#newServerModal_confirm', 'disabled');
existingName.should.be.true;
existingUrl.should.be.false;
(disabled === '').should.be.true;
@@ -100,8 +99,8 @@ describe('Add Server Modal', function desc() {
it('MM-T2826_1 should not be valid if an invalid server address has been set', async () => {
await newServerView.type('#serverUrlInput', 'superInvalid url');
await newServerView.waitForSelector('#urlValidation.error');
const existing = await newServerView.isVisible('#urlValidation.error');
await newServerView.waitForSelector('#customMessage_url.Input___error');
const existing = await newServerView.isVisible('#customMessage_url.Input___error');
existing.should.be.true;
});
@@ -109,16 +108,16 @@ describe('Add Server Modal', function desc() {
beforeEach(async () => {
await newServerView.type('#serverUrlInput', 'http://example.org');
await newServerView.type('#serverNameInput', 'TestServer');
await newServerView.waitForSelector('#urlValidation.warning');
await newServerView.waitForSelector('#customMessage_url.Input___warning');
});
it('should be possible to click add', async () => {
const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled');
const disabled = await newServerView.getAttribute('#newServerModal_confirm', 'disabled');
(disabled === null).should.be.true;
});
it('MM-T2826_2 should add the server to the config file', async () => {
await newServerView.click('#saveNewServerModal');
await newServerView.click('#newServerModal_confirm');
await asyncSleep(2000);
const existing = Boolean(this.app.windows().find((window) => window.url().includes('newServer')));
existing.should.be.false;

View File

@@ -40,7 +40,7 @@ describe('EditServerModal', function desc() {
let editServerView;
it('should not edit server when Cancel is pressed', async () => {
await editServerView.click('#cancelNewServerModal');
await editServerView.click('#newServerModal_cancel');
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer')));
existing.should.be.false;
@@ -70,7 +70,7 @@ describe('EditServerModal', function desc() {
});
it('MM-T4391_1 should not edit server when Save is pressed but nothing edited', async () => {
await editServerView.click('#saveNewServerModal');
await editServerView.click('#newServerModal_confirm');
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer')));
existing.should.be.false;
@@ -100,15 +100,15 @@ describe('EditServerModal', function desc() {
});
it('MM-T2826_3 should not edit server if an invalid server address has been set', async () => {
await editServerView.type('#serverUrlInput', 'superInvalid url');
await editServerView.waitForSelector('#urlValidation.error');
const existing = await editServerView.isVisible('#urlValidation.error');
await editServerView.fill('#serverUrlInput', 'superInvalid url');
await editServerView.waitForSelector('#customMessage_url.Input___error');
const existing = await editServerView.isVisible('#customMessage_url.Input___error');
existing.should.be.true;
});
it('MM-T4391_2 should edit server when Save is pressed and name edited', async () => {
await editServerView.fill('#serverNameInput', 'NewTestServer');
await editServerView.click('#saveNewServerModal');
await editServerView.click('#newServerModal_confirm');
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer')));
existing.should.be.false;
@@ -160,7 +160,7 @@ describe('EditServerModal', function desc() {
it('MM-T4391_3 should edit server when Save is pressed and URL edited', async () => {
await editServerView.fill('#serverUrlInput', 'http://google.com');
await editServerView.click('#saveNewServerModal');
await editServerView.click('#newServerModal_confirm');
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer')));
existing.should.be.false;
@@ -213,7 +213,7 @@ describe('EditServerModal', function desc() {
it('MM-T4391_4 should edit server when Save is pressed and both edited', async () => {
await editServerView.fill('#serverNameInput', 'NewTestServer');
await editServerView.fill('#serverUrlInput', 'http://google.com');
await editServerView.click('#saveNewServerModal');
await editServerView.click('#newServerModal_confirm');
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('editServer')));
existing.should.be.false;

View File

@@ -45,7 +45,7 @@ describe('LongServerName', function desc() {
it('MM-T4050 Long server name', async () => {
await newServerView.type('#serverNameInput', longServerName);
await newServerView.type('#serverUrlInput', longServerUrl);
await newServerView.click('#saveNewServerModal');
await newServerView.click('#newServerModal_confirm');
await asyncSleep(1000);
const existing = Boolean(this.app.windows().find((window) => window.url().includes('newServer')));

View File

@@ -73,7 +73,7 @@ describe('RemoveServerModal', function desc() {
it('MM-T4390_4 should disappear on click background', async () => {
// ignore any target closed error
try {
await removeServerView.click('.modal', {position: {x: 20, y: 20}});
await removeServerView.click('.Modal', {position: {x: 20, y: 20}});
} catch {} // eslint-disable-line no-empty
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('removeServer')));