diff --git a/studio/components/interfaces/Organization/TeamSettings/MembersView.tsx b/studio/components/interfaces/Organization/TeamSettings/MembersView.tsx
index d6002c16996..f4333c9e7fd 100644
--- a/studio/components/interfaces/Organization/TeamSettings/MembersView.tsx
+++ b/studio/components/interfaces/Organization/TeamSettings/MembersView.tsx
@@ -5,7 +5,8 @@ import { Fragment, useState } from 'react'
import { useParams } from 'common/hooks'
import Table from 'components/to-be-cleaned/Table'
-import ShimmeringLoader from 'components/ui/ShimmeringLoader'
+import AlertError from 'components/ui/AlertError'
+import { GenericSkeletonLoader } from 'components/ui/ShimmeringLoader'
import { useOrganizationDetailQuery } from 'data/organizations/organization-detail-query'
import { useOrganizationMemberUpdateMutation } from 'data/organizations/organization-member-update-mutation'
import { useOrganizationRolesQuery } from 'data/organizations/organization-roles-query'
@@ -35,8 +36,19 @@ const MembersView = ({ searchString }: MembersViewProps) => {
const { profile } = useProfile()
const { data: permissions } = usePermissionsQuery()
- const { data: detailData, isLoading: isLoadingOrgDetails } = useOrganizationDetailQuery({ slug })
- const { data: rolesData, isLoading: isLoadingRoles } = useOrganizationRolesQuery({ slug })
+ const {
+ data: detailData,
+ error: detailError,
+ isLoading: isLoadingOrgDetails,
+ isError: isErrorOrgDetails,
+ isSuccess: isSuccessOrgDetails,
+ } = useOrganizationDetailQuery({ slug })
+ const {
+ data: rolesData,
+ error: rolesError,
+ isLoading: isLoadingRoles,
+ isError: isErrorRoles,
+ } = useOrganizationRolesQuery({ slug })
const { mutateAsync: updateOrganizationMember, isLoading } = useOrganizationMemberUpdateMutation({
onSuccess() {
ui.setNotification({
@@ -44,10 +56,12 @@ const MembersView = ({ searchString }: MembersViewProps) => {
message: `Successfully updated role for ${getUserDisplayName(selectedMember)}`,
})
},
- onError() {
+ onError(error) {
ui.setNotification({
category: 'error',
- message: `Failed to update role for ${getUserDisplayName(selectedMember)}`,
+ message: `Failed to update role for ${getUserDisplayName(selectedMember)}: ${
+ error.message
+ }`,
})
},
})
@@ -94,230 +108,233 @@ const MembersView = ({ searchString }: MembersViewProps) => {
setUserRoleChangeModalVisible(false)
}
- if (isLoadingOrgDetails) {
- return (
-
-
-
-
-
- )
- }
-
return (
<>
-
-
- User,
- ,
-
- Role
-
- ,
- ,
- ]}
- body={[
- ...filteredMembers.map((x: Member, i: number) => {
- const [memberRoleId] = x.role_ids ?? []
- const role = (roles || []).find((role) => role.id === memberRoleId)
- const memberIsUser = x.primary_email == profile?.primary_email
- const memberIsPendingInvite = !!x.invited_id
- const canRemoveRole = rolesRemovable.includes(memberRoleId)
- const disableRoleEdit = !canRemoveRole || memberIsUser || memberIsPendingInvite
- const isEmailUser = x.username === x.primary_email
+ {isLoadingOrgDetails && }
- const validateSelectedRoleToChange = (roleId: any) => {
- if (!role || role.id === roleId) return
+ {isErrorOrgDetails && (
+
+ )}
- const selectedRole = (roles || []).find((role) => role.id === roleId)
- const canAddRole = rolesAddable.includes(selectedRole?.id ?? -1)
+ {isErrorRoles && (
+
+ )}
- if (!canAddRole) {
- return ui.setNotification({
- category: 'error',
- duration: 4000,
- message: `You do not have permission to update this team member to ${
- selectedRole!.name
- }`,
- })
+ {isSuccessOrgDetails && (
+
+
+ User,
+ ,
+
+ Role
+
+ ,
+ ,
+ ]}
+ body={[
+ ...filteredMembers.map((x: Member, i: number) => {
+ const [memberRoleId] = x.role_ids ?? []
+ const role = (roles || []).find((role) => role.id === memberRoleId)
+ const memberIsUser = x.primary_email == profile?.primary_email
+ const memberIsPendingInvite = !!x.invited_id
+ const canRemoveRole = rolesRemovable.includes(memberRoleId)
+ const disableRoleEdit = !canRemoveRole || memberIsUser || memberIsPendingInvite
+ const isEmailUser = x.username === x.primary_email
+
+ const validateSelectedRoleToChange = (roleId: any) => {
+ if (!role || role.id === roleId) return
+
+ const selectedRole = (roles || []).find((role) => role.id === roleId)
+ const canAddRole = rolesAddable.includes(selectedRole?.id ?? -1)
+
+ if (!canAddRole) {
+ return ui.setNotification({
+ category: 'error',
+ duration: 4000,
+ message: `You do not have permission to update this team member to ${
+ selectedRole!.name
+ }`,
+ })
+ }
+
+ setUserRoleChangeModalVisible(true)
+ setSelectedMember({ ...x, oldRoleId: role.id, newRoleId: roleId })
}
- setUserRoleChangeModalVisible(true)
- setSelectedMember({ ...x, oldRoleId: role.id, newRoleId: roleId })
- }
-
- return (
-
-
-
-
-
- {x.invited_id ? (
-
-
-
- ) : isEmailUser ? (
-
-
-
- ) : (
-
- )}
+ return (
+
+
+
+
+
+ {x.invited_id ? (
+
+
+
+ ) : isEmailUser ? (
+
+
+
+ ) : (
+
+ )}
+
+
+
{getUserDisplayName(x)}
+ {x.invited_id === undefined && (
+
{x.primary_email}
+ )}
+
-
-
{getUserDisplayName(x)}
- {x.invited_id === undefined && (
-
{x.primary_email}
- )}
-
-
-
+
-
- {x.invited_id && x.invited_at && (
-
- {isInviteExpired(x.invited_at) ? 'Expired' : 'Invited'}
-
- )}
-
+
+ {x.invited_id && x.invited_at && (
+
+ {isInviteExpired(x.invited_at) ? 'Expired' : 'Invited'}
+
+ )}
+
-
- {isLoadingRoles ? (
-
-
-
- ) : role !== undefined ? (
-
-
-
- {roles.map((r: any) => (
-
- {r.name}
-
- ))}
-
-
- {memberIsPendingInvite ? (
-
-
-
-
-
- Role can only be changed after the user has accepted the
- invite
-
-
-
-
- ) : !memberIsUser && !canRemoveRole ? (
-
-
-
-
-
- You need additional permissions to manage this team member
-
-
-
-
- ) : (
- <>>
- )}
-
- ) : (
-
-
Invalid role
+
+ {isLoadingRoles ? (
+
+
+
+ ) : role !== undefined ? (
-
-
+
+
+ {roles.map((r: any) => (
+
+ {r.name}
+
+ ))}
+
-
-
-
-
-
- This user has an invalid role, please reach out to us via
- support
-
-
-
-
+ {memberIsPendingInvite ? (
+
+
+
+
+
+ Role can only be changed after the user has accepted the
+ invite
+
+
+
+
+ ) : !memberIsUser && !canRemoveRole ? (
+
+
+
+
+
+ You need additional permissions to manage this team member
+
+
+
+
+ ) : (
+ <>>
+ )}
+ ) : (
+
+
Invalid role
+
+
+
+
+
+
+
+
+
+ This user has an invalid role, please reach out to us via
+ support
+
+
+
+
+
+
+ )}
+
+
+ {!memberIsUser && }
+
+
+
+ )
+ }),
+ ...(searchString.length > 0 && filteredMembers.length === 0
+ ? [
+
+
+
+
+
+ No users matched the search query "{searchString}"
+
- )}
-
-
- {!memberIsUser && }
-
-
-
- )
- }),
- ...(searchString.length > 0 && filteredMembers.length === 0
- ? [
-
-
-
-
-
- No users matched the search query "{searchString}"
-
-
-
- ,
- ]
- : []),
-
-
-
- {searchString ? `${filteredMembers.length} of ` : ''}
- {members.length || '0'} {members.length == 1 ? 'user' : 'users'}
-
-
- ,
- ]}
- />
-
-
+
+ ,
+ ]
+ : []),
+
+
+
+ {searchString ? `${filteredMembers.length} of ` : ''}
+ {members.length || '0'} {members.length == 1 ? 'user' : 'users'}
+
+
+ ,
+ ]}
+ />
+
+
+ )}
{
@@ -133,7 +134,9 @@ const TeamSettings = () => {
-
+
+
+
)
diff --git a/studio/data/organizations/organization-detail-query.ts b/studio/data/organizations/organization-detail-query.ts
index 34c46d9e306..f07aa19e74d 100644
--- a/studio/data/organizations/organization-detail-query.ts
+++ b/studio/data/organizations/organization-detail-query.ts
@@ -2,7 +2,7 @@ import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query
import { get } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { useCallback } from 'react'
-import { Member } from 'types'
+import { Member, ResponseError } from 'types'
import { organizationKeys } from './keys'
export type OrganizationDetailVariables = {
@@ -56,7 +56,7 @@ export async function getOrganizationDetail(
}
export type OrganizationDetailData = Awaited>
-export type OrganizationDetailError = unknown
+export type OrganizationDetailError = ResponseError
export const useOrganizationDetailQuery = (
{ slug }: OrganizationDetailVariables,
diff --git a/studio/data/organizations/organization-member-invite-delete-mutation.ts b/studio/data/organizations/organization-member-invite-delete-mutation.ts
index 0ab1efd7bc0..374f3146d50 100644
--- a/studio/data/organizations/organization-member-invite-delete-mutation.ts
+++ b/studio/data/organizations/organization-member-invite-delete-mutation.ts
@@ -1,9 +1,10 @@
import { useMutation, UseMutationOptions, useQueryClient } from '@tanstack/react-query'
+import { toast } from 'react-hot-toast'
+
import { delete_ } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
-import { organizationKeys } from './keys'
-import { toast } from 'react-hot-toast'
import { ResponseError } from 'types'
+import { organizationKeys } from './keys'
export type OrganizationMemberInviteDeleteVariables = {
slug: string
@@ -18,10 +19,7 @@ export async function deleteOrganizationMemberInvite({
`${API_URL}/organizations/${slug}/members/invite?invited_id=${invitedId}`,
{}
)
- if (response.error) {
- throw response.error
- }
-
+ if (response.error) throw response.error
return response
}
diff --git a/studio/data/organizations/organization-roles-query.ts b/studio/data/organizations/organization-roles-query.ts
index 67618853e85..699eef8cd89 100644
--- a/studio/data/organizations/organization-roles-query.ts
+++ b/studio/data/organizations/organization-roles-query.ts
@@ -2,7 +2,7 @@ import { useQuery, useQueryClient, UseQueryOptions } from '@tanstack/react-query
import { get } from 'lib/common/fetch'
import { API_URL } from 'lib/constants'
import { useCallback } from 'react'
-import { Role } from 'types'
+import { ResponseError, Role } from 'types'
import { organizationKeys } from './keys'
export type OrganizationRolesVariables = {
@@ -32,7 +32,7 @@ export async function getOrganizationRoles(
}
export type OrganizationRolesData = Awaited>
-export type OrganizationRolesError = unknown
+export type OrganizationRolesError = ResponseError
export const useOrganizationRolesQuery = (
{ slug }: OrganizationRolesVariables,
diff --git a/studio/types/base.ts b/studio/types/base.ts
index 53bef164213..96d370f8242 100644
--- a/studio/types/base.ts
+++ b/studio/types/base.ts
@@ -89,7 +89,7 @@ export type SupaResponse = T & ResponseFailure
export type SupaResponseV2 = T | ResponseFailure
export interface ResponseError {
- code: number
+ code?: number
message: string
- requestId: string
+ requestId?: string
}