mirror of
https://github.com/Unleash/unleash.git
synced 2025-05-22 01:16:07 +02:00
feat: Align switches in table actions (#1082)
* feat: strateges state changing switch * refactor: ActionCell for table * fix: remove image clipping for webhook icons * feat: align addons switch in table * feat: align enviromnemnts table switch * fix: disallow turning off protected environment * refactor: move environment table sub-components * feat: add predefined badge to default environment * feat: environment reorder handle hightlight * fix: environment table padding when searching * Update src/hooks/api/actions/useStrategiesApi/useStrategiesApi.ts Co-authored-by: olav <mail@olav.io> * refactor: toggle addon promise * remove dragging highlight * fix: strategy switch tooltip * fix: switch tooltips Co-authored-by: olav <mail@olav.io>
This commit is contained in:
parent
407e3a5f55
commit
51e5939f68
@ -12,7 +12,6 @@ const style: React.CSSProperties = {
|
|||||||
width: '32.5px',
|
width: '32.5px',
|
||||||
height: '32.5px',
|
height: '32.5px',
|
||||||
marginRight: '16px',
|
marginRight: '16px',
|
||||||
borderRadius: '50%',
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IAddonIconProps {
|
interface IAddonIconProps {
|
||||||
|
@ -87,7 +87,6 @@ export const AvailableAddons = ({
|
|||||||
sortType: 'alphanumeric',
|
sortType: 'alphanumeric',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: 'Actions',
|
|
||||||
id: 'Actions',
|
id: 'Actions',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
Cell: ({ row: { original } }: any) => (
|
Cell: ({ row: { original } }: any) => (
|
||||||
|
@ -52,10 +52,13 @@ export const ConfiguredAddons = () => {
|
|||||||
setToastData({
|
setToastData({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Success',
|
title: 'Success',
|
||||||
text: 'Addon state switched successfully',
|
text: !addon.enabled
|
||||||
|
? 'Addon is now active'
|
||||||
|
: 'Addon is now disabled',
|
||||||
});
|
});
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
setToastApiError(formatUnknownError(error));
|
setToastApiError(formatUnknownError(error));
|
||||||
|
throw error; // caught by optimistic update
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[setToastApiError, refetchAddons, setToastData, updateAddon]
|
[setToastApiError, refetchAddons, setToastData, updateAddon]
|
||||||
@ -96,12 +99,16 @@ export const ConfiguredAddons = () => {
|
|||||||
Header: 'Actions',
|
Header: 'Actions',
|
||||||
id: 'Actions',
|
id: 'Actions',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
Cell: ({ row: { original } }: any) => (
|
Cell: ({
|
||||||
|
row: { original },
|
||||||
|
}: {
|
||||||
|
row: { original: IAddon };
|
||||||
|
}) => (
|
||||||
<ConfiguredAddonsActionsCell
|
<ConfiguredAddonsActionsCell
|
||||||
setShowDelete={setShowDelete}
|
setShowDelete={setShowDelete}
|
||||||
toggleAddon={toggleAddon}
|
toggleAddon={toggleAddon}
|
||||||
setDeletedAddon={setDeletedAddon}
|
setDeletedAddon={setDeletedAddon}
|
||||||
original={original as IAddon}
|
original={original}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
width: 150,
|
width: 150,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
import { Visibility, VisibilityOff, Edit, Delete } from '@mui/icons-material';
|
import { Edit, Delete } from '@mui/icons-material';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { Tooltip } from '@mui/material';
|
||||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||||
|
import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch';
|
||||||
import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell';
|
import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell';
|
||||||
|
import { useOptimisticUpdate } from 'component/project/Project/ProjectFeatureToggles/FeatureToggleSwitch/hooks/useOptimisticUpdate';
|
||||||
import {
|
import {
|
||||||
UPDATE_ADDON,
|
UPDATE_ADDON,
|
||||||
DELETE_ADDON,
|
DELETE_ADDON,
|
||||||
@ -23,19 +25,32 @@ export const ConfiguredAddonsActionsCell = ({
|
|||||||
original,
|
original,
|
||||||
}: IConfiguredAddonsActionsCellProps) => {
|
}: IConfiguredAddonsActionsCellProps) => {
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
|
const [isEnabled, setIsEnabled, rollbackIsChecked] =
|
||||||
|
useOptimisticUpdate<boolean>(original.enabled);
|
||||||
|
|
||||||
|
const onClick = () => {
|
||||||
|
setIsEnabled(!isEnabled);
|
||||||
|
toggleAddon(original).catch(rollbackIsChecked);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ActionCell>
|
<ActionCell>
|
||||||
<PermissionIconButton
|
<Tooltip
|
||||||
permission={UPDATE_ADDON}
|
title={
|
||||||
onClick={() => toggleAddon(original)}
|
isEnabled
|
||||||
tooltipProps={{ title: 'Toggle addon' }}
|
? `Disable addon ${original.provider}`
|
||||||
|
: `Enable addon ${original.provider}`
|
||||||
|
}
|
||||||
|
arrow
|
||||||
|
describeChild
|
||||||
>
|
>
|
||||||
<ConditionallyRender
|
<PermissionSwitch
|
||||||
condition={original.enabled}
|
permission={UPDATE_ADDON}
|
||||||
show={<Visibility />}
|
checked={isEnabled}
|
||||||
elseShow={<VisibilityOff />}
|
onClick={onClick}
|
||||||
/>
|
/>
|
||||||
</PermissionIconButton>
|
</Tooltip>
|
||||||
|
<ActionCell.Divider />
|
||||||
<PermissionIconButton
|
<PermissionIconButton
|
||||||
permission={UPDATE_ADDON}
|
permission={UPDATE_ADDON}
|
||||||
tooltipProps={{ title: 'Edit Addon' }}
|
tooltipProps={{ title: 'Edit Addon' }}
|
||||||
|
@ -0,0 +1,15 @@
|
|||||||
|
import { makeStyles } from 'tss-react/mui';
|
||||||
|
|
||||||
|
export const useStyles = makeStyles()(theme => ({
|
||||||
|
container: {
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'flex-end',
|
||||||
|
alignItems: 'center',
|
||||||
|
padding: theme.spacing(0, 1.5),
|
||||||
|
},
|
||||||
|
divider: {
|
||||||
|
borderColor: theme.palette.dividerAlternative,
|
||||||
|
height: theme.spacing(3),
|
||||||
|
margin: theme.spacing(0, 2),
|
||||||
|
},
|
||||||
|
}));
|
@ -1,14 +1,26 @@
|
|||||||
import { Box } from '@mui/material';
|
import { Box, Divider } from '@mui/material';
|
||||||
import { ReactNode } from 'react';
|
import { FC, VFC } from 'react';
|
||||||
|
import { useStyles } from './ActionCell.styles';
|
||||||
|
|
||||||
interface IContextActionsCellProps {
|
const ActionCellDivider: VFC = () => {
|
||||||
children: ReactNode;
|
const { classes } = useStyles();
|
||||||
}
|
|
||||||
|
|
||||||
export const ActionCell = ({ children }: IContextActionsCellProps) => {
|
|
||||||
return (
|
return (
|
||||||
<Box sx={{ display: 'flex', justifyContent: 'flex-end', px: 2 }}>
|
<Divider
|
||||||
{children}
|
className={classes.divider}
|
||||||
</Box>
|
orientation="vertical"
|
||||||
|
variant="middle"
|
||||||
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ActionCellComponent: FC & {
|
||||||
|
Divider: typeof ActionCellDivider;
|
||||||
|
} = ({ children }) => {
|
||||||
|
const { classes } = useStyles();
|
||||||
|
|
||||||
|
return <Box className={classes.container}>{children}</Box>;
|
||||||
|
};
|
||||||
|
|
||||||
|
ActionCellComponent.Divider = ActionCellDivider;
|
||||||
|
|
||||||
|
export const ActionCell = ActionCellComponent;
|
||||||
|
@ -22,7 +22,7 @@ export const useStyles = makeStyles()(theme => ({
|
|||||||
infoContainer: {
|
infoContainer: {
|
||||||
marginTop: '1rem',
|
marginTop: '1rem',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-around',
|
||||||
},
|
},
|
||||||
infoInnerContainer: {
|
infoInnerContainer: {
|
||||||
textAlign: 'center',
|
textAlign: 'center',
|
||||||
|
@ -3,12 +3,7 @@ import {
|
|||||||
DELETE_ENVIRONMENT,
|
DELETE_ENVIRONMENT,
|
||||||
UPDATE_ENVIRONMENT,
|
UPDATE_ENVIRONMENT,
|
||||||
} from 'component/providers/AccessProvider/permissions';
|
} from 'component/providers/AccessProvider/permissions';
|
||||||
import {
|
import { Edit, Delete } from '@mui/icons-material';
|
||||||
Edit,
|
|
||||||
Delete,
|
|
||||||
DragIndicator,
|
|
||||||
PowerSettingsNew,
|
|
||||||
} from '@mui/icons-material';
|
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { IconButton, Tooltip } from '@mui/material';
|
import { IconButton, Tooltip } from '@mui/material';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
@ -16,14 +11,14 @@ import AccessContext from 'contexts/AccessContext';
|
|||||||
import { useContext, useState } from 'react';
|
import { useContext, useState } from 'react';
|
||||||
import { IEnvironment } from 'interfaces/environments';
|
import { IEnvironment } from 'interfaces/environments';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import EnvironmentToggleConfirm from '../EnvironmentToggleConfirm/EnvironmentToggleConfirm';
|
import EnvironmentToggleConfirm from '../../EnvironmentToggleConfirm/EnvironmentToggleConfirm';
|
||||||
import EnvironmentDeleteConfirm from '../EnvironmentDeleteConfirm/EnvironmentDeleteConfirm';
|
import EnvironmentDeleteConfirm from '../../EnvironmentDeleteConfirm/EnvironmentDeleteConfirm';
|
||||||
import useEnvironmentApi from 'hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
|
import useEnvironmentApi from 'hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
|
||||||
import useProjectRolePermissions from 'hooks/api/getters/useProjectRolePermissions/useProjectRolePermissions';
|
import useProjectRolePermissions from 'hooks/api/getters/useProjectRolePermissions/useProjectRolePermissions';
|
||||||
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
|
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import { useId } from 'hooks/useId';
|
import { useId } from 'hooks/useId';
|
||||||
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch';
|
||||||
|
|
||||||
interface IEnvironmentTableActionsProps {
|
interface IEnvironmentTableActionsProps {
|
||||||
environment: IEnvironment;
|
environment: IEnvironment;
|
||||||
@ -35,7 +30,6 @@ export const EnvironmentActionCell = ({
|
|||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const { hasAccess } = useContext(AccessContext);
|
const { hasAccess } = useContext(AccessContext);
|
||||||
const updatePermission = hasAccess(UPDATE_ENVIRONMENT);
|
const updatePermission = hasAccess(UPDATE_ENVIRONMENT);
|
||||||
const { searchQuery } = useSearchHighlightContext();
|
|
||||||
|
|
||||||
const { setToastApiError, setToastData } = useToast();
|
const { setToastApiError, setToastData } = useToast();
|
||||||
const { refetchEnvironments } = useEnvironments();
|
const { refetchEnvironments } = useEnvironments();
|
||||||
@ -73,8 +67,8 @@ export const EnvironmentActionCell = ({
|
|||||||
|
|
||||||
const handleToggleEnvironmentOn = async () => {
|
const handleToggleEnvironmentOn = async () => {
|
||||||
try {
|
try {
|
||||||
await toggleEnvironmentOn(environment.name);
|
|
||||||
setToggleModal(false);
|
setToggleModal(false);
|
||||||
|
await toggleEnvironmentOn(environment.name);
|
||||||
setToastData({
|
setToastData({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Project environment enabled',
|
title: 'Project environment enabled',
|
||||||
@ -88,8 +82,8 @@ export const EnvironmentActionCell = ({
|
|||||||
|
|
||||||
const handleToggleEnvironmentOff = async () => {
|
const handleToggleEnvironmentOff = async () => {
|
||||||
try {
|
try {
|
||||||
await toggleEnvironmentOff(environment.name);
|
|
||||||
setToggleModal(false);
|
setToggleModal(false);
|
||||||
|
await toggleEnvironmentOff(environment.name);
|
||||||
setToastData({
|
setToastData({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
title: 'Project environment disabled',
|
title: 'Project environment disabled',
|
||||||
@ -102,37 +96,28 @@ export const EnvironmentActionCell = ({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleIconTooltip = environment.enabled
|
const toggleIconTooltip = environment.enabled
|
||||||
? 'Disable environment'
|
? `Disable environment ${environment.name}`
|
||||||
: 'Enable environment';
|
: `Enable environment ${environment.name}`;
|
||||||
|
|
||||||
const editId = useId();
|
const editId = useId();
|
||||||
const deleteId = useId();
|
const deleteId = useId();
|
||||||
|
|
||||||
// Allow drag and drop if the user is permitted to reorder environments.
|
|
||||||
// Disable drag and drop while searching since some rows may be hidden.
|
|
||||||
const enableDragAndDrop = updatePermission && !searchQuery;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ActionCell>
|
<ActionCell>
|
||||||
<ConditionallyRender
|
|
||||||
condition={enableDragAndDrop}
|
|
||||||
show={
|
|
||||||
<IconButton size="large">
|
|
||||||
<DragIndicator titleAccess="Drag" cursor="grab" />
|
|
||||||
</IconButton>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
condition={updatePermission}
|
condition={updatePermission}
|
||||||
show={
|
show={
|
||||||
<Tooltip title={toggleIconTooltip} arrow>
|
<>
|
||||||
<IconButton
|
<Tooltip title={toggleIconTooltip} arrow describeChild>
|
||||||
onClick={() => setToggleModal(true)}
|
<PermissionSwitch
|
||||||
size="large"
|
permission={UPDATE_ENVIRONMENT}
|
||||||
>
|
checked={environment.enabled}
|
||||||
<PowerSettingsNew />
|
onClick={() => setToggleModal(true)}
|
||||||
</IconButton>
|
disabled={environment.protected}
|
||||||
</Tooltip>
|
/>
|
||||||
|
</Tooltip>
|
||||||
|
<ActionCell.Divider />
|
||||||
|
</>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
<ConditionallyRender
|
<ConditionallyRender
|
||||||
@ -141,7 +126,7 @@ export const EnvironmentActionCell = ({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
environment.protected
|
environment.protected
|
||||||
? 'You cannot edit environment'
|
? 'You cannot edit protected environment'
|
||||||
: 'Edit environment'
|
: 'Edit environment'
|
||||||
}
|
}
|
||||||
arrow
|
arrow
|
||||||
@ -169,9 +154,10 @@ export const EnvironmentActionCell = ({
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
title={
|
title={
|
||||||
environment.protected
|
environment.protected
|
||||||
? 'You cannot delete environment'
|
? 'You cannot delete protected environment'
|
||||||
: 'Delete environment'
|
: 'Delete environment'
|
||||||
}
|
}
|
||||||
|
describeChild
|
||||||
arrow
|
arrow
|
||||||
>
|
>
|
||||||
<span id={deleteId}>
|
<span id={deleteId}>
|
@ -0,0 +1,42 @@
|
|||||||
|
import { useContext, VFC } from 'react';
|
||||||
|
import { styled } from '@mui/material';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { useSearchHighlightContext } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
|
import { Box, IconButton } from '@mui/material';
|
||||||
|
import { CloudCircle, DragIndicator } from '@mui/icons-material';
|
||||||
|
import { UPDATE_ENVIRONMENT } from 'component/providers/AccessProvider/permissions';
|
||||||
|
import AccessContext from 'contexts/AccessContext';
|
||||||
|
|
||||||
|
const DragIcon = styled(IconButton)(
|
||||||
|
({ theme }) => `
|
||||||
|
padding: ${theme.spacing(0, 1, 0, 0)};
|
||||||
|
cursor: inherit;
|
||||||
|
transition: color 0.2s ease-in-out;
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
export const EnvironmentIconCell: VFC = () => {
|
||||||
|
const { hasAccess } = useContext(AccessContext);
|
||||||
|
const updatePermission = hasAccess(UPDATE_ENVIRONMENT);
|
||||||
|
const { searchQuery } = useSearchHighlightContext();
|
||||||
|
|
||||||
|
// Allow drag and drop if the user is permitted to reorder environments.
|
||||||
|
// Disable drag and drop while searching since some rows may be hidden.
|
||||||
|
const enableDragAndDrop = updatePermission && !searchQuery;
|
||||||
|
return (
|
||||||
|
<Box sx={{ display: 'flex', alignItems: 'center', pl: 2 }}>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={enableDragAndDrop}
|
||||||
|
show={
|
||||||
|
<DragIcon size="large" disableRipple disabled>
|
||||||
|
<DragIndicator
|
||||||
|
titleAccess="Drag to reorder"
|
||||||
|
cursor="grab"
|
||||||
|
/>
|
||||||
|
</DragIcon>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
<CloudCircle color="disabled" />
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
};
|
@ -21,6 +21,10 @@ export const EnvironmentNameCell = ({
|
|||||||
condition={!environment.enabled}
|
condition={!environment.enabled}
|
||||||
show={<StatusBadge severity="warning">Disabled</StatusBadge>}
|
show={<StatusBadge severity="warning">Disabled</StatusBadge>}
|
||||||
/>
|
/>
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={environment.protected}
|
||||||
|
show={<StatusBadge severity="success">Predefined</StatusBadge>}
|
||||||
|
/>
|
||||||
</TextCell>
|
</TextCell>
|
||||||
);
|
);
|
||||||
};
|
};
|
@ -11,11 +11,6 @@ import {
|
|||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
import { SearchHighlightProvider } from 'component/common/Table/SearchHighlightContext/SearchHighlightContext';
|
||||||
import { Alert, styled, TableBody } from '@mui/material';
|
import { Alert, styled, TableBody } from '@mui/material';
|
||||||
import { CloudCircle } from '@mui/icons-material';
|
|
||||||
import { IconCell } from 'component/common/Table/cells/IconCell/IconCell';
|
|
||||||
import { EnvironmentActionCell } from 'component/environments/EnvironmentActionCell/EnvironmentActionCell';
|
|
||||||
import { EnvironmentNameCell } from 'component/environments/EnvironmentNameCell/EnvironmentNameCell';
|
|
||||||
import { EnvironmentRow } from 'component/environments/EnvironmentRow/EnvironmentRow';
|
|
||||||
import { MoveListItem } from 'hooks/useDragItem';
|
import { MoveListItem } from 'hooks/useDragItem';
|
||||||
import useToast from 'hooks/useToast';
|
import useToast from 'hooks/useToast';
|
||||||
import useEnvironmentApi, {
|
import useEnvironmentApi, {
|
||||||
@ -23,6 +18,10 @@ import useEnvironmentApi, {
|
|||||||
} from 'hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
|
} from 'hooks/api/actions/useEnvironmentApi/useEnvironmentApi';
|
||||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import { EnvironmentRow } from './EnvironmentRow/EnvironmentRow';
|
||||||
|
import { EnvironmentNameCell } from './EnvironmentNameCell/EnvironmentNameCell';
|
||||||
|
import { EnvironmentActionCell } from './EnvironmentActionCell/EnvironmentActionCell';
|
||||||
|
import { EnvironmentIconCell } from './EnvironmentIconCell/EnvironmentIconCell';
|
||||||
import { Search } from 'component/common/Search/Search';
|
import { Search } from 'component/common/Search/Search';
|
||||||
|
|
||||||
const StyledAlert = styled(Alert)(({ theme }) => ({
|
const StyledAlert = styled(Alert)(({ theme }) => ({
|
||||||
@ -137,7 +136,7 @@ const COLUMNS = [
|
|||||||
{
|
{
|
||||||
id: 'Icon',
|
id: 'Icon',
|
||||||
width: '1%',
|
width: '1%',
|
||||||
Cell: () => <IconCell icon={<CloudCircle color="disabled" />} />,
|
Cell: () => <EnvironmentIconCell />,
|
||||||
disableGlobalFilter: true,
|
disableGlobalFilter: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -1,17 +1,7 @@
|
|||||||
import { useState, useMemo } from 'react';
|
import { useState, useMemo, useCallback } from 'react';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { IconButton, Tooltip, Box } from '@mui/material';
|
import { Box } from '@mui/material';
|
||||||
import {
|
import { Extension } from '@mui/icons-material';
|
||||||
Delete,
|
|
||||||
Edit,
|
|
||||||
Extension,
|
|
||||||
Visibility,
|
|
||||||
VisibilityOff,
|
|
||||||
} from '@mui/icons-material';
|
|
||||||
import {
|
|
||||||
DELETE_STRATEGY,
|
|
||||||
UPDATE_STRATEGY,
|
|
||||||
} from 'component/providers/AccessProvider/permissions';
|
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
SortableTableHeader,
|
SortableTableHeader,
|
||||||
@ -20,11 +10,11 @@ import {
|
|||||||
TableRow,
|
TableRow,
|
||||||
TablePlaceholder,
|
TablePlaceholder,
|
||||||
} from 'component/common/Table';
|
} from 'component/common/Table';
|
||||||
|
import { ActionCell } from 'component/common/Table/cells/ActionCell/ActionCell';
|
||||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
import { PageContent } from 'component/common/PageContent/PageContent';
|
import { PageContent } from 'component/common/PageContent/PageContent';
|
||||||
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
import { PageHeader } from 'component/common/PageHeader/PageHeader';
|
||||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||||
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
|
||||||
import { formatStrategyName } from 'utils/strategyNames';
|
import { formatStrategyName } from 'utils/strategyNames';
|
||||||
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
|
import { useStrategies } from 'hooks/api/getters/useStrategies/useStrategies';
|
||||||
import useStrategiesApi from 'hooks/api/actions/useStrategiesApi/useStrategiesApi';
|
import useStrategiesApi from 'hooks/api/actions/useStrategiesApi/useStrategiesApi';
|
||||||
@ -37,6 +27,9 @@ import { sortTypes } from 'utils/sortTypes';
|
|||||||
import { useTable, useGlobalFilter, useSortBy } from 'react-table';
|
import { useTable, useGlobalFilter, useSortBy } from 'react-table';
|
||||||
import { AddStrategyButton } from './AddStrategyButton/AddStrategyButton';
|
import { AddStrategyButton } from './AddStrategyButton/AddStrategyButton';
|
||||||
import { StatusBadge } from 'component/common/StatusBadge/StatusBadge';
|
import { StatusBadge } from 'component/common/StatusBadge/StatusBadge';
|
||||||
|
import { StrategySwitch } from './StrategySwitch/StrategySwitch';
|
||||||
|
import { StrategyEditButton } from './StrategyEditButton/StrategyEditButton';
|
||||||
|
import { StrategyDeleteButton } from './StrategyDeleteButton/StrategyDeleteButton';
|
||||||
import { Search } from 'component/common/Search/Search';
|
import { Search } from 'component/common/Search/Search';
|
||||||
|
|
||||||
interface IDialogueMetaData {
|
interface IDialogueMetaData {
|
||||||
@ -78,6 +71,85 @@ export const StrategiesList = () => {
|
|||||||
);
|
);
|
||||||
}, [strategies, loading]);
|
}, [strategies, loading]);
|
||||||
|
|
||||||
|
const onToggle = useCallback(
|
||||||
|
(strategy: IStrategy) => (deprecated: boolean) => {
|
||||||
|
if (deprecated) {
|
||||||
|
setDialogueMetaData({
|
||||||
|
show: true,
|
||||||
|
title: 'Really reactivate strategy?',
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
await reactivateStrategy(strategy);
|
||||||
|
refetchStrategies();
|
||||||
|
setToastData({
|
||||||
|
type: 'success',
|
||||||
|
title: 'Success',
|
||||||
|
text: 'Strategy reactivated successfully',
|
||||||
|
});
|
||||||
|
} catch (error: unknown) {
|
||||||
|
setToastApiError(formatUnknownError(error));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
setDialogueMetaData({
|
||||||
|
show: true,
|
||||||
|
title: 'Really deprecate strategy?',
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
await deprecateStrategy(strategy);
|
||||||
|
refetchStrategies();
|
||||||
|
setToastData({
|
||||||
|
type: 'success',
|
||||||
|
title: 'Success',
|
||||||
|
text: 'Strategy deprecated successfully',
|
||||||
|
});
|
||||||
|
} catch (error: unknown) {
|
||||||
|
setToastApiError(formatUnknownError(error));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[
|
||||||
|
deprecateStrategy,
|
||||||
|
reactivateStrategy,
|
||||||
|
refetchStrategies,
|
||||||
|
setToastApiError,
|
||||||
|
setToastData,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onDeleteStrategy = useCallback(
|
||||||
|
(strategy: IStrategy) => {
|
||||||
|
setDialogueMetaData({
|
||||||
|
show: true,
|
||||||
|
title: 'Really delete strategy?',
|
||||||
|
onConfirm: async () => {
|
||||||
|
try {
|
||||||
|
await removeStrategy(strategy);
|
||||||
|
refetchStrategies();
|
||||||
|
setToastData({
|
||||||
|
type: 'success',
|
||||||
|
title: 'Success',
|
||||||
|
text: 'Strategy deleted successfully',
|
||||||
|
});
|
||||||
|
} catch (error: unknown) {
|
||||||
|
setToastApiError(formatUnknownError(error));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[removeStrategy, refetchStrategies, setToastApiError, setToastData]
|
||||||
|
);
|
||||||
|
|
||||||
|
const onEditStrategy = useCallback(
|
||||||
|
(strategy: IStrategy) => {
|
||||||
|
navigate(`/strategies/${strategy.name}/edit`);
|
||||||
|
},
|
||||||
|
[navigate]
|
||||||
|
);
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
@ -86,7 +158,7 @@ export const StrategiesList = () => {
|
|||||||
<Box
|
<Box
|
||||||
data-loading
|
data-loading
|
||||||
sx={{
|
sx={{
|
||||||
pl: 2,
|
pl: 3,
|
||||||
pr: 1,
|
pr: 1,
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
@ -134,18 +206,22 @@ export const StrategiesList = () => {
|
|||||||
id: 'Actions',
|
id: 'Actions',
|
||||||
align: 'center',
|
align: 'center',
|
||||||
Cell: ({ row: { original } }: any) => (
|
Cell: ({ row: { original } }: any) => (
|
||||||
<Box
|
<ActionCell>
|
||||||
sx={{ display: 'flex', justifyContent: 'flex-end' }}
|
<StrategySwitch
|
||||||
data-loading
|
deprecated={original.deprecated}
|
||||||
>
|
onToggle={onToggle(original)}
|
||||||
<ConditionallyRender
|
disabled={original.name === 'default'}
|
||||||
condition={original.deprecated}
|
|
||||||
show={reactivateButton(original)}
|
|
||||||
elseShow={deprecateButton(original)}
|
|
||||||
/>
|
/>
|
||||||
{editButton(original)}
|
<ActionCell.Divider />
|
||||||
{deleteButton(original)}
|
<StrategyEditButton
|
||||||
</Box>
|
strategy={original}
|
||||||
|
onClick={() => onEditStrategy(original)}
|
||||||
|
/>
|
||||||
|
<StrategyDeleteButton
|
||||||
|
strategy={original}
|
||||||
|
onClick={() => onDeleteStrategy(original)}
|
||||||
|
/>
|
||||||
|
</ActionCell>
|
||||||
),
|
),
|
||||||
width: 150,
|
width: 150,
|
||||||
disableGlobalFilter: true,
|
disableGlobalFilter: true,
|
||||||
@ -161,8 +237,7 @@ export const StrategiesList = () => {
|
|||||||
sortType: 'number',
|
sortType: 'number',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
[onToggle, onEditStrategy, onDeleteStrategy]
|
||||||
[]
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const initialState = useMemo(
|
const initialState = useMemo(
|
||||||
@ -195,152 +270,6 @@ export const StrategiesList = () => {
|
|||||||
useSortBy
|
useSortBy
|
||||||
);
|
);
|
||||||
|
|
||||||
const onReactivateStrategy = (strategy: IStrategy) => {
|
|
||||||
setDialogueMetaData({
|
|
||||||
show: true,
|
|
||||||
title: 'Really reactivate strategy?',
|
|
||||||
onConfirm: async () => {
|
|
||||||
try {
|
|
||||||
await reactivateStrategy(strategy);
|
|
||||||
refetchStrategies();
|
|
||||||
setToastData({
|
|
||||||
type: 'success',
|
|
||||||
title: 'Success',
|
|
||||||
text: 'Strategy reactivated successfully',
|
|
||||||
});
|
|
||||||
} catch (error: unknown) {
|
|
||||||
setToastApiError(formatUnknownError(error));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeprecateStrategy = (strategy: IStrategy) => {
|
|
||||||
setDialogueMetaData({
|
|
||||||
show: true,
|
|
||||||
title: 'Really deprecate strategy?',
|
|
||||||
onConfirm: async () => {
|
|
||||||
try {
|
|
||||||
await deprecateStrategy(strategy);
|
|
||||||
refetchStrategies();
|
|
||||||
setToastData({
|
|
||||||
type: 'success',
|
|
||||||
title: 'Success',
|
|
||||||
text: 'Strategy deprecated successfully',
|
|
||||||
});
|
|
||||||
} catch (error: unknown) {
|
|
||||||
setToastApiError(formatUnknownError(error));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const onDeleteStrategy = (strategy: IStrategy) => {
|
|
||||||
setDialogueMetaData({
|
|
||||||
show: true,
|
|
||||||
title: 'Really delete strategy?',
|
|
||||||
onConfirm: async () => {
|
|
||||||
try {
|
|
||||||
await removeStrategy(strategy);
|
|
||||||
refetchStrategies();
|
|
||||||
setToastData({
|
|
||||||
type: 'success',
|
|
||||||
title: 'Success',
|
|
||||||
text: 'Strategy deleted successfully',
|
|
||||||
});
|
|
||||||
} catch (error: unknown) {
|
|
||||||
setToastApiError(formatUnknownError(error));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const reactivateButton = (strategy: IStrategy) => (
|
|
||||||
<PermissionIconButton
|
|
||||||
onClick={() => onReactivateStrategy(strategy)}
|
|
||||||
permission={UPDATE_STRATEGY}
|
|
||||||
tooltipProps={{ title: 'Reactivate activation strategy' }}
|
|
||||||
>
|
|
||||||
<VisibilityOff />
|
|
||||||
</PermissionIconButton>
|
|
||||||
);
|
|
||||||
|
|
||||||
const deprecateButton = (strategy: IStrategy) => (
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={strategy.name === 'default'}
|
|
||||||
show={
|
|
||||||
<Tooltip title="You cannot deprecate the default strategy">
|
|
||||||
<div>
|
|
||||||
<IconButton disabled size="large">
|
|
||||||
<Visibility titleAccess="Deprecate strategy" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
elseShow={
|
|
||||||
<div>
|
|
||||||
<PermissionIconButton
|
|
||||||
onClick={() => onDeprecateStrategy(strategy)}
|
|
||||||
permission={UPDATE_STRATEGY}
|
|
||||||
tooltipProps={{ title: 'Deprecate strategy' }}
|
|
||||||
>
|
|
||||||
<Visibility />
|
|
||||||
</PermissionIconButton>
|
|
||||||
</div>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const editButton = (strategy: IStrategy) => (
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={strategy?.editable}
|
|
||||||
show={
|
|
||||||
<PermissionIconButton
|
|
||||||
onClick={() =>
|
|
||||||
navigate(`/strategies/${strategy?.name}/edit`)
|
|
||||||
}
|
|
||||||
permission={UPDATE_STRATEGY}
|
|
||||||
tooltipProps={{ title: 'Edit strategy' }}
|
|
||||||
>
|
|
||||||
<Edit />
|
|
||||||
</PermissionIconButton>
|
|
||||||
}
|
|
||||||
elseShow={
|
|
||||||
<Tooltip title="You cannot edit a built-in strategy" arrow>
|
|
||||||
<div>
|
|
||||||
<IconButton disabled size="large">
|
|
||||||
<Edit titleAccess="Edit strategy" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const deleteButton = (strategy: IStrategy) => (
|
|
||||||
<ConditionallyRender
|
|
||||||
condition={strategy?.editable}
|
|
||||||
show={
|
|
||||||
<PermissionIconButton
|
|
||||||
onClick={() => onDeleteStrategy(strategy)}
|
|
||||||
permission={DELETE_STRATEGY}
|
|
||||||
tooltipProps={{ title: 'Delete strategy' }}
|
|
||||||
>
|
|
||||||
<Delete />
|
|
||||||
</PermissionIconButton>
|
|
||||||
}
|
|
||||||
elseShow={
|
|
||||||
<Tooltip title="You cannot delete a built-in strategy" arrow>
|
|
||||||
<div>
|
|
||||||
<IconButton disabled size="large">
|
|
||||||
<Delete titleAccess="Delete strategy" />
|
|
||||||
</IconButton>
|
|
||||||
</div>
|
|
||||||
</Tooltip>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
|
|
||||||
const onDialogConfirm = () => {
|
const onDialogConfirm = () => {
|
||||||
dialogueMetaData?.onConfirm();
|
dialogueMetaData?.onConfirm();
|
||||||
setDialogueMetaData((prev: IDialogueMetaData) => ({
|
setDialogueMetaData((prev: IDialogueMetaData) => ({
|
||||||
|
@ -0,0 +1,41 @@
|
|||||||
|
import { VFC } from 'react';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||||
|
import { Delete } from '@mui/icons-material';
|
||||||
|
import { IconButton, Tooltip } from '@mui/material';
|
||||||
|
import { IStrategy } from 'interfaces/strategy';
|
||||||
|
import { DELETE_STRATEGY } from 'component/providers/AccessProvider/permissions';
|
||||||
|
|
||||||
|
interface IStrategyDeleteButtonProps {
|
||||||
|
strategy: IStrategy;
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StrategyDeleteButton: VFC<IStrategyDeleteButtonProps> = ({
|
||||||
|
strategy,
|
||||||
|
onClick,
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={strategy?.editable}
|
||||||
|
show={
|
||||||
|
<PermissionIconButton
|
||||||
|
onClick={onClick}
|
||||||
|
permission={DELETE_STRATEGY}
|
||||||
|
tooltipProps={{ title: 'Delete strategy' }}
|
||||||
|
>
|
||||||
|
<Delete />
|
||||||
|
</PermissionIconButton>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<Tooltip title="You cannot delete a built-in strategy" arrow>
|
||||||
|
<div>
|
||||||
|
<IconButton disabled size="large">
|
||||||
|
<Delete titleAccess="Delete strategy" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
@ -0,0 +1,39 @@
|
|||||||
|
import { VFC } from 'react';
|
||||||
|
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||||
|
import PermissionIconButton from 'component/common/PermissionIconButton/PermissionIconButton';
|
||||||
|
import { Edit } from '@mui/icons-material';
|
||||||
|
import { IconButton, Tooltip } from '@mui/material';
|
||||||
|
import { UPDATE_STRATEGY } from 'component/providers/AccessProvider/permissions';
|
||||||
|
import { IStrategy } from 'interfaces/strategy';
|
||||||
|
|
||||||
|
interface IStrategyEditButtonProps {
|
||||||
|
strategy: IStrategy;
|
||||||
|
onClick: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StrategyEditButton: VFC<IStrategyEditButtonProps> = ({
|
||||||
|
strategy,
|
||||||
|
onClick,
|
||||||
|
}) => (
|
||||||
|
<ConditionallyRender
|
||||||
|
condition={strategy?.editable}
|
||||||
|
show={
|
||||||
|
<PermissionIconButton
|
||||||
|
onClick={onClick}
|
||||||
|
permission={UPDATE_STRATEGY}
|
||||||
|
tooltipProps={{ title: 'Edit strategy' }}
|
||||||
|
>
|
||||||
|
<Edit />
|
||||||
|
</PermissionIconButton>
|
||||||
|
}
|
||||||
|
elseShow={
|
||||||
|
<Tooltip title="You cannot edit a built-in strategy" arrow>
|
||||||
|
<div>
|
||||||
|
<IconButton disabled size="large">
|
||||||
|
<Edit titleAccess="Edit strategy" />
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
);
|
@ -0,0 +1,43 @@
|
|||||||
|
import { VFC } from 'react';
|
||||||
|
import PermissionSwitch from 'component/common/PermissionSwitch/PermissionSwitch';
|
||||||
|
import { UPDATE_STRATEGY } from 'component/providers/AccessProvider/permissions';
|
||||||
|
import { Tooltip } from '@mui/material';
|
||||||
|
import { useId } from 'hooks/useId';
|
||||||
|
|
||||||
|
interface IStrategySwitchProps {
|
||||||
|
deprecated: boolean;
|
||||||
|
onToggle: (state: boolean) => void;
|
||||||
|
disabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const StrategySwitch: VFC<IStrategySwitchProps> = ({
|
||||||
|
deprecated,
|
||||||
|
disabled,
|
||||||
|
onToggle,
|
||||||
|
}) => {
|
||||||
|
const onClick = () => {
|
||||||
|
onToggle(deprecated);
|
||||||
|
};
|
||||||
|
const id = useId();
|
||||||
|
|
||||||
|
const title = deprecated
|
||||||
|
? 'Excluded from strategy list'
|
||||||
|
: 'Included in strategy list';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip
|
||||||
|
title={disabled ? 'You cannot disable default strategy' : title}
|
||||||
|
describeChild
|
||||||
|
arrow
|
||||||
|
>
|
||||||
|
<div id={id} role="tooltip">
|
||||||
|
<PermissionSwitch
|
||||||
|
checked={!deprecated}
|
||||||
|
permission={UPDATE_STRATEGY}
|
||||||
|
onClick={onClick}
|
||||||
|
disabled={disabled}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Tooltip>
|
||||||
|
);
|
||||||
|
};
|
@ -1,83 +1,94 @@
|
|||||||
import { IStrategyPayload } from 'interfaces/strategy';
|
import { IStrategyPayload } from 'interfaces/strategy';
|
||||||
|
import { useCallback } from 'react';
|
||||||
import useAPI from '../useApi/useApi';
|
import useAPI from '../useApi/useApi';
|
||||||
|
|
||||||
|
const URI = 'api/admin/strategies';
|
||||||
|
|
||||||
const useStrategiesApi = () => {
|
const useStrategiesApi = () => {
|
||||||
const { makeRequest, createRequest, errors, loading } = useAPI({
|
const { makeRequest, createRequest, errors, loading } = useAPI({
|
||||||
propagateErrors: true,
|
propagateErrors: true,
|
||||||
});
|
});
|
||||||
const URI = 'api/admin/strategies';
|
|
||||||
|
|
||||||
const createStrategy = async (strategy: IStrategyPayload) => {
|
const createStrategy = useCallback(
|
||||||
const req = createRequest(URI, {
|
async (strategy: IStrategyPayload) => {
|
||||||
method: 'POST',
|
const req = createRequest(URI, {
|
||||||
body: JSON.stringify(strategy),
|
method: 'POST',
|
||||||
});
|
body: JSON.stringify(strategy),
|
||||||
|
});
|
||||||
|
|
||||||
try {
|
return makeRequest(req.caller, req.id);
|
||||||
const res = await makeRequest(req.caller, req.id);
|
},
|
||||||
|
[createRequest, makeRequest]
|
||||||
|
);
|
||||||
|
|
||||||
return res;
|
const updateStrategy = useCallback(
|
||||||
} catch (e) {
|
async (strategy: IStrategyPayload) => {
|
||||||
throw e;
|
const path = `${URI}/${strategy.name}`;
|
||||||
}
|
const req = createRequest(path, {
|
||||||
};
|
method: 'PUT',
|
||||||
|
body: JSON.stringify(strategy),
|
||||||
|
});
|
||||||
|
|
||||||
const updateStrategy = async (strategy: IStrategyPayload) => {
|
try {
|
||||||
const path = `${URI}/${strategy.name}`;
|
const res = await makeRequest(req.caller, req.id);
|
||||||
const req = createRequest(path, {
|
|
||||||
method: 'PUT',
|
|
||||||
body: JSON.stringify(strategy),
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
return res;
|
||||||
const res = await makeRequest(req.caller, req.id);
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[createRequest, makeRequest]
|
||||||
|
);
|
||||||
|
|
||||||
return res;
|
const removeStrategy = useCallback(
|
||||||
} catch (e) {
|
async (strategy: IStrategyPayload) => {
|
||||||
throw e;
|
const path = `${URI}/${strategy.name}`;
|
||||||
}
|
const req = createRequest(path, { method: 'DELETE' });
|
||||||
};
|
|
||||||
|
|
||||||
const removeStrategy = async (strategy: IStrategyPayload) => {
|
try {
|
||||||
const path = `${URI}/${strategy.name}`;
|
const res = await makeRequest(req.caller, req.id);
|
||||||
const req = createRequest(path, { method: 'DELETE' });
|
|
||||||
|
|
||||||
try {
|
return res;
|
||||||
const res = await makeRequest(req.caller, req.id);
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[createRequest, makeRequest]
|
||||||
|
);
|
||||||
|
|
||||||
return res;
|
const deprecateStrategy = useCallback(
|
||||||
} catch (e) {
|
async (strategy: IStrategyPayload) => {
|
||||||
throw e;
|
const path = `${URI}/${strategy.name}/deprecate`;
|
||||||
}
|
const req = createRequest(path, {
|
||||||
};
|
method: 'POST',
|
||||||
|
});
|
||||||
|
|
||||||
const deprecateStrategy = async (strategy: IStrategyPayload) => {
|
try {
|
||||||
const path = `${URI}/${strategy.name}/deprecate`;
|
const res = await makeRequest(req.caller, req.id);
|
||||||
const req = createRequest(path, {
|
|
||||||
method: 'POST',
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
return res;
|
||||||
const res = await makeRequest(req.caller, req.id);
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[createRequest, makeRequest]
|
||||||
|
);
|
||||||
|
|
||||||
return res;
|
const reactivateStrategy = useCallback(
|
||||||
} catch (e) {
|
async (strategy: IStrategyPayload) => {
|
||||||
throw e;
|
const path = `${URI}/${strategy.name}/reactivate`;
|
||||||
}
|
const req = createRequest(path, { method: 'POST' });
|
||||||
};
|
|
||||||
|
|
||||||
const reactivateStrategy = async (strategy: IStrategyPayload) => {
|
try {
|
||||||
const path = `${URI}/${strategy.name}/reactivate`;
|
const res = await makeRequest(req.caller, req.id);
|
||||||
const req = createRequest(path, { method: 'POST' });
|
|
||||||
|
|
||||||
try {
|
return res;
|
||||||
const res = await makeRequest(req.caller, req.id);
|
} catch (e) {
|
||||||
|
throw e;
|
||||||
return res;
|
}
|
||||||
} catch (e) {
|
},
|
||||||
throw e;
|
[createRequest, makeRequest]
|
||||||
}
|
);
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createStrategy,
|
createStrategy,
|
||||||
|
Loading…
Reference in New Issue
Block a user