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

feat: add input for api token in playground #5130

Merged
merged 13 commits into from
Oct 25, 2023

Conversation

andreas-unleash
Copy link
Contributor

@andreas-unleash andreas-unleash commented Oct 23, 2023

Adds a token input in playground.

In the case of tokens that span multiple projects ie []:development.etc it will look into the token definitions to find the token and get the projects

Otherwise it will try to parse the project and environment from the token itself (without checking for it being a valid token)

Also, does not support admin tokens *:*.etc

Closes # 1-1507
Screenshot 2023-10-23 at 16 38 11
Screenshot 2023-10-23 at 16 38 33

Screenshot 2023-10-25 at 17 06 43

@vercel
Copy link

vercel bot commented Oct 23, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
unleash-monorepo-frontend ✅ Ready (Inspect) Visit Preview 💬 Add feedback Oct 25, 2023 2:44pm
1 Ignored Deployment
Name Status Preview Comments Updated (UTC)
unleash-docs ⬜️ Ignored (Inspect) Visit Preview Oct 25, 2023 2:44pm

Copy link
Contributor

@kwasniew kwasniew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"If valid token, use the properties to populate the projects and environments inputs" - can we add a test that proves it?

Signed-off-by: andreas-unleash <[email protected]>
Signed-off-by: andreas-unleash <[email protected]>
Signed-off-by: andreas-unleash <[email protected]>
Signed-off-by: andreas-unleash <[email protected]>
Signed-off-by: andreas-unleash <[email protected]>
Signed-off-by: andreas-unleash <[email protected]>
Signed-off-by: andreas-unleash <[email protected]>

const envValue = environmentOptions.filter(({ id }) =>
environments.includes(id),
);

const onSetToken: ComponentProps<typeof TextField>['onChange'] = async (
Copy link
Contributor

@kwasniew kwasniew Oct 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd suggest to break the algorithm into smaller focused functions so that a reader can figure out the high level algorithm w/o reading all the details

E.g.

const onSetToken: ComponentProps<typeof TextField>['onChange'] = async (event) => {
    const tempToken = event.target.value;
    setToken?.(tempToken);

    if (tempToken === '') {
        resetTokenState();
        return;
    }

    try {
        validateTokenFormat(tempToken);
        const [tokenProject, tokenEnvironment] = extractProjectEnvironmentFromToken(tempToken);

        handleTokenProcessing(tokenProject, tempToken);
    } catch (e: any) {
        setTokenError(e.message);
    }
};

const resetTokenState = () => {
    setTokenError(undefined);
}

const handleTokenProcessing = (tokenProject: string, tempToken: string) => {
    setTokenError(undefined);
    setEnvironments([tokenEnvironment]);

    if (tokenProject === '[]') {
        processTokenWithEmptyProject(tempToken);
        return;
    }
    
    if (tokenProject === '*') {
        setProjects([allOption.id]);
        return;
    }

    validateTokenProject(tokenProject);
}

const processTokenWithEmptyProject = (tempToken: string) => {
    const validToken = tokens.find(({ secret }) => secret === tempToken);
    
    if (validToken) {
        if (!validToken.projects) {
            setProjects([allOption.id]);
        } else if (typeof validToken.projects === 'string') {
            setProjects([validToken.projects]);
        } else if (Array.isArray(validToken.projects)) {
            setProjects(validToken.projects);
        }
    } else {
        setTokenError('Invalid token. Please make sure you are using a valid token from this Unleash instance');
    }
}

const validateTokenProject = (tokenProject: string) => {
    if (!projectsOptions.map((option) => option.id).includes(tokenProject)) {
        setTokenError(`Invalid token. Project ${tokenProject} does not exist`);
    } else {
        setProjects([tokenProject]);
    }
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure thing. thanks

@@ -125,3 +125,20 @@ export const normalizeCustomContextProperties = (

return output;
};

export const validateTokenFormat = (token: string): void => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lots of interesting things to unit test with a dedicated test w/o the UI.

E.g

    it('should not throw an error for a valid token format', () => {
        const validToken = 'project:environment.otherstuff';
        expect(() => validateTokenFormat(validToken)).not.toThrow();
    });

    it('should throw an error if the token does not have a project or environment', () => {
        const invalidToken1 = '.otherstuff';  // Missing project and environment
        const invalidToken2 = 'project.otherstuff';  // Missing ':'
        const invalidToken3 = 'project:.otherstuff';  // Missing environment

        expect(() => validateTokenFormat(invalidToken1)).toThrow('Invalid token format');
        expect(() => validateTokenFormat(invalidToken2)).toThrow('Invalid token format');
        expect(() => validateTokenFormat(invalidToken3)).toThrow('Invalid token format');
    });

    it('should throw an error if the environment is an admin token', () => {
        const adminToken = 'project:*.otherstuff';
        expect(() => validateTokenFormat(adminToken)).toThrow('Admin tokens are not supported in the playground');
    });

    it('should not throw an error if the environment is not an admin token', () => {
        const validToken = 'project:dev.otherstuff';
        expect(() => validateTokenFormat(validToken)).not.toThrow();
    });

Copy link
Contributor

@kwasniew kwasniew left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work. Added some extra hints but non-blocking approve

Signed-off-by: andreas-unleash <[email protected]>
Signed-off-by: andreas-unleash <[email protected]>
Signed-off-by: andreas-unleash <[email protected]>
@andreas-unleash andreas-unleash merged commit 8e3863a into main Oct 25, 2023
12 checks passed
@andreas-unleash andreas-unleash deleted the feat/add_token_input_playground branch October 25, 2023 14:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants