1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-02-09 00:18:00 +01:00

feat: token input improvements (#5155)

Rename `Api` to `API`
Add clear btn to token input
Add arrow to project and environment input tooltips

Closes #
[1-1549](https://linear.app/unleash/issue/1-1549/token-input-improvements)

---------

Signed-off-by: andreas-unleash <andreas@getunleash.ai>
This commit is contained in:
andreas-unleash 2023-10-26 12:39:30 +03:00 committed by GitHub
parent 2c7b7c90e0
commit ee44fae6ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 55 additions and 8 deletions

View File

@ -7,7 +7,7 @@ import { useState } from 'react';
const server = testServerSetup(); const server = testServerSetup();
beforeEach(() => { beforeEach(() => {
testServerRoute(server, '/api/admin/ui-config', { testServerRoute(server, '/API/admin/ui-config', {
versionInfo: { versionInfo: {
current: { oss: 'version', enterprise: 'version' }, current: { oss: 'version', enterprise: 'version' },
}, },
@ -17,7 +17,7 @@ beforeEach(() => {
}); });
testServerRoute( testServerRoute(
server, server,
'/api/admin/projects', '/API/admin/projects',
{ {
projects: [ projects: [
{ {
@ -35,7 +35,7 @@ beforeEach(() => {
); );
testServerRoute( testServerRoute(
server, server,
'/api/admin/api-tokens', '/API/admin/API-tokens',
{ {
tokens: [ tokens: [
{ {
@ -72,7 +72,7 @@ const Component = () => {
test('should parse project and environment from token input', async () => { test('should parse project and environment from token input', async () => {
render(<Component />); render(<Component />);
const tokenInput = await screen.findByLabelText('Api token'); const tokenInput = await screen.findByLabelText('API token');
fireEvent.change(tokenInput, { fireEvent.change(tokenInput, {
target: { target: {
value: 'default:development.964a287e1b728cb5f4f3e0120df92cb5', value: 'default:development.964a287e1b728cb5f4f3e0120df92cb5',
@ -100,7 +100,7 @@ test('should parse project and environment from token input', async () => {
test('should load projects from token definition if project is []', async () => { test('should load projects from token definition if project is []', async () => {
render(<Component />); render(<Component />);
const tokenInput = await screen.findByLabelText('Api token'); const tokenInput = await screen.findByLabelText('API token');
fireEvent.change(tokenInput, { fireEvent.change(tokenInput, {
target: { value: '[]:development.964a287e1b728cb5f4f3e0120df92cb5' }, target: { value: '[]:development.964a287e1b728cb5f4f3e0120df92cb5' },
}); });
@ -127,7 +127,7 @@ test('should load projects from token definition if project is []', async () =>
test('should show an error when admin token', async () => { test('should show an error when admin token', async () => {
render(<Component />); render(<Component />);
const tokenInput = await screen.findByLabelText('Api token'); const tokenInput = await screen.findByLabelText('API token');
fireEvent.change(tokenInput, { fireEvent.change(tokenInput, {
target: { value: '*:*.964a287e1b728cb5f4f3e0120df92cb5' }, target: { value: '*:*.964a287e1b728cb5f4f3e0120df92cb5' },
}); });
@ -148,3 +148,20 @@ test('should show an error when admin token', async () => {
expect(environmentInput).toBeDisabled(); expect(environmentInput).toBeDisabled();
await screen.findByText('Admin tokens are not supported in the playground'); await screen.findByText('Admin tokens are not supported in the playground');
}); });
test('should have a working clear button when token is filled', async () => {
render(<Component />);
const tokenInput = await screen.findByLabelText('API token');
fireEvent.change(tokenInput, {
target: {
value: 'default:development.964a287e1b728cb5f4f3e0120df92cb5',
},
});
const clear = await screen.findByTestId('TOKEN_INPUT_CLEAR_BTN');
const button = within(clear).getByRole('button');
fireEvent.click(button);
expect(tokenInput).toHaveValue('');
});

View File

@ -2,6 +2,9 @@ import React, { ComponentProps, useState, VFC } from 'react';
import { import {
Autocomplete, Autocomplete,
Box, Box,
IconButton,
InputAdornment,
styled,
TextField, TextField,
Tooltip, Tooltip,
Typography, Typography,
@ -20,6 +23,7 @@ import {
extractProjectEnvironmentFromToken, extractProjectEnvironmentFromToken,
validateTokenFormat, validateTokenFormat,
} from '../../playground.utils'; } from '../../playground.utils';
import { Clear } from '@mui/icons-material';
interface IPlaygroundConnectionFieldsetProps { interface IPlaygroundConnectionFieldsetProps {
environments: string[]; environments: string[];
@ -38,6 +42,10 @@ interface IOption {
const allOption: IOption = { label: 'ALL', id: '*' }; const allOption: IOption = { label: 'ALL', id: '*' };
const SmallClear = styled(Clear)({
fontSize: '1.25rem',
});
export const PlaygroundConnectionFieldset: VFC< export const PlaygroundConnectionFieldset: VFC<
IPlaygroundConnectionFieldsetProps IPlaygroundConnectionFieldsetProps
> = ({ > = ({
@ -201,6 +209,23 @@ export const PlaygroundConnectionFieldset: VFC<
setTokenError(undefined); setTokenError(undefined);
}; };
const clearToken = () => {
setToken?.('');
resetTokenState();
};
const renderClearButton = () => (
<InputAdornment position='end' data-testid='TOKEN_INPUT_CLEAR_BTN'>
<IconButton
aria-label='toggle password visibility'
onClick={clearToken}
edge='end'
>
<SmallClear />
</IconButton>
</InputAdornment>
);
return ( return (
<Box sx={{ pb: 2 }}> <Box sx={{ pb: 2 }}>
<Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}> <Box sx={{ display: 'flex', alignItems: 'center', mb: 2 }}>
@ -214,6 +239,7 @@ export const PlaygroundConnectionFieldset: VFC<
</Box> </Box>
<Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}> <Box sx={{ display: 'flex', gap: 2, flexWrap: 'wrap' }}>
<Tooltip <Tooltip
arrow
title={ title={
token token
? 'Environment is automatically selected because you are using a token' ? 'Environment is automatically selected because you are using a token'
@ -241,6 +267,7 @@ export const PlaygroundConnectionFieldset: VFC<
/> />
</Tooltip> </Tooltip>
<Tooltip <Tooltip
arrow
title={ title={
token token
? 'Project is automatically selected because you are using a token' ? 'Project is automatically selected because you are using a token'
@ -279,14 +306,17 @@ export const PlaygroundConnectionFieldset: VFC<
show={ show={
<Input <Input
sx={{ mt: 2, width: '50%', pr: 1 }} sx={{ mt: 2, width: '50%', pr: 1 }}
label='Api token' label='API token'
value={token || ''} value={token || ''}
onChange={onSetToken} onChange={onSetToken}
type={'text'} type={'text'}
error={Boolean(tokenError)} error={Boolean(tokenError)}
errorText={tokenError} errorText={tokenError}
placeholder={'Enter your api token'} placeholder={'Enter your API token'}
data-testid={'PLAYGROUND_TOKEN_INPUT'} data-testid={'PLAYGROUND_TOKEN_INPUT'}
InputProps={{
endAdornment: token ? renderClearButton() : null,
}}
/> />
} }
/> />