Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[redhat-3.10] ui: Allow adding user from create team wizard (PROJQUAY-6336) #2502

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions web/cypress/e2e/default-permissions.cy.ts
Expand Up @@ -164,7 +164,7 @@ describe('Default permissions page', () => {
cy.get('[data-testid="next-btn"]').click();

// step - Add team member
cy.get('#search-robot-account-dropdown').click();
cy.get('#search-member-dropdown').click();
cy.get(`[data-testid="${robotAccnt}-robot-accnt"]`).click();
cy.get('[data-testid="next-btn"]').click();

Expand Down Expand Up @@ -251,7 +251,7 @@ describe('Default permissions page', () => {
cy.get('[data-testid="next-btn"]').click();

// step - Add team member from the drawer
cy.get('#search-robot-account-dropdown').click();
cy.get('#search-member-dropdown').click();
cy.get(`[data-testid="create-new-robot-accnt-btn"]`).click();
cy.get('[data-testid="new-robot-name-input"]').type(`${newRobotName}`);
cy.get('[data-testid="new-robot-description-input"]').type(
Expand Down
8 changes: 8 additions & 0 deletions web/cypress/e2e/teams-and-membership.cy.ts
Expand Up @@ -82,6 +82,9 @@ describe('Teams and membership page', () => {
cy.get('[data-testid="next-btn"]').click();

// step - Add team member
cy.get('#search-member-dropdown').click();
cy.get('#search-member-dropdown-input').type('user1');
cy.get(`[data-testid="user1"]`).click();
cy.get('[data-testid="next-btn"]').click();

// step - Review and Finish
Expand All @@ -99,6 +102,11 @@ describe('Teams and membership page', () => {
);
cy.get('[data-testid="review-and-finish-wizard-btn"]').click();

// verify success alert
cy.get('.pf-v5-c-alert.pf-m-success')
.contains('Successfully added members to team')
.should('exist');

// verify newly created team is shown under teams view
cy.get('#teams-view-search').type(`${newTeam}`);
cy.contains('1 - 1 of 1');
Expand Down
10 changes: 8 additions & 2 deletions web/src/components/EntitySearch.tsx
Expand Up @@ -67,6 +67,12 @@ export default function EntitySearch(props: EntitySearchProps) {
setSearchTerm(value as string);
setSelectedEntityName(value as string);
}
// onClear() prop can be skipped in case the value needs to be cleared automatically from
// the dropdown after selection (used in AddTeamMember wizard step)
if (!props.onClear) {
setSearchTerm('');
setSelectedEntityName('');
}
setIsOpen(false);
setFocusedItemIndex(null);
};
Expand Down Expand Up @@ -109,7 +115,7 @@ export default function EntitySearch(props: EntitySearchProps) {
setSelectedEntityName('');
setSearchTerm('');
textInputRef?.current?.focus();
props?.onClear({});
props?.onClear();
}}
aria-label="Clear input value"
>
Expand Down Expand Up @@ -160,7 +166,7 @@ interface EntitySearchProps {
org: string;
includeTeams?: boolean;
onSelect: (selectedItem: Entity) => void;
onClear?: (entity: any) => void;
onClear?: () => void;
onError?: () => void;
id?: string;
defaultOptions?: any;
Expand Down
2 changes: 1 addition & 1 deletion web/src/hooks/UseMembers.ts
Expand Up @@ -29,8 +29,8 @@ export function useAddMembersToTeam(org: string, {onSuccess, onError}) {
{
onSuccess: () => {
onSuccess();
queryClient.invalidateQueries(['members']);
queryClient.invalidateQueries(['teams']);
queryClient.invalidateQueries(['members']);
queryClient.invalidateQueries(['teamMembers']);
},
onError: () => {
Expand Down
Expand Up @@ -148,7 +148,7 @@ export default function CreatePermissionDrawer(
onSelect={(e: Entity) => {
setRepositoryCreator(e);
}}
onClear={setRepositoryCreator}
onClear={() => setRepositoryCreator(null)}
value={repositoryCreator?.name}
onError={() => setError('Unable to look up users')}
defaultOptions={creatorDefaultOptions}
Expand Down Expand Up @@ -314,8 +314,10 @@ export default function CreatePermissionDrawer(
id="applied-to-dropdown"
org={props.orgName}
includeTeams={true}
onSelect={() => undefined}
onClear={setAppliedTo}
onSelect={(e: Entity) => {
setAppliedTo(e);
}}
onClear={() => setAppliedTo(null)}
value={appliedTo?.name}
onError={() => setError('Unable to look up teams')}
defaultOptions={appliedToDefaultOptions}
Expand Down
Expand Up @@ -63,25 +63,25 @@ export default function AddTeamMember(props: AddTeamMemberProps) {
},
});

const addTeamMemberHandler = (robotName) => {
const addTeamMemberHandler = (memberName: string, isRobot: boolean) => {
const robotExists = props.tableItems?.some(
(item) => item.name === robotName,
(item) => item.name === memberName,
);
if (!robotExists) {
props.setTableItems((prev) => [
...prev,
{
name: robotName,
name: memberName,
kind: 'user',
is_robot: true,
is_robot: isRobot,
},
]);
props.setAddedTeamMembers((prev) => [
...prev,
{
name: robotName,
name: memberName,
kind: 'user',
is_robot: true,
is_robot: isRobot,
},
]);
}
Expand All @@ -94,7 +94,7 @@ export default function AddTeamMember(props: AddTeamMemberProps) {
description: newRobotAccntDescription,
});
props.setDrawerExpanded(false);
addTeamMemberHandler(`${props.orgName}+${newRobotAccntName}`);
addTeamMemberHandler(`${props.orgName}+${newRobotAccntName}`, true);
};

const validateRobotName = () => {
Expand Down Expand Up @@ -148,6 +148,11 @@ export default function AddTeamMember(props: AddTeamMemberProps) {
prev.filter((item) => member.name !== item.name),
);

// remove member if added to potential team member list
props.setAddedTeamMembers((prev) =>
prev.filter((item) => item.name !== member.name),
);

// Add to delete member list if member already exists in db
props.setDeletedTeamMembers((prev) => {
const memberExists = props?.allMembers.find(
Expand All @@ -164,53 +169,51 @@ export default function AddTeamMember(props: AddTeamMemberProps) {
}

return (
<>
<PageSection padding={{default: 'noPadding'}}>
<AddTeamToolbar
orgName={props.orgName}
allItems={props.tableItems}
page={page}
setPage={setPage}
perPage={perPage}
setPerPage={setPerPage}
robots={robots}
addTeamMemberHandler={addTeamMemberHandler}
setDrawerExpanded={props.setDrawerExpanded}
>
<Table aria-label="Selectable table" variant="compact">
<Thead>
<Tr>
<Th>{memberAndRobotColNames.teamMember}</Th>
<Th>{memberAndRobotColNames.account}</Th>
<Th />
<PageSection padding={{default: 'noPadding'}}>
<AddTeamToolbar
orgName={props.orgName}
allItems={props.tableItems}
page={page}
setPage={setPage}
perPage={perPage}
setPerPage={setPerPage}
robots={robots}
addTeamMemberHandler={addTeamMemberHandler}
setDrawerExpanded={props.setDrawerExpanded}
>
<Table aria-label="Selectable table" variant="compact">
<Thead>
<Tr>
<Th>{memberAndRobotColNames.teamMember}</Th>
<Th>{memberAndRobotColNames.account}</Th>
<Th />
</Tr>
</Thead>
<Tbody>
{paginatedItems?.map((member, rowIndex) => (
<Tr key={rowIndex}>
<Td dataLabel={memberAndRobotColNames.teamMember}>
{member.name}
</Td>
<Td dataLabel={memberAndRobotColNames.account}>
{getAccountTypeForMember(member)}
</Td>
<Td>
<Button
icon={<TrashIcon />}
variant="plain"
onClick={() => {
handleDeleteTeamMember(member);
}}
data-testid={`${member.name}-delete-icon`}
/>
</Td>
</Tr>
</Thead>
<Tbody>
{paginatedItems?.map((member, rowIndex) => (
<Tr key={rowIndex}>
<Td dataLabel={memberAndRobotColNames.teamMember}>
{member.name}
</Td>
<Td dataLabel={memberAndRobotColNames.account}>
{getAccountTypeForMember(member)}
</Td>
<Td>
<Button
icon={<TrashIcon />}
variant="plain"
onClick={() => {
handleDeleteTeamMember(member);
}}
data-testid={`${member.name}-delete-icon`}
/>
</Td>
</Tr>
))}
</Tbody>
</Table>
</AddTeamToolbar>
</PageSection>
</>
))}
</Tbody>
</Table>
</AddTeamToolbar>
</PageSection>
);
}

Expand Down
Expand Up @@ -13,6 +13,7 @@ import EntitySearch from 'src/components/EntitySearch';
import {ToolbarPagination} from 'src/components/toolbar/ToolbarPagination';
import {ITeamMember} from 'src/hooks/UseMembers';
import {IRobot} from 'src/resources/RobotsResource';
import {Entity} from 'src/resources/UserResource';

export default function AddTeamToolbar(props: AddTeamToolbarProps) {
const [error, setError] = useState<string>('');
Expand All @@ -26,9 +27,7 @@ export default function AddTeamToolbar(props: AddTeamToolbarProps) {
data-testid={`${name}-robot-accnt`}
key={name}
value={name}
onClick={() => {
props.addTeamMemberHandler(name);
}}
onClick={() => props.addTeamMemberHandler(name, true)}
>
{name}
</SelectOption>
Expand All @@ -54,11 +53,12 @@ export default function AddTeamToolbar(props: AddTeamToolbarProps) {
<ToolbarContent>
<ToolbarItem variant="search-filter">
<EntitySearch
id={'search-robot-account-dropdown'}
id={'search-member-dropdown'}
org={props.orgName}
includeTeams={false}
onSelect={() => undefined}
onClear={() => undefined}
onSelect={(e: Entity) =>
props.addTeamMemberHandler(e.name, false)
}
onError={() => setError('Unable to look up robot accounts')}
defaultOptions={searchRobotAccntOptions}
placeholderText="Add a user, robot to the team"
Expand Down Expand Up @@ -87,6 +87,6 @@ interface AddTeamToolbarProps {
setPerPage: (perPage: number) => void;
children?: React.ReactNode;
robots: IRobot[];
addTeamMemberHandler: (robotAccnt: string) => void;
addTeamMemberHandler: (robotAccnt: string, isRobot: boolean) => void;
setDrawerExpanded?: (boolean) => void;
}
Expand Up @@ -32,6 +32,8 @@ import AddTeamMember from './AddTeamMember';
import Review from './ReviewTeam';
import ReviewAndFinishFooter from './ReviewAndFinishFooter';
import {useAddRepoPermissionToTeam} from 'src/hooks/UseTeams';
import {useAlerts} from 'src/hooks/UseAlerts';
import {AlertVariant} from 'src/atoms/AlertState';

export const CreateTeamWizard = (props: CreateTeamWizardProps): JSX.Element => {
const [selectedRepoPerms, setSelectedRepoPerms] = useRecoilState(
Expand All @@ -45,6 +47,7 @@ export const CreateTeamWizard = (props: CreateTeamWizardProps): JSX.Element => {
const [deletedTeamMembers, setDeletedTeamMembers] = useState<ITeamMember[]>(
[],
);
const {addAlert} = useAlerts();

// Fetching repos
const {repos} = useRepositories(props.orgName);
Expand All @@ -70,8 +73,18 @@ export const CreateTeamWizard = (props: CreateTeamWizardProps): JSX.Element => {
successAddingMemberToTeam: success,
resetAddingMemberToTeam: reset,
} = useAddMembersToTeam(props.orgName, {
onSuccess: {},
onError: {},
onSuccess: () => {
addAlert({
variant: AlertVariant.Success,
title: 'Successfully added members to team',
});
},
onError: () => {
addAlert({
variant: AlertVariant.Failure,
title: 'Unable to add members to team',
});
},
});

const {addRepoPermToTeam} = useAddRepoPermissionToTeam(
Expand Down Expand Up @@ -108,6 +121,7 @@ export const CreateTeamWizard = (props: CreateTeamWizardProps): JSX.Element => {
});
}
props.handleWizardToggle();
setSelectedRepoPerms([]);
};

return (
Expand Down Expand Up @@ -135,17 +149,26 @@ export const CreateTeamWizard = (props: CreateTeamWizardProps): JSX.Element => {
aria-label="CreateTeam"
variant={ModalVariant.large}
isOpen={props.isTeamWizardOpen}
onClose={props.handleWizardToggle}
onClose={() => {
props.handleWizardToggle();
setSelectedRepoPerms([]);
}}
showClose={false}
hasNoBodyWrapper
>
<Wizard
onClose={props.handleWizardToggle}
onClose={() => {
props.handleWizardToggle();
setSelectedRepoPerms([]);
}}
height={600}
width={1170}
header={
<WizardHeader
onClose={props.handleWizardToggle}
onClose={() => {
props.handleWizardToggle();
setSelectedRepoPerms([]);
}}
title="Create team"
description=""
/>
Expand Down
Expand Up @@ -89,7 +89,7 @@ export default function AddNewTeamMemberDrawer(
onSelect={(e: Entity) => {
setSelectedEntity(e);
}}
onClear={setSelectedEntity}
onClear={() => setSelectedEntity(null)}
value={selectedEntity?.name}
onError={() => setError('Unable to look up users')}
defaultOptions={creatorDefaultOptions}
Expand Down
Expand Up @@ -217,7 +217,8 @@ export default function SetRepoPermissionForTeamModal(
rowIndex,
onSelect: (_event, isSelecting) =>
onSelectRepoPerm(repoPerm, rowIndex, isSelecting),
isSelected: isItemSelected(repoPerm),
isSelected:
isItemSelected(repoPerm) || repoPerm.role !== 'none',
}}
/>
<Td dataLabel={setRepoPermForTeamColumnNames.repoName}>
Expand Down