diff --git a/grafana-plugin/src/components/ScheduleBorderedAvatar/ScheduleBorderedAvatar.tsx b/grafana-plugin/src/components/ScheduleBorderedAvatar/ScheduleBorderedAvatar.tsx
index 88b5ecb5..af2899dc 100644
--- a/grafana-plugin/src/components/ScheduleBorderedAvatar/ScheduleBorderedAvatar.tsx
+++ b/grafana-plugin/src/components/ScheduleBorderedAvatar/ScheduleBorderedAvatar.tsx
@@ -6,19 +6,21 @@ import styles from './ScheduleBorderedAvatar.module.scss';
const cx = cn.bind(styles);
+interface ScheduleBorderedAvatarProps {
+ colors: string[];
+ width: number;
+ height: number;
+ renderAvatar: () => JSX.Element;
+ renderIcon: () => JSX.Element;
+}
+
export default function ScheduleBorderedAvatar({
colors,
renderAvatar,
renderIcon,
width,
height,
-}: {
- colors: string[];
- width: number;
- height: number;
- renderAvatar: () => JSX.Element;
- renderIcon: () => JSX.Element;
-}) {
+}: ScheduleBorderedAvatarProps) {
return
{colors?.length ? renderSVG() : renderAvatarIcon()}
;
function renderAvatarIcon() {
@@ -50,16 +52,16 @@ export default function ScheduleBorderedAvatar({
}
const stepAngle = (2 * Math.PI) / colors.length;
- const radius = 100;
+ const RADIUS = 100;
let lastX = 0;
- let lastY = -radius;
+ let lastY = -RADIUS;
return colorSchemeList.map((_color, colorIndex) => {
const angle = (colorIndex + 1) * stepAngle;
- const x = radius * Math.sin(angle);
- const y = -radius * Math.cos(angle);
- const d = `M ${lastX.toFixed(3)},${lastY.toFixed(3)} A 100,100 0 0,1 ${x.toFixed(3)},${y.toFixed(3)}`;
+ const x = RADIUS * Math.sin(angle);
+ const y = -RADIUS * Math.cos(angle);
+ const d = `M ${lastX.toFixed(3)},${lastY.toFixed(3)} A ${RADIUS},${RADIUS} 0 0,1 ${x.toFixed(3)},${y.toFixed(3)}`;
lastX = x;
lastY = y;
diff --git a/grafana-plugin/src/containers/Rotations/Rotations.tsx b/grafana-plugin/src/containers/Rotations/Rotations.tsx
index 43ea3716..e1a8d51e 100644
--- a/grafana-plugin/src/containers/Rotations/Rotations.tsx
+++ b/grafana-plugin/src/containers/Rotations/Rotations.tsx
@@ -30,6 +30,7 @@ interface RotationsProps extends WithStoreProps {
startMoment: dayjs.Dayjs;
currentTimezone: Timezone;
shiftIdToShowRotationForm?: Shift['id'] | 'new';
+ scheduleId: Schedule['id'];
onShowRotationForm: (shiftId: Shift['id'] | 'new') => void;
onClick: (id: Shift['id'] | 'new') => void;
onCreate: () => void;
@@ -50,9 +51,8 @@ class Rotations extends Component {
};
render() {
- const { startMoment, currentTimezone, onCreate, onUpdate, onDelete, store, shiftIdToShowRotationForm } = this.props;
+ const { scheduleId, startMoment, currentTimezone, onCreate, onUpdate, onDelete, store, shiftIdToShowRotationForm } = this.props;
const { layerPriority, shiftMomentToShowRotationForm } = this.state;
- const { scheduleId } = store.scheduleStore;
const base = 7 * 24 * 60; // in minutes
const diff = dayjs().tz(currentTimezone).diff(startMoment, 'minutes');
@@ -239,8 +239,6 @@ class Rotations extends Component {
};
hideRotationForm = () => {
- const { store } = this.props;
-
this.setState(
{
layerPriority: undefined,
diff --git a/grafana-plugin/src/containers/Rotations/ScheduleFinal.tsx b/grafana-plugin/src/containers/Rotations/ScheduleFinal.tsx
index 5bac8b04..f5ed2945 100644
--- a/grafana-plugin/src/containers/Rotations/ScheduleFinal.tsx
+++ b/grafana-plugin/src/containers/Rotations/ScheduleFinal.tsx
@@ -8,7 +8,7 @@ import { CSSTransition, TransitionGroup } from 'react-transition-group';
import TimelineMarks from 'components/TimelineMarks/TimelineMarks';
import Rotation from 'containers/Rotation/Rotation';
-import { getColor, getFromString, getOverrideColor } from 'models/schedule/schedule.helpers';
+import { getColor, getFromString, getLayersFromStore, getOverrideColor, getOverridesFromStore, getShiftsFromStore } from 'models/schedule/schedule.helpers';
import { Event, Layer, Schedule, Shift } from 'models/schedule/schedule.types';
import { Timezone } from 'models/timezone/timezone.types';
import { WithStoreProps } from 'state/types';
@@ -24,6 +24,7 @@ const cx = cn.bind(styles);
interface ScheduleFinalProps extends WithStoreProps {
startMoment: dayjs.Dayjs;
currentTimezone: Timezone;
+ scheduleId: Schedule['id'];
hideHeader?: boolean;
onClick: (shiftId: Shift['id']) => void;
}
@@ -39,28 +40,19 @@ class ScheduleFinal extends Component);
+ const shifts = getShiftsFromStore(store, scheduleId, startMoment, false);
- const layers = store.scheduleStore.rotationPreview
- ? store.scheduleStore.rotationPreview
- : (store.scheduleStore.events[scheduleId]?.['rotation']?.[getFromString(startMoment)] as Layer[]);
+ const layers = getLayersFromStore(store, scheduleId, startMoment);
+
+ const overrides = getOverridesFromStore(store, scheduleId, startMoment, true);
- const overrides = store.scheduleStore.overridePreview
- ? store.scheduleStore.overridePreview
- : store.scheduleStore.events[scheduleId]?.['override']?.[getFromString(startMoment)];
const currentTimeHidden = currentTimeX < 0 || currentTimeX > 1;
return (
diff --git a/grafana-plugin/src/containers/Rotations/ScheduleOverrides.tsx b/grafana-plugin/src/containers/Rotations/ScheduleOverrides.tsx
index e03dc26f..1fdc5121 100644
--- a/grafana-plugin/src/containers/Rotations/ScheduleOverrides.tsx
+++ b/grafana-plugin/src/containers/Rotations/ScheduleOverrides.tsx
@@ -10,7 +10,7 @@ import TimelineMarks from 'components/TimelineMarks/TimelineMarks';
import Rotation from 'containers/Rotation/Rotation';
import { RotationCreateData } from 'containers/RotationForm/RotationForm.types';
import ScheduleOverrideForm from 'containers/RotationForm/ScheduleOverrideForm';
-import { getFromString, getOverrideColor } from 'models/schedule/schedule.helpers';
+import { getFromString, getOverrideColor, getShiftsFromStore } from 'models/schedule/schedule.helpers';
import { Event, Schedule, Shift } from 'models/schedule/schedule.types';
import { Timezone } from 'models/timezone/timezone.types';
import { WithStoreProps } from 'state/types';
@@ -26,6 +26,7 @@ const cx = cn.bind(styles);
interface ScheduleOverridesProps extends WithStoreProps {
startMoment: dayjs.Dayjs;
currentTimezone: Timezone;
+ scheduleId: Schedule['id'];
shiftIdToShowRotationForm?: Shift['id'] | 'new';
onShowRotationForm: (shiftId: Shift['id'] | 'new') => void;
onCreate: () => void;
@@ -44,18 +45,11 @@ class ScheduleOverrides extends Component);
+ const shifts = getShiftsFromStore(store, scheduleId, startMoment, true);
const base = 7 * 24 * 60; // in minutes
const diff = dayjs().tz(currentTimezone).diff(startMoment, 'minutes');
diff --git a/grafana-plugin/src/containers/UsersTimezones/UsersTimezones.tsx b/grafana-plugin/src/containers/UsersTimezones/UsersTimezones.tsx
index 66e2e247..231673e2 100644
--- a/grafana-plugin/src/containers/UsersTimezones/UsersTimezones.tsx
+++ b/grafana-plugin/src/containers/UsersTimezones/UsersTimezones.tsx
@@ -12,8 +12,15 @@ import ScheduleUserDetails from 'components/ScheduleUserDetails/ScheduleUserDeta
import Text from 'components/Text/Text';
import { findColor } from 'containers/Rotations/Rotations.helpers';
import { IsOncallIcon } from 'icons';
-import { getColor, getFromString, getOverrideColor } from 'models/schedule/schedule.helpers';
-import { Event, Layer } from 'models/schedule/schedule.types';
+import {
+ getColor,
+ getFromString,
+ getLayersFromStore,
+ getOverrideColor,
+ getOverridesFromStore,
+ getShiftsFromStore,
+} from 'models/schedule/schedule.helpers';
+import { Event, Layer, Schedule } from 'models/schedule/schedule.types';
import { Timezone } from 'models/timezone/timezone.types';
import { User } from 'models/user/user.types';
import { getStartOfWeek } from 'pages/schedule/Schedule.helpers';
@@ -130,7 +137,7 @@ const UsersTimezones: FC = (props) => {
interface UserAvatarsProps {
users: User[];
currentMoment: dayjs.Dayjs;
- scheduleId: string;
+ scheduleId: Schedule['id'];
onTzChange: (timezone: Timezone) => void;
onCallNow: Array>;
}
@@ -195,7 +202,7 @@ interface AvatarGroupProps {
xPos: number;
currentMoment: dayjs.Dayjs;
utcOffset: number;
- scheduleId: string;
+ scheduleId: Schedule['id'];
onSetActiveUtcOffset: (utcOffset: number | undefined) => void;
activeUtcOffset: number;
onTzChange: (timezone: Timezone) => void;
@@ -308,17 +315,11 @@ const AvatarGroup = (props: AvatarGroupProps) => {
function getColorSchemeMappingForUsers(store: RootStore, scheduleId: string): { [userId: string]: Set } {
const startMoment = getStartOfWeek(store.currentTimezone);
- const shifts: Array<{ shiftId: string; events: Event[] }> = false
- ? store.scheduleStore.finalPreview
- : (store.scheduleStore.events[scheduleId]?.['final']?.[getFromString(startMoment)] as any);
+ const shifts = getShiftsFromStore(store, scheduleId, startMoment, false);
- const layers = store.scheduleStore.rotationPreview
- ? store.scheduleStore.rotationPreview
- : (store.scheduleStore.events[scheduleId]?.['rotation']?.[getFromString(startMoment)] as Layer[]);
+ const layers = getLayersFromStore(store, scheduleId, startMoment);
- const overrides = store.scheduleStore.overridePreview
- ? store.scheduleStore.overridePreview
- : store.scheduleStore.events[scheduleId]?.['override']?.[getFromString(startMoment)];
+ const overrides = getOverridesFromStore(store, scheduleId, startMoment, false);
const usersColorSchemeHash: { [userId: string]: Set } = {};
diff --git a/grafana-plugin/src/models/schedule/schedule.helpers.ts b/grafana-plugin/src/models/schedule/schedule.helpers.ts
index d626d32e..b97aa545 100644
--- a/grafana-plugin/src/models/schedule/schedule.helpers.ts
+++ b/grafana-plugin/src/models/schedule/schedule.helpers.ts
@@ -1,6 +1,7 @@
import dayjs from 'dayjs';
+import { RootStore } from 'state';
-import { Event, Layer, ScheduleType, Shift } from './schedule.types';
+import { Event, Layer, Schedule, ScheduleType, Shift } from './schedule.types';
export const getFromString = (moment: dayjs.Dayjs) => {
return moment.format('YYYY-MM-DD');
@@ -57,6 +58,43 @@ export const splitToShiftsAndFillGaps = (events: Event[]) => {
return shifts;
};
+export const getShiftsFromStore = (
+ store: RootStore,
+ scheduleId: Schedule['id'],
+ startMoment: dayjs.Dayjs,
+ isOverridePreview: boolean,
+): Array<{ shiftId: string; events: Event[], isPreview?: boolean; }> => {
+ const source = isOverridePreview ? store.scheduleStore.overridePreview : store.scheduleStore.finalPreview;
+ return source
+ ? store.scheduleStore.finalPreview
+ : (store.scheduleStore.events[scheduleId]?.['final']?.[getFromString(startMoment)] as any);
+};
+
+export const getLayersFromStore = (store: RootStore, scheduleId: Schedule['id'], startMoment: dayjs.Dayjs): Layer[] => {
+ return store.scheduleStore.rotationPreview
+ ? store.scheduleStore.rotationPreview
+ : (store.scheduleStore.events[scheduleId]?.['rotation']?.[getFromString(startMoment)] as Layer[]);
+};
+
+export const getOverridesFromStore = (
+ store: RootStore,
+ scheduleId: Schedule['id'],
+ startMoment: dayjs.Dayjs,
+ isOverridePreview: boolean
+):
+ | Layer[]
+ | {
+ shiftId: string;
+ events: Event[];
+ isPreview?: boolean;
+ }[] => {
+
+ const source = isOverridePreview ? store.scheduleStore.overridePreview : store.scheduleStore.rotationPreview;
+ return source
+ ? store.scheduleStore.rotationPreview
+ : (store.scheduleStore.events[scheduleId]?.['rotation']?.[getFromString(startMoment)] as Layer[]);
+};
+
export const splitToLayers = (
shifts: Array<{ shiftId: Shift['id']; priority: Shift['priority_level']; events: Event[] }>
) => {
diff --git a/grafana-plugin/src/models/schedule/schedule.ts b/grafana-plugin/src/models/schedule/schedule.ts
index 9bf6d6a2..cfd9a4ca 100644
--- a/grafana-plugin/src/models/schedule/schedule.ts
+++ b/grafana-plugin/src/models/schedule/schedule.ts
@@ -77,7 +77,7 @@ export class ScheduleStore extends BaseStore {
byDayOptions: SelectOption[];
@observable
- scheduleId: string;
+ scheduleId: Schedule['id'];
constructor(rootStore: RootStore) {
super(rootStore);
diff --git a/grafana-plugin/src/pages/schedule/Schedule.tsx b/grafana-plugin/src/pages/schedule/Schedule.tsx
index 11203db6..adf816bf 100644
--- a/grafana-plugin/src/pages/schedule/Schedule.tsx
+++ b/grafana-plugin/src/pages/schedule/Schedule.tsx
@@ -86,8 +86,6 @@ class SchedulePage extends React.Component
this.updateEvents(),
]);
- store.scheduleStore.scheduleId = id;
-
this.setState({ isLoading: false });
}
@@ -95,19 +93,16 @@ class SchedulePage extends React.Component
const { store } = this.props;
store.scheduleStore.clearPreview();
- store.scheduleStore.scheduleId = undefined
}
render() {
const { query: { id: scheduleId }, store } = this.props;
- const { isLoading, startMoment, shiftIdToShowRotationForm, shiftIdToShowOverridesForm } = this.state;
+ const { startMoment, shiftIdToShowRotationForm, shiftIdToShowOverridesForm } = this.state;
const { scheduleStore, currentTimezone } = store;
const users = store.userStore.getSearchResult().results;
const schedule = scheduleStore.items[scheduleId];
- if (isLoading) {return }
-
return (
@@ -173,6 +168,7 @@ class SchedulePage extends React.Component
currentTimezone={currentTimezone}
startMoment={startMoment}
onClick={this.handleShowForm}
+ scheduleId={scheduleId}
/>
onDelete={this.handleDeleteRotation}
shiftIdToShowRotationForm={shiftIdToShowRotationForm}
onShowRotationForm={this.handleShowRotationForm}
+ scheduleId={scheduleId}
/>
onDelete={this.handleDeleteOverride}
shiftIdToShowRotationForm={shiftIdToShowOverridesForm}
onShowRotationForm={this.handleShowOverridesForm}
+ scheduleId={scheduleId}
/>
diff --git a/grafana-plugin/src/pages/schedules/Schedules.tsx b/grafana-plugin/src/pages/schedules/Schedules.tsx
index 9b2e5e3a..d1df28ba 100644
--- a/grafana-plugin/src/pages/schedules/Schedules.tsx
+++ b/grafana-plugin/src/pages/schedules/Schedules.tsx
@@ -99,7 +99,7 @@ class SchedulesPage extends React.Component {
- const { store } = this.props;
- const { scheduleStore } = store;
-
this.setState({ filters }, () => {
const { filters, expandedSchedulesKeys } = this.state;