mirror of
https://github.com/Unleash/unleash.git
synced 2025-02-09 00:18:00 +01:00
refactor: port EventHistory to TS/SWR (#669)
* refactor: port EventHistory to TS/SWR * refactor: fix interface type prefix * refactor: split useEvents and useFeatureEvents hooks Co-authored-by: Fredrik Strand Oseberg <fredrik.no@gmail.com>
This commit is contained in:
parent
25ca7b7216
commit
72acf2309c
@ -2,16 +2,20 @@ import { useParams } from 'react-router';
|
||||
import useFeature from '../../../../hooks/api/getters/useFeature/useFeature';
|
||||
import { useStyles } from './FeatureLog.styles';
|
||||
import { IFeatureViewParams } from '../../../../interfaces/params';
|
||||
import HistoryComponent from '../../../history/FeatureEventHistory';
|
||||
import { FeatureEventHistory } from '../../../history/FeatureEventHistory/FeatureEventHistory';
|
||||
|
||||
const FeatureLog = () => {
|
||||
const styles = useStyles();
|
||||
const { projectId, featureId } = useParams<IFeatureViewParams>();
|
||||
const { feature } = useFeature(projectId, featureId);
|
||||
|
||||
if (!feature.name) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<HistoryComponent toggleName={feature.name} />
|
||||
<FeatureEventHistory toggleName={feature.name} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
@ -1,22 +1,12 @@
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import EventLog from '../EventLog';
|
||||
import { useEvents } from '../../../hooks/api/getters/useEvents/useEvents';
|
||||
|
||||
interface IEventLogProps {
|
||||
fetchHistory: () => void;
|
||||
history: History;
|
||||
}
|
||||
export const EventHistory = () => {
|
||||
const { events } = useEvents();
|
||||
|
||||
const EventHistory = ({ fetchHistory, history }: IEventLogProps) => {
|
||||
useEffect(() => {
|
||||
fetchHistory();
|
||||
}, [fetchHistory]);
|
||||
|
||||
if (history.length < 0) {
|
||||
if (events.length < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return <EventLog history={history} title="Recent changes" />;
|
||||
return <EventLog history={events} title="Recent changes" />;
|
||||
};
|
||||
|
||||
export default EventHistory;
|
||||
|
@ -1,16 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import EventHistory from './EventHistory';
|
||||
import { fetchHistory } from '../../../store/history/actions';
|
||||
|
||||
const mapStateToProps = state => {
|
||||
const history = state.history.get('list').toArray();
|
||||
return {
|
||||
history,
|
||||
};
|
||||
};
|
||||
|
||||
const EventHistoryContainer = connect(mapStateToProps, { fetchHistory })(
|
||||
EventHistory
|
||||
);
|
||||
|
||||
export default EventHistoryContainer;
|
@ -1,29 +1,19 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import { useEffect } from 'react';
|
||||
import EventLog from '../EventLog';
|
||||
import { useFeatureEvents } from '../../../hooks/api/getters/useFeatureEvents/useFeatureEvents';
|
||||
|
||||
const FeatureEventHistory = ({
|
||||
toggleName,
|
||||
history,
|
||||
fetchHistoryForToggle,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
fetchHistoryForToggle(toggleName);
|
||||
}, [fetchHistoryForToggle, toggleName]);
|
||||
export const FeatureEventHistory = ({ toggleName }) => {
|
||||
const { events } = useFeatureEvents(toggleName);
|
||||
|
||||
if (!history || history.length === 0) {
|
||||
return <span>fetching..</span>;
|
||||
if (events.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<EventLog history={history} hideName title="Change log" displayInline />
|
||||
<EventLog history={events} hideName title="Change log" displayInline />
|
||||
);
|
||||
};
|
||||
|
||||
FeatureEventHistory.propTypes = {
|
||||
toggleName: PropTypes.string.isRequired,
|
||||
history: PropTypes.array,
|
||||
fetchHistoryForToggle: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default FeatureEventHistory;
|
||||
|
@ -1,25 +0,0 @@
|
||||
import { connect } from 'react-redux';
|
||||
import FeatureEventHistory from './FeatureEventHistory';
|
||||
import { fetchHistoryForToggle } from '../../../store/history/actions';
|
||||
|
||||
function getHistoryFromToggle(state, toggleName) {
|
||||
if (!toggleName) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (state.history.hasIn(['toggles', toggleName])) {
|
||||
return state.history.getIn(['toggles', toggleName]).toArray();
|
||||
}
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
const mapStateToProps = (state, props) => ({
|
||||
history: getHistoryFromToggle(state, props.toggleName),
|
||||
});
|
||||
|
||||
const FeatureEventHistoryContainer = connect(mapStateToProps, {
|
||||
fetchHistoryForToggle,
|
||||
})(FeatureEventHistory);
|
||||
|
||||
export default FeatureEventHistoryContainer;
|
39
frontend/src/hooks/api/getters/useEvents/useEvents.ts
Normal file
39
frontend/src/hooks/api/getters/useEvents/useEvents.ts
Normal file
@ -0,0 +1,39 @@
|
||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||
import { useCallback } from 'react';
|
||||
import { formatApiPath } from '../../../../utils/format-path';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { IEvent } from '../../../../interfaces/event';
|
||||
|
||||
const PATH = formatApiPath('api/admin/events');
|
||||
|
||||
export interface IUseEventsOutput {
|
||||
events: IEvent[];
|
||||
refetchEvents: () => void;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
export const useEvents = (options?: SWRConfiguration): IUseEventsOutput => {
|
||||
const { data, error } = useSWR<{ events: IEvent[] }>(
|
||||
PATH,
|
||||
fetchAllEvents,
|
||||
options
|
||||
);
|
||||
|
||||
const refetchEvents = useCallback(() => {
|
||||
mutate(PATH).catch(console.warn);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
events: data?.events || [],
|
||||
loading: !error && !data,
|
||||
refetchEvents,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
||||
const fetchAllEvents = () => {
|
||||
return fetch(PATH, { method: 'GET' })
|
||||
.then(handleErrorResponses('Event history'))
|
||||
.then(res => res.json());
|
||||
};
|
@ -0,0 +1,42 @@
|
||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||
import { useCallback } from 'react';
|
||||
import { formatApiPath } from '../../../../utils/format-path';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
import { IEvent } from '../../../../interfaces/event';
|
||||
|
||||
const PATH = formatApiPath('api/admin/events');
|
||||
|
||||
export interface IUseEventsOutput {
|
||||
events: IEvent[];
|
||||
refetchEvents: () => void;
|
||||
loading: boolean;
|
||||
error?: Error;
|
||||
}
|
||||
|
||||
export const useFeatureEvents = (
|
||||
featureName: string,
|
||||
options?: SWRConfiguration
|
||||
): IUseEventsOutput => {
|
||||
const { data, error } = useSWR<{ events: IEvent[] }>(
|
||||
[PATH, featureName],
|
||||
() => fetchFeatureEvents(featureName),
|
||||
options
|
||||
);
|
||||
|
||||
const refetchEvents = useCallback(() => {
|
||||
mutate(PATH).catch(console.warn);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
events: data?.events || [],
|
||||
loading: !error && !data,
|
||||
refetchEvents,
|
||||
error,
|
||||
};
|
||||
};
|
||||
|
||||
const fetchFeatureEvents = (featureName: string) => {
|
||||
return fetch(`${PATH}/${featureName}`, { method: 'GET' })
|
||||
.then(handleErrorResponses('Event history'))
|
||||
.then(res => res.json());
|
||||
};
|
14
frontend/src/interfaces/event.ts
Normal file
14
frontend/src/interfaces/event.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { ITag } from './tags';
|
||||
|
||||
export interface IEvent {
|
||||
id: number;
|
||||
createdAt: string;
|
||||
type: string;
|
||||
createdBy: string;
|
||||
project?: string;
|
||||
environment?: string;
|
||||
featureName?: string;
|
||||
data?: any;
|
||||
preData?: any;
|
||||
tags?: ITag[];
|
||||
}
|
@ -2,16 +2,16 @@ import { Alert } from '@material-ui/lab';
|
||||
import React, { useContext } from 'react';
|
||||
import { ADMIN } from '../../component/providers/AccessProvider/permissions';
|
||||
import ConditionallyRender from '../../component/common/ConditionallyRender';
|
||||
import HistoryComponent from '../../component/history/EventHistory';
|
||||
import { EventHistory } from '../../component/history/EventHistory/EventHistory';
|
||||
import AccessContext from '../../contexts/AccessContext';
|
||||
|
||||
const HistoryPage = ({ history }) => {
|
||||
const HistoryPage = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
|
||||
return (
|
||||
<ConditionallyRender
|
||||
condition={hasAccess(ADMIN)}
|
||||
show={<HistoryComponent />}
|
||||
show={<EventHistory />}
|
||||
elseShow={
|
||||
<Alert severity="error">
|
||||
You need instance admin to access this section.
|
||||
|
@ -1,9 +1,9 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import HistoryListToggle from '../../component/history/FeatureEventHistory';
|
||||
import { FeatureEventHistory } from '../../component/history/FeatureEventHistory/FeatureEventHistory';
|
||||
|
||||
const render = ({ match: { params } }) => (
|
||||
<HistoryListToggle toggleName={params.toggleName} />
|
||||
<FeatureEventHistory toggleName={params.toggleName} />
|
||||
);
|
||||
|
||||
render.propTypes = {
|
@ -1,33 +0,0 @@
|
||||
import api from './api';
|
||||
import { dispatchError } from '../util';
|
||||
|
||||
export const RECEIVE_HISTORY = 'RECEIVE_HISTORY';
|
||||
export const ERROR_RECEIVE_HISTORY = 'ERROR_RECEIVE_HISTORY';
|
||||
|
||||
export const RECEIVE_HISTORY_FOR_TOGGLE = 'RECEIVE_HISTORY_FOR_TOGGLE';
|
||||
|
||||
const receiveHistory = json => ({
|
||||
type: RECEIVE_HISTORY,
|
||||
value: json.events,
|
||||
});
|
||||
|
||||
const receiveHistoryforToggle = json => ({
|
||||
type: RECEIVE_HISTORY_FOR_TOGGLE,
|
||||
value: json,
|
||||
});
|
||||
|
||||
export function fetchHistory() {
|
||||
return dispatch =>
|
||||
api
|
||||
.fetchAll()
|
||||
.then(json => dispatch(receiveHistory(json)))
|
||||
.catch(dispatchError(dispatch, ERROR_RECEIVE_HISTORY));
|
||||
}
|
||||
|
||||
export function fetchHistoryForToggle(toggleName) {
|
||||
return dispatch =>
|
||||
api
|
||||
.fetchHistoryForToggle(toggleName)
|
||||
.then(json => dispatch(receiveHistoryforToggle(json)))
|
||||
.catch(dispatchError(dispatch, ERROR_RECEIVE_HISTORY));
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
import { formatApiPath } from '../../utils/format-path';
|
||||
import { throwIfNotSuccess } from '../api-helper';
|
||||
|
||||
const URI = formatApiPath('api/admin/events');
|
||||
|
||||
function fetchAll() {
|
||||
return fetch(URI, { credentials: 'include' })
|
||||
.then(throwIfNotSuccess)
|
||||
.then(response => response.json());
|
||||
}
|
||||
|
||||
function fetchHistoryForToggle(toggleName) {
|
||||
return fetch(`${URI}/${toggleName}`, { credentials: 'include' })
|
||||
.then(throwIfNotSuccess)
|
||||
.then(response => response.json());
|
||||
}
|
||||
|
||||
export default {
|
||||
fetchAll,
|
||||
fetchHistoryForToggle,
|
||||
};
|
@ -1,23 +0,0 @@
|
||||
import { List, Map as $Map } from 'immutable';
|
||||
import { RECEIVE_HISTORY, RECEIVE_HISTORY_FOR_TOGGLE } from './actions';
|
||||
import { USER_LOGOUT, USER_LOGIN } from '../user/actions';
|
||||
|
||||
function getInitState() {
|
||||
return new $Map({ list: new List(), toggles: new $Map() });
|
||||
}
|
||||
|
||||
const historyStore = (state = getInitState(), action) => {
|
||||
switch (action.type) {
|
||||
case RECEIVE_HISTORY_FOR_TOGGLE:
|
||||
return state.setIn(['toggles', action.value.toggleName], new List(action.value.events));
|
||||
case RECEIVE_HISTORY:
|
||||
return state.set('list', new List(action.value));
|
||||
case USER_LOGOUT:
|
||||
case USER_LOGIN:
|
||||
return getInitState();
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
export default historyStore;
|
@ -6,7 +6,6 @@ import featureTags from './feature-tags';
|
||||
import tagTypes from './tag-type';
|
||||
import tags from './tag';
|
||||
import strategies from './strategy';
|
||||
import history from './history'; // eslint-disable-line
|
||||
import archive from './archive';
|
||||
import error from './error';
|
||||
import settings from './settings';
|
||||
@ -29,7 +28,6 @@ const unleashStore = combineReducers({
|
||||
tagTypes,
|
||||
tags,
|
||||
featureTags,
|
||||
history,
|
||||
archive,
|
||||
error,
|
||||
settings,
|
||||
|
Loading…
Reference in New Issue
Block a user