mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
Merge pull request #648 from Unleash/feat/addons
refactor: addons to hook
This commit is contained in:
commit
014cdaa7d4
@ -1,5 +1,4 @@
|
||||
import React, { useContext, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useContext, useEffect } from 'react';
|
||||
import ConfiguredAddons from './ConfiguredAddons';
|
||||
import AvailableAddons from './AvailableAddons';
|
||||
import { Avatar } from '@material-ui/core';
|
||||
@ -14,6 +13,8 @@ import webhooksIcon from '../../../assets/icons/webhooks.svg';
|
||||
import teamsIcon from '../../../assets/icons/teams.svg';
|
||||
import dataDogIcon from '../../../assets/icons/datadog.svg';
|
||||
import { formatAssetPath } from '../../../utils/format-path';
|
||||
import useAddons from '../../../hooks/api/getters/useAddons/useAddons';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
const style = {
|
||||
width: '40px',
|
||||
@ -73,18 +74,14 @@ const getIcon = name => {
|
||||
}
|
||||
};
|
||||
|
||||
const AddonList = ({
|
||||
addons,
|
||||
providers,
|
||||
fetchAddons,
|
||||
removeAddon,
|
||||
toggleAddon,
|
||||
history,
|
||||
}) => {
|
||||
const AddonList = () => {
|
||||
const { hasAccess } = useContext(AccessContext);
|
||||
const { addons, providers, refetchAddons } = useAddons();
|
||||
const history = useHistory();
|
||||
|
||||
useEffect(() => {
|
||||
if (addons.length === 0) {
|
||||
fetchAddons();
|
||||
refetchAddons();
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [addons.length]);
|
||||
@ -96,9 +93,7 @@ const AddonList = ({
|
||||
show={
|
||||
<ConfiguredAddons
|
||||
addons={addons}
|
||||
toggleAddon={toggleAddon}
|
||||
hasAccess={hasAccess}
|
||||
removeAddon={removeAddon}
|
||||
getIcon={getIcon}
|
||||
/>
|
||||
}
|
||||
@ -115,13 +110,4 @@ const AddonList = ({
|
||||
);
|
||||
};
|
||||
|
||||
AddonList.propTypes = {
|
||||
addons: PropTypes.array.isRequired,
|
||||
providers: PropTypes.array.isRequired,
|
||||
fetchAddons: PropTypes.func.isRequired,
|
||||
removeAddon: PropTypes.func.isRequired,
|
||||
toggleAddon: PropTypes.func.isRequired,
|
||||
history: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
export default AddonList;
|
||||
|
@ -13,6 +13,7 @@ import { CREATE_ADDON } from '../../../providers/AccessProvider/permissions';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
const AvailableAddons = ({ providers, getIcon, hasAccess, history }) => {
|
||||
|
||||
const renderProvider = provider => (
|
||||
<ListItem key={provider.name}>
|
||||
<ListItemAvatar>{getIcon(provider.name)}</ListItemAvatar>
|
||||
|
@ -17,15 +17,47 @@ import {
|
||||
import { Link } from 'react-router-dom';
|
||||
import PageContent from '../../../common/PageContent/PageContent';
|
||||
import PropTypes from 'prop-types';
|
||||
import useAddons from '../../../../hooks/api/getters/useAddons/useAddons';
|
||||
import useToast from '../../../../hooks/useToast';
|
||||
import useAddonsApi from '../../../../hooks/api/actions/useAddonsApi/useAddonsApi';
|
||||
|
||||
const ConfiguredAddons = ({ addons, hasAccess, getIcon }) => {
|
||||
const { refetchAddons } = useAddons();
|
||||
const { updateAddon, removeAddon } = useAddonsApi();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
|
||||
const toggleAddon = async addon => {
|
||||
try {
|
||||
await updateAddon({ ...addon, enabled: !addon.enabled });
|
||||
refetchAddons();
|
||||
setToastData({
|
||||
type: 'success',
|
||||
title: 'Success',
|
||||
text: 'Addon state switched successfully',
|
||||
});
|
||||
} catch (e) {
|
||||
setToastApiError(e.toString());
|
||||
}
|
||||
};
|
||||
|
||||
const onRemoveAddon = addon => async () => {
|
||||
try {
|
||||
await removeAddon(addon.id);
|
||||
refetchAddons();
|
||||
setToastData({
|
||||
type: 'success',
|
||||
title: 'Success',
|
||||
text: 'Deleted addon successfully',
|
||||
});
|
||||
} catch (e) {
|
||||
setToastData({
|
||||
type: 'error',
|
||||
title: 'Error',
|
||||
text: 'Can not delete addon',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const ConfiguredAddons = ({
|
||||
addons,
|
||||
hasAccess,
|
||||
removeAddon,
|
||||
getIcon,
|
||||
toggleAddon,
|
||||
}) => {
|
||||
const onRemoveAddon = addon => () => removeAddon(addon);
|
||||
const renderAddon = addon => (
|
||||
<ListItem key={addon.id}>
|
||||
<ListItemAvatar>{getIcon(addon.provider)}</ListItemAvatar>
|
||||
@ -95,7 +127,6 @@ const ConfiguredAddons = ({
|
||||
ConfiguredAddons.propTypes = {
|
||||
addons: PropTypes.array.isRequired,
|
||||
hasAccess: PropTypes.func.isRequired,
|
||||
removeAddon: PropTypes.func.isRequired,
|
||||
toggleAddon: PropTypes.func.isRequired,
|
||||
getIcon: PropTypes.func.isRequired,
|
||||
};
|
||||
|
@ -10,15 +10,15 @@ import cloneDeep from 'lodash.clonedeep';
|
||||
|
||||
import styles from './form-addon-component.module.scss';
|
||||
import PageContent from '../common/PageContent/PageContent';
|
||||
import useAddonsApi from '../../hooks/api/actions/useAddonsApi/useAddonsApi';
|
||||
import useToast from '../../hooks/useToast';
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
const AddonFormComponent = ({ editMode, provider, addon, fetch }) => {
|
||||
const { createAddon, updateAddon } = useAddonsApi();
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
const history = useHistory();
|
||||
|
||||
const AddonFormComponent = ({
|
||||
editMode,
|
||||
provider,
|
||||
addon,
|
||||
fetch,
|
||||
cancel,
|
||||
submit,
|
||||
}) => {
|
||||
const [config, setConfig] = useState(addon);
|
||||
const [errors, setErrors] = useState({
|
||||
parameters: {},
|
||||
@ -73,6 +73,10 @@ const AddonFormComponent = ({
|
||||
setErrors({ ...errors, events: undefined });
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
history.goBack();
|
||||
};
|
||||
|
||||
const onSubmit = async evt => {
|
||||
evt.preventDefault();
|
||||
if (!provider) return;
|
||||
@ -100,8 +104,25 @@ const AddonFormComponent = ({
|
||||
}
|
||||
|
||||
try {
|
||||
await submit(config);
|
||||
if (editMode) {
|
||||
await updateAddon(config);
|
||||
history.push('/addons');
|
||||
setToastData({
|
||||
type: 'success',
|
||||
title: 'Addon updated successfully',
|
||||
});
|
||||
} else {
|
||||
await createAddon(config);
|
||||
history.push('/addons');
|
||||
setToastData({
|
||||
type: 'success',
|
||||
title: 'Addon created successfully',
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
setToastApiError({
|
||||
text: e.toString(),
|
||||
});
|
||||
setErrors({ parameters: {}, general: e.message });
|
||||
}
|
||||
};
|
||||
@ -175,7 +196,7 @@ const AddonFormComponent = ({
|
||||
/>
|
||||
</section>
|
||||
<section className={styles.formSection}>
|
||||
<FormButtons submitText={submitText} onCancel={cancel} />
|
||||
<FormButtons submitText={submitText} onCancel={handleCancel} />
|
||||
</section>
|
||||
</form>
|
||||
</PageContent>
|
||||
|
65
frontend/src/hooks/api/actions/useAddonsApi/useAddonsApi.ts
Normal file
65
frontend/src/hooks/api/actions/useAddonsApi/useAddonsApi.ts
Normal file
@ -0,0 +1,65 @@
|
||||
import { IAddons } from '../../../../interfaces/addons';
|
||||
import useAPI from '../useApi/useApi';
|
||||
|
||||
const useAddonsApi = () => {
|
||||
const { makeRequest, createRequest, errors, loading } = useAPI({
|
||||
propagateErrors: true,
|
||||
});
|
||||
|
||||
const URI = 'api/admin/addons';
|
||||
|
||||
const createAddon = async (addonConfig: IAddons) => {
|
||||
const path = URI;
|
||||
const req = createRequest(path, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(addonConfig),
|
||||
});
|
||||
|
||||
try {
|
||||
const res = await makeRequest(req.caller, req.id);
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
const removeAddon = async (id: number) => {
|
||||
const path = `${URI}/${id}`;
|
||||
const req = createRequest(path, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
try {
|
||||
const res = await makeRequest(req.caller, req.id);
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
const updateAddon = async (addonConfig: IAddons) => {
|
||||
const path = `${URI}/${addonConfig.id}`;
|
||||
const req = createRequest(path, {
|
||||
method: 'PUT',
|
||||
body: JSON.stringify(addonConfig),
|
||||
});
|
||||
try {
|
||||
const res = await makeRequest(req.caller, req.id);
|
||||
|
||||
return res;
|
||||
} catch (e) {
|
||||
throw e;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
createAddon,
|
||||
updateAddon,
|
||||
removeAddon,
|
||||
errors,
|
||||
loading,
|
||||
};
|
||||
};
|
||||
|
||||
export default useAddonsApi;
|
37
frontend/src/hooks/api/getters/useAddons/useAddons.ts
Normal file
37
frontend/src/hooks/api/getters/useAddons/useAddons.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import useSWR, { mutate, SWRConfiguration } from 'swr';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { formatApiPath } from '../../../../utils/format-path';
|
||||
import handleErrorResponses from '../httpErrorResponseHandler';
|
||||
|
||||
const useAddons = (options: SWRConfiguration = {}) => {
|
||||
const fetcher = async () => {
|
||||
const path = formatApiPath(`api/admin/addons`);
|
||||
const res = await fetch(path, {
|
||||
method: 'GET',
|
||||
}).then(handleErrorResponses('Addons'));
|
||||
return res.json();
|
||||
};
|
||||
|
||||
const KEY = `api/admin/addons`;
|
||||
|
||||
const { data, error } = useSWR(KEY, fetcher, options);
|
||||
const [loading, setLoading] = useState(!error && !data);
|
||||
|
||||
const refetchAddons = () => {
|
||||
mutate(KEY);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
setLoading(!error && !data);
|
||||
}, [data, error]);
|
||||
|
||||
return {
|
||||
addons: data?.addons || [],
|
||||
providers: data?.providers || [],
|
||||
error,
|
||||
loading,
|
||||
refetchAddons,
|
||||
};
|
||||
};
|
||||
|
||||
export default useAddons;
|
8
frontend/src/interfaces/addons.ts
Normal file
8
frontend/src/interfaces/addons.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface IAddons {
|
||||
id: number;
|
||||
provider: string;
|
||||
description: string;
|
||||
enabled: boolean;
|
||||
events: string[];
|
||||
parameters: object;
|
||||
}
|
Loading…
Reference in New Issue
Block a user