Browse Source

SONAR-16565 Preselect token type or project options if only one is available (#6297)

tags/9.6.0.59041
guillaume-peoch-sonarsource 1 year ago
parent
commit
19e81c4249

+ 33
- 2
server/sonar-web/src/main/js/apps/account/__tests__/Account-it.tsx View File

@@ -344,7 +344,7 @@ describe('security page', () => {
).not.toBeInTheDocument();
});

it("should not suggest creating a Project token if the user doesn't have at least one scannable Projects", async () => {
it("should not suggest creating a Project token if the user doesn't have at least one scannable Projects", () => {
(getScannableProjects as jest.Mock).mockResolvedValueOnce({
projects: []
});
@@ -353,10 +353,41 @@ describe('security page', () => {
securityPagePath
);

await selectEvent.openMenu(screen.getAllByRole('textbox')[1]);
selectEvent.openMenu(screen.getAllByRole('textbox')[1]);
expect(screen.queryByText(`users.tokens.${TokenType.Project}`)).not.toBeInTheDocument();
});

it('should preselect the user token type if the user has no scan rights', async () => {
(getScannableProjects as jest.Mock).mockResolvedValueOnce({
projects: []
});
renderAccountApp(mockLoggedInUser(), securityPagePath);

const globalToken = await screen.findByText(`users.tokens.${TokenType.User}`);
expect(globalToken).toBeInTheDocument();
});

it('should preselect the only project the user has access to if they select project token', async () => {
(getScannableProjects as jest.Mock).mockResolvedValueOnce({
projects: [
{
key: 'project-key-1',
name: 'Project Name 1'
}
]
});
renderAccountApp(
mockLoggedInUser({ permissions: { global: [Permissions.Scan] } }),
securityPagePath
);

await selectEvent.select(screen.getAllByRole('textbox')[1], [
`users.tokens.${TokenType.Project}`
]);

expect(screen.getByText('Project Name 1')).toBeInTheDocument();
});

it('should allow local users to change password', async () => {
const user = userEvent.setup();
renderAccountApp(mockLoggedInUser({ local: true }), securityPagePath);

+ 20
- 13
server/sonar-web/src/main/js/apps/users/components/TokensForm.tsx View File

@@ -54,7 +54,7 @@ interface State {
newTokenType?: TokenType;
tokens: UserToken[];
projects: BasicSelectOption[];
selectedProject: { key: string; name: string };
selectedProject?: BasicSelectOption;
newTokenExpiration: TokenExpiration;
tokenExpirationOptions: { value: TokenExpiration; label: string }[];
}
@@ -66,7 +66,6 @@ export class TokensForm extends React.PureComponent<Props, State> {
loading: true,
newTokenName: '',
newTokenType: this.props.displayTokenTypeInput ? undefined : TokenType.User,
selectedProject: { key: '', name: '' },
tokens: [],
projects: [],
newTokenExpiration: TokenExpiration.OneMonth,
@@ -113,7 +112,8 @@ export class TokensForm extends React.PureComponent<Props, State> {
const { projects: projectArray } = await getScannableProjects();
const projects = projectArray.map(project => ({ label: project.name, value: project.key }));
this.setState({
projects
projects,
selectedProject: projects.length === 1 ? projects[0] : undefined
});
};

@@ -139,7 +139,8 @@ export class TokensForm extends React.PureComponent<Props, State> {
name: newTokenName,
login,
type: newTokenType,
...(newTokenType === TokenType.Project && { projectKey: selectedProject.key }),
...(newTokenType === TokenType.Project &&
selectedProject !== undefined && { projectKey: selectedProject.value }),
...(newTokenExpiration !== TokenExpiration.NoExpiration && {
expirationDate: computeTokenExpirationDate(newTokenExpiration)
})
@@ -155,17 +156,19 @@ export class TokensForm extends React.PureComponent<Props, State> {
isExpired: false,
expirationDate: newToken.expirationDate,
type: newTokenType,
...(newTokenType === TokenType.Project && {
project: { key: selectedProject.key, name: selectedProject.name }
})
...(newTokenType === TokenType.Project &&
selectedProject !== undefined && {
project: { key: selectedProject.value, name: selectedProject.label }
})
}
];
return {
generating: false,
newToken,
newTokenName: '',
selectedProject: { key: '', name: '' },
selectedProject: undefined,
newTokenType: undefined,
newTokenExpiration: TokenExpiration.OneMonth,
tokens
};
}, this.updateTokensCount);
@@ -198,7 +201,7 @@ export class TokensForm extends React.PureComponent<Props, State> {
return true;
}
if (newTokenType === TokenType.Project) {
return !selectedProject.key;
return !selectedProject?.value;
}

return !newTokenType;
@@ -212,8 +215,8 @@ export class TokensForm extends React.PureComponent<Props, State> {
this.setState({ newTokenType: value });
};

handleProjectChange = ({ value, label }: { value: string; label: string }) => {
this.setState({ selectedProject: { key: value, name: label } });
handleProjectChange = (selectedProject: BasicSelectOption) => {
this.setState({ selectedProject });
};

handleNewTokenExpirationChange = ({ value }: { value: TokenExpiration }) => {
@@ -277,7 +280,11 @@ export class TokensForm extends React.PureComponent<Props, State> {
onChange={this.handleNewTokenTypeChange}
options={tokenTypeOptions}
placeholder={translate('users.tokens.select_type')}
value={tokenTypeOptions.find(option => option.value === newTokenType) || null}
value={
tokenTypeOptions.length === 1
? tokenTypeOptions[0]
: tokenTypeOptions.find(option => option.value === newTokenType) || null
}
/>
</div>
{newTokenType === TokenType.Project && (
@@ -291,7 +298,7 @@ export class TokensForm extends React.PureComponent<Props, State> {
onChange={this.handleProjectChange}
options={projects}
placeholder={translate('users.tokens.select_project')}
value={projects.find(project => project.value === selectedProject.key)}
value={selectedProject}
/>
</div>
)}

+ 1
- 1
server/sonar-web/src/main/js/apps/users/components/TokensFormModal.tsx View File

@@ -33,7 +33,7 @@ interface Props {

export default function TokensFormModal(props: Props) {
return (
<Modal size="medium" contentLabel={translate('users.tokens')} onRequestClose={props.onClose}>
<Modal size="large" contentLabel={translate('users.tokens')} onRequestClose={props.onClose}>
<header className="modal-head">
<h2>
<FormattedMessage

+ 1
- 1
server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/TokensFormModal-test.tsx.snap View File

@@ -4,7 +4,7 @@ exports[`should render correctly 1`] = `
<Modal
contentLabel="users.tokens"
onRequestClose={[MockFunction]}
size="medium"
size="large"
>
<header
className="modal-head"

Loading…
Cancel
Save