refactor: remove usage of scopes for target access tokens (#6330)

This commit is contained in:
Laurin Quast 2025-01-10 16:58:36 +01:00 committed by GitHub
parent 7d3291f954
commit 24391ab6e3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 12 additions and 234 deletions

View file

@ -330,7 +330,7 @@ export class SchemaVersionHelper {
return schemaLog?.sdl ?? null;
}
async getIsValid(schemaVersion: SchemaVersion) {
getIsValid(schemaVersion: SchemaVersion) {
return schemaVersion.isComposable && schemaVersion.hasContractCompositionErrors === false;
}

View file

@ -1,9 +1,9 @@
import { useState } from 'react';
import { useForm, UseFormReturn } from 'react-hook-form';
import { AnyVariables, useMutation, UseMutationState, useQuery } from 'urql';
import { AnyVariables, useMutation, UseMutationState } from 'urql';
import { z } from 'zod';
import { Tag } from '@/components//v2/tag';
import { PermissionScopeItem, usePermissionsManager } from '@/components/organization/Permissions';
import { PermissionScopeItem } from '@/components/organization/Permissions';
import { Button } from '@/components/ui/button';
import {
Dialog,
@ -18,7 +18,7 @@ import { Input } from '@/components/ui/input';
import { InputCopy } from '@/components/ui/input-copy';
import { useToast } from '@/components/ui/use-toast';
import { Accordion } from '@/components/v2/accordion';
import { FragmentType, graphql, useFragment } from '@/gql';
import { graphql } from '@/gql';
import { TargetAccessScope } from '@/gql/graphql';
import { RegistryAccessScope } from '@/lib/access/common';
import { zodResolver } from '@hookform/resolvers/zod';
@ -48,16 +48,6 @@ export const CreateAccessToken_CreateTokenMutation = graphql(`
}
`);
const CreateAccessTokenModalQuery = graphql(`
query CreateAccessTokenModalQuery($organizationSlug: String!) {
organization(selector: { organizationSlug: $organizationSlug }) {
organization {
...CreateAccessTokenModalContent_OrganizationFragment
}
}
}
`);
export function CreateAccessTokenModal(props: {
isOpen: boolean;
toggleModalOpen: () => void;
@ -66,52 +56,19 @@ export function CreateAccessTokenModal(props: {
targetSlug: string;
}) {
const { isOpen, toggleModalOpen } = props;
const [organizationQuery] = useQuery({
query: CreateAccessTokenModalQuery,
variables: {
organizationSlug: props.organizationSlug,
},
});
const organization = organizationQuery.data?.organization?.organization;
return (
<Dialog open={isOpen} onOpenChange={toggleModalOpen}>
{organization ? (
<ModalContent
organization={organization}
organizationSlug={props.organizationSlug}
projectSlug={props.projectSlug}
targetSlug={props.targetSlug}
toggleModalOpen={toggleModalOpen}
/>
) : (
<DialogContent className="container w-4/5 max-w-[600px] md:w-3/5">
<DialogHeader>
<DialogTitle>Organization not found</DialogTitle>
<DialogDescription>
The organization you are trying to access does not exist.
</DialogDescription>
</DialogHeader>
<DialogFooter>
<Button onClick={toggleModalOpen}>Ok, got it!</Button>
</DialogFooter>
</DialogContent>
)}
<ModalContent
organizationSlug={props.organizationSlug}
projectSlug={props.projectSlug}
targetSlug={props.targetSlug}
toggleModalOpen={toggleModalOpen}
/>
</Dialog>
);
}
const CreateAccessTokenModalContent_OrganizationFragment = graphql(`
fragment CreateAccessTokenModalContent_OrganizationFragment on Organization {
id
...UsePermissionManager_OrganizationFragment
me {
...UsePermissionManager_MemberFragment
}
}
`);
function getFinalTargetAccessScopes(
selectedScope: 'no-access' | TargetAccessScope,
): Array<TargetAccessScope> {
@ -142,25 +99,14 @@ const createRegistryTokenFormSchema = z.object({
});
export function ModalContent(props: {
organization: FragmentType<typeof CreateAccessTokenModalContent_OrganizationFragment>;
organizationSlug: string;
projectSlug: string;
targetSlug: string;
toggleModalOpen: () => void;
}) {
const { toast } = useToast();
const organization = useFragment(
CreateAccessTokenModalContent_OrganizationFragment,
props.organization,
);
const [selectedScope, setSelectedScope] = useState<'no-access' | TargetAccessScope>('no-access');
const manager = usePermissionsManager({
organization,
member: organization.me,
passMemberScopes: false,
});
const form = useForm<z.infer<typeof createRegistryTokenFormSchema>>({
mode: 'onChange',
resolver: zodResolver(createRegistryTokenFormSchema),
@ -205,7 +151,6 @@ export function ModalContent(props: {
return (
<GenerateTokenContent
form={form}
manager={manager}
noPermissionsSelected={noPermissionsSelected}
onSubmit={onSubmit}
selectedScope={selectedScope} // Ensure selectedScope is passed correctly
@ -246,7 +191,6 @@ export function CreatedTokenContent(props: {
export function GenerateTokenContent(props: {
form: UseFormReturn<z.infer<typeof createRegistryTokenFormSchema>>;
onSubmit: (values: z.infer<typeof createRegistryTokenFormSchema>) => void;
manager: ReturnType<typeof usePermissionsManager>;
setSelectedScope: (scope: 'no-access' | TargetAccessScope) => void;
selectedScope: 'no-access' | TargetAccessScope;
toggleModalOpen: () => void;
@ -292,11 +236,8 @@ export function GenerateTokenContent(props: {
dataCy="registry-access-scope"
key={props.selectedScope}
scope={RegistryAccessScope}
canManageScope={
props.manager.canAccessTarget(RegistryAccessScope.mapping['read-only']) ||
props.manager.canAccessTarget(RegistryAccessScope.mapping['read-write'])
}
checkAccess={props.manager.canAccessTarget}
canManageScope
checkAccess={() => true}
onChange={value => {
if (value === 'no-access') {
props.setSelectedScope('no-access');

View file

@ -62,9 +62,6 @@ const MemberFields = graphql(`
email
}
isOwner
organizationAccessScopes
projectAccessScopes
targetAccessScopes
}
`);
@ -240,9 +237,6 @@ export const TransferOrganizationOwnershipModal = ({
>
{({ selected }: { selected?: boolean }) => (
<div className="flex flex-row items-center justify-between gap-2">
{/* <div className="ml-2.5 flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-gray-800">
<img src={member.image} className="block h-full w-full" />
</div> */}
<div className="ml-2 flex flex-1 flex-col gap-x-2">
<div className="block truncate text-sm">{member.user.displayName}</div>
<div className="text-xs font-normal text-gray-400">

View file

@ -1,6 +1,5 @@
import { FragmentType, graphql, useFragment } from '@/gql';
import { TargetAccessScope } from '@/gql/graphql';
import { useRedirect } from './common';
export { TargetAccessScope };
@ -23,40 +22,3 @@ export function canAccessTarget(
return member.targetAccessScopes.includes(scope);
}
export function useTargetAccess({
scope,
member: mmember,
redirect = false,
organizationSlug,
projectSlug,
targetSlug,
}: {
scope: TargetAccessScope;
member: null | FragmentType<typeof CanAccessTarget_MemberFragment>;
redirect?: boolean;
organizationSlug: string;
projectSlug: string;
targetSlug: string;
}) {
const member = useFragment(CanAccessTarget_MemberFragment, mmember);
const canAccess = canAccessTarget(scope, mmember);
useRedirect({
canAccess,
redirectTo: redirect
? router => {
void router.navigate({
to: '/$organizationSlug/$projectSlug/$targetSlug',
params: {
organizationSlug,
projectSlug,
targetSlug,
},
});
}
: undefined,
entity: member,
});
return canAccess;
}

View file

@ -1,119 +0,0 @@
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { z } from 'zod';
import { usePermissionsManager } from '@/components/organization/Permissions';
import {
CreatedTokenContent,
GenerateTokenContent,
} from '@/components/target/settings/registry-access-token';
import { Button } from '@/components/ui/button';
import { Dialog, DialogTrigger } from '@/components/ui/dialog';
import { TargetAccessScope } from '@/gql/graphql';
import { zodResolver } from '@hookform/resolvers/zod';
import { Meta, StoryObj } from '@storybook/react';
const meta: Meta<typeof CreatedTokenContent> = {
title: 'Modals/Create Access Token',
component: CreatedTokenContent,
};
export default meta;
type Story = StoryObj<typeof CreatedTokenContent>;
const formSchema = z.object({
tokenDescription: z
.string()
.min(2, { message: 'Token description must be at least 2 characters long' }),
});
export const GenerateToken: Story = {
render: () => {
const [openModal, setOpenModal] = useState(false);
const toggleModalOpen = () => setOpenModal(!openModal);
const form = useForm<z.infer<typeof formSchema>>({
mode: 'onChange',
resolver: zodResolver(formSchema),
defaultValues: {
tokenDescription: '',
},
});
const manager = {
canAccessOrganization: () => true,
canAccessProject: () => true,
canAccessTarget: () => true,
noneSelected: false,
organizationScopes: [],
projectScopes: [],
targetScopes: [],
setOrganizationScopes: () => {},
setProjectScopes: () => {},
setTargetScopes: () => {},
submit: () => {},
} as unknown as ReturnType<typeof usePermissionsManager>;
const [selectedScope, setSelectedScope] = useState<'no-access' | TargetAccessScope>(
'no-access',
);
const noPermissionsSelected = selectedScope === 'no-access';
return (
<Dialog open={openModal} onOpenChange={toggleModalOpen}>
<DialogTrigger asChild>
<Button onClick={toggleModalOpen}>Open Modal</Button>
</DialogTrigger>
<GenerateTokenContent
form={form}
manager={manager}
noPermissionsSelected={noPermissionsSelected}
onSubmit={values => console.log('Submit:', values)}
selectedScope={selectedScope}
setSelectedScope={setSelectedScope}
toggleModalOpen={toggleModalOpen}
/>
</Dialog>
);
},
};
export const CreatedToken: Story = {
render: () => {
const [openModal, setOpenModal] = useState(false);
const toggleModalOpen = () => setOpenModal(!openModal);
return (
<Dialog open={openModal} onOpenChange={toggleModalOpen}>
<DialogTrigger asChild>
<Button onClick={toggleModalOpen}>Open Modal</Button>
</DialogTrigger>
<CreatedTokenContent
mutation={{
fetching: false,
data: {
createToken: {
ok: {
selector: {
organization: '',
project: '',
target: '',
},
createdToken: {
id: 'token-id',
name: 'Token Name',
alias: 'token-alias',
date: '2023-07-17',
lastUsedAt: null,
},
secret: 'token-secret',
},
},
},
stale: false,
}}
toggleModalOpen={toggleModalOpen}
/>
</Dialog>
);
},
};