feat: billing fixes

This commit is contained in:
=
2025-10-20 00:40:27 +05:30
parent 03e4918362
commit 8afc391e97
22 changed files with 103 additions and 52 deletions

View File

@@ -48,9 +48,9 @@ import { registerSshCertRouter } from "./ssh-certificate-router";
import { registerSshCertificateTemplateRouter } from "./ssh-certificate-template-router";
import { registerSshHostGroupRouter } from "./ssh-host-group-router";
import { registerSshHostRouter } from "./ssh-host-router";
import { registerSubOrgRouter } from "./sub-org-router";
import { registerTrustedIpRouter } from "./trusted-ip-router";
import { registerUserAdditionalPrivilegeRouter } from "./user-additional-privilege-router";
import { registerSubOrgRouter } from "./sub-org-router";
export const registerV1EERoutes = async (server: FastifyZodProvider) => {
// org role starts with organization

View File

@@ -10,6 +10,7 @@ export const licenseDALFactory = (db: TDbClient) => {
const countOfOrgMembers = async (orgId: string | null, tx?: Knex) => {
try {
const doc = await (tx || db.replicaNode())(TableName.Membership)
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
.andWhere((bd) => {
if (orgId) {
@@ -18,6 +19,7 @@ export const licenseDALFactory = (db: TDbClient) => {
})
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
.where(`${TableName.Users}.isGhost`, false)
.whereNull(`${TableName.Organization}.rootOrgId`)
.count();
return Number(doc?.[0]?.count ?? 0);
} catch (error) {
@@ -25,10 +27,31 @@ export const licenseDALFactory = (db: TDbClient) => {
}
};
const countOfOrgIdentities = async (orgId: string | null, tx?: Knex) => {
try {
// count org identities
const identityDoc = await (tx || db.replicaNode())(TableName.Identity)
.join(TableName.Organization, `${TableName.Identity}.orgId`, `${TableName.Organization}.id`)
.where((bd) => {
if (orgId) {
void bd.where(`${TableName.Organization}.rootOrgId`, orgId).orWhere(`${TableName.Organization}.id`, orgId);
}
})
.count();
const identityCount = Number(identityDoc?.[0].count);
return identityCount;
} catch (error) {
throw new DatabaseError({ error, name: "Count of Org Users + Identities" });
}
};
const countOrgUsersAndIdentities = async (orgId: string | null, tx?: Knex) => {
try {
// count org users
const userDoc = await (tx || db.replicaNode())(TableName.Membership)
.join(TableName.Organization, `${TableName.Organization}.id`, `${TableName.Membership}.scopeOrgId`)
.where({ status: OrgMembershipStatus.Accepted, scope: AccessScope.Organization })
.whereNotNull(`${TableName.Membership}.actorUserId`)
.andWhere((bd) => {
@@ -38,17 +61,17 @@ export const licenseDALFactory = (db: TDbClient) => {
})
.join(TableName.Users, `${TableName.Membership}.actorUserId`, `${TableName.Users}.id`)
.where(`${TableName.Users}.isGhost`, false)
.whereNull(`${TableName.Organization}.rootOrgId`)
.count();
const userCount = Number(userDoc?.[0].count);
// count org identities
const identityDoc = await (tx || db.replicaNode())(TableName.Membership)
.where({ scope: AccessScope.Organization })
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
const identityDoc = await (tx || db.replicaNode())(TableName.Identity)
.join(TableName.Organization, `${TableName.Identity}.orgId`, `${TableName.Organization}.id`)
.where((bd) => {
if (orgId) {
void bd.where(`${TableName.Membership}.scopeOrgId`, orgId);
void bd.where(`${TableName.Organization}.rootOrgId`, orgId).orWhere(`${TableName.Organization}.id`, orgId);
}
})
.count();
@@ -61,5 +84,5 @@ export const licenseDALFactory = (db: TDbClient) => {
}
};
return { countOfOrgMembers, countOrgUsersAndIdentities };
return { countOfOrgMembers, countOrgUsersAndIdentities, countOfOrgIdentities };
};

View File

@@ -15,7 +15,6 @@ import { getConfig } from "@app/lib/config/env";
import { verifyOfflineLicense } from "@app/lib/crypto";
import { BadRequestError, NotFoundError } from "@app/lib/errors";
import { logger } from "@app/lib/logger";
import { TIdentityOrgDALFactory } from "@app/services/identity/identity-org-dal";
import { TOrgDALFactory } from "@app/services/org/org-dal";
import { TProjectDALFactory } from "@app/services/project/project-dal";
@@ -46,11 +45,10 @@ import {
} from "./license-types";
type TLicenseServiceFactoryDep = {
orgDAL: Pick<TOrgDALFactory, "findOrgById" | "countAllOrgMembers">;
orgDAL: Pick<TOrgDALFactory, "findRootOrgDetails" | "countAllOrgMembers" | "findById">;
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;
licenseDAL: TLicenseDALFactory;
keyStore: Pick<TKeyStoreFactory, "setItemWithExpiry" | "getItem" | "deleteItem">;
identityOrgMembershipDAL: TIdentityOrgDALFactory;
projectDAL: TProjectDALFactory;
};
@@ -67,7 +65,6 @@ export const licenseServiceFactory = ({
permissionService,
licenseDAL,
keyStore,
identityOrgMembershipDAL,
projectDAL
}: TLicenseServiceFactoryDep) => {
let isValidLicense = false;
@@ -200,19 +197,21 @@ export const licenseServiceFactory = ({
return JSON.parse(cachedPlan) as TFeatureSet;
}
const org = await orgDAL.findOrgById(orgId);
const org = await orgDAL.findRootOrgDetails(orgId);
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
const rootOrgId = org.id;
const {
data: { currentPlan }
} = await licenseServerCloudApi.request.get<{ currentPlan: TFeatureSet }>(
`/api/license-server/v1/customers/${org.customerId}/cloud-plan`
);
const workspacesUsed = await projectDAL.countOfOrgProjects(orgId);
const workspacesUsed = await projectDAL.countOfOrgProjects(rootOrgId);
currentPlan.workspacesUsed = workspacesUsed;
const membersUsed = await licenseDAL.countOfOrgMembers(orgId);
const membersUsed = await licenseDAL.countOfOrgMembers(rootOrgId);
currentPlan.membersUsed = membersUsed;
const identityUsed = await licenseDAL.countOrgUsersAndIdentities(orgId);
const identityUsed = await licenseDAL.countOrgUsersAndIdentities(rootOrgId);
currentPlan.identitiesUsed = identityUsed;
if (currentPlan.identityLimit && currentPlan.identityLimit !== identityUsed) {
@@ -285,10 +284,10 @@ export const licenseServiceFactory = ({
};
const updateSubscriptionOrgMemberCount = async (orgId: string, tx?: Knex) => {
const org = await orgDAL.findOrgById(orgId);
const org = await orgDAL.findRootOrgDetails(orgId);
if (!org) throw new NotFoundError({ message: `Organization with ID '${orgId}' not found` });
const rootOrgId = org.rootOrgId || org.id;
const rootOrgId = org.id;
if (instanceType === InstanceType.Cloud) {
const quantity = await licenseDAL.countOfOrgMembers(rootOrgId, tx);
const quantityIdentities = await licenseDAL.countOrgUsersAndIdentities(rootOrgId, tx);
@@ -381,7 +380,7 @@ export const licenseServiceFactory = ({
OrgPermissionSubjects.Billing
);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -420,7 +419,7 @@ export const licenseServiceFactory = ({
OrgPermissionSubjects.Billing
);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: "Organization not found"
@@ -473,7 +472,7 @@ export const licenseServiceFactory = ({
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -539,7 +538,7 @@ export const licenseServiceFactory = ({
const getUsageMetrics = async (orgId: string) => {
const [orgMembersUsed, identityUsed, projectCount] = await Promise.all([
orgDAL.countAllOrgMembers(orgId),
identityOrgMembershipDAL.countAllOrgIdentities({ scopeOrgId: orgId }),
licenseDAL.countOfOrgIdentities(orgId),
projectDAL.countOfOrgProjects(orgId)
]);
@@ -563,7 +562,7 @@ export const licenseServiceFactory = ({
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -607,7 +606,7 @@ export const licenseServiceFactory = ({
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -642,7 +641,7 @@ export const licenseServiceFactory = ({
OrgPermissionSubjects.Billing
);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -669,7 +668,7 @@ export const licenseServiceFactory = ({
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -706,7 +705,7 @@ export const licenseServiceFactory = ({
OrgPermissionSubjects.Billing
);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -745,7 +744,7 @@ export const licenseServiceFactory = ({
OrgPermissionSubjects.Billing
);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -781,7 +780,7 @@ export const licenseServiceFactory = ({
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -809,7 +808,7 @@ export const licenseServiceFactory = ({
OrgPermissionSubjects.Billing
);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -840,7 +839,7 @@ export const licenseServiceFactory = ({
OrgPermissionSubjects.Billing
);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -864,7 +863,7 @@ export const licenseServiceFactory = ({
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -888,7 +887,7 @@ export const licenseServiceFactory = ({
});
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionBillingActions.Read, OrgPermissionSubjects.Billing);
const organization = await orgDAL.findOrgById(orgId);
const organization = await orgDAL.findById(orgId);
if (!organization) {
throw new NotFoundError({
message: `Organization with ID '${orgId}' not found`
@@ -933,7 +932,6 @@ export const licenseServiceFactory = ({
getLicenseId,
invalidateGetPlan,
updateSubscriptionOrgMemberCount,
refreshPlan,
getOrgPlan,
getOrgPlansTableByBillCycle,
startOrgTrial,

View File

@@ -561,7 +561,6 @@ export const registerRoutes = async (
orgDAL,
licenseDAL,
keyStore,
identityOrgMembershipDAL,
projectDAL
});

View File

@@ -32,6 +32,7 @@ import { registerIdentityKubernetesRouter } from "./identity-kubernetes-auth-rou
import { registerIdentityLdapAuthRouter } from "./identity-ldap-auth-router";
import { registerIdentityOciAuthRouter } from "./identity-oci-auth-router";
import { registerIdentityOidcAuthRouter } from "./identity-oidc-auth-router";
import { registerOrgIdentityMembershipRouter } from "./identity-org-membership-router";
import { registerIdentityProjectRouter } from "./identity-project-router";
import { registerIdentityRouter } from "./identity-router";
import { registerIdentityTlsCertAuthRouter } from "./identity-tls-cert-auth-router";
@@ -65,7 +66,6 @@ import { registerUserEngagementRouter } from "./user-engagement-router";
import { registerUserRouter } from "./user-router";
import { registerWebhookRouter } from "./webhook-router";
import { registerWorkflowIntegrationRouter } from "./workflow-integration-router";
import { registerOrgIdentityMembershipRouter } from "./identity-org-membership-router";
export const registerV1Routes = async (server: FastifyZodProvider) => {
await server.register(registerSsoRouter, { prefix: "/sso" });

View File

@@ -654,7 +654,7 @@ export const identityOrgDALFactory = (db: TDbClient) => {
tx?: Knex
) => {
try {
const query = (tx || db.replicaNode())(TableName.Membership)
const query = (tx || db.replicaNode())(TableName.Identity)
.where(`${TableName.Membership}.scope`, AccessScope.Organization)
.whereNotNull(`${TableName.Membership}.actorIdentityId`)
.where(filter)

View File

@@ -12,6 +12,7 @@ import { TKeyStoreFactory } from "@app/keystore/keystore";
import { BadRequestError, NotFoundError, PermissionBoundaryError } from "@app/lib/errors";
import { TIdentityProjectDALFactory } from "@app/services/identity-project/identity-project-dal";
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
import { TMembershipRoleDALFactory } from "../membership/membership-role-dal";
import { TMembershipIdentityDALFactory } from "../membership-identity/membership-identity-dal";
import { TOrgDALFactory } from "../org/org-dal";
@@ -28,7 +29,6 @@ import {
TSearchOrgIdentitiesByOrgIdDTO,
TUpdateIdentityDTO
} from "./identity-types";
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
type TIdentityServiceFactoryDep = {
identityDAL: TIdentityDALFactory;
@@ -347,6 +347,13 @@ export const identityServiceFactory = ({
}
await membershipIdentityDAL.transaction(async (tx) => {
await identityMetadataDAL.delete(
{
identityId: id,
orgId: actorOrgId
},
tx
);
const identityProjectMembership = await membershipIdentityDAL.find(
{
actorIdentityId: id,

View File

@@ -6,6 +6,7 @@ import { ms } from "@app/lib/ms";
import { SearchResourceOperators } from "@app/lib/search-resource/search";
import { TAdditionalPrivilegeDALFactory } from "../additional-privilege/additional-privilege-dal";
import { TIdentityDALFactory } from "../identity/identity-dal";
import { TMembershipRoleDALFactory } from "../membership/membership-role-dal";
import { TOrgDALFactory } from "../org/org-dal";
import { TRoleDALFactory } from "../role/role-dal";
@@ -20,7 +21,6 @@ import {
import { newNamespaceMembershipIdentityFactory } from "./namespace/namespace-membership-identity-factory";
import { newOrgMembershipIdentityFactory } from "./org/org-membership-identity-factory";
import { newProjectMembershipIdentityFactory } from "./project/project-membership-identity-factory";
import { TIdentityDALFactory } from "../identity/identity-dal";
type TMembershipIdentityServiceFactoryDep = {
membershipIdentityDAL: TMembershipIdentityDALFactory;

View File

@@ -8,11 +8,11 @@ import {
} from "@app/ee/services/permission/permission-fns";
import { TPermissionServiceFactory } from "@app/ee/services/permission/permission-service-types";
import { BadRequestError, InternalServerError, PermissionBoundaryError } from "@app/lib/errors";
import { TIdentityDALFactory } from "@app/services/identity/identity-dal";
import { TOrgDALFactory } from "@app/services/org/org-dal";
import { isCustomOrgRole } from "@app/services/org/org-role-fns";
import { TMembershipIdentityScopeFactory } from "../membership-identity-types";
import { TIdentityDALFactory } from "@app/services/identity/identity-dal";
type TOrgMembershipIdentityScopeFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission" | "getOrgPermissionByRoles">;

View File

@@ -15,8 +15,8 @@ import { isCustomOrgRole } from "@app/services/org/org-role-fns";
import { SmtpTemplates, TSmtpService } from "@app/services/smtp/smtp-service";
import { TUserDALFactory } from "@app/services/user/user-dal";
import { TMembershipUserScopeFactory } from "../membership-user-types";
import { TMembershipUserDALFactory } from "../membership-user-dal";
import { TMembershipUserScopeFactory } from "../membership-user-types";
type TOrgMembershipUserScopeFactoryDep = {
permissionService: Pick<TPermissionServiceFactory, "getOrgPermission">;

View File

@@ -705,6 +705,25 @@ export const orgDALFactory = (db: TDbClient) => {
}
};
const findRootOrgDetails = async (orgId: string): Promise<TOrganizations | undefined> => {
try {
const org = await db
.replicaNode()(TableName.Organization)
.select(selectAllTableCols(TableName.Organization))
.where(
"id",
db(TableName.Organization)
.select(db.raw(`CASE WHEN "rootOrgId" IS NULL THEN id ELSE "rootOrgId" END`))
.where("id", orgId)
)
.first();
return org;
} catch (error) {
throw new DatabaseError({ error, name: "FindRootOrgDetails" });
}
};
return withTransaction(db, {
...orgOrm,
findOrgByProjectId,
@@ -728,6 +747,7 @@ export const orgDALFactory = (db: TDbClient) => {
deleteMembershipById,
deleteMembershipsById,
updateMembership,
findIdentityOrganization
findIdentityOrganization,
findRootOrgDetails
});
};

View File

@@ -14,6 +14,7 @@ import { logger } from "@app/lib/logger";
import { TAccessTokenQueueServiceFactory } from "../access-token-queue/access-token-queue";
import { ActorType } from "../auth/auth-type";
import { TOrgDALFactory } from "../org/org-dal";
import { TProjectDALFactory } from "../project/project-dal";
import { TProjectEnvDALFactory } from "../project-env/project-env-dal";
import { SmtpTemplates, TSmtpService } from "../smtp/smtp-service";
@@ -25,7 +26,6 @@ import {
TGetServiceTokenInfoDTO,
TProjectServiceTokensDTO
} from "./service-token-types";
import { TOrgDALFactory } from "../org/org-dal";
type TServiceTokenServiceFactoryDep = {
serviceTokenDAL: TServiceTokenDALFactory;

View File

@@ -1,2 +1,6 @@
export { useCreateOrgIdentityMembership, useDeleteOrgIdentityMembership } from "./mutation";
export type { TCreateOrgIdentityMembershipDTO, TDeleteOrgIdentityMembershipDTO, TOrgIdentityMembership } from "./types";
export type {
TCreateOrgIdentityMembershipDTO,
TDeleteOrgIdentityMembershipDTO,
TOrgIdentityMembership
} from "./types";

View File

@@ -1,12 +1,12 @@
export {
useAddOrgPmtMethod,
useGetAvailableOrgIdentities,
useAddOrgTaxId,
useCreateCustomerPortalSession,
useCreateOrg,
useDeleteOrgById,
useDeleteOrgPmtMethod,
useDeleteOrgTaxId,
useGetAvailableOrgIdentities,
useGetIdentityMembershipOrgs,
useGetOrganizationGroups,
useGetOrganizations,

View File

@@ -582,7 +582,7 @@ export const useGetAvailableOrgIdentities = (enabled = true) =>
queryKey: organizationKeys.getAvailableIdentities(),
queryFn: async () => {
const { data } = await apiRequest.get<{ identities: { name: string; id: string }[] }>(
`/api/v1/organization/identities/available`
"/api/v1/organization/identities/available"
);
return data.identities;
@@ -596,7 +596,7 @@ export const useGetAvailableOrgUsers = (enabled = true) =>
queryFn: async () => {
const { data } = await apiRequest.get<{
users: { username: string; id: string; firstName: string; lastName: string }[];
}>(`/api/v1/organization/users/available`);
}>("/api/v1/organization/users/available");
return data.users;
},

View File

@@ -58,8 +58,8 @@ import { AuthMethod } from "@app/hooks/api/users/types";
import { navigateUserToOrg } from "@app/pages/auth/LoginPage/Login.utils";
import { ServerAdminsPanel } from "../ServerAdminsPanel/ServerAdminsPanel";
import { NotificationDropdown } from "./NotificationDropdown";
import { NewSubOrganizationForm } from "./NewSubOrganizationForm";
import { NotificationDropdown } from "./NotificationDropdown";
const getPlan = (subscription: SubscriptionPlan) => {
if (subscription.groups) return "Enterprise";

View File

@@ -4,8 +4,8 @@ import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, FormControl, Input } from "@app/components/v2";
import { GenericResourceNameSchema } from "@app/lib/schemas";
import { useCreateSubOrganization } from "@app/hooks/api";
import { GenericResourceNameSchema } from "@app/lib/schemas";
type ContentProps = {
onClose: () => void;

View File

@@ -105,7 +105,7 @@ export const IdentityLinkForm = ({ onClose }: Props) => {
placeholder="Select role..."
getOptionValue={(option) => option.slug}
getOptionLabel={(option) => option.name}
menuPortalTarget={document.body}
// menuPortalTarget={document.body}
/>
</FormControl>
)}

View File

@@ -53,7 +53,7 @@ export const IdentityModal = ({ popUp, handlePopUpToggle }: Props) => {
const orgId = currentOrg?.id || "";
const { data: roles } = useGetOrgRoles(orgId);
const isOrgIdentity = orgId === popUp?.identity?.data?.orgId;
const isOrgIdentity = popUp?.identity?.data ? orgId === popUp?.identity?.data?.orgId : true;
const { mutateAsync: createMutateAsync } = useCreateIdentity();
const { mutateAsync: updateMutateAsync } = useUpdateIdentity();

View File

@@ -24,11 +24,11 @@ import { usePopUp } from "@app/hooks/usePopUp";
import { IdentityAuthTemplateModal } from "./IdentityAuthTemplateModal";
import { IdentityAuthTemplatesTable } from "./IdentityAuthTemplatesTable";
import { IdentityLinkForm } from "./IdentityLinkForm";
import { IdentityModal } from "./IdentityModal";
import { IdentityTable } from "./IdentityTable";
import { IdentityTokenAuthTokenModal } from "./IdentityTokenAuthTokenModal";
import { MachineAuthTemplateUsagesModal } from "./MachineAuthTemplateUsagesModal";
import { IdentityLinkForm } from "./IdentityLinkForm";
export const IdentitySection = withPermission(
() => {

View File

@@ -3,6 +3,7 @@ import { useSearch } from "@tanstack/react-router";
import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ROUTE_PATHS } from "@app/const/routes";
import { useOrganization } from "@app/context";
import { AuditLogStreamsTab } from "../AuditLogStreamTab";
import { ExternalMigrationsTab } from "../ExternalMigrationsTab";
@@ -14,7 +15,6 @@ import { OrgSecurityTab } from "../OrgSecurityTab";
import { OrgSsoTab } from "../OrgSsoTab";
import { OrgWorkflowIntegrationTab } from "../OrgWorkflowIntegrationTab";
import { ProjectTemplatesTab } from "../ProjectTemplatesTab";
import { useOrganization } from "@app/context";
export const OrgTabGroup = () => {
const search = useSearch({

View File

@@ -1,7 +1,7 @@
import { createFileRoute, retainSearchParams } from "@tanstack/react-router";
import { z } from "zod";
import { OrganizationLayout } from "@app/layouts/OrganizationLayout";
import { z } from "zod";
export const Route = createFileRoute("/_authenticate/_inject-org-details/_org-layout")({
component: OrganizationLayout,