Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d08658e
feat(message-list): Implement virtual scroll table
shadowbas Nov 29, 2024
9fec25e
fixup! feat(message-list): Implement virtual scroll table
Jun 18, 2025
6f7d128
fixup! fixup! fixup! feat(message-list): Implement virtual scroll table
Jun 18, 2025
05c5d02
fixup! fixup! fixup! fixup! feat(message-list): Implement virtual scr…
Jun 18, 2025
8833047
fixup! fixup! fixup! fixup! fixup! feat(message-list): Implement virt…
Jun 18, 2025
399ac92
fixup! fixup! fixup! fixup! fixup! fixup! feat(message-list): Impleme…
Jun 18, 2025
4224f1c
fixup! fixup! fixup! fixup! fixup! fixup! fixup! feat(message-list): …
Jun 18, 2025
b5f3632
fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! feat(message-…
Jun 18, 2025
390069d
fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! feat(m…
Jun 18, 2025
9112bbf
fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup!…
Jun 19, 2025
6bc39f4
fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup! fixup!…
Jun 19, 2025
47cfacc
Some more cleanup of canvas code
Sep 3, 2025
70673e7
fixup! Some more cleanup of canvas code
Sep 3, 2025
e2d62bb
fixup! fixup! Some more cleanup of canvas code
Sep 3, 2025
db20725
Remove the canvastable components
Sep 3, 2025
c3b4e50
Remove the dollar postfix for rxjs streams
Sep 3, 2025
94f0325
Do reset column no longer used
Sep 3, 2025
b7f451b
Fix lint issues of accessible table changes
Sep 3, 2025
23b040f
Fix failing build
Sep 3, 2025
3e0375c
fixup! Fix failing build
shadowbas Sep 4, 2025
4122b13
fixup! fixup! Fix failing build
shadowbas Sep 4, 2025
7af8acc
fixup! fixup! fixup! Fix failing build
shadowbas Sep 4, 2025
3ece240
fixup! fixup! fixup! fixup! Fix failing build
shadowbas Sep 4, 2025
1d211ba
fixup! fixup! fixup! fixup! fixup! Fix failing build
shadowbas Sep 4, 2025
cbd1a67
fixup! fixup! fixup! fixup! fixup! fixup! Fix failing build
shadowbas Sep 4, 2025
956b583
Trying to fix reactive bulk action issue
shadowbas Sep 8, 2025
4e8542c
Remove update message list height callback from app template
Sep 9, 2025
706a346
Fix scroll to index rename
Sep 9, 2025
e67b007
Remove unused mutations arg
Sep 9, 2025
26207f0
fixup! Remove update message list height callback from app template
Sep 9, 2025
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
37 changes: 37 additions & 0 deletions e2e/cypress/component/message_list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
const pick = (functions) => {
const randomIndex = Math.floor(Math.random() * functions.length);
return functions[randomIndex]; // Returns a randomly selected function
};

export function rangeCheckMessages(from, to) {
checkMessage(from)
cy.get('body').type('{shift}', { release: false }); // Press Shift
checkMessage(to)
cy.get('body').type('{shift}'); // Release Shift
}

function table() {
return cy.get('app-virtual-scroll-table');
}

export function firstMessage() {
return nthMessage(0)
}

export function nthMessage(n) {
return table().find('tbody').eq(n);
}

export function checkMessage(n) {
const checkboxClick = () => nthMessage(n).find('mat-checkbox').click()
const ctrlMessageClick = () => nthMessage(n).click({ ctrlKey: true })

return pick([
checkboxClick,
ctrlMessageClick,
])()
}

export function checkedMessages() {
return cy.get('tbody .mat-checkbox-checked')
}
44 changes: 25 additions & 19 deletions e2e/cypress/integration/canvastable.ts
Original file line number Diff line number Diff line change
@@ -1,38 +1,44 @@
/// <reference types="cypress" />

describe('Selecting rows in canvastable', () => {
function canvas() {
return cy.get('canvastable canvas:first-of-type');
}
import { checkMessage, checkedMessages, rangeCheckMessages } from '../component/message_list.ts';

function moveButton() {
return cy.get('button[mattooltip*="Move"]');
}
function moveButton() {
return cy.get('button[mattooltip*="Move"]');
}

it('should select one row', () => {
describe('Selecting rows in canvastable', () => {
it('should select and deselect one row', () => {
cy.viewport('iphone-6');
cy.visit('/');

// select
canvas().click({ x: 15, y: 40 });
moveButton().should('not.exist');
checkMessage(0)
moveButton().should('be.visible');
// unselect
canvas().click({ x: 21, y: 41, force: true });
checkedMessages().should('have.length', 1)
checkMessage(0)
moveButton().should('not.exist');
})

it('should select multiple rows', () => {
cy.viewport('iphone-6');
cy.visit('/');

canvas().trigger('mousedown', { x: 15, y: 10 });
for (let ndx = 0; ndx <= 5; ndx++) {
canvas().trigger('mousemove', { x: 20, y: 36 * ndx + 11 });
}
rangeCheckMessages(0, 5)


// Verify multiple checkboxes are checked
checkedMessages().should('have.length', 6);

moveButton().should('be.visible');

// unselect by moving mouse back up
canvas().trigger('mousemove', { x: 21, y: 12 });
checkMessage(0)

// Verify count decreases
checkedMessages().should('have.length', 5)

rangeCheckMessages(1, 5)
checkedMessages().should('have.length', 0)
moveButton().should('not.exist');
})
});

})
5 changes: 2 additions & 3 deletions e2e/cypress/integration/compose.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
/// <reference types="cypress" />

import { firstMessage } from '../component/message_list.ts';

describe('Composing emails', () => {
beforeEach(async () => {
localStorage.setItem('221:localSearchPromptDisplayed', JSON.stringify('true'));
Expand Down Expand Up @@ -104,10 +106,7 @@ describe('Composing emails', () => {
});

it('closing a new reply should return to inbox', () => {
cy.visit('/');
cy.wait(1000);
cy.visit('/#Inbox:1');
cy.get('canvastable canvas:first-of-type').click({ x: 300, y: 10 });
cy.get('single-mail-viewer').should('exist');
cy.get('button[mattooltip="Reply"]').click();
cy.get('button[mattooltip="Close draft"').click();
Expand Down
11 changes: 5 additions & 6 deletions e2e/cypress/integration/folder-switching.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
/// <reference types="cypress" />

describe('Switching between folders (and not-folders)', () => {

function goToInbox() {
cy.get('rmm-folderlist mat-tree-node:contains(Inbox)', {'timeout':10000}).click();
cy.url().should('match', /\/(#Inbox)?$/);
cy.get('rmm-folderlist mat-tree-node:contains(Inbox)').should('have.class', 'selectedFolder');
}

it('can switch from welcome to inbox', () => {
localStorage.setItem('221:localSearchPromptDisplayed', JSON.stringify('true'));
localStorage.setItem('221:localSearchPromptDisplayed', JSON.stringify('true'));
it('can switch from welcome to inbox', () => {
localStorage.setItem('221:localSearchPromptDisplayed', JSON.stringify('true'));
localStorage.setItem('221:localSearchPromptDisplayed', JSON.stringify('true'));

// start of on /welcome, like a fresh new user
cy.visit('/welcome');
// start of on /welcome, like a fresh new user
cy.visit('/welcome');

// should be able to switch to inbox...
goToInbox();
Expand Down
16 changes: 8 additions & 8 deletions e2e/cypress/integration/folders.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/// <reference types="cypress" />

describe('Folder management', () => {
function canvas() {
return cy.get('canvastable canvas:first-of-type');
}
import { firstMessage } from '../component/message_list.ts'

describe('Folder management', () => {
it('should create folder at root level', () => {
cy.intercept('GET', '/rest/v1/email_folder/list').as('getEmailFolders');
cy.visit('/');

cy.wait('@getEmailFolders');
cy.wait(5000);
cy.get('#createFolderButton').click();
cy.get('.mat-dialog-title').should('contain', 'Add new folder');
cy.get('mat-dialog-container mat-dialog-content').should('contain', 'root level');
Expand All @@ -32,9 +32,9 @@ describe('Folder management', () => {
});

it('should create new draft on templates folder message click', () => {
cy.visit('/')
cy.contains('mat-tree-node', 'Templates').click()
canvas().click({ x: 55, y: 40 });
cy.visit('/')
cy.contains('mat-tree-node', 'Templates').click()
firstMessage().click();
cy.location().should((loc) => {
expect(loc.pathname).to.eq('/compose');
});
Expand Down
43 changes: 6 additions & 37 deletions e2e/cypress/integration/mailviewer.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
/// <reference types="cypress" />

describe('Interacting with mailviewer', () => {
function canvas() {
return cy.get('canvastable canvas:first-of-type');
}
import { nthMessage } from '../component/message_list.ts'

describe('Interacting with mailviewer', () => {
beforeEach(async () => {
localStorage.setItem('221:localSearchPromptDisplayed', JSON.stringify('true'));
localStorage.setItem('221:Global:messageSubjectDragTipShown', JSON.stringify('true'));
Expand All @@ -26,30 +24,20 @@ describe('Interacting with mailviewer', () => {
// });

it('can open an email and go back and forth in browser history', () => {
cy.intercept('/rest/v1/email/download/*').as('get11');
cy.visit('/#Inbox:11');

cy.wait('@get11', {'timeout':10000});
// canvas().click(400, 300);

cy.hash().should('equal', '#Inbox:11');
/* TODO: apparently forward broke at some point
* in headless mode. Works normally in a proper browser
nthMessage(1).click();
cy.hash().should('equal', '#Inbox:2');
cy.go('back');
cy.hash().should('not.contain', 'Inbox:11');
cy.go('forward');
cy.hash().should('equal', '#Inbox:11');
cy.go('forward');
cy.hash().should('equal', '#Inbox:2');
cy.get('button[mattooltip="Close"]').click();
cy.hash().should('equal', '#Inbox');
*/
});

it('can reply to an email with no "To"', () => {
cy.intercept('/rest/v1/email/download/*').as('get11');
cy.visit('/#Inbox:11')
cy.wait('@get11', {'timeout':10000});
// cy.get('#messageContents');

cy.get('button[mattooltip="Reply"]').click();
cy.location().should((loc) => {
expect(loc.pathname).to.eq('/compose');
Expand All @@ -59,11 +47,8 @@ describe('Interacting with mailviewer', () => {
});

it('can forward an email with no "To"', () => {
cy.intercept('/rest/v1/email/download/*').as('get11');
cy.visit('/');
cy.wait('@get11', {'timeout':10000});
cy.visit('/#Inbox:11');
// cy.get('#messageContents');

cy.get('button[mattooltip="Forward"]').click();
cy.location().should((loc) => {
Expand All @@ -74,11 +59,8 @@ describe('Interacting with mailviewer', () => {
});

it('can reply to an email with no "To" or "Subject"', () => {
cy.intercept('/rest/v1/email/download/*').as('get13');
cy.visit('/');
cy.wait('@get13', {'timeout':10000});
cy.visit('/#Inbox:13');
// cy.get('#messageContents');

cy.get('button[mattooltip="Reply"]').click();
cy.location().should((loc) => {
Expand All @@ -89,11 +71,8 @@ describe('Interacting with mailviewer', () => {
});

it('can forward an email with no "To" or "Subject"', () => {
cy.intercept('/rest/v1/email/download/*').as('get13');
cy.visit('/');
cy.wait('@get13', {'timeout':10000});
cy.visit('/#Inbox:13');
// cy.get('#messageContents');

cy.get('button[mattooltip="Forward"]').click();
cy.location().should((loc) => {
Expand All @@ -104,9 +83,7 @@ describe('Interacting with mailviewer', () => {
});

it('Vertical to horizontal mode exposes full height button', () => {
cy.intercept('/rest/v1/email/download/*').as('get11');
cy.visit('/');
cy.wait('@get11', {'timeout':10000});
cy.visit('/#Inbox:11');

// Make sure we're in vertical mode
Expand All @@ -116,9 +93,7 @@ describe('Interacting with mailviewer', () => {
});

it('Changing viewpane height is stored', () => {
cy.intercept('/rest/v1/email/download/*').as('get11');
cy.visit('/');
cy.wait('@get11', {'timeout':10000});
cy.visit('/#Inbox:11');
// cy.hash().should('equal', '#Inbox:11');

Expand All @@ -133,9 +108,7 @@ describe('Interacting with mailviewer', () => {
});

it('Half height reduces stored pane height', () => {
cy.intercept('/rest/v1/email/download/*').as('get11');
cy.visit('/');
cy.wait('@get11', {'timeout':10000});
cy.visit('/#Inbox:11');
// cy.hash().should('equal', '#Inbox:11');

Expand All @@ -161,9 +134,7 @@ describe('Interacting with mailviewer', () => {
});

it('Revisit open email in horizontal mode loads it', () => {
cy.intercept('/rest/v1/email/download/*').as('get11');
cy.visit('/');
cy.wait('@get11', {'timeout':10000});
cy.visit('/#Inbox:11');
// cy.hash().should('equal', '#Inbox:11');

Expand All @@ -177,9 +148,7 @@ describe('Interacting with mailviewer', () => {
});

it('Can go out of mailviewer and back and still see our email', () => {
cy.intercept('/rest/v1/email/download/*').as('get12');
cy.visit('/');
cy.wait('@get12',{'timeout':10000});
cy.visit('/#Inbox:12');
// cy.hash().should('equal', '#Inbox:12');

Expand Down
38 changes: 0 additions & 38 deletions e2e/cypress/integration/message-caching.ts

This file was deleted.

Loading
Loading