Merge pull request #840 from grafana/schedules-fixes-bunch-4

Web schedules minor bug fixes after initial release
This commit is contained in:
Matias Bordese 2022-11-21 11:09:41 -03:00 committed by GitHub
commit 5e03e3ad93
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 70 additions and 52 deletions

View file

@ -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')}

View file

@ -1,3 +1,3 @@
.root {
width: 300px;
width: auto;
}

View file

@ -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>
);
};

View file

@ -22,6 +22,9 @@
padding: 6px 10px;
z-index: 1;
color: #fff;
width: 330px;
overflow: hidden;
white-space: nowrap;
}
.working-hours {

View file

@ -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"

View file

@ -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')}>

View file

@ -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

View file

@ -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();

View file

@ -1,6 +1,7 @@
.schedule {
position: relative;
margin: 20px 0;
max-width: calc(100vw - 104px);
}
.title {