1
0
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:
Youssef Khedher 2022-02-01 16:19:29 +01:00 committed by GitHub
commit 014cdaa7d4
7 changed files with 190 additions and 41 deletions

View File

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

View File

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

View File

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

View File

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

View 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;

View 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;

View File

@ -0,0 +1,8 @@
export interface IAddons {
id: number;
provider: string;
description: string;
enabled: boolean;
events: string[];
parameters: object;
}