Fixed Schedules modals dragging/initial positioning (#4953)
# What this PR does Closes https://github.com/grafana/oncall/issues/4944
This commit is contained in:
parent
bd919f6e74
commit
754fa8728e
4 changed files with 55 additions and 15 deletions
|
|
@ -191,26 +191,24 @@ export function getDraggableModalCoordinatesOnInit(
|
|||
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 body = document.body;
|
||||
const baseReferenceElRect = body.getBoundingClientRect();
|
||||
const { innerHeight } = window;
|
||||
|
||||
const { right, bottom } = baseReferenceElRect;
|
||||
|
||||
return isTopNavbar()
|
||||
? {
|
||||
// values are adjusted by any padding/margin differences
|
||||
left: -data.node.offsetLeft + 4,
|
||||
left: -data.node.offsetLeft + 12,
|
||||
right: right - (data.node.offsetLeft + data.node.offsetWidth) - 12,
|
||||
top: -offsetTop + GRAFANA_HEADER_HEIGHT + 4,
|
||||
bottom: bottom - data.node.offsetHeight - offsetTop - 12,
|
||||
top: -offsetTop + GRAFANA_HEADER_HEIGHT + 12,
|
||||
bottom: innerHeight - data.node.offsetHeight - offsetTop - 12,
|
||||
}
|
||||
: {
|
||||
left: -data.node.offsetLeft + 4 + GRAFANA_LEGACY_SIDEBAR_WIDTH,
|
||||
left: -data.node.offsetLeft + 12 + GRAFANA_LEGACY_SIDEBAR_WIDTH,
|
||||
right: right - (data.node.offsetLeft + data.node.offsetWidth) - 12,
|
||||
top: -offsetTop + 4,
|
||||
top: -offsetTop + 12,
|
||||
bottom: bottom - data.node.offsetHeight - offsetTop - 12,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -809,7 +809,8 @@ export const RotationForm = observer((props: RotationFormProps) => {
|
|||
return;
|
||||
}
|
||||
|
||||
setDraggableBounds(getDraggableModalCoordinatesOnInit(data, offsetTop));
|
||||
const bounds = getDraggableModalCoordinatesOnInit(data, offsetTop);
|
||||
setDraggableBounds(bounds);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -3,20 +3,23 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|||
import { Button, Field, IconButton, Input, TextArea, Stack } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import dayjs from 'dayjs';
|
||||
import Draggable from 'react-draggable';
|
||||
import Draggable, { DraggableData, DraggableEvent } from 'react-draggable';
|
||||
|
||||
import { Modal } from 'components/Modal/Modal';
|
||||
import { Tag } from 'components/Tag/Tag';
|
||||
import { Text } from 'components/Text/Text';
|
||||
import { WithConfirm } from 'components/WithConfirm/WithConfirm';
|
||||
import { calculateScheduleFormOffset } from 'containers/Rotations/Rotations.helpers';
|
||||
import { WithPermissionControlTooltip } from 'containers/WithPermissionControl/WithPermissionControlTooltip';
|
||||
import { SHIFT_SWAP_COLOR } from 'models/schedule/schedule.helpers';
|
||||
import { Schedule, ShiftSwap } from 'models/schedule/schedule.types';
|
||||
import { getUTCString } from 'pages/schedule/Schedule.helpers';
|
||||
import { useStore } from 'state/useStore';
|
||||
import { UserActions } from 'utils/authorization/authorization';
|
||||
import { StackSize } from 'utils/consts';
|
||||
import { GRAFANA_HEADER_HEIGHT, StackSize } from 'utils/consts';
|
||||
import { useDebouncedCallback, useResize } from 'utils/hooks';
|
||||
|
||||
import { getDraggableModalCoordinatesOnInit } from './RotationForm.helpers';
|
||||
import { DateTimePicker } from './parts/DateTimePicker';
|
||||
import { UserItem } from './parts/UserItem';
|
||||
|
||||
|
|
@ -36,6 +39,15 @@ export const ShiftSwapForm = (props: ShiftSwapFormProps) => {
|
|||
const { onUpdate, onHide, id, scheduleId, params: defaultParams } = props;
|
||||
|
||||
const [shiftSwap, setShiftSwap] = useState({ ...defaultParams });
|
||||
const [offsetTop, setOffsetTop] = useState(GRAFANA_HEADER_HEIGHT + 10);
|
||||
const [draggablePosition, setDraggablePosition] = useState<{ x: number; y: number }>(undefined);
|
||||
const [bounds, setDraggableBounds] = useState<{ left: number; right: number; top: number; bottom: number }>(
|
||||
undefined
|
||||
);
|
||||
|
||||
const debouncedOnResize = useDebouncedCallback(onResize, 250);
|
||||
|
||||
useResize(debouncedOnResize);
|
||||
|
||||
const store = useStore();
|
||||
const {
|
||||
|
|
@ -44,6 +56,12 @@ export const ShiftSwapForm = (props: ShiftSwapFormProps) => {
|
|||
timezoneStore: { selectedTimezoneOffset },
|
||||
} = store;
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
setOffsetTop(await calculateScheduleFormOffset(`.${cx('draggable')}`));
|
||||
})();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (id !== 'new') {
|
||||
|
|
@ -131,7 +149,15 @@ export const ShiftSwapForm = (props: ShiftSwapFormProps) => {
|
|||
width="430px"
|
||||
onDismiss={handleHide}
|
||||
contentElement={(props, children) => (
|
||||
<Draggable handle=".drag-handler" defaultClassName={cx('draggable')} positionOffset={{ x: 0, y: 200 }}>
|
||||
<Draggable
|
||||
handle=".drag-handler"
|
||||
defaultClassName={cx('draggable')}
|
||||
positionOffset={{ x: 0, y: offsetTop }}
|
||||
position={draggablePosition}
|
||||
bounds={{ ...bounds } || 'body'}
|
||||
onStart={onDraggableInit}
|
||||
onStop={(_e, data) => setDraggablePosition({ x: data.x, y: data.y })}
|
||||
>
|
||||
<div {...props}>{children}</div>
|
||||
</Draggable>
|
||||
)}
|
||||
|
|
@ -235,4 +261,19 @@ export const ShiftSwapForm = (props: ShiftSwapFormProps) => {
|
|||
</div>
|
||||
</Modal>
|
||||
);
|
||||
|
||||
async function onResize() {
|
||||
setOffsetTop(await calculateScheduleFormOffset(`.${cx('draggable')}`));
|
||||
|
||||
setDraggablePosition({ x: 0, y: 0 });
|
||||
}
|
||||
|
||||
function onDraggableInit(_e: DraggableEvent, data: DraggableData) {
|
||||
if (!data) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bounds = getDraggableModalCoordinatesOnInit(data, offsetTop);
|
||||
setDraggableBounds(bounds);
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ export const calculateScheduleFormOffset = async (queryClassName: string) => {
|
|||
const modal = await waitForElement(queryClassName);
|
||||
const modalHeight = modal.clientHeight;
|
||||
|
||||
return document.documentElement.scrollHeight / 2 - modalHeight / 2;
|
||||
return window.innerHeight / 2 - modalHeight / 2;
|
||||
};
|
||||
|
||||
// DatePickers will convert the date passed to local timezone, instead we want to use the date in the given timezone
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue