console: handle renaming cron triggers (#5167)

This commit is contained in:
Aleksandra Sikora 2020-06-23 15:56:51 +02:00 committed by GitHub
parent ea23571049
commit 9936ace6ab
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 76 additions and 32 deletions

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useState, useEffect } from 'react';
import Helmet from 'react-helmet';
import CommonTabLayout from '../../../Common/Layout/CommonTabLayout/CommonTabLayout';
import {
@ -21,7 +21,12 @@ interface Props {
allTriggers: Triggers;
tabName: STTab;
dispatch: Dispatch;
eventsLoading?: boolean;
}
type TriggerPresence =
| 'not-missing'
| { type: 'timeout'; timeoutHandle: number }
| 'error-not-found';
const STContainer: React.FC<Props> = ({
triggerName,
@ -29,7 +34,11 @@ const STContainer: React.FC<Props> = ({
allTriggers,
tabName,
dispatch,
eventsLoading,
}) => {
const [triggerPresence, setTriggerPresence] = useState<TriggerPresence>(
'not-missing'
);
React.useEffect(() => {
dispatch(setCurrentTrigger(triggerName));
return () => {
@ -39,8 +48,28 @@ const STContainer: React.FC<Props> = ({
const currentTrigger = findScheduledTrigger(allTriggers, triggerName);
// TODO: This is a hack to deal with renaming cron triggers and stale props
// https://react-redux.js.org/api/hooks#stale-props-and-zombie-children
// Needs remodelling the state and careful handling of cron triggers rename
useEffect(() => {
if (currentTrigger) {
if (
typeof triggerPresence === 'object' &&
triggerPresence.type === 'timeout'
) {
window.clearTimeout(triggerPresence.timeoutHandle);
setTriggerPresence('not-missing');
}
} else if (triggerPresence === 'not-missing') {
const timeoutHandle = window.setTimeout(() => {
setTriggerPresence('error-not-found');
}, 1200 /* arbitrary value */);
setTriggerPresence({ type: 'timeout', timeoutHandle });
}
}, [currentTrigger]);
if (!currentTrigger) {
dispatch(setCurrentTrigger(''));
if (eventsLoading || triggerPresence !== 'error-not-found') return null;
throw new NotFoundError();
}

View File

@ -1,21 +1,27 @@
import React from 'react';
import { connect, ConnectedProps } from 'react-redux';
import STContainer from '../Container';
import { Triggers, RouterTriggerProps } from '../../types';
import { MapStateToProps } from '../../../../../types';
import Modify from './Modify';
import { mapDispatchToPropsEmpty } from '../../../../Common/utils/reactUtils';
import { ReduxState } from '../../../../../types';
interface Props extends InjectedProps {}
const ModifyContainer: React.FC<Props> = props => {
const { dispatch, allTriggers, triggerName, readOnlyMode } = props;
const {
dispatch,
allTriggers,
triggerName,
readOnlyMode,
eventsLoading,
} = props;
return (
<STContainer
tabName="modify"
dispatch={dispatch}
triggerName={triggerName}
allTriggers={allTriggers}
eventsLoading={eventsLoading}
>
{readOnlyMode ? (
'Cannot modify in read-only mode'
@ -26,20 +32,15 @@ const ModifyContainer: React.FC<Props> = props => {
);
};
type PropsFromState = {
allTriggers: Triggers;
triggerName: string;
readOnlyMode: boolean;
};
const mapStateToProps: MapStateToProps<PropsFromState, RouterTriggerProps> = (
state,
ownProps
const mapStateToProps = (
state: ReduxState,
ownProps: { params: { triggerName: string } }
) => {
return {
allTriggers: state.events.triggers,
readOnlyMode: state.main.readOnlyMode,
triggerName: ownProps.params.triggerName,
eventsLoading: state.events.loading,
};
};

View File

@ -1,4 +1,4 @@
import { push } from 'react-router-redux';
import { push, replace } from 'react-router-redux';
import {
fetchEventTriggersQuery,
fetchScheduledTriggersQuery,
@ -35,8 +35,14 @@ import {
EventTrigger,
EventKind,
InvocationLog,
LOADING_TRIGGERS,
} from './types';
import { setScheduledTriggers, setEventTriggers, setTriggers } from './reducer';
import {
setScheduledTriggers,
setEventTriggers,
setTriggers,
setCurrentTrigger,
} from './reducer';
import { LocalScheduledTriggerState } from './CronTriggers/state';
import { LocalAdhocEventState } from './AdhocEvents/Add/state';
import {
@ -59,6 +65,8 @@ import { getLogsTableDef } from './utils';
export const fetchTriggers = (
kind: Nullable<TriggerKind>
): Thunk<Promise<void>> => (dispatch, getState) => {
dispatch({ type: LOADING_TRIGGERS });
const bulkQueryArgs = [];
if (kind) {
bulkQueryArgs.push(
@ -194,8 +202,8 @@ export const saveScheduledTrigger = (
);
const upRenameQueries = [
getDropScheduledTriggerQuery(existingTrigger.name),
generateCreateScheduledTriggerQuery(state),
getDropScheduledTriggerQuery(existingTrigger.name),
];
const downRenameQueries = [
getDropScheduledTriggerQuery(state.name),
@ -209,18 +217,19 @@ export const saveScheduledTrigger = (
const successMsg = 'Updated scheduled trigger successfully';
const customOnSuccess = () => {
if (isRenamed) {
const newHref = window.location.href.replace(
getSTModifyRoute(existingTrigger.name, 'relative'),
getSTModifyRoute(state.name, 'relative')
);
return window.location.replace(newHref);
}
return dispatch(fetchTriggers('cron'))
.then(() => {
if (successCb) {
successCb();
}
if (isRenamed) {
const newHref = window.location.href.replace(
getSTModifyRoute(existingTrigger.name, 'relative'),
getSTModifyRoute(state.name, 'relative')
);
dispatch(replace(newHref));
dispatch(setCurrentTrigger(state.name));
}
})
.catch(() => {
if (errorCb) {

View File

@ -12,6 +12,7 @@ import {
RASetCurrentTrigger,
RASetEventTriggers,
RASetScheduledTriggers,
LOADING_TRIGGERS,
} from './types';
export const setTriggers = (data: Triggers): RASetAllTriggers => ({
@ -41,6 +42,7 @@ const reducer = (state = defaultState, action: RAEvents) => {
return {
...state,
triggers: action.data,
loading: false,
};
case LOADED_SCHEDULED_TRIGGERS:
return {
@ -49,6 +51,7 @@ const reducer = (state = defaultState, action: RAEvents) => {
...state.triggers,
scheduled: action.data,
},
loading: false,
};
case LOADED_EVENT_TRIGGERS:
return {
@ -57,12 +60,18 @@ const reducer = (state = defaultState, action: RAEvents) => {
...state.triggers,
event: action.data,
},
loading: false,
};
case SET_CURRENT_TRIGGER:
return {
...state,
currentTrigger: action.name,
};
case LOADING_TRIGGERS:
return {
...state,
loading: true,
};
default:
return state;
}

View File

@ -3,9 +3,7 @@ import { Triggers } from './types';
export type EventsState = {
triggers: Triggers;
currentTrigger: string;
loading: {
[component: string]: boolean;
};
loading: boolean;
error: {
[component: string]: any;
};
@ -17,7 +15,7 @@ const state: EventsState = {
event: [],
},
currentTrigger: '',
loading: {},
loading: true,
error: {},
};

View File

@ -6,11 +6,8 @@ import { Dispatch } from '../../../types';
export const LOADING_TRIGGERS = 'Events/LOADING_TRIGGERS';
export const LOADED_TRIGGERS = 'Events/LOADED_TRIGGERS';
export const LOADING_SCHEDULED_TRIGGERS = 'Events/LOADING_SCHEDULED_TRIGGERS';
export const LOADED_SCHEDULED_TRIGGERS = 'Events/LOADED_SCHEDULED_TRIGGERS';
export const LOADING_EVENT_TRIGGERS = 'Events/LOADING_EVENT_TRIGGERS';
export const LOADED_EVENT_TRIGGERS = 'Events/LOADED_EVENT_TRIGGERS';
export const LOADING_TRIGGERS_ERROR = 'Events/LOADING_TRIGGERS_ERROR';
export const SET_CURRENT_TRIGGER = 'Events/SET_CURRENT_TRIGGER';
export const LOAD_PENDING_DATA_EVENTS = 'Events/LOAD_PENDING_DATA_EVENTS';
@ -161,4 +158,5 @@ export type RAEvents =
| RASetAllTriggers
| RASetScheduledTriggers
| RASetEventTriggers
| RASetCurrentTrigger;
| RASetCurrentTrigger
| { type: typeof LOADING_TRIGGERS };