feat: refactor organization membership logic and simplify admin role checks

This commit is contained in:
Abhimanyu Saharan
2026-02-08 23:49:34 +05:30
parent cd732e312f
commit a4aced9a88
12 changed files with 55 additions and 187 deletions

View File

@@ -22,10 +22,7 @@ import {
type listBoardsApiV1BoardsGetResponse,
useListBoardsApiV1BoardsGet,
} from "@/api/generated/boards/boards";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type {
ActivityEventRead,
AgentRead,
@@ -84,19 +81,7 @@ export default function AgentDetailPage() {
const agentIdParam = params?.agentId;
const agentId = Array.isArray(agentIdParam) ? agentIdParam[0] : agentIdParam;
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const [deleteOpen, setDeleteOpen] = useState(false);
const [deleteError, setDeleteError] = useState<string | null>(null);

View File

@@ -13,10 +13,7 @@ import {
useListBoardsApiV1BoardsGet,
} from "@/api/generated/boards/boards";
import { useCreateAgentApiV1AgentsPost } from "@/api/generated/agents/agents";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type { BoardRead } from "@/api/generated/model";
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
@@ -86,19 +83,7 @@ export default function NewAgentPage() {
const router = useRouter();
const { isSignedIn } = useAuth();
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const [name, setName] = useState("");
const [boardId, setBoardId] = useState<string>("");

View File

@@ -42,10 +42,7 @@ import {
getListBoardsApiV1BoardsGetQueryKey,
useListBoardsApiV1BoardsGet,
} from "@/api/generated/boards/boards";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type { AgentRead } from "@/api/generated/model";
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
@@ -94,19 +91,7 @@ export default function AgentsPage() {
const queryClient = useQueryClient();
const router = useRouter();
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const [sorting, setSorting] = useState<SortingState>([
{ id: "name", desc: false },

View File

@@ -22,10 +22,7 @@ import {
type listGatewaysApiV1GatewaysGetResponse,
useListGatewaysApiV1GatewaysGet,
} from "@/api/generated/gateways/gateways";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type {
BoardGroupRead,
BoardRead,
@@ -65,19 +62,7 @@ export default function EditBoardPage() {
const boardIdParam = params?.boardId;
const boardId = Array.isArray(boardIdParam) ? boardIdParam[0] : boardIdParam;
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const mainRef = useRef<HTMLElement | null>(null);

View File

@@ -18,10 +18,7 @@ import {
type listGatewaysApiV1GatewaysGetResponse,
useListGatewaysApiV1GatewaysGet,
} from "@/api/generated/gateways/gateways";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type { BoardGroupRead } from "@/api/generated/model";
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
@@ -42,19 +39,7 @@ export default function NewBoardPage() {
const router = useRouter();
const { isSignedIn } = useAuth();
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const [name, setName] = useState("");
const [gatewayId, setGatewayId] = useState<string>("");

View File

@@ -25,10 +25,7 @@ import {
type listBoardGroupsApiV1BoardGroupsGetResponse,
useListBoardGroupsApiV1BoardGroupsGet,
} from "@/api/generated/board-groups/board-groups";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type { BoardGroupRead, BoardRead } from "@/api/generated/model";
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
import { DashboardShell } from "@/components/templates/DashboardShell";
@@ -62,19 +59,7 @@ export default function BoardsPage() {
const { isSignedIn } = useAuth();
const queryClient = useQueryClient();
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const [deleteTarget, setDeleteTarget] = useState<BoardRead | null>(null);
const boardsKey = getListBoardsApiV1BoardsGetQueryKey();

View File

@@ -13,10 +13,7 @@ import {
useGetGatewayApiV1GatewaysGatewayIdGet,
useUpdateGatewayApiV1GatewaysGatewayIdPatch,
} from "@/api/generated/gateways/gateways";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type { GatewayUpdate } from "@/api/generated/model";
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
@@ -40,19 +37,7 @@ export default function EditGatewayPage() {
? gatewayIdParam[0]
: gatewayIdParam;
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const [name, setName] = useState<string | undefined>(undefined);
const [gatewayUrl, setGatewayUrl] = useState<string | undefined>(undefined);

View File

@@ -18,10 +18,7 @@ import {
type listAgentsApiV1AgentsGetResponse,
useListAgentsApiV1AgentsGet,
} from "@/api/generated/agents/agents";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
import { DashboardSidebar } from "@/components/organisms/DashboardSidebar";
@@ -55,19 +52,7 @@ export default function GatewayDetailPage() {
? gatewayIdParam[0]
: gatewayIdParam;
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const gatewayQuery = useGetGatewayApiV1GatewaysGatewayIdGet<
getGatewayApiV1GatewaysGatewayIdGetResponse,

View File

@@ -9,10 +9,7 @@ import { SignedIn, SignedOut, useAuth } from "@/auth/clerk";
import { ApiError } from "@/api/mutator";
import { useCreateGatewayApiV1GatewaysPost } from "@/api/generated/gateways/gateways";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
import { GatewayForm } from "@/components/gateways/GatewayForm";
@@ -30,19 +27,7 @@ export default function NewGatewayPage() {
const { isSignedIn } = useAuth();
const router = useRouter();
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const [name, setName] = useState("");
const [gatewayUrl, setGatewayUrl] = useState("");

View File

@@ -35,10 +35,7 @@ import {
useDeleteGatewayApiV1GatewaysGatewayIdDelete,
useListGatewaysApiV1GatewaysGet,
} from "@/api/generated/gateways/gateways";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import type { GatewayRead } from "@/api/generated/model";
import { AdminOnlyNotice } from "@/components/auth/AdminOnlyNotice";
import { SignedOutPanel } from "@/components/auth/SignedOutPanel";
@@ -65,19 +62,7 @@ export default function GatewaysPage() {
const { isSignedIn } = useAuth();
const queryClient = useQueryClient();
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const [sorting, setSorting] = useState<SortingState>([
{ id: "name", desc: false },
]);

View File

@@ -15,10 +15,7 @@ import {
import { useAuth } from "@/auth/clerk";
import { ApiError } from "@/api/mutator";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
import { useOrganizationMembership } from "@/lib/use-organization-membership";
import {
type healthzHealthzGetResponse,
useHealthzHealthzGet,
@@ -28,19 +25,7 @@ import { cn } from "@/lib/utils";
export function DashboardSidebar() {
const pathname = usePathname();
const { isSignedIn } = useAuth();
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
const isAdmin = member ? ["owner", "admin"].includes(member.role) : false;
const { isAdmin } = useOrganizationMembership(isSignedIn);
const healthQuery = useHealthzHealthzGet<healthzHealthzGetResponse, ApiError>(
{
query: {

View File

@@ -0,0 +1,33 @@
import { ApiError } from "@/api/mutator";
import {
type getMyMembershipApiV1OrganizationsMeMemberGetResponse,
useGetMyMembershipApiV1OrganizationsMeMemberGet,
} from "@/api/generated/organizations/organizations";
export const isOrganizationAdminRole = (
role: string | null | undefined,
): boolean => role === "owner" || role === "admin";
export function useOrganizationMembership(
isSignedIn: boolean | null | undefined,
) {
const membershipQuery = useGetMyMembershipApiV1OrganizationsMeMemberGet<
getMyMembershipApiV1OrganizationsMeMemberGetResponse,
ApiError
>({
query: {
enabled: Boolean(isSignedIn),
refetchOnMount: "always",
retry: false,
},
});
const member =
membershipQuery.data?.status === 200 ? membershipQuery.data.data : null;
return {
membershipQuery,
member,
isAdmin: isOrganizationAdminRole(member?.role),
};
}