mirror of
https://github.com/Unleash/unleash.git
synced 2024-12-22 19:07:54 +01:00
chore: project actions table (#6039)
https://linear.app/unleash/issue/2-1877/ui-add-actions-table Implements the new project actions table. ![image](https://github.com/Unleash/unleash/assets/14320932/2ce96669-4b8f-46cd-9a87-8b14f0682694) ![image](https://github.com/Unleash/unleash/assets/14320932/d73327f2-1e1a-4d57-8ef8-1f4518c4b5d9) ![image](https://github.com/Unleash/unleash/assets/14320932/27b9ffab-4fff-4fdf-808f-b778987fa198)
This commit is contained in:
parent
00b3cbaa8b
commit
32484460ef
@ -57,7 +57,12 @@ export const ProjectActions = () => {
|
||||
}
|
||||
>
|
||||
<PermissionGuard permissions={ADMIN}>
|
||||
<ProjectActionsTable />
|
||||
<ProjectActionsTable
|
||||
modalOpen={actionModalOpen}
|
||||
setModalOpen={setActionModalOpen}
|
||||
selectedAction={selectedAction}
|
||||
setSelectedAction={setSelectedAction}
|
||||
/>
|
||||
</PermissionGuard>
|
||||
</PageContent>
|
||||
);
|
||||
|
@ -0,0 +1,64 @@
|
||||
import { styled } from '@mui/material';
|
||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||
import { IActionSet } from 'interfaces/action';
|
||||
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
||||
import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
|
||||
|
||||
const StyledActionItems = styled('div')(({ theme }) => ({
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: theme.spacing(1),
|
||||
fontSize: theme.fontSizes.smallerBody,
|
||||
}));
|
||||
|
||||
const StyledParameterList = styled('ul')(({ theme }) => ({
|
||||
listStyle: 'none',
|
||||
paddingLeft: theme.spacing(1),
|
||||
margin: 0,
|
||||
}));
|
||||
|
||||
interface IProjectActionsActionsCellProps {
|
||||
action: IActionSet;
|
||||
onCreateAction?: () => void;
|
||||
}
|
||||
|
||||
export const ProjectActionsActionsCell = ({
|
||||
action,
|
||||
onCreateAction,
|
||||
}: IProjectActionsActionsCellProps) => {
|
||||
const { actions } = action;
|
||||
|
||||
if (actions.length === 0) {
|
||||
if (!onCreateAction) return <TextCell>0 actions</TextCell>;
|
||||
else return <LinkCell title='Create action' onClick={onCreateAction} />;
|
||||
}
|
||||
|
||||
return (
|
||||
<TextCell>
|
||||
<TooltipLink
|
||||
tooltip={
|
||||
<StyledActionItems>
|
||||
{actions.map(({ id, action, executionParams }) => (
|
||||
<div key={id}>
|
||||
<strong>{action}</strong>
|
||||
<StyledParameterList>
|
||||
{Object.entries(executionParams).map(
|
||||
([param, value]) => (
|
||||
<li key={param}>
|
||||
{param}: {value}
|
||||
</li>
|
||||
),
|
||||
)}
|
||||
</StyledParameterList>
|
||||
</div>
|
||||
))}
|
||||
</StyledActionItems>
|
||||
}
|
||||
>
|
||||
{actions.length === 1
|
||||
? '1 action'
|
||||
: `${actions.length} actions`}
|
||||
</TooltipLink>
|
||||
</TextCell>
|
||||
);
|
||||
};
|
@ -0,0 +1,23 @@
|
||||
import { LinkCell } from 'component/common/Table/cells/LinkCell/LinkCell';
|
||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||
import { IActionSet } from 'interfaces/action';
|
||||
import { IServiceAccount } from 'interfaces/service-account';
|
||||
|
||||
interface IProjectActionsActorCellProps {
|
||||
action: IActionSet;
|
||||
serviceAccounts: IServiceAccount[];
|
||||
}
|
||||
|
||||
export const ProjectActionsActorCell = ({
|
||||
action,
|
||||
serviceAccounts,
|
||||
}: IProjectActionsActorCellProps) => {
|
||||
const { actorId } = action;
|
||||
const actor = serviceAccounts.find(({ id }) => id === actorId);
|
||||
|
||||
if (!actor) {
|
||||
return <TextCell>No service account</TextCell>;
|
||||
}
|
||||
|
||||
return <LinkCell to='/admin/service-accounts'>{actor.name}</LinkCell>;
|
||||
};
|
@ -0,0 +1,31 @@
|
||||
import { Dialogue } from 'component/common/Dialogue/Dialogue';
|
||||
import { IActionSet } from 'interfaces/action';
|
||||
|
||||
interface IProjectActionsDeleteDialogProps {
|
||||
action?: IActionSet;
|
||||
open: boolean;
|
||||
setOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
onConfirm: (action: IActionSet) => void;
|
||||
}
|
||||
|
||||
export const ProjectActionsDeleteDialog = ({
|
||||
action,
|
||||
open,
|
||||
setOpen,
|
||||
onConfirm,
|
||||
}: IProjectActionsDeleteDialogProps) => (
|
||||
<Dialogue
|
||||
title='Delete action?'
|
||||
open={open}
|
||||
primaryButtonText='Delete action'
|
||||
secondaryButtonText='Cancel'
|
||||
onClick={() => onConfirm(action!)}
|
||||
onClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
You are about to delete action: <strong>{action?.name}</strong>
|
||||
</p>
|
||||
</Dialogue>
|
||||
);
|
@ -0,0 +1,43 @@
|
||||
import { styled, Typography } from '@mui/material';
|
||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||
import { IActionSet } from 'interfaces/action';
|
||||
import { TooltipLink } from 'component/common/TooltipLink/TooltipLink';
|
||||
|
||||
const StyledItem = styled(Typography)(({ theme }) => ({
|
||||
fontSize: theme.fontSizes.smallerBody,
|
||||
}));
|
||||
|
||||
interface IProjectActionsFiltersCellProps {
|
||||
action: IActionSet;
|
||||
}
|
||||
|
||||
export const ProjectActionsFiltersCell = ({
|
||||
action,
|
||||
}: IProjectActionsFiltersCellProps) => {
|
||||
const { payload } = action.match;
|
||||
const filters = Object.entries(payload);
|
||||
|
||||
if (filters.length === 0) {
|
||||
return <TextCell>0 filters</TextCell>;
|
||||
}
|
||||
|
||||
return (
|
||||
<TextCell>
|
||||
<TooltipLink
|
||||
tooltip={
|
||||
<>
|
||||
{filters.map(([parameter, value]) => (
|
||||
<StyledItem key={parameter}>
|
||||
{parameter}: {value}
|
||||
</StyledItem>
|
||||
))}
|
||||
</>
|
||||
}
|
||||
>
|
||||
{filters.length === 1
|
||||
? '1 filter'
|
||||
: `${filters.length} filters`}
|
||||
</TooltipLink>
|
||||
</TextCell>
|
||||
);
|
||||
};
|
@ -1,3 +1,253 @@
|
||||
export const ProjectActionsTable = () => {
|
||||
return <span>TODO</span>;
|
||||
import { useMemo, useState } from 'react';
|
||||
import { TablePlaceholder, VirtualizedTable } from 'component/common/Table';
|
||||
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
|
||||
import useToast from 'hooks/useToast';
|
||||
import { formatUnknownError } from 'utils/formatUnknownError';
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
import { useFlexLayout, useSortBy, useTable } from 'react-table';
|
||||
import { sortTypes } from 'utils/sortTypes';
|
||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||
import theme from 'themes/theme';
|
||||
import { useConditionallyHiddenColumns } from 'hooks/useConditionallyHiddenColumns';
|
||||
import { useActions } from 'hooks/api/getters/useActions/useActions';
|
||||
import { useActionsApi } from 'hooks/api/actions/useActionsApi/useActionsApi';
|
||||
import { IActionSet } from 'interfaces/action';
|
||||
import { ToggleCell } from 'component/common/Table/cells/ToggleCell/ToggleCell';
|
||||
import { ProjectActionsTriggerCell } from './ProjectActionsTriggerCell';
|
||||
import { ProjectActionsFiltersCell } from './ProjectActionsFiltersCell';
|
||||
import { ProjectActionsActorCell } from './ProjectActionsActorCell';
|
||||
import { ProjectActionsActionsCell } from './ProjectActionsActionsCell';
|
||||
import { ProjectActionsTableActionsCell } from './ProjectActionsTableActionsCell';
|
||||
// import { ProjectActionsModal } from '../ProjectActionsModal/ProjectActionsModal';
|
||||
import { ProjectActionsDeleteDialog } from './ProjectActionsDeleteDialog';
|
||||
import { useServiceAccounts } from 'hooks/api/getters/useServiceAccounts/useServiceAccounts';
|
||||
import { useIncomingWebhooks } from 'hooks/api/getters/useIncomingWebhooks/useIncomingWebhooks';
|
||||
|
||||
interface IProjectActionsTableProps {
|
||||
modalOpen: boolean;
|
||||
setModalOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
selectedAction?: IActionSet;
|
||||
setSelectedAction: React.Dispatch<
|
||||
React.SetStateAction<IActionSet | undefined>
|
||||
>;
|
||||
}
|
||||
|
||||
export const ProjectActionsTable = ({
|
||||
modalOpen,
|
||||
setModalOpen,
|
||||
selectedAction,
|
||||
setSelectedAction,
|
||||
}: IProjectActionsTableProps) => {
|
||||
const { setToastData, setToastApiError } = useToast();
|
||||
|
||||
const { actions, refetch } = useActions();
|
||||
const { toggleActionSet, removeActionSet } = useActionsApi();
|
||||
|
||||
const { incomingWebhooks } = useIncomingWebhooks();
|
||||
const { serviceAccounts } = useServiceAccounts();
|
||||
|
||||
const [deleteOpen, setDeleteOpen] = useState(false);
|
||||
|
||||
const onToggleAction = async (action: IActionSet, enabled: boolean) => {
|
||||
try {
|
||||
await toggleActionSet(action.id, enabled);
|
||||
setToastData({
|
||||
title: `"${action.name}" has been ${
|
||||
enabled ? 'enabled' : 'disabled'
|
||||
}`,
|
||||
type: 'success',
|
||||
});
|
||||
refetch();
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
}
|
||||
};
|
||||
|
||||
const onDeleteConfirm = async (action: IActionSet) => {
|
||||
try {
|
||||
await removeActionSet(action.id);
|
||||
setToastData({
|
||||
title: `"${action.name}" has been deleted`,
|
||||
type: 'success',
|
||||
});
|
||||
refetch();
|
||||
setDeleteOpen(false);
|
||||
} catch (error: unknown) {
|
||||
setToastApiError(formatUnknownError(error));
|
||||
}
|
||||
};
|
||||
|
||||
const isExtraSmallScreen = useMediaQuery(theme.breakpoints.down('sm'));
|
||||
const isMediumScreen = useMediaQuery(theme.breakpoints.down('lg'));
|
||||
|
||||
const columns = useMemo(
|
||||
() => [
|
||||
{
|
||||
Header: 'Name',
|
||||
accessor: 'name',
|
||||
minWidth: 60,
|
||||
},
|
||||
{
|
||||
id: 'trigger',
|
||||
Header: 'Trigger',
|
||||
Cell: ({
|
||||
row: { original: action },
|
||||
}: { row: { original: IActionSet } }) => (
|
||||
<ProjectActionsTriggerCell
|
||||
action={action}
|
||||
incomingWebhooks={incomingWebhooks}
|
||||
/>
|
||||
),
|
||||
},
|
||||
{
|
||||
id: 'filters',
|
||||
Header: 'Filters',
|
||||
Cell: ({
|
||||
row: { original: action },
|
||||
}: {
|
||||
row: { original: IActionSet };
|
||||
}) => <ProjectActionsFiltersCell action={action} />,
|
||||
maxWidth: 90,
|
||||
},
|
||||
{
|
||||
id: 'actor',
|
||||
Header: 'Service account',
|
||||
Cell: ({
|
||||
row: { original: action },
|
||||
}: {
|
||||
row: { original: IActionSet };
|
||||
}) => (
|
||||
<ProjectActionsActorCell
|
||||
action={action}
|
||||
serviceAccounts={serviceAccounts}
|
||||
/>
|
||||
),
|
||||
minWidth: 160,
|
||||
},
|
||||
{
|
||||
id: 'actions',
|
||||
Header: 'Actions',
|
||||
Cell: ({
|
||||
row: { original: action },
|
||||
}: {
|
||||
row: { original: IActionSet };
|
||||
}) => (
|
||||
<ProjectActionsActionsCell
|
||||
action={action}
|
||||
onCreateAction={() => {
|
||||
setSelectedAction(action);
|
||||
setModalOpen(true);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
maxWidth: 130,
|
||||
},
|
||||
{
|
||||
Header: 'Enabled',
|
||||
accessor: 'enabled',
|
||||
Cell: ({
|
||||
row: { original: action },
|
||||
}: { row: { original: IActionSet } }) => (
|
||||
<ToggleCell
|
||||
checked={action.enabled}
|
||||
setChecked={(enabled) =>
|
||||
onToggleAction(action, enabled)
|
||||
}
|
||||
/>
|
||||
),
|
||||
sortType: 'boolean',
|
||||
width: 90,
|
||||
maxWidth: 90,
|
||||
},
|
||||
{
|
||||
id: 'table-actions',
|
||||
Header: '',
|
||||
align: 'center',
|
||||
Cell: ({
|
||||
row: { original: action },
|
||||
}: { row: { original: IActionSet } }) => (
|
||||
<ProjectActionsTableActionsCell
|
||||
actionId={action.id}
|
||||
onEdit={() => {
|
||||
setSelectedAction(action);
|
||||
setModalOpen(true);
|
||||
}}
|
||||
onDelete={() => {
|
||||
setSelectedAction(action);
|
||||
setDeleteOpen(true);
|
||||
}}
|
||||
/>
|
||||
),
|
||||
width: 50,
|
||||
disableSortBy: true,
|
||||
},
|
||||
],
|
||||
[actions, incomingWebhooks, serviceAccounts],
|
||||
);
|
||||
|
||||
const [initialState] = useState({
|
||||
sortBy: [{ id: 'name', desc: true }],
|
||||
});
|
||||
|
||||
const { headerGroups, rows, prepareRow, setHiddenColumns } = useTable(
|
||||
{
|
||||
columns: columns as any,
|
||||
data: actions,
|
||||
initialState,
|
||||
sortTypes,
|
||||
autoResetHiddenColumns: false,
|
||||
autoResetSortBy: false,
|
||||
disableSortRemove: true,
|
||||
disableMultiSort: true,
|
||||
defaultColumn: {
|
||||
Cell: TextCell,
|
||||
},
|
||||
},
|
||||
useSortBy,
|
||||
useFlexLayout,
|
||||
);
|
||||
|
||||
useConditionallyHiddenColumns(
|
||||
[
|
||||
{
|
||||
condition: isMediumScreen,
|
||||
columns: ['actor', 'enabled'],
|
||||
},
|
||||
{
|
||||
condition: isExtraSmallScreen,
|
||||
columns: ['filters', 'actions'],
|
||||
},
|
||||
],
|
||||
setHiddenColumns,
|
||||
columns,
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<VirtualizedTable
|
||||
rows={rows}
|
||||
headerGroups={headerGroups}
|
||||
prepareRow={prepareRow}
|
||||
/>
|
||||
<ConditionallyRender
|
||||
condition={rows.length === 0}
|
||||
show={
|
||||
<TablePlaceholder>
|
||||
No actions available. Get started by adding one.
|
||||
</TablePlaceholder>
|
||||
}
|
||||
/>
|
||||
{/* <ProjectActionsModal
|
||||
action={selectedAction}
|
||||
open={modalOpen}
|
||||
setOpen={setModalOpen}
|
||||
/> */}
|
||||
<ProjectActionsDeleteDialog
|
||||
action={selectedAction}
|
||||
open={deleteOpen}
|
||||
setOpen={setDeleteOpen}
|
||||
onConfirm={onDeleteConfirm}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -0,0 +1,123 @@
|
||||
import { useState } from 'react';
|
||||
import {
|
||||
Box,
|
||||
IconButton,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
MenuItem,
|
||||
MenuList,
|
||||
Popover,
|
||||
Tooltip,
|
||||
Typography,
|
||||
styled,
|
||||
} from '@mui/material';
|
||||
import MoreVertIcon from '@mui/icons-material/MoreVert';
|
||||
import { Delete, Edit } from '@mui/icons-material';
|
||||
import { PermissionHOC } from 'component/common/PermissionHOC/PermissionHOC';
|
||||
import { ADMIN } from 'component/providers/AccessProvider/permissions';
|
||||
import { defaultBorderRadius } from 'themes/themeStyles';
|
||||
|
||||
const StyledBoxCell = styled(Box)({
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
});
|
||||
|
||||
interface IProjectActionsTableActionsCellProps {
|
||||
actionId: number;
|
||||
onEdit: (event: React.SyntheticEvent) => void;
|
||||
onDelete: (event: React.SyntheticEvent) => void;
|
||||
}
|
||||
|
||||
export const ProjectActionsTableActionsCell = ({
|
||||
actionId,
|
||||
onEdit,
|
||||
onDelete,
|
||||
}: IProjectActionsTableActionsCellProps) => {
|
||||
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
|
||||
|
||||
const open = Boolean(anchorEl);
|
||||
|
||||
const handleClick = (event: React.MouseEvent<HTMLButtonElement>) => {
|
||||
setAnchorEl(event.currentTarget);
|
||||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setAnchorEl(null);
|
||||
};
|
||||
|
||||
const id = `action-${actionId}-actions`;
|
||||
const menuId = `${id}-menu`;
|
||||
|
||||
return (
|
||||
<StyledBoxCell>
|
||||
<Tooltip title='Action actions' arrow describeChild>
|
||||
<IconButton
|
||||
id={id}
|
||||
data-loading
|
||||
aria-controls={open ? menuId : undefined}
|
||||
aria-haspopup='true'
|
||||
aria-expanded={open ? 'true' : undefined}
|
||||
onClick={handleClick}
|
||||
type='button'
|
||||
>
|
||||
<MoreVertIcon />
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<Popover
|
||||
id={menuId}
|
||||
anchorEl={anchorEl}
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
onClick={handleClose}
|
||||
transformOrigin={{ horizontal: 'right', vertical: 'top' }}
|
||||
anchorOrigin={{ horizontal: 'right', vertical: 'bottom' }}
|
||||
disableScrollLock={true}
|
||||
PaperProps={{
|
||||
sx: (theme) => ({
|
||||
borderRadius: `${theme.shape.borderRadius}px`,
|
||||
padding: theme.spacing(1, 1.5),
|
||||
}),
|
||||
}}
|
||||
>
|
||||
<MenuList aria-labelledby={id}>
|
||||
<PermissionHOC permission={ADMIN}>
|
||||
{({ hasAccess }) => (
|
||||
<MenuItem
|
||||
sx={defaultBorderRadius}
|
||||
onClick={onEdit}
|
||||
disabled={!hasAccess}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Edit />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography variant='body2'>
|
||||
Edit
|
||||
</Typography>
|
||||
</ListItemText>
|
||||
</MenuItem>
|
||||
)}
|
||||
</PermissionHOC>
|
||||
<PermissionHOC permission={ADMIN}>
|
||||
{({ hasAccess }) => (
|
||||
<MenuItem
|
||||
sx={defaultBorderRadius}
|
||||
onClick={onDelete}
|
||||
disabled={!hasAccess}
|
||||
>
|
||||
<ListItemIcon>
|
||||
<Delete />
|
||||
</ListItemIcon>
|
||||
<ListItemText>
|
||||
<Typography variant='body2'>
|
||||
Remove
|
||||
</Typography>
|
||||
</ListItemText>
|
||||
</MenuItem>
|
||||
)}
|
||||
</PermissionHOC>
|
||||
</MenuList>
|
||||
</Popover>
|
||||
</StyledBoxCell>
|
||||
);
|
||||
};
|
@ -0,0 +1,66 @@
|
||||
import { Avatar, Box, Link, styled } from '@mui/material';
|
||||
import { TextCell } from 'component/common/Table/cells/TextCell/TextCell';
|
||||
import { IActionSet } from 'interfaces/action';
|
||||
import { IIncomingWebhook } from 'interfaces/incomingWebhook';
|
||||
import webhooksIcon from 'assets/icons/webhooks.svg';
|
||||
import { Link as RouterLink } from 'react-router-dom';
|
||||
import { ComponentType } from 'react';
|
||||
import { wrapperStyles } from 'component/common/Table/cells/LinkCell/LinkCell.styles';
|
||||
|
||||
const StyledCell = styled(Box)({
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
});
|
||||
|
||||
const StyledIcon = styled(Avatar)(({ theme }) => ({
|
||||
borderRadius: theme.shape.borderRadius,
|
||||
overflow: 'hidden',
|
||||
width: theme.spacing(3),
|
||||
height: theme.spacing(3),
|
||||
}));
|
||||
|
||||
const StyledLink = styled(Link)<{
|
||||
component?: ComponentType<any>;
|
||||
to?: string;
|
||||
}>(({ theme }) => ({
|
||||
...wrapperStyles(theme),
|
||||
'&:hover, &:focus': {
|
||||
textDecoration: 'underline',
|
||||
},
|
||||
}));
|
||||
|
||||
interface IProjectActionsTriggerCellProps {
|
||||
action: IActionSet;
|
||||
incomingWebhooks: IIncomingWebhook[];
|
||||
}
|
||||
|
||||
export const ProjectActionsTriggerCell = ({
|
||||
action,
|
||||
incomingWebhooks,
|
||||
}: IProjectActionsTriggerCellProps) => {
|
||||
const { sourceId } = action.match;
|
||||
const trigger = incomingWebhooks.find(({ id }) => id === sourceId);
|
||||
|
||||
if (!trigger) {
|
||||
return <TextCell>No trigger</TextCell>;
|
||||
}
|
||||
|
||||
return (
|
||||
<TextCell>
|
||||
<StyledCell>
|
||||
<StyledIcon
|
||||
src={webhooksIcon}
|
||||
alt='Incoming webhook'
|
||||
variant='rounded'
|
||||
/>
|
||||
<StyledLink
|
||||
component={RouterLink}
|
||||
to='/integrations/incoming-webhooks'
|
||||
underline='hover'
|
||||
>
|
||||
{trigger.name}
|
||||
</StyledLink>
|
||||
</StyledCell>
|
||||
</TextCell>
|
||||
);
|
||||
};
|
@ -52,6 +52,40 @@ export const useActionsApi = () => {
|
||||
await makeRequest(req.caller, req.id);
|
||||
};
|
||||
|
||||
const enableActionSet = async (actionSetId: number) => {
|
||||
const requestId = 'enableActionSet';
|
||||
const req = createRequest(
|
||||
`${ENDPOINT}/${actionSetId}/on`,
|
||||
{
|
||||
method: 'POST',
|
||||
},
|
||||
requestId,
|
||||
);
|
||||
|
||||
await makeRequest(req.caller, req.id);
|
||||
};
|
||||
|
||||
const disableActionSet = async (actionSetId: number) => {
|
||||
const requestId = 'disableActionSet';
|
||||
const req = createRequest(
|
||||
`${ENDPOINT}/${actionSetId}/off`,
|
||||
{
|
||||
method: 'POST',
|
||||
},
|
||||
requestId,
|
||||
);
|
||||
|
||||
await makeRequest(req.caller, req.id);
|
||||
};
|
||||
|
||||
const toggleActionSet = async (actionSetId: number, enabled: boolean) => {
|
||||
if (enabled) {
|
||||
await enableActionSet(actionSetId);
|
||||
} else {
|
||||
await disableActionSet(actionSetId);
|
||||
}
|
||||
};
|
||||
|
||||
const removeActionSet = async (actionSetId: number) => {
|
||||
const requestId = 'removeActionSet';
|
||||
const req = createRequest(
|
||||
@ -67,6 +101,7 @@ export const useActionsApi = () => {
|
||||
addActionSet,
|
||||
updateActionSet,
|
||||
removeActionSet,
|
||||
toggleActionSet,
|
||||
errors,
|
||||
loading,
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
export interface IActionSet {
|
||||
id: number;
|
||||
enabled: boolean;
|
||||
name: string;
|
||||
project: string;
|
||||
actorId: number;
|
||||
|
Loading…
Reference in New Issue
Block a user