1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-08-04 13:48:56 +02:00

chore: improve action parameters UI (#6549)

https://linear.app/unleash/issue/2-2041/improve-action-parameters-ui

Improves the UI of action parameters, implementing a new
`ProjectActionsActionParameterAutocomplete` component that allows
search.


![image](https://github.com/Unleash/unleash/assets/14320932/b87de507-2feb-433b-846f-0f3cc61721fa)
This commit is contained in:
Nuno Góis 2024-03-14 11:25:14 +00:00 committed by GitHub
parent a2c4b8c320
commit a1af0dd41c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 47 additions and 23 deletions

View File

@ -2,14 +2,13 @@ import { Alert, IconButton, Tooltip, styled } from '@mui/material';
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect'; import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
import Delete from '@mui/icons-material/Delete'; import Delete from '@mui/icons-material/Delete';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import { useFeatureSearch } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch';
import { ActionsActionState } from '../../useProjectActionsForm'; import { ActionsActionState } from '../../useProjectActionsForm';
import { ProjectActionsFormItem } from '../ProjectActionsFormItem'; import { ProjectActionsFormItem } from '../ProjectActionsFormItem';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender';
import { useServiceAccountAccessMatrix } from 'hooks/api/getters/useServiceAccountAccessMatrix/useServiceAccountAccessMatrix'; import { useServiceAccountAccessMatrix } from 'hooks/api/getters/useServiceAccountAccessMatrix/useServiceAccountAccessMatrix';
import { useEffect, useMemo } from 'react'; import { useEffect, useMemo } from 'react';
import { ACTIONS } from '@server/util/constants/actions'; import { ACTIONS } from '@server/util/constants/actions';
import { ProjectActionsActionParameterAutocomplete } from './ProjectActionsActionParameter/ProjectActionsActionParameterAutocomplete';
const StyledItemBody = styled('div')(({ theme }) => ({ const StyledItemBody = styled('div')(({ theme }) => ({
display: 'flex', display: 'flex',
@ -35,6 +34,8 @@ interface IProjectActionsItemProps {
stateChanged: (action: ActionsActionState) => void; stateChanged: (action: ActionsActionState) => void;
actorId: number; actorId: number;
onDelete: () => void; onDelete: () => void;
featureToggles: string[];
environments: string[];
validated: boolean; validated: boolean;
} }
@ -44,11 +45,12 @@ export const ProjectActionsActionItem = ({
stateChanged, stateChanged,
actorId, actorId,
onDelete, onDelete,
featureToggles,
environments,
validated, validated,
}: IProjectActionsItemProps) => { }: IProjectActionsItemProps) => {
const { action: actionName, executionParams, error } = action; const { action: actionName, executionParams, error } = action;
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const { project } = useProjectOverview(projectId);
const { permissions } = useServiceAccountAccessMatrix( const { permissions } = useServiceAccountAccessMatrix(
actorId, actorId,
projectId, projectId,
@ -97,12 +99,6 @@ export const ProjectActionsActionItem = ({
} }
}, [actionDefinition, executionParams]); }, [actionDefinition, executionParams]);
const environments = project.environments.map(
({ environment }) => environment,
);
const { features } = useFeatureSearch({ project: `IS:${projectId}` });
const header = ( const header = (
<> <>
<span>Action {index + 1}</span> <span>Action {index + 1}</span>
@ -139,13 +135,8 @@ export const ProjectActionsActionItem = ({
/> />
</StyledFieldContainer> </StyledFieldContainer>
<StyledFieldContainer> <StyledFieldContainer>
<GeneralSelect <ProjectActionsActionParameterAutocomplete
label='Environment' label='Environment'
name='environment'
options={environments.map((environment) => ({
label: environment,
key: environment,
}))}
value={executionParams.environment as string} value={executionParams.environment as string}
onChange={(selected) => onChange={(selected) =>
stateChanged({ stateChanged({
@ -156,17 +147,12 @@ export const ProjectActionsActionItem = ({
}, },
}) })
} }
fullWidth options={environments}
/> />
</StyledFieldContainer> </StyledFieldContainer>
<StyledFieldContainer> <StyledFieldContainer>
<GeneralSelect <ProjectActionsActionParameterAutocomplete
label='Flag name' label='Flag name'
name='flag'
options={features.map((feature) => ({
label: feature.name,
key: feature.name,
}))}
value={executionParams.featureName as string} value={executionParams.featureName as string}
onChange={(selected) => onChange={(selected) =>
stateChanged({ stateChanged({
@ -177,7 +163,7 @@ export const ProjectActionsActionItem = ({
}, },
}) })
} }
fullWidth options={featureToggles}
/> />
</StyledFieldContainer> </StyledFieldContainer>
</StyledItemRow> </StyledItemRow>

View File

@ -0,0 +1,26 @@
import { Autocomplete, TextField } from '@mui/material';
interface IProjectActionsActionParameterAutocompleteProps {
label: string;
value: string;
onChange: (value: string) => void;
options: string[];
}
export const ProjectActionsActionParameterAutocomplete = ({
label,
value,
onChange,
options,
}: IProjectActionsActionParameterAutocompleteProps) => (
<Autocomplete
options={options}
autoHighlight
autoSelect
value={value}
onInputChange={(_, parameter) => onChange(parameter)}
renderInput={(params) => (
<TextField {...params} size='small' label={label} />
)}
/>
);

View File

@ -9,6 +9,8 @@ import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
import Add from '@mui/icons-material/Add'; import Add from '@mui/icons-material/Add';
import { IServiceAccount } from 'interfaces/service-account'; import { IServiceAccount } from 'interfaces/service-account';
import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam';
import useProjectOverview from 'hooks/api/getters/useProjectOverview/useProjectOverview';
import { useFeatureSearch } from 'hooks/api/getters/useFeatureSearch/useFeatureSearch';
const StyledDivider = styled(Divider)(({ theme }) => ({ const StyledDivider = styled(Divider)(({ theme }) => ({
margin: theme.spacing(2, 0), margin: theme.spacing(2, 0),
@ -44,6 +46,14 @@ export const ProjectActionsFormStepActions = ({
validated, validated,
}: IProjectActionsFormStepActionsProps) => { }: IProjectActionsFormStepActionsProps) => {
const projectId = useRequiredPathParam('projectId'); const projectId = useRequiredPathParam('projectId');
const { project } = useProjectOverview(projectId);
const { features } = useFeatureSearch({ project: `IS:${projectId}` });
const featureToggles = features.map(({ name }) => name).sort();
const environments = project.environments.map(
({ environment }) => environment,
);
const addAction = (projectId: string) => { const addAction = (projectId: string) => {
const id = uuidv4(); const id = uuidv4();
@ -112,6 +122,8 @@ export const ProjectActionsFormStepActions = ({
actions.filter((a) => a.id !== action.id), actions.filter((a) => a.id !== action.id),
) )
} }
featureToggles={featureToggles}
environments={environments}
validated={validated} validated={validated}
/> />
))} ))}