Merge pull request #840 from grafana/schedules-fixes-bunch-4
Web schedules minor bug fixes after initial release
This commit is contained in:
commit
5e03e3ad93
9 changed files with 70 additions and 52 deletions
|
|
@ -42,7 +42,7 @@ const SchedulesFilters = (props: SchedulesFiltersProps) => {
|
|||
return (
|
||||
<div className={cx('root')}>
|
||||
<HorizontalGroup spacing="lg">
|
||||
<Field label="Search by name, user or object ID">
|
||||
<Field label="Search by name">
|
||||
<Input
|
||||
autoFocus
|
||||
className={cx('search')}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
.root {
|
||||
width: 300px;
|
||||
width: auto;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ const UserTimezoneSelect: FC<UserTimezoneSelectProps> = (props) => {
|
|||
|
||||
return (
|
||||
<div className={cx('root')}>
|
||||
<Select value={value} onChange={handleChange} width={100} placeholder={propValue} options={options} />
|
||||
<Select value={value} onChange={handleChange} width={30} placeholder={propValue} options={options} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -22,6 +22,9 @@
|
|||
padding: 6px 10px;
|
||||
z-index: 1;
|
||||
color: #fff;
|
||||
width: 330px;
|
||||
overflow: hidden;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.working-hours {
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import { SelectableValue } from '@grafana/data';
|
||||
import { ValuePicker, HorizontalGroup, Button } from '@grafana/ui';
|
||||
import { ValuePicker, HorizontalGroup, Button, Tooltip } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import dayjs from 'dayjs';
|
||||
import { observer } from 'mobx-react';
|
||||
|
|
@ -13,7 +13,7 @@ import Rotation from 'containers/Rotation/Rotation';
|
|||
import RotationForm from 'containers/RotationForm/RotationForm';
|
||||
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
|
||||
import { getColor, getFromString } from 'models/schedule/schedule.helpers';
|
||||
import { Layer, Schedule, Shift } from 'models/schedule/schedule.types';
|
||||
import { Layer, Schedule, ScheduleType, Shift } from 'models/schedule/schedule.types';
|
||||
import { Timezone } from 'models/timezone/timezone.types';
|
||||
import { WithStoreProps } from 'state/types';
|
||||
import { UserAction } from 'state/userAction';
|
||||
|
|
@ -87,6 +87,11 @@ class Rotations extends Component<RotationsProps, RotationsState> {
|
|||
|
||||
options.push({ label: 'New Layer', value: nextPriority });
|
||||
|
||||
const schedule = store.scheduleStore.items[scheduleId];
|
||||
|
||||
const isTypeReadOnly =
|
||||
schedule && (schedule?.type === ScheduleType.Ical || schedule?.type === ScheduleType.Calendar);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={cx('root')}>
|
||||
|
|
@ -98,11 +103,21 @@ class Rotations extends Component<RotationsProps, RotationsState> {
|
|||
</Text.Title>
|
||||
</div>
|
||||
{disabled ? (
|
||||
<WithPermissionControl userAction={UserAction.UpdateSchedules}>
|
||||
<Button variant="primary" icon="plus" disabled>
|
||||
Add rotation
|
||||
</Button>
|
||||
</WithPermissionControl>
|
||||
isTypeReadOnly ? (
|
||||
<Tooltip content="Ical and API/Terraform schedules are read-only" placement="top">
|
||||
<div>
|
||||
<Button variant="primary" icon="plus" disabled>
|
||||
Add rotation
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<WithPermissionControl userAction={UserAction.UpdateSchedules}>
|
||||
<Button variant="primary" icon="plus" disabled>
|
||||
Add rotation
|
||||
</Button>
|
||||
</WithPermissionControl>
|
||||
)
|
||||
) : (
|
||||
<ValuePicker
|
||||
label="Add rotation"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import { Button, HorizontalGroup } from '@grafana/ui';
|
||||
import { Button, HorizontalGroup, Tooltip } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import dayjs from 'dayjs';
|
||||
import { observer } from 'mobx-react';
|
||||
|
|
@ -12,7 +12,7 @@ import Rotation from 'containers/Rotation/Rotation';
|
|||
import ScheduleOverrideForm from 'containers/RotationForm/ScheduleOverrideForm';
|
||||
import { WithPermissionControl } from 'containers/WithPermissionControl/WithPermissionControl';
|
||||
import { getOverrideColor, getOverridesFromStore } from 'models/schedule/schedule.helpers';
|
||||
import { Schedule, Shift, ShiftEvents } from 'models/schedule/schedule.types';
|
||||
import { Schedule, ScheduleType, Shift, ShiftEvents } from 'models/schedule/schedule.types';
|
||||
import { Timezone } from 'models/timezone/timezone.types';
|
||||
import { WithStoreProps } from 'state/types';
|
||||
import { UserAction } from 'state/userAction';
|
||||
|
|
@ -70,6 +70,11 @@ class ScheduleOverrides extends Component<ScheduleOverridesProps, ScheduleOverri
|
|||
|
||||
const currentTimeHidden = currentTimeX < 0 || currentTimeX > 1;
|
||||
|
||||
const schedule = store.scheduleStore.items[scheduleId];
|
||||
|
||||
const isTypeReadOnly =
|
||||
schedule && (schedule?.type === ScheduleType.Ical || schedule?.type === ScheduleType.Calendar);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div id="overrides-list" className={cx('root')}>
|
||||
|
|
@ -80,11 +85,21 @@ class ScheduleOverrides extends Component<ScheduleOverridesProps, ScheduleOverri
|
|||
Overrides
|
||||
</Text.Title>
|
||||
</div>
|
||||
<WithPermissionControl userAction={UserAction.UpdateSchedules}>
|
||||
<Button disabled={disabled} icon="plus" onClick={this.handleAddOverride} variant="secondary">
|
||||
Add override
|
||||
</Button>
|
||||
</WithPermissionControl>
|
||||
{isTypeReadOnly ? (
|
||||
<Tooltip content="Ical and API/Terraform schedules are read-only" placement="top">
|
||||
<div>
|
||||
<Button variant="primary" icon="plus" disabled>
|
||||
Add override
|
||||
</Button>
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : (
|
||||
<WithPermissionControl userAction={UserAction.UpdateSchedules}>
|
||||
<Button disabled={disabled} icon="plus" onClick={this.handleAddOverride} variant="secondary">
|
||||
Add override
|
||||
</Button>
|
||||
</WithPermissionControl>
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
<div className={cx('header-plus-content')}>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ export class UserStore extends BaseStore {
|
|||
@observable.shallow
|
||||
items: { [pk: string]: User } = {};
|
||||
|
||||
itemsCurrentlyUpdating = {};
|
||||
|
||||
@observable
|
||||
notificationPolicies: any = {};
|
||||
|
||||
|
|
@ -87,12 +89,20 @@ export class UserStore extends BaseStore {
|
|||
|
||||
@action
|
||||
async updateItem(userPk: User['pk']) {
|
||||
if (this.itemsCurrentlyUpdating[userPk]) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.itemsCurrentlyUpdating[userPk] = true;
|
||||
|
||||
const user = await this.getById(userPk);
|
||||
|
||||
this.items = {
|
||||
...this.items,
|
||||
[user.pk]: { ...user, timezone: getTimezone(user) },
|
||||
};
|
||||
|
||||
delete this.itemsCurrentlyUpdating[userPk];
|
||||
}
|
||||
|
||||
@action
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import { Button, HorizontalGroup, VerticalGroup, IconButton, ToolbarButton, Icon
|
|||
import { PluginPage } from 'PluginPage';
|
||||
import cn from 'classnames/bind';
|
||||
import dayjs from 'dayjs';
|
||||
import { omit } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import PageErrorHandlingWrapper from 'components/PageErrorHandlingWrapper/PageErrorHandlingWrapper';
|
||||
|
|
@ -138,16 +137,16 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
</HorizontalGroup>
|
||||
)}
|
||||
<HorizontalGroup>
|
||||
{schedule?.type === ScheduleType.Ical && (
|
||||
<HorizontalGroup>
|
||||
<Button variant="secondary" onClick={this.handleExportClick()}>
|
||||
Export
|
||||
</Button>
|
||||
<HorizontalGroup>
|
||||
<Button variant="secondary" onClick={this.handleExportClick()}>
|
||||
Export
|
||||
</Button>
|
||||
{(schedule?.type === ScheduleType.Ical || schedule?.type === ScheduleType.Calendar) && (
|
||||
<Button variant="secondary" onClick={this.handleReloadClick(scheduleId)}>
|
||||
Reload
|
||||
</Button>
|
||||
</HorizontalGroup>
|
||||
)}
|
||||
)}
|
||||
</HorizontalGroup>
|
||||
<ToolbarButton
|
||||
icon="cog"
|
||||
tooltip="Settings"
|
||||
|
|
@ -162,11 +161,6 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
</HorizontalGroup>
|
||||
</HorizontalGroup>
|
||||
</div>
|
||||
{schedule?.type !== ScheduleType.API && (
|
||||
<Text className={cx('desc')} type="secondary">
|
||||
Ical and API/Terraform schedules are read-only
|
||||
</Text>
|
||||
)}
|
||||
<div className={cx('users-timezones')}>
|
||||
<UsersTimezones
|
||||
scheduleId={scheduleId}
|
||||
|
|
@ -418,31 +412,11 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
return async () => {
|
||||
await scheduleStore.reloadIcal(scheduleId);
|
||||
|
||||
scheduleStore.updateItem(scheduleId);
|
||||
this.updateEventsFor(scheduleId);
|
||||
store.scheduleStore.updateOncallShifts(scheduleId);
|
||||
this.updateEvents();
|
||||
};
|
||||
};
|
||||
|
||||
updateEventsFor = async (scheduleId: Schedule['id'], withEmpty = true, with_gap = true) => {
|
||||
const { store } = this.props;
|
||||
const { id } = getQueryParams();
|
||||
|
||||
const { scheduleStore } = store;
|
||||
|
||||
store.scheduleStore.scheduleToScheduleEvents = omit(store.scheduleStore.scheduleToScheduleEvents, [scheduleId]);
|
||||
|
||||
await scheduleStore.updateScheduleEvents(
|
||||
scheduleId,
|
||||
withEmpty,
|
||||
with_gap,
|
||||
dayjs().format('YYYY-MM-DD').toString(),
|
||||
dayjs.tz.guess()
|
||||
);
|
||||
|
||||
await store.scheduleStore.updateOncallShifts(id);
|
||||
await this.updateEvents();
|
||||
};
|
||||
|
||||
handleDelete = () => {
|
||||
const { store } = this.props;
|
||||
const { id: scheduleId } = getQueryParams();
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
.schedule {
|
||||
position: relative;
|
||||
margin: 20px 0;
|
||||
max-width: calc(100vw - 104px);
|
||||
}
|
||||
|
||||
.title {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue