Merge branch 'main' into ENG-2647

This commit is contained in:
x
2025-05-02 19:03:08 -04:00
108 changed files with 3763 additions and 258 deletions
+1
View File
@@ -107,6 +107,7 @@ export type CompleteAccountSignupDTO = CompleteAccountDTO & {
providerAuthToken?: string;
attributionSource?: string;
organizationName: string;
useDefaultOrg?: boolean;
};
export type VerifySignupInviteDTO = {
+1
View File
@@ -44,6 +44,7 @@ export * from "./serviceTokens";
export * from "./sshCa";
export * from "./sshCertificateTemplates";
export * from "./sshHost";
export * from "./sshHostGroup";
export * from "./ssoConfig";
export * from "./subscriptions";
export * from "./tags";
+16 -19
View File
@@ -1,3 +1,16 @@
export enum LoginMappingSource {
HOST = "host",
HOST_GROUP = "hostGroup"
}
export type TLoginMapping = {
loginUser: string;
allowedPrincipals: {
usernames: string[];
};
source: LoginMappingSource;
};
export type TSshHost = {
id: string;
projectId: string;
@@ -5,26 +18,15 @@ export type TSshHost = {
alias: string | null;
userCertTtl: string;
hostCertTtl: string;
loginMappings: {
loginUser: string;
allowedPrincipals: {
usernames: string[];
};
}[];
loginMappings: TLoginMapping[];
};
export type TCreateSshHostDTO = {
projectId: string;
hostname: string;
alias?: string;
userCertTtl?: string;
hostCertTtl?: string;
loginMappings: {
loginUser: string;
allowedPrincipals: {
usernames: string[];
};
}[];
loginMappings: Omit<TLoginMapping, "source">[];
};
export type TUpdateSshHostDTO = {
@@ -33,12 +35,7 @@ export type TUpdateSshHostDTO = {
alias?: string;
userCertTtl?: string;
hostCertTtl?: string;
loginMappings?: {
loginUser: string;
allowedPrincipals: {
usernames: string[];
};
}[];
loginMappings?: Omit<TLoginMapping, "source">[];
};
export type TDeleteSshHostDTO = {
@@ -0,0 +1,8 @@
export {
useAddHostToSshHostGroup,
useCreateSshHostGroup,
useDeleteSshHostGroup,
useRemoveHostFromSshHostGroup,
useUpdateSshHostGroup
} from "./mutations";
export { useGetSshHostGroupById, useListSshHostGroupHosts } from "./queries";
@@ -0,0 +1,105 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { workspaceKeys } from "../workspace/query-keys";
import { sshHostGroupKeys } from "./queries";
import {
TCreateSshHostGroupDTO,
TDeleteSshHostGroupDTO,
TSshHostGroup,
TUpdateSshHostGroupDTO
} from "./types";
export const useCreateSshHostGroup = () => {
const queryClient = useQueryClient();
return useMutation<TSshHostGroup, object, TCreateSshHostGroupDTO>({
mutationFn: async (body) => {
const { data: hostGroup } = await apiRequest.post("/api/v1/ssh/host-groups", body);
return hostGroup;
},
onSuccess: ({ projectId, id }) => {
queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId)
});
queryClient.invalidateQueries({
queryKey: sshHostGroupKeys.getSshHostGroupById(id)
});
}
});
};
export const useUpdateSshHostGroup = () => {
const queryClient = useQueryClient();
return useMutation<TSshHostGroup, object, TUpdateSshHostGroupDTO>({
mutationFn: async ({ sshHostGroupId, ...body }) => {
const { data: hostGroup } = await apiRequest.patch(
`/api/v1/ssh/host-groups/${sshHostGroupId}`,
body
);
return hostGroup;
},
onSuccess: ({ projectId }, { sshHostGroupId }) => {
queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId)
});
queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceSshHosts(projectId)
});
queryClient.invalidateQueries({
queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId)
});
}
});
};
export const useDeleteSshHostGroup = () => {
const queryClient = useQueryClient();
return useMutation<TSshHostGroup, object, TDeleteSshHostGroupDTO>({
mutationFn: async ({ sshHostGroupId }) => {
const { data: hostGroup } = await apiRequest.delete(
`/api/v1/ssh/host-groups/${sshHostGroupId}`
);
return hostGroup;
},
onSuccess: ({ projectId }, { sshHostGroupId }) => {
queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId)
});
queryClient.invalidateQueries({
queryKey: workspaceKeys.getWorkspaceSshHosts(projectId)
});
queryClient.invalidateQueries({
queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId)
});
}
});
};
export const useAddHostToSshHostGroup = () => {
const queryClient = useQueryClient();
return useMutation<void, object, { sshHostGroupId: string; sshHostId: string }>({
mutationFn: async ({ sshHostGroupId, sshHostId }) => {
await apiRequest.post(`/api/v1/ssh/host-groups/${sshHostGroupId}/hosts/${sshHostId}`);
},
onSuccess: (_, { sshHostGroupId }) => {
queryClient.invalidateQueries({
queryKey: sshHostGroupKeys.forSshHostGroupHosts(sshHostGroupId)
});
}
});
};
export const useRemoveHostFromSshHostGroup = () => {
const queryClient = useQueryClient();
return useMutation<void, object, { sshHostGroupId: string; sshHostId: string }>({
mutationFn: async ({ sshHostGroupId, sshHostId }) => {
await apiRequest.delete(`/api/v1/ssh/host-groups/${sshHostGroupId}/hosts/${sshHostId}`);
},
onSuccess: (_, { sshHostGroupId }) => {
queryClient.invalidateQueries({
queryKey: sshHostGroupKeys.forSshHostGroupHosts(sshHostGroupId)
});
}
});
};
@@ -0,0 +1,60 @@
import { useQuery } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { EHostGroupMembershipFilter, TListSshHostGroupHostsResponse, TSshHostGroup } from "./types";
export const sshHostGroupKeys = {
getSshHostGroupById: (sshHostGroupId: string) => [{ sshHostGroupId }, "ssh-host-group"],
allSshHostGroupHosts: () => ["ssh-host-group-hosts"] as const,
forSshHostGroupHosts: (sshHostGroupId: string) =>
[...sshHostGroupKeys.allSshHostGroupHosts(), sshHostGroupId] as const,
specificSshHostGroupHosts: ({
sshHostGroupId,
filter
}: {
sshHostGroupId: string;
filter?: EHostGroupMembershipFilter;
}) => [...sshHostGroupKeys.forSshHostGroupHosts(sshHostGroupId), { filter }] as const
};
export const useGetSshHostGroupById = (sshHostGroupId: string) => {
return useQuery({
queryKey: sshHostGroupKeys.getSshHostGroupById(sshHostGroupId),
queryFn: async () => {
const { data: sshHostGroup } = await apiRequest.get<TSshHostGroup>(
`/api/v1/ssh/host-groups/${sshHostGroupId}`
);
return sshHostGroup;
},
enabled: Boolean(sshHostGroupId)
});
};
export const useListSshHostGroupHosts = ({
sshHostGroupId,
filter
}: {
sshHostGroupId: string;
filter?: EHostGroupMembershipFilter;
}) => {
return useQuery({
queryKey: sshHostGroupKeys.specificSshHostGroupHosts({ sshHostGroupId, filter }),
queryFn: async () => {
const params = new URLSearchParams({
...(filter ? { filter } : {})
});
const { data } = await apiRequest.get<TListSshHostGroupHostsResponse>(
`/api/v1/ssh/host-groups/${sshHostGroupId}/hosts`,
{
params
}
);
return data;
},
enabled: Boolean(sshHostGroupId),
staleTime: 0,
gcTime: 0
});
};
@@ -0,0 +1,34 @@
import { TLoginMapping, TSshHost } from "../sshHost/types";
export type TSshHostGroup = {
id: string;
projectId: string;
name: string;
loginMappings: Omit<TLoginMapping, "source">[];
};
export type TCreateSshHostGroupDTO = {
projectId: string;
name: string;
loginMappings: Omit<TLoginMapping, "source">[];
};
export type TUpdateSshHostGroupDTO = {
sshHostGroupId: string;
name?: string;
loginMappings?: Omit<TLoginMapping, "source">[];
};
export type TDeleteSshHostGroupDTO = {
sshHostGroupId: string;
};
export type TListSshHostGroupHostsResponse = {
hosts: (TSshHost & { joinedGroupAt: string; isPartOfGroup: boolean })[];
totalCount: number;
};
export enum EHostGroupMembershipFilter {
GROUP_MEMBERS = "group-members",
NON_GROUP_MEMBERS = "non-group-members"
}
@@ -24,6 +24,7 @@ export type SubscriptionPlan = {
workspacesUsed: number;
environmentLimit: number;
samlSSO: boolean;
sshHostGroups: boolean;
secretAccessInsights: boolean;
hsm: boolean;
oidcSSO: boolean;
@@ -38,6 +38,7 @@ export {
useListWorkspaceSshCas,
useListWorkspaceSshCertificates,
useListWorkspaceSshCertificateTemplates,
useListWorkspaceSshHostGroups,
useListWorkspaceSshHosts,
useNameWorkspaceSecrets,
useSearchProjects,
@@ -18,6 +18,7 @@ import { EncryptedSecret } from "../secrets/types";
import { TSshCertificate, TSshCertificateAuthority } from "../sshCa/types";
import { TSshCertificateTemplate } from "../sshCertificateTemplates/types";
import { TSshHost } from "../sshHost/types";
import { TSshHostGroup } from "../sshHostGroup/types";
import { userKeys } from "../users/query-keys";
import { TWorkspaceUser } from "../users/types";
import {
@@ -873,6 +874,21 @@ export const useListWorkspaceSshHosts = (projectId: string) => {
});
};
export const useListWorkspaceSshHostGroups = (projectId: string) => {
return useQuery({
queryKey: workspaceKeys.getWorkspaceSshHostGroups(projectId),
queryFn: async () => {
const {
data: { groups }
} = await apiRequest.get<{ groups: (TSshHostGroup & { hostCount: number })[] }>(
`/api/v2/workspace/${projectId}/ssh-host-groups`
);
return groups;
},
enabled: Boolean(projectId)
});
};
export const useListWorkspaceSshCertificateTemplates = (projectId: string) => {
return useQuery({
queryKey: workspaceKeys.getWorkspaceSshCertificateTemplates(projectId),
@@ -63,6 +63,8 @@ export const workspaceKeys = {
allWorkspaceSshCertificates: (projectId: string) =>
[{ projectId }, "workspace-ssh-certificates"] as const,
getWorkspaceSshHosts: (projectId: string) => [{ projectId }, "workspace-ssh-hosts"] as const,
getWorkspaceSshHostGroups: (projectId: string) =>
[{ projectId }, "workspace-ssh-host-groups"] as const,
specificWorkspaceSshCertificates: ({
offset,
limit,