diff --git a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/InnerContainerBox.tsx b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/InnerContainerBox.tsx deleted file mode 100644 index 4401114167..0000000000 --- a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/InnerContainerBox.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import { Box, styled } from '@mui/material'; - -export const StyledInnerBox = styled(Box)(({ theme }) => ({ - display: 'flex', - flexDirection: 'column', - backgroundColor: theme.palette.background.default, - border: `1px solid ${theme.palette.divider}`, - padding: theme.spacing(2), - borderRadius: `${theme.shape.borderRadiusMedium}px`, -})); - -export const StyledInnerBoxHeader = styled('div')(({ theme }) => ({ - marginLeft: 'auto', - whiteSpace: 'nowrap', - [theme.breakpoints.down('sm')]: { - display: 'none', - }, -})); - -// row for inner containers -export const StyledRow = styled('div')({ - display: 'flex', - flexDirection: 'row', - width: '100%', -}); - -export const StyledCol = styled('div')({ - flex: 1, - margin: '0 4px', -}); - -const StyledBoxContent = styled('div')(({ theme }) => ({ - padding: theme.spacing(0.75, 1), - color: theme.palette.text.primary, - fontSize: theme.fontSizes.smallerBody, - backgroundColor: theme.palette.seen.primary, - borderRadius: theme.shape.borderRadius, - position: 'absolute', - zIndex: theme.zIndex.fab, - top: '50%', - left: theme.spacing(2), - transform: 'translateY(-50%)', - lineHeight: 1, -})); - -export const BoxSeparator: React.FC = ({ children }) => { - return ( - - {children} - - ); -}; diff --git a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsActionItem.tsx b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsActionItem.tsx index 29f20e9392..48911c78c3 100644 --- a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsActionItem.tsx +++ b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsActionItem.tsx @@ -1,19 +1,22 @@ -import { IconButton, Tooltip } from '@mui/material'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; -import { Fragment } from 'react'; +import { IconButton, Tooltip, styled } from '@mui/material'; import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect'; import { Delete } from '@mui/icons-material'; import { useProjectEnvironments } from 'hooks/api/getters/useProjectEnvironments/useProjectEnvironments'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { useFeatureSearch } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch'; -import { - BoxSeparator, - StyledCol, - StyledInnerBoxHeader, - StyledRow, - StyledInnerBox, -} from './InnerContainerBox'; import { ActionsActionState } from './useProjectActionsForm'; +import { ProjectActionsFormItem } from './ProjectActionsFormItem'; + +const StyledItemRow = styled('div')(({ theme }) => ({ + display: 'flex', + alignItems: 'center', + gap: theme.spacing(1), + width: '100%', +})); + +const StyledFieldContainer = styled('div')({ + flex: 1, +}); export const ProjectActionsActionItem = ({ action, @@ -30,92 +33,90 @@ export const ProjectActionsActionItem = ({ const projectId = useRequiredPathParam('projectId'); const environments = useProjectEnvironments(projectId); const { features } = useFeatureSearch({ project: `IS:${projectId}` }); + + const header = ( + <> + Action {index + 1} +
+ + + + + +
+ + ); + return ( - - 0} - show={THEN} - /> - - - Action {index + 1} - - - - - - - - - - - + + + + stateChanged({ + ...action, + action: selected, + }) + } + fullWidth + /> + + + ({ + label: env.name, + key: env.name, + }))} + value={action.executionParams.environment as string} + onChange={(selected) => + stateChanged({ + ...action, + executionParams: { + ...action.executionParams, + environment: selected, }, - { - label: 'Disable flag', - key: 'TOGGLE_FEATURE_OFF', + }) + } + fullWidth + /> + + + ({ + label: feature.name, + key: feature.name, + }))} + value={action.executionParams.featureName as string} + onChange={(selected) => + stateChanged({ + ...action, + executionParams: { + ...action.executionParams, + featureName: selected, }, - ]} - value={actionName} - onChange={(selected) => - stateChanged({ - ...action, - action: selected, - }) - } - fullWidth - /> - - - ({ - label: env.name, - key: env.name, - }))} - value={action.executionParams.environment as string} - onChange={(selected) => - stateChanged({ - ...action, - executionParams: { - ...action.executionParams, - environment: selected, - }, - }) - } - fullWidth - /> - - - ({ - label: feature.name, - key: feature.name, - }))} - value={action.executionParams.featureName as string} - onChange={(selected) => - stateChanged({ - ...action, - executionParams: { - ...action.executionParams, - featureName: selected, - }, - }) - } - fullWidth - /> - - - - + }) + } + fullWidth + /> + + + ); }; diff --git a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsFilterItem.tsx b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsFilterItem.tsx index 6595271ce0..e0949f3c6a 100644 --- a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsFilterItem.tsx +++ b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsFilterItem.tsx @@ -1,23 +1,20 @@ import { Badge, IconButton, Tooltip, styled } from '@mui/material'; -import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ActionsFilterState } from './useProjectActionsForm'; -import { Fragment } from 'react'; import { Delete } from '@mui/icons-material'; import Input from 'component/common/Input/Input'; -import { - BoxSeparator, - StyledInnerBoxHeader, - StyledRow, - StyledInnerBox, -} from './InnerContainerBox'; +import { ProjectActionsFormItem } from './ProjectActionsFormItem'; -const StyledInput = styled(Input)(() => ({ +const StyledInputContainer = styled('div')({ + flex: 1, +}); + +const StyledInput = styled(Input)({ width: '100%', -})); +}); const StyledBadge = styled(Badge)(({ theme }) => ({ - color: 'primary', - margin: theme.spacing(1), + margin: theme.spacing(0, 1), + fontSize: theme.fontSizes.mainHeader, })); export const ProjectActionsFilterItem = ({ @@ -32,47 +29,47 @@ export const ProjectActionsFilterItem = ({ onDelete: () => void; }) => { const { parameter, value } = filter; + + const header = ( + <> + Filter {index + 1} +
+ + + + + +
+ + ); + return ( - - 0} - show={AND} - /> - - - Filter {index + 1} - - - - - - - - - - - stateChanged({ - ...filter, - parameter: e.target.value, - }) - } - /> - = - - stateChanged({ - ...filter, - value: e.target.value, - }) - } - /> - - - + + + + stateChanged({ + ...filter, + parameter: e.target.value, + }) + } + /> + + = + + + stateChanged({ + ...filter, + value: e.target.value, + }) + } + /> + + ); }; diff --git a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsForm.tsx b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsForm.tsx index 791eb60b5c..b5d1612b73 100644 --- a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsForm.tsx +++ b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsForm.tsx @@ -1,7 +1,6 @@ -import { Alert, Box, Button, Link, styled } from '@mui/material'; +import { Alert, Button, Divider, Link, styled } from '@mui/material'; import { Link as RouterLink } from 'react-router-dom'; import Input from 'component/common/Input/Input'; -import { Badge } from 'component/common/Badge/Badge'; import { FormSwitch } from 'component/common/FormSwitch/FormSwitch'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { @@ -16,9 +15,9 @@ import { useMemo } from 'react'; import GeneralSelect, {} from 'component/common/GeneralSelect/GeneralSelect'; import { Add } from '@mui/icons-material'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; -import { StyledRow } from './InnerContainerBox'; import { ProjectActionsActionItem } from './ProjectActionsActionItem'; import { ProjectActionsFilterItem } from './ProjectActionsFilterItem'; +import { ProjectActionsFormStep } from './ProjectActionsFormStep'; const StyledServiceAccountAlert = styled(Alert)(({ theme }) => ({ marginBottom: theme.spacing(4), @@ -44,27 +43,20 @@ const StyledInput = styled(Input)(() => ({ width: '100%', })); -const StyledBadge = styled(Badge)(({ theme }) => ({ - color: 'primary', - margin: 'auto', - marginBottom: theme.spacing(1.5), -})); - -const StyledBox = styled(Box)(({ theme }) => ({ +const StyledSecondaryDescription = styled('p')(({ theme }) => ({ display: 'flex', - flexDirection: 'column', - backgroundColor: theme.palette.background.elevation1, - marginTop: theme.spacing(2), - padding: theme.spacing(2), - borderRadius: theme.shape.borderRadiusMedium, + color: theme.palette.text.secondary, + fontSize: theme.fontSizes.smallBody, })); -const Step = ({ name, children }: any) => ( - - {name} - {children} - -); +const StyledButtonContainer = styled('div')(({ theme }) => ({ + marginTop: theme.spacing(2), +})); + +const StyledDivider = styled(Divider)(({ theme }) => ({ + margin: theme.spacing(3, 0), + marginBottom: theme.spacing(2), +})); interface IProjectActionsFormProps { enabled: boolean; @@ -101,6 +93,7 @@ export const ProjectActionsForm = ({ validateName, validated, }: IProjectActionsFormProps) => { + const projectId = useRequiredPathParam('projectId'); const { serviceAccounts, loading: serviceAccountsLoading } = useServiceAccounts(); const { incomingWebhooks, loading: incomingWebhooksLoading } = @@ -177,7 +170,7 @@ export const ProjectActionsForm = ({ }, [serviceAccountsLoading, serviceAccounts]); const showErrors = validated && Object.values(errors).some(Boolean); - const projectId = useRequiredPathParam('projectId'); + return (
- + Create incoming webhooks from  @@ -235,9 +228,13 @@ export const ProjectActionsForm = ({ setSourceId(parseInt(v)); }} /> - + - + + + If no filters are defined then the action will be triggered + every time the incoming webhook is called. + {filters.map((filter, index) => ( ))} - -
- + - -
+ + - + Create service accounts from  @@ -283,7 +277,7 @@ export const ProjectActionsForm = ({ setActorId(parseInt(v)); }} /> -
+ {actions.map((action, index) => ( ))} -
- + - -
+ + ({ + marginTop: theme.spacing(1), + position: 'relative', +})); + +const StyledItemSeparator = styled('div')(({ theme }) => ({ + padding: theme.spacing(0.75, 1), + fontSize: theme.fontSizes.smallerBody, + backgroundColor: theme.palette.seen.primary, + borderRadius: theme.shape.borderRadius, + position: 'absolute', + zIndex: theme.zIndex.fab, + top: theme.spacing(-2), + left: theme.spacing(2), + lineHeight: 1, +})); + +const StyledInnerBox = styled('div')(({ theme }) => ({ + display: 'flex', + flexDirection: 'column', + backgroundColor: theme.palette.background.default, + border: `1px solid ${theme.palette.divider}`, + padding: theme.spacing(2), + paddingTop: theme.spacing(1), + borderRadius: theme.shape.borderRadiusMedium, +})); + +const StyledRow = styled('div')({ + display: 'flex', + alignItems: 'center', +}); + +const StyledHeaderRow = styled(StyledRow)(({ theme }) => ({ + justifyContent: 'space-between', + marginBottom: theme.spacing(1), +})); + +interface IProjectActionsFormItemProps { + index: number; + header: ReactNode; + separator?: string; + children: ReactNode; +} + +export const ProjectActionsFormItem = ({ + index, + header, + separator = 'AND', + children, +}: IProjectActionsFormItemProps) => { + return ( + + 0} + show={{separator}} + /> + + {header} + {children} + + + ); +}; diff --git a/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsFormStep.tsx b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsFormStep.tsx new file mode 100644 index 0000000000..f4139e185a --- /dev/null +++ b/frontend/src/component/project/Project/ProjectSettings/ProjectActions/ProjectActionsTable/ProjectActionsModal/ProjectActionsForm/ProjectActionsFormStep.tsx @@ -0,0 +1,49 @@ +import { Box, Divider, styled } from '@mui/material'; +import { Badge } from 'component/common/Badge/Badge'; +import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; +import { ReactNode } from 'react'; + +const StyledBadge = styled(Badge)(({ theme }) => ({ + margin: 'auto', + marginBottom: theme.spacing(2), +})); + +const StyledBox = styled(Box, { + shouldForwardProp: (prop) => prop !== 'verticalConnector', +})<{ verticalConnector?: boolean }>(({ theme, verticalConnector }) => ({ + display: 'flex', + flexDirection: 'column', + backgroundColor: theme.palette.background.elevation1, + marginTop: verticalConnector ? 0 : theme.spacing(3), + padding: theme.spacing(3), + borderRadius: theme.shape.borderRadiusMedium, +})); + +const StyledVerticalConnector = styled(Divider)(({ theme }) => ({ + margin: 'auto', + width: 1, + height: theme.spacing(3), +})); + +interface IProjectActionsFormStepProps { + name: string; + verticalConnector?: boolean; + children: ReactNode; +} + +export const ProjectActionsFormStep = ({ + name, + verticalConnector, + children, +}: IProjectActionsFormStepProps) => ( + <> + } + /> + + {name} + {children} + + +);