diff --git a/ee/tabby-ui/app/(dashboard)/settings/team/components/invitation-table.tsx b/ee/tabby-ui/app/(dashboard)/settings/team/components/invitation-table.tsx index ce36ae690256..e4fda868791b 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/team/components/invitation-table.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/team/components/invitation-table.tsx @@ -35,7 +35,7 @@ import CreateInvitationForm from './create-invitation-form' const deleteInvitationMutation = graphql(/* GraphQL */ ` mutation DeleteInvitation($id: ID!) { - deleteInvitationNext(id: $id) + deleteInvitation(id: $id) } `) @@ -50,8 +50,8 @@ export default function InvitationTable() { const [fetchingLastPage, setFetchingLastPage] = React.useState(false) const [currentPage, setCurrentPage] = React.useState(1) - const edges = data?.invitationsNext?.edges - const pageInfo = data?.invitationsNext?.pageInfo + const edges = data?.invitations?.edges + const pageInfo = data?.invitations?.pageInfo const pageNum = Math.ceil((edges?.length || 0) / PAGE_SIZE) const currentPageInvits = React.useMemo(() => { @@ -72,8 +72,8 @@ export default function InvitationTable() { cursor?: string ): Promise => { const res = await fetchInvitations({ first: PAGE_SIZE, after: cursor }) - let count = res?.data?.invitationsNext?.edges?.length || 0 - const _pageInfo = res?.data?.invitationsNext?.pageInfo + let count = res?.data?.invitations?.edges?.length || 0 + const _pageInfo = res?.data?.invitations?.pageInfo if (_pageInfo?.hasNextPage && _pageInfo?.endCursor) { // cacheExchange will merge the edges count = await fetchInvitationsSequentially(_pageInfo.endCursor) @@ -121,7 +121,7 @@ export default function InvitationTable() { fetchInvitations({ first: PAGE_SIZE, after: pageInfo?.endCursor }).then( data => { - if (data?.data?.invitationsNext?.edges?.length) { + if (data?.data?.invitations?.edges?.length) { setCurrentPage(p => p + 1) } } @@ -134,7 +134,7 @@ export default function InvitationTable() { toast.error(res.error.message) return } - if (res?.data?.deleteInvitationNext) { + if (res?.data?.deleteInvitation) { toast.success(`${node.email} deleted`) } }) diff --git a/ee/tabby-ui/app/(dashboard)/settings/team/components/user-table.tsx b/ee/tabby-ui/app/(dashboard)/settings/team/components/user-table.tsx index 4fdf24c5958e..e418ea249fb4 100644 --- a/ee/tabby-ui/app/(dashboard)/settings/team/components/user-table.tsx +++ b/ee/tabby-ui/app/(dashboard)/settings/team/components/user-table.tsx @@ -6,7 +6,7 @@ import { toast } from 'sonner' import { useQuery } from 'urql' import { graphql } from '@/lib/gql/generates' -import type { ListUsersNextQuery } from '@/lib/gql/generates/graphql' +import type { ListUsersQuery } from '@/lib/gql/generates/graphql' import { QueryVariables, useMutation } from '@/lib/tabby/gql' import type { ArrayElementType } from '@/lib/types' import { Badge } from '@/components/ui/badge' @@ -35,13 +35,8 @@ import { } from '@/components/ui/table' const listUsers = graphql(/* GraphQL */ ` - query ListUsersNext( - $after: String - $before: String - $first: Int - $last: Int - ) { - usersNext(after: $after, before: $before, first: $first, last: $last) { + query ListUsers($after: String, $before: String, $first: Int, $last: Int) { + users(after: $after, before: $before, first: $first, last: $last) { edges { node { id @@ -77,10 +72,10 @@ export default function UsersTable() { query: listUsers, variables: queryVariables }) - const [users, setUsers] = React.useState() + const [users, setUsers] = React.useState() React.useEffect(() => { - const _users = data?.usersNext + const _users = data?.users if (_users?.edges?.length) { setUsers(_users) } @@ -95,7 +90,7 @@ export default function UsersTable() { const updateUserActive = useMutation(updateUserActiveMutation) const onUpdateUserActive = ( - node: ArrayElementType['node'], + node: ArrayElementType['node'], active: boolean ) => { updateUserActive({ id: node.id, active }).then(response => { diff --git a/ee/tabby-ui/lib/tabby/gql.ts b/ee/tabby-ui/lib/tabby/gql.ts index 0dc71b9a0037..7406a48f69e4 100644 --- a/ee/tabby-ui/lib/tabby/gql.ts +++ b/ee/tabby-ui/lib/tabby/gql.ts @@ -95,16 +95,16 @@ const client = new Client({ cacheExchange({ resolvers: { Query: { - invitationsNext: relayPagination() + invitations: relayPagination() } }, updates: { Mutation: { - deleteInvitationNext(result, args, cache, info) { - if (result.deleteInvitationNext) { + deleteInvitation(result, args, cache, info) { + if (result.deleteInvitation) { cache .inspectFields('Query') - .filter(field => field.fieldName === 'invitationsNext') + .filter(field => field.fieldName === 'invitations') .forEach(field => { cache.updateQuery( { @@ -113,11 +113,10 @@ const client = new Client({ field.arguments as ListInvitationsQueryVariables }, data => { - if (data?.invitationsNext?.edges) { - data.invitationsNext.edges = - data.invitationsNext.edges.filter( - e => e.node.id !== args.id - ) + if (data?.invitations?.edges) { + data.invitations.edges = data.invitations.edges.filter( + e => e.node.id !== args.id + ) } return data } diff --git a/ee/tabby-ui/lib/tabby/query.ts b/ee/tabby-ui/lib/tabby/query.ts index ccacb6458437..f382d2fb4386 100644 --- a/ee/tabby-ui/lib/tabby/query.ts +++ b/ee/tabby-ui/lib/tabby/query.ts @@ -7,12 +7,7 @@ export const listInvitations = graphql(/* GraphQL */ ` $first: Int $last: Int ) { - invitationsNext( - after: $after - before: $before - first: $first - last: $last - ) { + invitations(after: $after, before: $before, first: $first, last: $last) { edges { node { id diff --git a/ee/tabby-webserver/graphql/schema.graphql b/ee/tabby-webserver/graphql/schema.graphql index dc69fc19659e..35f1826c45d9 100644 --- a/ee/tabby-webserver/graphql/schema.graphql +++ b/ee/tabby-webserver/graphql/schema.graphql @@ -12,11 +12,10 @@ type Mutation { verifyToken(token: String!): VerifyTokenResponse! refreshToken(refreshToken: String!): RefreshTokenResponse! createInvitation(email: String!): ID! - deleteInvitation(id: Int!): Int! @deprecated createRepository(name: String!, gitUrl: String!): ID! deleteRepository(id: ID!): Boolean! updateRepository(id: ID!, name: String!, gitUrl: String!): Boolean! - deleteInvitationNext(id: ID!): ID! + deleteInvitation(id: ID!): ID! updateOauthCredential(provider: OAuthProvider!, clientId: String!, clientSecret: String!, redirectUri: String): Boolean! updateEmailSetting(smtpUsername: String!, smtpPassword: String, smtpServer: String!): Boolean! deleteEmailSetting: Boolean! @@ -55,11 +54,9 @@ type Query { workers: [Worker!]! registrationToken: String! isAdminInitialized: Boolean! - invitations: [Invitation!]! @deprecated me: User! - users: [User!]! @deprecated - usersNext(after: String, before: String, first: Int, last: Int): UserConnection! - invitationsNext(after: String, before: String, first: Int, last: Int): InvitationConnection! + users(after: String, before: String, first: Int, last: Int): UserConnection! + invitations(after: String, before: String, first: Int, last: Int): InvitationConnection! jobRuns(after: String, before: String, first: Int, last: Int): JobRunConnection! emailSetting: EmailSetting repositories(after: String, before: String, first: Int, last: Int): RepositoryConnection! @@ -92,13 +89,6 @@ type RepositoryConnection { pageInfo: PageInfo! } -type InvitationNext { - id: ID! - email: String! - code: String! - createdAt: String! -} - type UserConnection { edges: [UserEdge!]! pageInfo: PageInfo! @@ -107,6 +97,8 @@ type UserConnection { type OAuthCredential { provider: OAuthProvider! clientId: String! + "Won't be passed to client side." + clientSecret: String redirectUri: String createdAt: DateTimeUtc! updatedAt: DateTimeUtc! @@ -117,7 +109,7 @@ type VerifyTokenResponse { } type Invitation { - id: Int! + id: ID! email: String! code: String! createdAt: String! @@ -154,7 +146,7 @@ type Worker { } type InvitationEdge { - node: InvitationNext! + node: Invitation! cursor: String! } diff --git a/ee/tabby-webserver/src/schema/auth.rs b/ee/tabby-webserver/src/schema/auth.rs index a774778a33fe..8a9a5928b24b 100644 --- a/ee/tabby-webserver/src/schema/auth.rs +++ b/ee/tabby-webserver/src/schema/auth.rs @@ -296,30 +296,9 @@ impl relay::NodeType for User { } } -#[deprecated] -#[derive(Debug, Default, Serialize, Deserialize, GraphQLObject)] -pub struct Invitation { - pub id: i32, - pub email: String, - pub code: String, - - pub created_at: String, -} - -impl From for Invitation { - fn from(value: InvitationNext) -> Self { - Self { - id: value.id.parse::().unwrap(), - email: value.email, - code: value.code, - created_at: value.created_at, - } - } -} - #[derive(Debug, Serialize, Deserialize, GraphQLObject)] #[graphql(context = Context)] -pub struct InvitationNext { +pub struct Invitation { pub id: juniper::ID, pub email: String, pub code: String, @@ -327,7 +306,7 @@ pub struct InvitationNext { pub created_at: String, } -impl relay::NodeType for InvitationNext { +impl relay::NodeType for Invitation { type Cursor = String; fn cursor(&self) -> Self::Cursor { @@ -406,7 +385,7 @@ pub trait AuthenticationService: Send + Sync { before: Option, first: Option, last: Option, - ) -> Result>; + ) -> Result>; async fn oauth( &self, diff --git a/ee/tabby-webserver/src/schema/dao.rs b/ee/tabby-webserver/src/schema/dao.rs index bb90a8fc2487..b7b0e2204d0b 100644 --- a/ee/tabby-webserver/src/schema/dao.rs +++ b/ee/tabby-webserver/src/schema/dao.rs @@ -10,7 +10,7 @@ use crate::schema::{ job, }; -impl From for auth::InvitationNext { +impl From for auth::Invitation { fn from(val: InvitationDAO) -> Self { Self { id: juniper::ID::new(val.id.to_string()), diff --git a/ee/tabby-webserver/src/schema/mod.rs b/ee/tabby-webserver/src/schema/mod.rs index 52098806b583..a44ae7521c70 100644 --- a/ee/tabby-webserver/src/schema/mod.rs +++ b/ee/tabby-webserver/src/schema/mod.rs @@ -8,9 +8,8 @@ pub mod worker; use std::{num::ParseIntError, sync::Arc}; use auth::{ - validate_jwt, AuthenticationService, Invitation, InvitationNext, RefreshTokenError, - RefreshTokenResponse, RegisterError, RegisterResponse, TokenAuthError, TokenAuthResponse, User, - VerifyTokenResponse, + validate_jwt, AuthenticationService, Invitation, RefreshTokenError, RefreshTokenResponse, + RegisterError, RegisterResponse, TokenAuthError, TokenAuthResponse, User, VerifyTokenResponse, }; use job::{JobRun, JobService}; use juniper::{ @@ -118,25 +117,6 @@ impl Query { Ok(ctx.locator.auth().is_admin_initialized().await?) } - #[deprecated] - async fn invitations(ctx: &Context) -> Result> { - if let Some(claims) = &ctx.claims { - if claims.is_admin { - return Ok(ctx - .locator - .auth() - .list_invitations(None, None, None, None) - .await? - .into_iter() - .map(|x| x.into()) - .collect()); - } - } - Err(CoreError::Unauthorized( - "Only admin is able to query invitations", - )) - } - async fn me(ctx: &Context) -> Result { if let Some(claims) = &ctx.claims { let user = ctx.locator.auth().get_user_by_email(&claims.sub).await?; @@ -146,21 +126,7 @@ impl Query { } } - #[deprecated] - async fn users(ctx: &Context) -> Result> { - if let Some(claims) = &ctx.claims { - if claims.is_admin { - return Ok(ctx - .locator - .auth() - .list_users(None, None, None, None) - .await?); - } - } - Err(CoreError::Unauthorized("Only admin is able to query users")) - } - - async fn users_next( + async fn users( ctx: &Context, after: Option, before: Option, @@ -194,13 +160,13 @@ impl Query { ))) } - async fn invitations_next( + async fn invitations( ctx: &Context, after: Option, before: Option, first: Option, last: Option, - ) -> FieldResult> { + ) -> FieldResult> { if let Some(claims) = &ctx.claims { if claims.is_admin { return relay::query_async( @@ -397,23 +363,6 @@ impl Mutation { Ok(ID::new(invitation.id.to_string())) } - #[deprecated] - async fn delete_invitation(ctx: &Context, id: i32) -> Result { - if let Some(claims) = &ctx.claims { - if claims.is_admin { - let id = ctx - .locator - .auth() - .delete_invitation(ID::new(id.to_string())) - .await?; - return Ok(id.parse::().unwrap()); - } - } - Err(CoreError::Unauthorized( - "Only admin is able to delete invitation", - )) - } - async fn create_repository( ctx: &Context, name: String, @@ -442,7 +391,7 @@ impl Mutation { .await?) } - async fn delete_invitation_next(ctx: &Context, id: ID) -> Result { + async fn delete_invitation(ctx: &Context, id: ID) -> Result { if let Some(claims) = &ctx.claims { if claims.is_admin { return Ok(ctx.locator.auth().delete_invitation(id).await?); diff --git a/ee/tabby-webserver/src/service/auth.rs b/ee/tabby-webserver/src/service/auth.rs index 59909a10d461..be612913adce 100644 --- a/ee/tabby-webserver/src/service/auth.rs +++ b/ee/tabby-webserver/src/service/auth.rs @@ -15,7 +15,7 @@ use super::graphql_pagination_to_filter; use crate::{ oauth, schema::auth::{ - generate_jwt, generate_refresh_token, validate_jwt, AuthenticationService, InvitationNext, + generate_jwt, generate_refresh_token, validate_jwt, AuthenticationService, Invitation, JWTPayload, OAuthCredential, OAuthError, OAuthProvider, OAuthResponse, RefreshTokenError, RefreshTokenResponse, RegisterError, RegisterResponse, TokenAuthError, TokenAuthResponse, User, VerifyTokenResponse, @@ -329,7 +329,7 @@ impl AuthenticationService for DbConn { before: Option, first: Option, last: Option, - ) -> Result> { + ) -> Result> { let (limit, skip_id, backwards) = graphql_pagination_to_filter(after, before, first, last)?; Ok(self .list_invitations_with_filter(limit, skip_id, backwards)