mirror of
				https://github.com/Unleash/unleash.git
				synced 2025-10-27 11:02:16 +01:00 
			
		
		
		
	Feat: embedded proxy token (#1222)
* initial frontend for embedded proxy token * update wording on tokens * embedded proxy feature flag * update in-app guidance for api tokens * simplify token form flag
This commit is contained in:
		
							parent
							
								
									98376d73d3
								
							
						
					
					
						commit
						1335e02648
					
				@ -9,15 +9,15 @@ export const ApiTokenDocs = () => {
 | 
				
			|||||||
            <p>
 | 
					            <p>
 | 
				
			||||||
                Read the{' '}
 | 
					                Read the{' '}
 | 
				
			||||||
                <a
 | 
					                <a
 | 
				
			||||||
                    href="https://docs.getunleash.io/docs"
 | 
					                    href="https://docs.getunleash.io/sdks"
 | 
				
			||||||
                    target="_blank"
 | 
					                    target="_blank"
 | 
				
			||||||
                    rel="noreferrer"
 | 
					                    rel="noreferrer"
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                    Getting started guide
 | 
					                    SDK overview
 | 
				
			||||||
                </a>{' '}
 | 
					                </a>{' '}
 | 
				
			||||||
                to learn how to connect to the Unleash API from your application
 | 
					                to connect Unleash to your application. Please note it can take
 | 
				
			||||||
                or programmatically. Please note it can take up to 1 minute
 | 
					                up to <strong>1 minute</strong> before a new API key is
 | 
				
			||||||
                before a new API key is activated.
 | 
					                activated.
 | 
				
			||||||
            </p>
 | 
					            </p>
 | 
				
			||||||
            <br />
 | 
					            <br />
 | 
				
			||||||
            <strong>API URL: </strong>{' '}
 | 
					            <strong>API URL: </strong>{' '}
 | 
				
			||||||
 | 
				
			|||||||
@ -17,6 +17,15 @@ export const useStyles = makeStyles()(theme => ({
 | 
				
			|||||||
            minWidth: '379px',
 | 
					            minWidth: '379px',
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    radioGroup: {
 | 
				
			||||||
 | 
					        marginBottom: theme.spacing(2),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    radioItem: {
 | 
				
			||||||
 | 
					        marginBottom: theme.spacing(1),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    radio: {
 | 
				
			||||||
 | 
					        marginLeft: theme.spacing(1.5),
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    label: {
 | 
					    label: {
 | 
				
			||||||
        minWidth: '300px',
 | 
					        minWidth: '300px',
 | 
				
			||||||
        [theme.breakpoints.down(600)]: {
 | 
					        [theme.breakpoints.down(600)]: {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,13 +1,22 @@
 | 
				
			|||||||
import { Button } from '@mui/material';
 | 
					import {
 | 
				
			||||||
 | 
					    Button,
 | 
				
			||||||
 | 
					    FormControl,
 | 
				
			||||||
 | 
					    FormControlLabel,
 | 
				
			||||||
 | 
					    Radio,
 | 
				
			||||||
 | 
					    RadioGroup,
 | 
				
			||||||
 | 
					    Typography,
 | 
				
			||||||
 | 
					} from '@mui/material';
 | 
				
			||||||
import { KeyboardArrowDownOutlined } from '@mui/icons-material';
 | 
					import { KeyboardArrowDownOutlined } from '@mui/icons-material';
 | 
				
			||||||
import React from 'react';
 | 
					import React from 'react';
 | 
				
			||||||
import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
 | 
					import { useEnvironments } from 'hooks/api/getters/useEnvironments/useEnvironments';
 | 
				
			||||||
import useProjects from 'hooks/api/getters/useProjects/useProjects';
 | 
					import useProjects from 'hooks/api/getters/useProjects/useProjects';
 | 
				
			||||||
import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
 | 
					import GeneralSelect from 'component/common/GeneralSelect/GeneralSelect';
 | 
				
			||||||
import Input from 'component/common/Input/Input';
 | 
					import Input from 'component/common/Input/Input';
 | 
				
			||||||
import { useStyles } from './ApiTokenForm.styles';
 | 
					import useUiConfig from 'hooks/api/getters/useUiConfig/useUiConfig';
 | 
				
			||||||
import { SelectProjectInput } from './SelectProjectInput/SelectProjectInput';
 | 
					import { SelectProjectInput } from './SelectProjectInput/SelectProjectInput';
 | 
				
			||||||
import { ApiTokenFormErrorType } from 'component/admin/apiToken/ApiTokenForm/useApiTokenForm';
 | 
					import { ApiTokenFormErrorType } from './useApiTokenForm';
 | 
				
			||||||
 | 
					import { useStyles } from './ApiTokenForm.styles';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
interface IApiTokenFormProps {
 | 
					interface IApiTokenFormProps {
 | 
				
			||||||
    username: string;
 | 
					    username: string;
 | 
				
			||||||
    type: string;
 | 
					    type: string;
 | 
				
			||||||
@ -40,15 +49,32 @@ const ApiTokenForm: React.FC<IApiTokenFormProps> = ({
 | 
				
			|||||||
    clearErrors,
 | 
					    clearErrors,
 | 
				
			||||||
}) => {
 | 
					}) => {
 | 
				
			||||||
    const TYPE_ADMIN = 'ADMIN';
 | 
					    const TYPE_ADMIN = 'ADMIN';
 | 
				
			||||||
 | 
					    const { uiConfig } = useUiConfig();
 | 
				
			||||||
    const { classes: styles } = useStyles();
 | 
					    const { classes: styles } = useStyles();
 | 
				
			||||||
    const { environments } = useEnvironments();
 | 
					    const { environments } = useEnvironments();
 | 
				
			||||||
    const { projects: availableProjects } = useProjects();
 | 
					    const { projects: availableProjects } = useProjects();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const selectableTypes = [
 | 
					    const selectableTypes = [
 | 
				
			||||||
        { key: 'CLIENT', label: 'Client', title: 'Client SDK token' },
 | 
					        {
 | 
				
			||||||
        { key: 'ADMIN', label: 'Admin', title: 'Admin API token' },
 | 
					            key: 'CLIENT',
 | 
				
			||||||
 | 
					            label: 'Server-side SDK (CLIENT)',
 | 
				
			||||||
 | 
					            title: 'Connect server-side SDK or Unleash Proxy',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            key: 'ADMIN',
 | 
				
			||||||
 | 
					            label: 'ADMIN',
 | 
				
			||||||
 | 
					            title: 'Full access for managing Unleash',
 | 
				
			||||||
 | 
					        },
 | 
				
			||||||
    ];
 | 
					    ];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (uiConfig.embedProxy) {
 | 
				
			||||||
 | 
					        selectableTypes.splice(1, 0, {
 | 
				
			||||||
 | 
					            key: 'FRONTEND',
 | 
				
			||||||
 | 
					            label: 'Client-side SDK (FRONTEND)',
 | 
				
			||||||
 | 
					            title: 'Connect web and mobile SDK directly to Unleash',
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    const selectableProjects = availableProjects.map(project => ({
 | 
					    const selectableProjects = availableProjects.map(project => ({
 | 
				
			||||||
        value: project.id,
 | 
					        value: project.id,
 | 
				
			||||||
        label: project.name,
 | 
					        label: project.name,
 | 
				
			||||||
@ -81,20 +107,38 @@ const ApiTokenForm: React.FC<IApiTokenFormProps> = ({
 | 
				
			|||||||
                    onFocus={() => clearErrors('username')}
 | 
					                    onFocus={() => clearErrors('username')}
 | 
				
			||||||
                    autoFocus
 | 
					                    autoFocus
 | 
				
			||||||
                />
 | 
					                />
 | 
				
			||||||
                <p className={styles.inputDescription}>
 | 
					                <FormControl className={styles.radioGroup}>
 | 
				
			||||||
                    What is your token type?
 | 
					                    <label id="token-type" className={styles.inputDescription}>
 | 
				
			||||||
                </p>
 | 
					                        What do you want to connect?
 | 
				
			||||||
                <GeneralSelect
 | 
					                    </label>
 | 
				
			||||||
                    options={selectableTypes}
 | 
					                    <RadioGroup
 | 
				
			||||||
                    value={type}
 | 
					                        aria-labelledby="token-type"
 | 
				
			||||||
                    onChange={setTokenType}
 | 
					                        defaultValue="CLIENT"
 | 
				
			||||||
                    label="Token Type"
 | 
					                        name="radio-buttons-group"
 | 
				
			||||||
                    id="api_key_type"
 | 
					                        value={type}
 | 
				
			||||||
                    name="type"
 | 
					                        onChange={(event, value) => setTokenType(value)}
 | 
				
			||||||
                    IconComponent={KeyboardArrowDownOutlined}
 | 
					                    >
 | 
				
			||||||
                    fullWidth
 | 
					                        {selectableTypes.map(({ key, label, title }) => (
 | 
				
			||||||
                    className={styles.selectInput}
 | 
					                            <FormControlLabel
 | 
				
			||||||
                />
 | 
					                                key={key}
 | 
				
			||||||
 | 
					                                value={key}
 | 
				
			||||||
 | 
					                                className={styles.radioItem}
 | 
				
			||||||
 | 
					                                control={<Radio className={styles.radio} />}
 | 
				
			||||||
 | 
					                                label={
 | 
				
			||||||
 | 
					                                    <>
 | 
				
			||||||
 | 
					                                        <Typography>{label}</Typography>
 | 
				
			||||||
 | 
					                                        <Typography
 | 
				
			||||||
 | 
					                                            variant="body2"
 | 
				
			||||||
 | 
					                                            color="text.secondary"
 | 
				
			||||||
 | 
					                                        >
 | 
				
			||||||
 | 
					                                            {title}
 | 
				
			||||||
 | 
					                                        </Typography>
 | 
				
			||||||
 | 
					                                    </>
 | 
				
			||||||
 | 
					                                }
 | 
				
			||||||
 | 
					                            />
 | 
				
			||||||
 | 
					                        ))}
 | 
				
			||||||
 | 
					                    </RadioGroup>
 | 
				
			||||||
 | 
					                </FormControl>
 | 
				
			||||||
                <p className={styles.inputDescription}>
 | 
					                <p className={styles.inputDescription}>
 | 
				
			||||||
                    Which project do you want to give access to?
 | 
					                    Which project do you want to give access to?
 | 
				
			||||||
                </p>
 | 
					                </p>
 | 
				
			||||||
 | 
				
			|||||||
@ -78,9 +78,14 @@ export const ApiTokenTable = () => {
 | 
				
			|||||||
                />
 | 
					                />
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        >
 | 
					        >
 | 
				
			||||||
            <Box sx={{ mb: 4 }}>
 | 
					            <ConditionallyRender
 | 
				
			||||||
                <ApiTokenDocs />
 | 
					                condition={rows.length > 0}
 | 
				
			||||||
            </Box>
 | 
					                show={
 | 
				
			||||||
 | 
					                    <Box sx={{ mb: 4 }}>
 | 
				
			||||||
 | 
					                        <ApiTokenDocs />
 | 
				
			||||||
 | 
					                    </Box>
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
            <Box sx={{ overflowX: 'auto' }}>
 | 
					            <Box sx={{ overflowX: 'auto' }}>
 | 
				
			||||||
                <SearchHighlightProvider value={globalFilter}>
 | 
					                <SearchHighlightProvider value={globalFilter}>
 | 
				
			||||||
                    <Table {...getTableProps()}>
 | 
					                    <Table {...getTableProps()}>
 | 
				
			||||||
@ -118,7 +123,17 @@ export const ApiTokenTable = () => {
 | 
				
			|||||||
                        }
 | 
					                        }
 | 
				
			||||||
                        elseShow={
 | 
					                        elseShow={
 | 
				
			||||||
                            <TablePlaceholder>
 | 
					                            <TablePlaceholder>
 | 
				
			||||||
                                No tokens available. Get started by adding one.
 | 
					                                <span>
 | 
				
			||||||
 | 
					                                    {'No tokens available. Read '}
 | 
				
			||||||
 | 
					                                    <a
 | 
				
			||||||
 | 
					                                        href="https://docs.getunleash.io/how-to/api"
 | 
				
			||||||
 | 
					                                        target="_blank"
 | 
				
			||||||
 | 
					                                        rel="noreferrer"
 | 
				
			||||||
 | 
					                                    >
 | 
				
			||||||
 | 
					                                        API How-to guides
 | 
				
			||||||
 | 
					                                    </a>{' '}
 | 
				
			||||||
 | 
					                                    {' to learn more.'}
 | 
				
			||||||
 | 
					                                </span>
 | 
				
			||||||
                            </TablePlaceholder>
 | 
					                            </TablePlaceholder>
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    />
 | 
					                    />
 | 
				
			||||||
@ -128,6 +143,21 @@ export const ApiTokenTable = () => {
 | 
				
			|||||||
    );
 | 
					    );
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const tokenDescriptions = {
 | 
				
			||||||
 | 
					    client: {
 | 
				
			||||||
 | 
					        label: 'CLIENT',
 | 
				
			||||||
 | 
					        title: 'Connect server-side SDK or Unleash Proxy',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    frontend: {
 | 
				
			||||||
 | 
					        label: 'FRONTEND',
 | 
				
			||||||
 | 
					        title: 'Connect web and mobile SDK',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    admin: {
 | 
				
			||||||
 | 
					        label: 'ADMIN',
 | 
				
			||||||
 | 
					        title: 'Full access for managing Unleash',
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const COLUMNS = [
 | 
					const COLUMNS = [
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        id: 'Icon',
 | 
					        id: 'Icon',
 | 
				
			||||||
@ -144,10 +174,13 @@ const COLUMNS = [
 | 
				
			|||||||
    {
 | 
					    {
 | 
				
			||||||
        Header: 'Type',
 | 
					        Header: 'Type',
 | 
				
			||||||
        accessor: 'type',
 | 
					        accessor: 'type',
 | 
				
			||||||
        Cell: ({ value }: { value: string }) => (
 | 
					        Cell: ({ value }: { value: 'admin' | 'client' | 'frontend' }) => (
 | 
				
			||||||
            <HighlightCell value={value.toUpperCase()} />
 | 
					            <HighlightCell
 | 
				
			||||||
 | 
					                value={tokenDescriptions[value].label}
 | 
				
			||||||
 | 
					                subtitle={tokenDescriptions[value].title}
 | 
				
			||||||
 | 
					            />
 | 
				
			||||||
        ),
 | 
					        ),
 | 
				
			||||||
        minWidth: 100,
 | 
					        minWidth: 280,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        Header: 'Project',
 | 
					        Header: 'Project',
 | 
				
			||||||
 | 
				
			|||||||
@ -16,6 +16,7 @@ export interface IUiConfig {
 | 
				
			|||||||
    toast?: IProclamationToast;
 | 
					    toast?: IProclamationToast;
 | 
				
			||||||
    segmentValuesLimit?: number;
 | 
					    segmentValuesLimit?: number;
 | 
				
			||||||
    strategySegmentsLimit?: number;
 | 
					    strategySegmentsLimit?: number;
 | 
				
			||||||
 | 
					    embedProxy?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface IProclamationToast {
 | 
					export interface IProclamationToast {
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user