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

Tweaks to overrides (added draggable bounds, take timezone into consideration) #4553

Merged
merged 16 commits into from
Jun 21, 2024
4 changes: 2 additions & 2 deletions grafana-plugin/e2e-tests/alerts/onCallSchedule.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ import { verifyThatAlertGroupIsTriggered } from '../utils/alertGroup';
import { createEscalationChain, EscalationStep } from '../utils/escalationChain';
import { generateRandomValue } from '../utils/forms';
import { createIntegrationAndSendDemoAlert } from '../utils/integrations';
import { createOnCallScheduleWithRotation } from '../utils/schedule';
import { createOnCallSchedule } from '../utils/schedule';

test('we can create an oncall schedule + receive an alert', async ({ adminRolePage }) => {
const { page, userName } = adminRolePage;
const escalationChainName = generateRandomValue();
const integrationName = generateRandomValue();
const onCallScheduleName = generateRandomValue();

await createOnCallScheduleWithRotation(page, onCallScheduleName, userName);
await createOnCallSchedule(page, onCallScheduleName, userName);
await createEscalationChain(
page,
escalationChainName,
Expand Down
4 changes: 2 additions & 2 deletions grafana-plugin/e2e-tests/insights/insights.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { createEscalationChain, EscalationStep } from '../utils/escalationChain'
import { clickButton, generateRandomValue } from '../utils/forms';
import { createIntegrationAndSendDemoAlert } from '../utils/integrations';
import { goToGrafanaPage, goToOnCallPage } from '../utils/navigation';
import { createOnCallScheduleWithRotation } from '../utils/schedule';
import { createOnCallSchedule } from '../utils/schedule';

/**
* Insights is dependent on Scenes which were only added in Grafana 10.0.0
Expand Down Expand Up @@ -66,7 +66,7 @@ test.describe.skip('Insights', () => {
const escalationChainName = generateRandomValue();
const integrationName = generateRandomValue();
const onCallScheduleName = generateRandomValue();
await createOnCallScheduleWithRotation(page, onCallScheduleName, userName);
await createOnCallSchedule(page, onCallScheduleName, userName);
await createEscalationChain(
page,
escalationChainName,
Expand Down
42 changes: 38 additions & 4 deletions grafana-plugin/e2e-tests/schedules/addOverride.test.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import dayjs from 'dayjs';

import { test, expect } from '../fixtures';
import { test, expect, Locator } from '../fixtures';
import { clickButton, generateRandomValue } from '../utils/forms';
import { createOnCallScheduleWithRotation, getOverrideFormDateInputs } from '../utils/schedule';
import { createOnCallSchedule, getOverrideFormDateInputs } from '../utils/schedule';

test('default dates in override creation modal are correct', async ({ adminRolePage }) => {
test('Default dates in override creation modal are set to today', async ({ adminRolePage }) => {
const { page, userName } = adminRolePage;

const onCallScheduleName = generateRandomValue();
await createOnCallScheduleWithRotation(page, onCallScheduleName, userName);
await createOnCallSchedule(page, onCallScheduleName, userName);

await clickButton({ page, buttonText: 'Add override' });

Expand All @@ -20,3 +20,37 @@ test('default dates in override creation modal are correct', async ({ adminRoleP
expect(overrideFormDateInputs.start.isSame(expectedStart)).toBe(true);
expect(overrideFormDateInputs.end.isSame(expectedEnd)).toBe(true);
});

test('Fills in override time and reacts to timezone change', async ({ adminRolePage }) => {
const { page, userName } = adminRolePage;

const onCallScheduleName = generateRandomValue();
await createOnCallSchedule(page, onCallScheduleName, userName, false);

await clickButton({ page, buttonText: 'Add override' });

const overrideStartEl = page.getByTestId('override-start');
await changeDatePickerTime(overrideStartEl, '02');
await expect(overrideStartEl.getByTestId('date-time-picker').getByRole('textbox')).toHaveValue('02:00');

const overrideEndEl = page.getByTestId('override-end');
await changeDatePickerTime(overrideEndEl, '12');
await expect(overrideEndEl.getByTestId('date-time-picker').getByRole('textbox')).toHaveValue('12:00');

await page.getByRole('dialog').click(); // clear focus

await page.getByTestId('timezone-select').locator('svg').click();
await page.getByTestId('timezone-select').getByText('GMT', { exact: true }).click();

// expect times to go back by -3
await expect(overrideStartEl.getByTestId('date-time-picker').getByRole('textbox')).toHaveValue('23:00');
await expect(overrideEndEl.getByTestId('date-time-picker').getByRole('textbox')).toHaveValue('09:00');
teodosii marked this conversation as resolved.
Show resolved Hide resolved

async function changeDatePickerTime(element: Locator, value: string) {
await element.getByRole('img').click();
// set minutes to {value}
await page.locator('.rc-time-picker-panel').getByRole('button', { name: value }).first().click();
// set seconds to 00
await page.getByRole('button', { name: '00' }).nth(1).click();
}
});
39 changes: 39 additions & 0 deletions grafana-plugin/e2e-tests/schedules/addRotation.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { test, expect, Locator } from '../fixtures';
import { clickButton, generateRandomValue } from '../utils/forms';
import { createOnCallSchedule } from '../utils/schedule';

test('Fills in Rotation time and reacts to timezone change', async ({ adminRolePage }) => {
const { page, userName } = adminRolePage;

const onCallScheduleName = generateRandomValue();
await createOnCallSchedule(page, onCallScheduleName, userName, false);

await clickButton({ page, buttonText: 'Add rotation' });
// enable Rotation End
await page.getByTestId('rotation-end').getByLabel('Toggle switch').click();

const startEl = page.getByTestId('rotation-start');
await changeDatePickerTime(startEl, '02');
await expect(startEl.getByTestId('date-time-picker').getByRole('textbox')).toHaveValue('02:00');

const endEl = page.getByTestId('rotation-end');
await changeDatePickerTime(endEl, '12');
await expect(endEl.getByTestId('date-time-picker').getByRole('textbox')).toHaveValue('12:00');

await page.getByRole('dialog').click(); // clear focus

await page.getByTestId('timezone-select').locator('svg').click();
await page.getByTestId('timezone-select').getByText('GMT', { exact: true }).click();

// expect times to go back by -3
await expect(startEl.getByTestId('date-time-picker').getByRole('textbox')).toHaveValue('23:00');
await expect(endEl.getByTestId('date-time-picker').getByRole('textbox')).toHaveValue('09:00');

async function changeDatePickerTime(element: Locator, value: string) {
Copy link
Member Author

Choose a reason for hiding this comment

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

In future iterations some parts will be reused, but for now I'll leave it like this

await element.getByRole('img').click();
// set minutes to {value}
await page.locator('.rc-time-picker-panel').getByRole('button', { name: value }).first().click();
// set seconds to 00
await page.getByRole('button', { name: '00' }).nth(1).click();
}
});
4 changes: 2 additions & 2 deletions grafana-plugin/e2e-tests/schedules/quality.test.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { test, expect } from '../fixtures';
import { generateRandomValue } from '../utils/forms';
import { createOnCallScheduleWithRotation } from '../utils/schedule';
import { createOnCallSchedule } from '../utils/schedule';

test('check schedule quality for simple 1-user schedule', async ({ adminRolePage }) => {
const { page, userName } = adminRolePage;
const onCallScheduleName = generateRandomValue();

await createOnCallScheduleWithRotation(page, onCallScheduleName, userName);
await createOnCallSchedule(page, onCallScheduleName, userName);

const scheduleQualityElement = page.getByTestId('schedule-quality');
await scheduleQualityElement.waitFor({ state: 'visible' });
Expand Down
4 changes: 2 additions & 2 deletions grafana-plugin/e2e-tests/schedules/scheduleDetails.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { test, expect } from '../fixtures';
import { generateRandomValue } from '../utils/forms';
import { createOnCallScheduleWithRotation, createRotation } from '../utils/schedule';
import { createOnCallSchedule, createRotation } from '../utils/schedule';

test(`user can see the other user's details`, async ({ adminRolePage, editorRolePage }) => {
const { page, userName: adminUserName } = adminRolePage;
const editorUserName = editorRolePage.userName;
const onCallScheduleName = generateRandomValue();

await createOnCallScheduleWithRotation(page, onCallScheduleName, adminUserName);
await createOnCallSchedule(page, onCallScheduleName, adminUserName);
await createRotation(page, editorUserName, false);

await page.waitForTimeout(1_000);
Expand Down
4 changes: 2 additions & 2 deletions grafana-plugin/e2e-tests/schedules/scheduleView.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import { HTML_ID } from 'utils/DOM';

import { expect, test } from '../fixtures';
import { generateRandomValue } from '../utils/forms';
import { createOnCallScheduleWithRotation } from '../utils/schedule';
import { createOnCallSchedule } from '../utils/schedule';

test.skip('schedule view (week/2 weeks/month) toggler works', async ({ adminRolePage }) => {
const { page, userName } = adminRolePage;

const onCallScheduleName = generateRandomValue();
await createOnCallScheduleWithRotation(page, onCallScheduleName, userName);
await createOnCallSchedule(page, onCallScheduleName, userName);

// ScheduleView.OneWeek is selected by default
expect(await page.getByLabel(ScheduleView.OneWeek, { exact: true }).isChecked()).toBe(true);
Expand Down
4 changes: 2 additions & 2 deletions grafana-plugin/e2e-tests/schedules/schedulesList.test.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { expect, test } from '../fixtures';
import { generateRandomValue } from '../utils/forms';
import { goToOnCallPage } from '../utils/navigation';
import { createOnCallScheduleWithRotation } from '../utils/schedule';
import { createOnCallSchedule } from '../utils/schedule';

test('schedule calendar and list of schedules is correctly displayed', async ({ adminRolePage }) => {
const { page, userName } = adminRolePage;

const onCallScheduleName = generateRandomValue();
await createOnCallScheduleWithRotation(page, onCallScheduleName, userName);
await createOnCallSchedule(page, onCallScheduleName, userName);

await goToOnCallPage(page, 'schedules');

Expand Down
4 changes: 2 additions & 2 deletions grafana-plugin/e2e-tests/schedules/timezones.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import utc from 'dayjs/plugin/utc';
import { test } from '../fixtures';
import { clickButton, generateRandomValue } from '../utils/forms';
import { setTimezoneInProfile } from '../utils/grafanaProfile';
import { createOnCallScheduleWithRotation } from '../utils/schedule';
import { createOnCallSchedule } from '../utils/schedule';

dayjs.extend(utc);
dayjs.extend(isoWeek);
Expand All @@ -25,7 +25,7 @@ test('dates in schedule are correct according to selected current timezone', asy
await setTimezoneInProfile(page, MOSCOW_TIMEZONE);

const onCallScheduleName = generateRandomValue();
await createOnCallScheduleWithRotation(page, onCallScheduleName, userName);
await createOnCallSchedule(page, onCallScheduleName, userName);

// Current timezone is selected by default to currently logged in user timezone
await expect(page.getByTestId('timezone-select')).toHaveText('GMT+3');
Expand Down
9 changes: 6 additions & 3 deletions grafana-plugin/e2e-tests/utils/schedule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import dayjs from 'dayjs';
import { clickButton, selectDropdownValue } from './forms';
import { goToOnCallPage } from './navigation';

export const createOnCallScheduleWithRotation = async (
export const createOnCallSchedule = async (
page: Page,
scheduleName: string,
userName: string
userName: string,
withRotation = true
): Promise<void> => {
// go to the schedules page
await goToOnCallPage(page, 'schedules');
Expand All @@ -22,7 +23,9 @@ export const createOnCallScheduleWithRotation = async (
// Add a new layer w/ the current user to it
await clickButton({ page, buttonText: 'Create Schedule' });

await createRotation(page, userName);
if (withRotation) {
await createRotation(page, userName);
}
};

export const createRotation = async (page: Page, userName: string, isFirstScheduleRotation = true) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Dayjs, ManipulateType } from 'dayjs';
import { DraggableData } from 'react-draggable';

import { isTopNavbar } from 'plugin/GrafanaPluginRootPage.helpers';
import { GRAFANA_HEADER_HEIGHT, GRAFANA_LEGACY_SIDEBAR_WIDTH } from 'utils/consts';

import { RepeatEveryPeriod } from './RotationForm.types';

Expand Down Expand Up @@ -173,3 +177,40 @@ export const dayJSAddWithDSTFixed = ({

return newDateCandidate.add(diff, 'minutes');
};

export function getDraggableModalCoordinatesOnInit(
data: DraggableData,
offsetTop: number
): {
left: number;
right: number;
top: number;
bottom: number;
} {
if (!data) {
return undefined;
}

const scrollBarReferenceElements = document.querySelectorAll<HTMLElement>('.scrollbar-view');
// top navbar display has 2 scrollbar-view elements (navbar & content)
const baseReferenceElRect = (
scrollBarReferenceElements.length === 1 ? scrollBarReferenceElements[0] : scrollBarReferenceElements[1]
).getBoundingClientRect();

const { right, bottom } = baseReferenceElRect;

return isTopNavbar()
? {
// values are adjusted by any padding/margin differences
left: -data.node.offsetLeft + 4,
right: right - (data.node.offsetLeft + data.node.offsetWidth) - 12,
top: -offsetTop + GRAFANA_HEADER_HEIGHT + 4,
bottom: bottom - data.node.offsetHeight - offsetTop - 12,
}
: {
left: -data.node.offsetLeft + 4 + GRAFANA_LEGACY_SIDEBAR_WIDTH,
right: right - (data.node.offsetLeft + data.node.offsetWidth) - 12,
top: -offsetTop + 4,
bottom: bottom - data.node.offsetHeight - offsetTop - 12,
};
}
Loading
Loading