Skip to content

Commit

Permalink
[Calendar] Adding support for bi-directional linking (#73)
Browse files Browse the repository at this point in the history
Using new setCursor API in the calendar widget, which will allow bi-directional linking to work.

New test was added and some updated.

#73
  • Loading branch information
berhalak authored Sep 27, 2023
1 parent acb935a commit c03f3a0
Show file tree
Hide file tree
Showing 4 changed files with 105 additions and 18 deletions.
13 changes: 7 additions & 6 deletions calendar/page.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ class CalendarHandler {
this.calendar.on('beforeUpdateEvent', onCalendarEventBeingUpdated);
this.calendar.on('clickEvent', async (info) => {
focusWidget();
await grist.setSelectedRows([info.event.id]);
await grist.setCursorPos({rowId: info.event.id});
});
this.calendar.on('selectDateTime', async (info) => {
focusWidget();
Expand All @@ -93,6 +93,7 @@ class CalendarHandler {
if (!isRecordValid(record) || this._selectedRecordId === record.id) {
return;
}
grist.setCursorPos({rowId: record.id});

if (this._selectedRecordId) {
this.calendar.updateEvent(this._selectedRecordId, CALENDAR_NAME, {backgroundColor: CalendarHandler._mainColor});
Expand Down Expand Up @@ -215,8 +216,6 @@ function updateUIAfterNavigation(){
}
// let's subscribe to all the events that we need
async function configureGristSettings() {
// table selection should change when another event is selected
grist.allowSelectBy();
// CRUD operations on records in table
grist.onRecords(updateCalendar);
// When cursor (selected record) change in the table
Expand All @@ -226,7 +225,7 @@ async function configureGristSettings() {

// bind columns mapping options to the GUI
const columnsMappingOptions = getGristOptions();
grist.ready({ requiredAccess: 'read table', columns: columnsMappingOptions });
grist.ready({ requiredAccess: 'read table', columns: columnsMappingOptions, allowSelectBy: true });
}

// when a user selects a record in the table, we want to select it on the calendar
Expand Down Expand Up @@ -291,7 +290,8 @@ async function upsertGristRecord(gristEvent) {
if (gristEvent.id) {
await table.update(eventInValidFormat);
} else {
await table.create(eventInValidFormat);
const {id} = await table.create(eventInValidFormat);
await grist.setCursorPos({rowId: id});
}
} catch (err) {
// Nothing clever we can do here, just log the error.
Expand Down Expand Up @@ -378,7 +378,8 @@ function testGetCalendarEvent(eventId) {
title: calendarObject?.title,
startDate: calendarObject?.start.d.d,
endDate: calendarObject?.end.d.d,
isAllDay: calendarObject?.isAllday ?? false
isAllDay: calendarObject?.isAllday ?? false,
selected: calendarObject?.backgroundColor === CalendarHandler._selectedColor
};
return JSON.stringify(eventData);
} else {
Expand Down
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
"serve:dev": "live-server --port=8585 --no-browser -q --middleware=$(pwd)/buildtools/rewriteUrl.js",
"watch": "nodemon --ignore manifest.json -e js,json --exec 'npm run build:dev'",
"dev": "echo 'Starting local server and watching for changes.\nStart Grist with an environmental variable GRIST_WIDGET_LIST_URL=http://localhost:8585/manifest.json' && npm run watch 1> /dev/null & npm run serve:dev 1> /dev/null",
"test": "docker image inspect gristlabs/grist --format 'gristlabs/grist image present' && NODE_PATH=_build SELENIUM_BROWSER=chrome mocha _build/test/*.js",
"pretest": "docker pull gristlabs/grist && tsc --build && node ./buildtools/publish.js http://localhost:9998"
"test": "docker image inspect gristlabs/grist --format 'gristlabs/grist image present' && NODE_PATH=_build SELENIUM_BROWSER=chrome mocha -g \"${GREP_TESTS}\" _build/test/*.js",
"test:ci": "MOCHA_WEBDRIVER_HEADLESS=1 npm run test",
"pretest": "docker pull gristlabs/grist && tsc --build && node ./buildtools/publish.js http://localhost:9998",
"grist": "docker run -t -i --rm --name grist-dev --network=host -e PORT=8484 -e GRIST_SINGLE_ORG=preview -e GRIST_WIDGET_LIST_URL=http://localhost:8585/manifest.json gristlabs/grist"
},
"devDependencies": {
"@types/chai": "^4.3.5",
Expand Down
89 changes: 79 additions & 10 deletions test/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ function buildGetCalendarObjectScript(eventId: number) {
}

describe('calendar', function () {
this.timeout(20000);
this.timeout('30s');
const grist = getGrist();
grist.bigScreen();

async function executeAndWaitForCalendar(action: () => Promise<void>) {
const oldDataVersion = await getDateVersion();
Expand Down Expand Up @@ -62,7 +63,8 @@ describe('calendar', function () {
title: "New Event",
startDate: new Date('2023-08-03 13:00').toJSON(),
endDate: new Date('2023-08-03 14:00').toJSON(),
isAllDay: false
isAllDay: false,
selected: false
})
});

Expand Down Expand Up @@ -99,7 +101,8 @@ describe('calendar', function () {
title: "New Event",
startDate: new Date('2023-08-03 13:00').toJSON(),
endDate: new Date('2023-08-03 15:00').toJSON(),
isAllDay: false
isAllDay: false,
selected: false
})
});

Expand Down Expand Up @@ -191,6 +194,8 @@ describe('calendar', function () {

// Now try to add a record. It should fail.
await clickDay(10);
await grist.waitForServer();
assert.equal(await eventsCount(), 0);

// We don't have a good way of checking it. So we just check at the end that we have only one event..

Expand All @@ -201,6 +206,8 @@ describe('calendar', function () {

// Now try to add a record. It should fail.
await clickDay(11);
await grist.waitForServer();
assert.equal(await eventsCount(), 0);

// Now with full access.
await grist.setCustomWidgetAccess('full');
Expand All @@ -211,18 +218,64 @@ describe('calendar', function () {
await grist.waitForServer();

await grist.waitToPass(async () => {
await grist.inCustomWidget(async () => {
// We see only summaries (like 1 more)
const texts = await driver.findAll(`.toastui-calendar-weekday-grid-more-events`, g => g.getText());
const numbers = texts.map(t => Number(t.replace(/[^0-9]/g, '')));
const sum = numbers.reduce((a, b) => a + b, 0);
assert.equal(sum, 1);
});
assert.equal(await eventsCount(), 1);
});

await grist.undo();

// TODO: add test for ACL permissions tests and looking at document as a different user.
});

it("should support bi-directional linking", async function () {
// Make sure we have clean view
assert.equal(await eventsCount(), 1);

// Now configure bi-directional mapping.
await grist.sendActionsAndWaitForServer([
['UpdateRecord', '_grist_Views_section', 1, {linkSrcSectionRef: 3}],
['UpdateRecord', '_grist_Views_section', 3, {linkSrcSectionRef: 1}],
]);

// Add 4 events in the calendar.
await clickDay(14);
await clickDay(15);
await clickDay(16);
await clickDay(17);

// Now test if bi-directional mapping works.
await grist.waitToPass(async () => {
assert.equal(await eventsCount(), 5);
});

// Select 2 row in grid view.
await clickRow(2);

assert.equal(await selectedRow(), 2);

// Calendar should be focues on 3rd event.
assert.isTrue(await getCalendarEvent(3).then(c => c.selected));

// Click 4th row
await clickRow(3);
assert.equal(await selectedRow(), 3);
assert.isTrue(await getCalendarEvent(4).then(c => c.selected));

// Now click on the last visible event
await grist.inCustomWidget(async () => {
const element = driver.findWait(`div[data-event-id="6"] .toastui-calendar-weekday-event-title`, 200);
await driver.withActions(ac =>
ac.move({origin: element}).press().pause(80).release()
);
});

// Grid should move to 5th row.
await grist.waitToPass(async () => {
assert.equal(await selectedRow(), 5);
});
await grist.undo(4); // Revert both changes to the view and events.
await grist.undo(1);
});

//Helpers
async function selectPerspective(perspective: 'month' | 'week' | 'day') {
await grist.inCustomWidget(async () => {
Expand Down Expand Up @@ -251,4 +304,20 @@ describe('calendar', function () {
await grist.waitForServer();
}

function eventsCount() {
return grist.inCustomWidget(async () => {
// We see only summaries (like 1 more)
const texts = await driver.findAll(`div[data-event-id]`, g => g.getAttribute('data-event-id'));
const numbers = new Set(texts.map(t => Number(t)));
return numbers.size;
});
}

async function clickRow(rowIndex: number) {
await driver.findContentWait('.gridview_data_row_num', String(rowIndex), 200).click();
}

async function selectedRow() {
return Number(await driver.findWait('.gridview_data_row_num.selected', 200).then(e => e.getText()));
}
});
15 changes: 15 additions & 0 deletions test/gristWebDriverUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,21 @@ export class GristWebDriverUtils {
}
await this.waitForServer(optTimeout);
}


/**
* Changes browser window dimensions to FullHd for a test suite.
*/
public bigScreen() {
let oldDimensions: WindowDimensions;
before(async () => {
oldDimensions = await this.driver.manage().window().getRect();
await this.driver.manage().window().setRect({width: 1920, height: 1080});
});
after(async () => {
await this.driver.manage().window().setRect(oldDimensions);
});
}
}

export interface WindowDimensions {
Expand Down

0 comments on commit c03f3a0

Please sign in to comment.