add schedules filtering, add checing web schedules feature flag
This commit is contained in:
parent
46ba3b3658
commit
23d706cc7f
19 changed files with 166 additions and 61 deletions
|
|
@ -139,9 +139,10 @@ export const Root = observer((props: AppRootProps) => {
|
|||
grafanaUser: window.grafanaBootData.user,
|
||||
enableLiveSettings: store.hasFeature(AppFeature.LiveSettings),
|
||||
enableCloudPage: store.hasFeature(AppFeature.CloudConnection),
|
||||
enableNewSchedulesPage: store.hasFeature(AppFeature.WebSchedules),
|
||||
backendLicense,
|
||||
}),
|
||||
[meta, pathWithoutLeadingSlash, page, store.features]
|
||||
[meta, pathWithoutLeadingSlash, page, store.features, backendLicense]
|
||||
)
|
||||
);
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ interface ScheduleCounterProps {
|
|||
count: number;
|
||||
tooltipTitle: string;
|
||||
tooltipContent: React.ReactNode;
|
||||
onHover: () => void;
|
||||
}
|
||||
|
||||
const typeToIcon = {
|
||||
|
|
@ -37,7 +38,7 @@ const typeToBackgroundColor = {
|
|||
const cx = cn.bind(styles);
|
||||
|
||||
const ScheduleCounter: FC<ScheduleCounterProps> = (props) => {
|
||||
const { type, count, tooltipTitle, tooltipContent } = props;
|
||||
const { type, count, tooltipTitle, tooltipContent, onHover } = props;
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
|
|
@ -52,7 +53,7 @@ const ScheduleCounter: FC<ScheduleCounterProps> = (props) => {
|
|||
</div>
|
||||
}
|
||||
>
|
||||
<div className={cx('root', { [`root__type_${type}`]: true })}>
|
||||
<div className={cx('root', { [`root__type_${type}`]: true })} onMouseEnter={onHover}>
|
||||
<HorizontalGroup spacing="xs">
|
||||
<Icon className={cx('icon', { [`icon__type_${type}`]: true })} name={typeToIcon[type]} />
|
||||
<Text type={typeToColor[type]}>{count}</Text>
|
||||
|
|
|
|||
|
|
@ -69,11 +69,12 @@ const SchedulesFilters = (props: SchedulesFiltersProps) => {
|
|||
</Field>
|
||||
<Field label="Type">
|
||||
<RadioButtonGroup
|
||||
disabled
|
||||
options={[
|
||||
{ label: 'All', value: 'all' },
|
||||
{
|
||||
label: 'Web',
|
||||
value: ScheduleType.Calendar,
|
||||
value: ScheduleType.API,
|
||||
},
|
||||
{
|
||||
label: 'ICal',
|
||||
|
|
@ -81,7 +82,7 @@ const SchedulesFilters = (props: SchedulesFiltersProps) => {
|
|||
},
|
||||
{
|
||||
label: 'API',
|
||||
value: ScheduleType.API,
|
||||
value: ScheduleType.Calendar,
|
||||
},
|
||||
]}
|
||||
value={value.type}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,10 @@
|
|||
background: rgba(63, 62, 62, 0.45);
|
||||
}
|
||||
|
||||
.root th:first-child {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
.root td {
|
||||
min-height: 60px;
|
||||
padding: 10px 0;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,11 @@ const UserGroups = (props: UserGroupsProps) => {
|
|||
}
|
||||
|
||||
const newGroups = [...value];
|
||||
const lastGroup = newGroups[newGroups.length - 1];
|
||||
let lastGroup = newGroups[newGroups.length - 1];
|
||||
if (!lastGroup) {
|
||||
lastGroup = [];
|
||||
newGroups.push(lastGroup);
|
||||
}
|
||||
|
||||
lastGroup.push(pk);
|
||||
|
||||
|
|
@ -73,11 +77,6 @@ const UserGroups = (props: UserGroupsProps) => {
|
|||
[value]
|
||||
);
|
||||
|
||||
const filterUsers = useCallback(
|
||||
({ value: itemValue }) => !value.some((group: Array<User['pk']>) => group.some((pk) => pk === itemValue)),
|
||||
[value]
|
||||
);
|
||||
|
||||
const items = useMemo(() => toPlainArray(value, getItemData), [value]);
|
||||
|
||||
const onSortEnd = useCallback(
|
||||
|
|
@ -134,7 +133,6 @@ const UserGroups = (props: UserGroupsProps) => {
|
|||
value={null}
|
||||
onChange={handleUserAdd}
|
||||
getOptionLabel={({ label, value }: SelectableValue) => <UserTooltip id={value} />}
|
||||
filterOptions={filterUsers}
|
||||
showError={showError}
|
||||
/>
|
||||
</VerticalGroup>
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ const RotationForm: FC<RotationFormProps> = observer((props) => {
|
|||
<Text size="medium">
|
||||
<HorizontalGroup spacing="sm">
|
||||
<span>[L{shiftId === 'new' ? layerPriority : shift?.priority_level}]</span>
|
||||
{shiftId === 'new' ? 'New Rotation' : shift?.id}
|
||||
{shiftId === 'new' ? 'New Rotation' : 'Update Rotation'}
|
||||
</HorizontalGroup>
|
||||
</Text>
|
||||
<HorizontalGroup>
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ const ScheduleOverrideForm: FC<RotationFormProps> = (props) => {
|
|||
>
|
||||
<VerticalGroup>
|
||||
<HorizontalGroup justify="space-between">
|
||||
<Text size="medium">{shiftId === 'new' ? 'New Override' : shift?.id}</Text>
|
||||
<Text size="medium">{shiftId === 'new' ? 'New Override' : 'Update Override'}</Text>
|
||||
<HorizontalGroup>
|
||||
<IconButton disabled variant="secondary" tooltip="Copy" name="copy" />
|
||||
<IconButton disabled variant="secondary" tooltip="Code" name="brackets-curly" />
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.root {
|
||||
border: var(--border-medium);
|
||||
border: var(--rotations-border);
|
||||
border-radius: 2px;
|
||||
background: var(--primary-background);
|
||||
background: var(--rotations-background);
|
||||
}
|
||||
|
||||
.current-time {
|
||||
|
|
|
|||
|
|
@ -56,7 +56,14 @@ const ScheduleSlot: FC<ScheduleSlotProps> = observer((props) => {
|
|||
|
||||
return (
|
||||
<div className={cx('stack')} style={{ width: `${width * 100}%` /*left: `${x * 100}%`*/ }}>
|
||||
{event.is_empty ? (
|
||||
{event.is_gap ? (
|
||||
<Tooltip content={<ScheduleGapDetails event={event} currentTimezone={currentTimezone} />}>
|
||||
<div className={cx('root', 'root__type_gap')} style={{}}>
|
||||
{trackMouse && mouseX > 0 && <div style={{ left: `${mouseX}px` }} className={cx('time')} />}
|
||||
{label && <div className={cx('label')}>{label}</div>}
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : event.is_empty ? (
|
||||
<div
|
||||
className={cx('root')}
|
||||
style={{
|
||||
|
|
@ -69,13 +76,6 @@ const ScheduleSlot: FC<ScheduleSlotProps> = observer((props) => {
|
|||
</div>
|
||||
)}
|
||||
</div>
|
||||
) : event.is_gap ? (
|
||||
<Tooltip content={<ScheduleGapDetails event={event} currentTimezone={currentTimezone} />}>
|
||||
<div className={cx('root', 'root__type_gap')} style={{}}>
|
||||
{trackMouse && mouseX > 0 && <div style={{ left: `${mouseX}px` }} className={cx('time')} />}
|
||||
{label && <div className={cx('label')}>{label}</div>}
|
||||
</div>
|
||||
</Tooltip>
|
||||
) : (
|
||||
users.map(({ pk: userPk }, userIndex) => {
|
||||
const storeUser = store.userStore.items[userPk];
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
export interface EscalationChain {
|
||||
id: string;
|
||||
pk: string; //? because GET related_escalation_chains returns {name,pk}[]
|
||||
is_default: boolean;
|
||||
name: string;
|
||||
number_of_integrations: number;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { action, observable, toJS } from 'mobx';
|
|||
import ReactCSSTransitionGroup from 'react-transition-group'; // ES6
|
||||
|
||||
import BaseStore from 'models/base_store';
|
||||
import { EscalationChain } from 'models/escalation_chain/escalation_chain.types';
|
||||
import { SlackChannel } from 'models/slack_channel/slack_channel.types';
|
||||
import { Timezone } from 'models/timezone/timezone.types';
|
||||
import { makeRequest } from 'network';
|
||||
|
|
@ -63,6 +64,9 @@ export class ScheduleStore extends BaseStore {
|
|||
@observable.shallow
|
||||
shifts: { [id: string]: Shift } = {};
|
||||
|
||||
@observable.shallow
|
||||
relatedEscalationChains: { [id: string]: EscalationChain[] } = {};
|
||||
|
||||
@observable.shallow
|
||||
rotations: {
|
||||
[id: string]: {
|
||||
|
|
@ -122,7 +126,7 @@ export class ScheduleStore extends BaseStore {
|
|||
|
||||
@action
|
||||
async updateItems(query = '') {
|
||||
const result = await this.getAll();
|
||||
const result = await makeRequest(this.path, { method: 'GET', params: { search: query } });
|
||||
|
||||
this.items = {
|
||||
...this.items,
|
||||
|
|
@ -259,6 +263,19 @@ export class ScheduleStore extends BaseStore {
|
|||
return response;
|
||||
}
|
||||
|
||||
updateRelatedEscalationChains = async (id: Schedule['id']) => {
|
||||
const response = await makeRequest(`/schedules/${id}/related_escalation_chains`, {
|
||||
method: 'GET',
|
||||
});
|
||||
|
||||
this.relatedEscalationChains = {
|
||||
...this.relatedEscalationChains,
|
||||
[id]: response,
|
||||
};
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
async updateRotationMock(rotationId: Rotation['id'], fromString: string, currentTimezone: Timezone) {
|
||||
if (this.rotations[rotationId]?.[fromString]) {
|
||||
return;
|
||||
|
|
@ -342,7 +359,7 @@ export class ScheduleStore extends BaseStore {
|
|||
async deleteOncallShift(shiftId: Shift['id']) {
|
||||
return await makeRequest(`/oncall_shifts/${shiftId}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
}).catch(this.onApiError);
|
||||
}
|
||||
|
||||
async updateEvents(scheduleId: Schedule['id'], startMoment: dayjs.Dayjs, type: RotationType = 'rotation', days = 9) {
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export interface Schedule {
|
|||
mention_oncall_next: boolean;
|
||||
mention_oncall_start: boolean;
|
||||
notify_empty_oncall: number;
|
||||
number_of_escalation_chains: number;
|
||||
}
|
||||
|
||||
export interface ScheduleEvent {
|
||||
|
|
|
|||
|
|
@ -64,14 +64,14 @@ export const pages: PageDefinition[] = [
|
|||
{
|
||||
component: SchedulesPage2,
|
||||
icon: 'calendar-alt',
|
||||
id: 'schedules-old',
|
||||
text: 'Schedules OLD',
|
||||
id: 'schedules',
|
||||
text: 'Schedules',
|
||||
},
|
||||
{
|
||||
component: SchedulesPage,
|
||||
icon: 'calendar-alt',
|
||||
id: 'schedules',
|
||||
text: 'Schedules',
|
||||
id: 'schedules-new',
|
||||
text: 'Schedules α',
|
||||
},
|
||||
{
|
||||
component: SchedulePage,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
|
||||
.root {
|
||||
max-width: 1600px;
|
||||
margin: 0 auto;
|
||||
margin-top: 24px;
|
||||
|
||||
--rotations-border: var(--border-medium);
|
||||
--rotations-background: var(--primary-background);
|
||||
}
|
||||
|
||||
.header {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import ScheduleFinal from 'containers/Rotations/ScheduleFinal';
|
|||
import ScheduleOverrides from 'containers/Rotations/ScheduleOverrides';
|
||||
import { Timezone } from 'models/timezone/timezone.types';
|
||||
import { User } from 'models/user/user.types';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { WithStoreProps } from 'state/types';
|
||||
import { withMobXProviderContext } from 'state/withStore';
|
||||
|
||||
|
|
@ -58,6 +59,10 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
const { store } = this.props;
|
||||
const { startMoment } = this.state;
|
||||
|
||||
if (!store.hasFeature(AppFeature.WebSchedules)) {
|
||||
getLocationSrv().update({ query: { page: 'schedules' } });
|
||||
}
|
||||
|
||||
store.userStore.updateItems();
|
||||
|
||||
const {
|
||||
|
|
@ -89,7 +94,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
<div className={cx('header')}>
|
||||
<HorizontalGroup justify="space-between">
|
||||
<HorizontalGroup>
|
||||
<PluginLink query={{ page: 'schedules' }}>
|
||||
<PluginLink query={{ page: 'schedules-new' }}>
|
||||
<IconButton style={{ marginTop: '5px' }} name="arrow-left" size="xxl" />
|
||||
</PluginLink>
|
||||
<Text.Title editable editModalTitle="Schedule name" level={3} onTextChange={this.handleNameChange}>
|
||||
|
|
@ -334,7 +339,7 @@ class SchedulePage extends React.Component<SchedulePageProps, SchedulePageState>
|
|||
} = this.props;
|
||||
|
||||
store.scheduleStore.delete(scheduleId).then(() => {
|
||||
getLocationSrv().update({ query: { page: 'schedules' } });
|
||||
getLocationSrv().update({ query: { page: 'schedules-new' } });
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@
|
|||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.loader {
|
||||
padding-left: 20px;
|
||||
}
|
||||
|
||||
/*
|
||||
.root .expanded-row {
|
||||
background: var(--secondary-background);
|
||||
|
|
|
|||
|
|
@ -1,9 +1,10 @@
|
|||
import React from 'react';
|
||||
|
||||
import { getLocationSrv } from '@grafana/runtime';
|
||||
import { Button, HorizontalGroup, IconButton, VerticalGroup } from '@grafana/ui';
|
||||
import { Button, HorizontalGroup, IconButton, LoadingPlaceholder, VerticalGroup } from '@grafana/ui';
|
||||
import cn from 'classnames/bind';
|
||||
import dayjs from 'dayjs';
|
||||
import { debounce } from 'lodash-es';
|
||||
import { observer } from 'mobx-react';
|
||||
|
||||
import Avatar from 'components/Avatar/Avatar';
|
||||
|
|
@ -17,13 +18,12 @@ import Text from 'components/Text/Text';
|
|||
import TimelineMarks from 'components/TimelineMarks/TimelineMarks';
|
||||
import UserTimezoneSelect from 'components/UserTimezoneSelect/UserTimezoneSelect';
|
||||
import WithConfirm from 'components/WithConfirm/WithConfirm';
|
||||
import Rotation from 'containers/Rotation/Rotation';
|
||||
import ScheduleFinal from 'containers/Rotations/ScheduleFinal';
|
||||
import { getFromString } from 'models/schedule/schedule.helpers';
|
||||
import { Schedule, ScheduleType } from 'models/schedule/schedule.types';
|
||||
import { getTzOffsetString } from 'models/timezone/timezone.helpers';
|
||||
import { Timezone } from 'models/timezone/timezone.types';
|
||||
import { getStartOfWeek } from 'pages/schedule/Schedule.helpers';
|
||||
import { AppFeature } from 'state/features';
|
||||
import { WithStoreProps } from 'state/types';
|
||||
import { withMobXProviderContext } from 'state/withStore';
|
||||
|
||||
|
|
@ -48,7 +48,7 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
const { store } = this.props;
|
||||
this.state = {
|
||||
startMoment: getStartOfWeek(store.currentTimezone),
|
||||
filters: { searchTerm: '', status: 'all', type: 'all' },
|
||||
filters: { searchTerm: '', status: 'all', type: ScheduleType.API },
|
||||
showNewScheduleSelector: false,
|
||||
expandedRowKeys: [],
|
||||
};
|
||||
|
|
@ -57,6 +57,10 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
async componentDidMount() {
|
||||
const { store } = this.props;
|
||||
|
||||
if (!store.hasFeature(AppFeature.WebSchedules)) {
|
||||
getLocationSrv().update({ query: { page: 'schedules' } });
|
||||
}
|
||||
|
||||
store.userStore.updateItems();
|
||||
store.scheduleStore.updateItems();
|
||||
}
|
||||
|
|
@ -67,8 +71,7 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
|
||||
const { scheduleStore } = store;
|
||||
|
||||
const schedules = scheduleStore.getSearchResult();
|
||||
|
||||
const schedules = scheduleStore.getSearchResult(/*filters.searchTerm*/);
|
||||
const columns = [
|
||||
{
|
||||
width: '10%',
|
||||
|
|
@ -84,7 +87,7 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
},
|
||||
{
|
||||
width: '45%',
|
||||
title: 'OnCall',
|
||||
title: 'Oncall',
|
||||
key: 'users',
|
||||
render: this.renderOncallNow,
|
||||
},
|
||||
|
|
@ -107,10 +110,20 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
},
|
||||
];
|
||||
|
||||
const moment = dayjs().tz(store.currentTimezone);
|
||||
|
||||
const users = store.userStore.getSearchResult().results;
|
||||
|
||||
const data = schedules
|
||||
? schedules
|
||||
.filter((schedule) => schedule.type === ScheduleType.API)
|
||||
.filter(
|
||||
(schedule) =>
|
||||
filters.status === 'all' ||
|
||||
(filters.status === 'used' && schedule.number_of_escalation_chains) ||
|
||||
(filters.status === 'unused' && !schedule.number_of_escalation_chains)
|
||||
)
|
||||
.filter((schedule) => !filters.searchTerm || schedule.name.includes(filters.searchTerm))
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={cx('root')}>
|
||||
|
|
@ -132,7 +145,7 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
</HorizontalGroup>
|
||||
<Table
|
||||
columns={columns}
|
||||
data={schedules}
|
||||
data={data}
|
||||
pagination={{ page: 1, total: 1, onChange: this.handlePageChange }}
|
||||
rowKey="id"
|
||||
expandable={{
|
||||
|
|
@ -142,6 +155,11 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
expandRowByClick: true,
|
||||
expandedRowClassName: () => cx('expanded-row'),
|
||||
}}
|
||||
emptyText={
|
||||
<div className={cx('loader')}>
|
||||
{data ? <Text type="secondary">Not found</Text> : <Text type="secondary">Loading schedules...</Text>}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</VerticalGroup>
|
||||
</div>
|
||||
|
|
@ -186,7 +204,9 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
this.setState({ expandedRowKeys: [...this.state.expandedRowKeys, data.id] }, this.updateEvents);
|
||||
} else if (!expanded && expandedRowKeys.includes(data.id)) {
|
||||
const index = expandedRowKeys.indexOf(data.id);
|
||||
this.setState({ expandedRowKeys: [...expandedRowKeys.splice(index, 1)] }, this.updateEvents);
|
||||
const newExpandedRowKeys = [...expandedRowKeys];
|
||||
newExpandedRowKeys.splice(index, 1);
|
||||
this.setState({ expandedRowKeys: newExpandedRowKeys }, this.updateEvents);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -195,7 +215,9 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
const { expandedRowKeys, startMoment } = this.state;
|
||||
|
||||
expandedRowKeys.forEach((scheduleId) => {
|
||||
store.scheduleStore.updateEvents(scheduleId, getFromString(startMoment), 'final');
|
||||
store.scheduleStore.updateEvents(scheduleId, startMoment, 'rotation');
|
||||
store.scheduleStore.updateEvents(scheduleId, startMoment, 'override');
|
||||
store.scheduleStore.updateEvents(scheduleId, startMoment, 'final');
|
||||
});
|
||||
};
|
||||
|
||||
|
|
@ -218,25 +240,37 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
);
|
||||
};
|
||||
|
||||
renderStatus = () => {
|
||||
const escalationsCount = Math.floor(Math.random() * 10) + 1;
|
||||
const warningsCount = Math.floor(Math.random() * 10) + 1;
|
||||
renderStatus = (item: Schedule) => {
|
||||
const {
|
||||
store: { scheduleStore },
|
||||
} = this.props;
|
||||
|
||||
const relatedEscalationChains = scheduleStore.relatedEscalationChains[item.id];
|
||||
|
||||
return (
|
||||
<HorizontalGroup>
|
||||
<ScheduleCounter
|
||||
type="link"
|
||||
count={escalationsCount}
|
||||
count={item.number_of_escalation_chains}
|
||||
tooltipTitle="Used in escalations"
|
||||
tooltipContent={
|
||||
<>
|
||||
<PluginLink query={{ page: 'integrations', id: 'CXBEG63MBJMDL' }}>Grafana 1</PluginLink>
|
||||
<br />
|
||||
<PluginLink query={{ page: 'integrations', id: 'CXBEG63MBJMDL' }}>Grafana 2</PluginLink>
|
||||
<br />
|
||||
<PluginLink query={{ page: 'integrations', id: 'CXBEG63MBJMDL' }}>Grafana 3</PluginLink>
|
||||
</>
|
||||
<VerticalGroup spacing="sm">
|
||||
{relatedEscalationChains ? (
|
||||
relatedEscalationChains.length ? (
|
||||
relatedEscalationChains.map((escalationChain) => (
|
||||
<PluginLink query={{ page: 'escalations', id: escalationChain.pk }}>
|
||||
{escalationChain.name}
|
||||
</PluginLink>
|
||||
))
|
||||
) : (
|
||||
'Not used yet'
|
||||
)
|
||||
) : (
|
||||
<LoadingPlaceholder>Loading related escalation chains....</LoadingPlaceholder>
|
||||
)}
|
||||
</VerticalGroup>
|
||||
}
|
||||
onHover={this.getUpdateRelatedEscalationChainsHandler(item.id)}
|
||||
/>
|
||||
{/* <ScheduleCounter
|
||||
type="warning"
|
||||
|
|
@ -305,9 +339,19 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
};
|
||||
|
||||
handleSchedulesFiltersChange = (filters: SchedulesFiltersType) => {
|
||||
this.setState({ filters });
|
||||
this.setState({ filters }, this.debouncedUpdateSchedules);
|
||||
};
|
||||
|
||||
applyFilters = () => {
|
||||
const { filters } = this.state;
|
||||
const { store } = this.props;
|
||||
const { scheduleStore } = store;
|
||||
|
||||
// scheduleStore.updateItems(filters.searchTerm);
|
||||
};
|
||||
|
||||
debouncedUpdateSchedules = debounce(this.applyFilters, 1000);
|
||||
|
||||
handlePageChange = (page: number) => {};
|
||||
|
||||
update = () => {
|
||||
|
|
@ -316,6 +360,17 @@ class SchedulesPage extends React.Component<SchedulesPageProps, SchedulesPageSta
|
|||
|
||||
return scheduleStore.updateItems();
|
||||
};
|
||||
|
||||
getUpdateRelatedEscalationChainsHandler = (scheduleId: Schedule['id']) => {
|
||||
const { store } = this.props;
|
||||
const { scheduleStore } = store;
|
||||
|
||||
return () => {
|
||||
scheduleStore.updateRelatedEscalationChains(scheduleId).then(() => {
|
||||
this.forceUpdate();
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export default withMobXProviderContext(SchedulesPage);
|
||||
|
|
|
|||
|
|
@ -5,4 +5,5 @@ export enum AppFeature {
|
|||
MobileApp = 'mobile_app',
|
||||
CloudNotifications = 'grafana_cloud_notifications',
|
||||
CloudConnection = 'grafana_cloud_connection',
|
||||
WebSchedules = 'web_schedules',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
import React, { useEffect, useRef, useState, useMemo } from 'react';
|
||||
|
||||
import { AppRootProps, NavModelItem } from '@grafana/data';
|
||||
|
||||
|
|
@ -18,11 +17,12 @@ type Args = {
|
|||
};
|
||||
enableLiveSettings: boolean;
|
||||
enableCloudPage: boolean;
|
||||
enableNewSchedulesPage: boolean;
|
||||
backendLicense: string;
|
||||
};
|
||||
|
||||
export function useForceUpdate() {
|
||||
const [value, setValue] = useState(0);
|
||||
const [, setValue] = useState(0);
|
||||
return () => setValue((value) => value + 1);
|
||||
}
|
||||
|
||||
|
|
@ -34,6 +34,7 @@ export function useNavModel({
|
|||
grafanaUser,
|
||||
enableLiveSettings,
|
||||
enableCloudPage,
|
||||
enableNewSchedulesPage,
|
||||
backendLicense,
|
||||
}: Args) {
|
||||
return useMemo(() => {
|
||||
|
|
@ -49,7 +50,8 @@ export function useNavModel({
|
|||
hideFromTabs ||
|
||||
(role === 'Admin' && grafanaUser.orgRole !== role) ||
|
||||
(id === 'live-settings' && !enableLiveSettings) ||
|
||||
(id === 'cloud' && !enableCloudPage),
|
||||
(id === 'cloud' && !enableCloudPage) ||
|
||||
(id === 'schedules-new' && !enableNewSchedulesPage),
|
||||
});
|
||||
|
||||
if (page === id) {
|
||||
|
|
@ -74,7 +76,17 @@ export function useNavModel({
|
|||
node,
|
||||
main: node,
|
||||
};
|
||||
}, [meta.info.logos.large, pages, path, page, enableLiveSettings, enableCloudPage]);
|
||||
}, [
|
||||
meta.info.logos.large,
|
||||
pages,
|
||||
path,
|
||||
page,
|
||||
enableLiveSettings,
|
||||
enableCloudPage,
|
||||
backendLicense,
|
||||
enableNewSchedulesPage,
|
||||
grafanaUser.orgRole,
|
||||
]);
|
||||
}
|
||||
|
||||
export function usePrevious(value: any) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue