Resolve PR review issues

This commit is contained in:
Tuan Dang
2024-04-11 20:44:38 -07:00
parent fa1b236f26
commit 747acfe070
14 changed files with 272 additions and 297 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ export const registerGroupRouter = async (server: FastifyZodProvider) => {
onRequest: verifyAuth([AuthMode.JWT]),
schema: {
body: z.object({
name: z.string().trim().min(1).describe(GROUPS.CREATE.name),
name: z.string().trim().min(1).max(50).describe(GROUPS.CREATE.name),
slug: z
.string()
.min(5)
+1 -2
View File
@@ -118,9 +118,8 @@ export const groupDALFactory = (db: TDbClient) => {
db.ref("firstName").withSchema(TableName.Users),
db.ref("lastName").withSchema(TableName.Users),
db.ref("id").withSchema(TableName.Users).as("userId")
// db.raw(`CASE WHEN "${TableName.UserGroupMembership}"."groupId" IS NOT NULL THEN TRUE ELSE FALSE END as isPartOfGroup`)
)
.where({ isGhost: false }) // MAKE SURE USER IS NOT A GHOST USER
.where({ isGhost: false })
.offset(offset);
if (limit) {
@@ -12,15 +12,15 @@ export const getDefaultOnPremFeatures = () => {
secretVersioning: true,
pitRecovery: false,
ipAllowlisting: true,
rbac: true,
rbac: false,
customRateLimits: false,
customAlerts: false,
auditLogs: false,
auditLogsRetentionDays: 0,
samlSSO: true,
scim: true,
samlSSO: false,
scim: false,
ldap: false,
groups: true,
groups: false,
status: null,
trial_end: null,
has_used_trial: true,
@@ -19,15 +19,15 @@ export const getDefaultOnPremFeatures = (): TFeatureSet => ({
secretVersioning: true,
pitRecovery: false,
ipAllowlisting: false,
rbac: true,
rbac: false,
customRateLimits: false,
customAlerts: false,
auditLogs: false,
auditLogsRetentionDays: 0,
samlSSO: true,
scim: true,
samlSSO: false,
scim: false,
ldap: false,
groups: true,
groups: false,
status: null,
trial_end: null,
has_used_trial: true,
@@ -35,15 +35,15 @@ export type TFeatureSet = {
secretVersioning: true;
pitRecovery: false;
ipAllowlisting: false;
rbac: true;
rbac: false;
customRateLimits: false;
customAlerts: false;
auditLogs: false;
auditLogsRetentionDays: 0;
samlSSO: true;
scim: true;
samlSSO: false;
scim: false;
ldap: false;
groups: true;
groups: false;
status: null;
trial_end: null;
has_used_trial: true;
@@ -92,8 +92,8 @@ export const groupProjectServiceFactory = ({
role,
project.id
);
const hasPriviledge = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPriviledge)
const hasPrivilege = isAtLeastAsPrivileged(permission, rolePermission);
if (!hasPrivilege)
throw new ForbiddenRequestError({
message: "Failed to add group to project with more privileged role"
});
@@ -226,7 +226,7 @@ export const groupProjectServiceFactory = ({
const customRolesGroupBySlug = groupBy(customRoles, ({ slug }) => slug);
const santiziedProjectMembershipRoles = roles.map((inputRole) => {
const sanitizedProjectMembershipRoles = roles.map((inputRole) => {
const isCustomRole = Boolean(customRolesGroupBySlug?.[inputRole.role]?.[0]);
if (!inputRole.isTemporary) {
return {
@@ -252,7 +252,7 @@ export const groupProjectServiceFactory = ({
const updatedRoles = await groupProjectMembershipRoleDAL.transaction(async (tx) => {
await groupProjectMembershipRoleDAL.delete({ projectMembershipId: projectGroup.id }, tx);
return groupProjectMembershipRoleDAL.insertMany(santiziedProjectMembershipRoles, tx);
return groupProjectMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
});
return updatedRoles;
@@ -325,8 +325,8 @@ export const groupProjectServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Groups);
const groupMemberhips = await groupProjectDAL.findByProjectId(project.id);
return groupMemberhips;
const groupMemberships = await groupProjectDAL.findByProjectId(project.id);
return groupMemberships;
};
return {
@@ -163,7 +163,7 @@ export const identityProjectServiceFactory = ({
const customRolesGroupBySlug = groupBy(customRoles, ({ slug }) => slug);
const santiziedProjectMembershipRoles = roles.map((inputRole) => {
const sanitizedProjectMembershipRoles = roles.map((inputRole) => {
const isCustomRole = Boolean(customRolesGroupBySlug?.[inputRole.role]?.[0]);
if (!inputRole.isTemporary) {
return {
@@ -189,7 +189,7 @@ export const identityProjectServiceFactory = ({
const updatedRoles = await identityProjectMembershipRoleDAL.transaction(async (tx) => {
await identityProjectMembershipRoleDAL.delete({ projectMembershipId: projectIdentity.id }, tx);
return identityProjectMembershipRoleDAL.insertMany(santiziedProjectMembershipRoles, tx);
return identityProjectMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
});
return updatedRoles;
@@ -226,7 +226,7 @@ export const identityProjectServiceFactory = ({
if (!hasRequiredPriviledges)
throw new ForbiddenRequestError({ message: "Failed to delete more privileged identity" });
const [deletedIdentity] = await identityProjectDAL.delete({ identityId }); // TODO: fix
const [deletedIdentity] = await identityProjectDAL.delete({ identityId });
return deletedIdentity;
};
@@ -246,8 +246,8 @@ export const identityProjectServiceFactory = ({
);
ForbiddenError.from(permission).throwUnlessCan(ProjectPermissionActions.Read, ProjectPermissionSub.Identity);
const identityMemberhips = await identityProjectDAL.findByProjectId(projectId);
return identityMemberhips;
const identityMemberships = await identityProjectDAL.findByProjectId(projectId);
return identityMemberships;
};
return {
@@ -157,8 +157,8 @@ export const identityServiceFactory = ({
const { permission } = await permissionService.getOrgPermission(actor, actorId, orgId, actorAuthMethod, actorOrgId);
ForbiddenError.from(permission).throwUnlessCan(OrgPermissionActions.Read, OrgPermissionSubjects.Identity);
const identityMemberhips = await identityOrgMembershipDAL.findByOrgId(orgId);
return identityMemberhips;
const identityMemberships = await identityOrgMembershipDAL.findByOrgId(orgId);
return identityMemberships;
};
return {
@@ -362,7 +362,7 @@ export const projectMembershipServiceFactory = ({
if (customRoles.length !== customInputRoles.length) throw new BadRequestError({ message: "Custom role not found" });
const customRolesGroupBySlug = groupBy(customRoles, ({ slug }) => slug);
const santiziedProjectMembershipRoles = roles.map((inputRole) => {
const sanitizedProjectMembershipRoles = roles.map((inputRole) => {
const isCustomRole = Boolean(customRolesGroupBySlug?.[inputRole.role]?.[0]);
if (!inputRole.isTemporary) {
return {
@@ -388,7 +388,7 @@ export const projectMembershipServiceFactory = ({
const updatedRoles = await projectMembershipDAL.transaction(async (tx) => {
await projectUserMembershipRoleDAL.delete({ projectMembershipId: membershipId }, tx);
return projectUserMembershipRoleDAL.insertMany(santiziedProjectMembershipRoles, tx);
return projectUserMembershipRoleDAL.insertMany(sanitizedProjectMembershipRoles, tx);
});
return updatedRoles;
+6 -3
View File
@@ -1,9 +1,12 @@
export {
useAddGroupToWorkspace,
useDeleteGroupFromWorkspace,
useUpdateGroupWorkspaceRole
} from "./mutations";
export {
useAddIdentityToWorkspace,
useCreateWorkspace,
useCreateWsEnvironment,
useDeleteGroupFromWorkspace,
useDeleteIdentityFromWorkspace,
useDeleteUserFromWorkspace,
useDeleteWorkspace,
@@ -22,8 +25,8 @@ export {
useNameWorkspaceSecrets,
useRenameWorkspace,
useToggleAutoCapitalization,
useUpdateGroupWorkspaceRole,
useUpdateIdentityWorkspaceRole,
useUpdateUserWorkspaceRole,
useUpdateWsEnvironment,
useUpgradeProject} from "./queries";
useUpgradeProject
} from "./queries";
@@ -0,0 +1,64 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import { apiRequest } from "@app/config/request";
import { workspaceKeys } from "./queries";
import { TUpdateWorkspaceGroupRoleDTO } from "./types";
export const useAddGroupToWorkspace = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
groupSlug,
projectSlug,
role
}: {
groupSlug: string;
projectSlug: string;
role?: string;
}) => {
const {
data: { groupMembership }
} = await apiRequest.post(`/api/v2/workspace/${projectSlug}/groups/${groupSlug}`, {
role
});
return groupMembership;
},
onSuccess: (_, { projectSlug }) => {
queryClient.invalidateQueries(workspaceKeys.getWorkspaceGroupMemberships(projectSlug));
}
});
};
export const useUpdateGroupWorkspaceRole = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ groupSlug, projectSlug, roles }: TUpdateWorkspaceGroupRoleDTO) => {
const {
data: { groupMembership }
} = await apiRequest.patch(`/api/v2/workspace/${projectSlug}/groups/${groupSlug}`, {
roles
});
return groupMembership;
},
onSuccess: (_, { projectSlug }) => {
queryClient.invalidateQueries(workspaceKeys.getWorkspaceGroupMemberships(projectSlug));
}
});
};
export const useDeleteGroupFromWorkspace = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ groupSlug, projectSlug }: { groupSlug: string; projectSlug: string }) => {
const {
data: { groupMembership }
} = await apiRequest.delete(`/api/v2/workspace/${projectSlug}/groups/${groupSlug}`);
return groupMembership;
},
onSuccess: (_, { projectSlug }) => {
queryClient.invalidateQueries(workspaceKeys.getWorkspaceGroupMemberships(projectSlug));
}
});
};
@@ -17,7 +17,6 @@ import {
RenameWorkspaceDTO,
TGetUpgradeProjectStatusDTO,
ToggleAutoCapitalizationDTO,
TUpdateWorkspaceGroupRoleDTO,
TUpdateWorkspaceIdentityRoleDTO,
TUpdateWorkspaceUserRoleDTO,
UpdateEnvironmentDTO,
@@ -455,77 +454,6 @@ export const useGetWorkspaceIdentityMemberships = (workspaceId: string) => {
});
};
export const useAddGroupToWorkspace = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
groupSlug,
projectSlug,
role
}: {
groupSlug: string;
projectSlug: string;
role?: string;
}) => {
const {
data: { groupMembership }
} = await apiRequest.post(
`/api/v2/workspace/${projectSlug}/groups/${groupSlug}`,
{
role
}
);
return groupMembership;
},
onSuccess: (_, { projectSlug }) => {
queryClient.invalidateQueries(workspaceKeys.getWorkspaceGroupMemberships(projectSlug));
}
});
};
export const useUpdateGroupWorkspaceRole = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({ groupSlug, projectSlug, roles }: TUpdateWorkspaceGroupRoleDTO) => {
const {
data: { groupMembership }
} = await apiRequest.patch(
`/api/v2/workspace/${projectSlug}/groups/${groupSlug}`, {
roles
}
);
return groupMembership;
},
onSuccess: (_, { projectSlug }) => {
queryClient.invalidateQueries(workspaceKeys.getWorkspaceGroupMemberships(projectSlug));
}
});
};
export const useDeleteGroupFromWorkspace = () => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async ({
groupSlug,
projectSlug
}: {
groupSlug: string;
projectSlug: string;
}) => {
const {
data: { groupMembership }
} = await apiRequest.delete(
`/api/v2/workspace/${projectSlug}/groups/${groupSlug}`
);
return groupMembership;
},
onSuccess: (_, { projectSlug }) => {
queryClient.invalidateQueries(workspaceKeys.getWorkspaceGroupMemberships(projectSlug));
}
});
};
export const useListWorkspaceGroups = (projectSlug: string) => {
return useQuery({
queryKey: workspaceKeys.getWorkspaceGroupMemberships(projectSlug),
@@ -4,18 +4,22 @@ import { zodResolver } from "@hookform/resolvers/zod";
import { z } from "zod";
import { createNotification } from "@app/components/notifications";
import { Button, FormControl, Input, Modal, ModalContent, Select, SelectItem } from "@app/components/v2";
import { useOrganization } from "@app/context";
import {
useCreateGroup,
useGetOrgRoles,
useUpdateGroup
} from "@app/hooks/api";
Button,
FormControl,
Input,
Modal,
ModalContent,
Select,
SelectItem
} from "@app/components/v2";
import { useOrganization } from "@app/context";
import { useCreateGroup, useGetOrgRoles, useUpdateGroup } from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp";
const GroupFormSchema = z.object({
name: z.string().min(1, "Name cannot be empty").max(50, "Name must be 50 characters or fewer"),
slug: z.string().min(1, "Slug cannot be empty").max(36, "Slug must be 36 characters or fewer"),
slug: z.string().min(5, "Slug cannot be empty").max(36, "Slug must be 36 characters or fewer"),
role: z.string()
});
@@ -27,21 +31,13 @@ type Props = {
handlePopUpToggle: (popUpName: keyof UsePopUpState<["group"]>, state?: boolean) => void;
};
export const OrgGroupModal = ({
popUp,
handlePopUpClose,
handlePopUpToggle
}: Props) => {
export const OrgGroupModal = ({ popUp, handlePopUpClose, handlePopUpToggle }: Props) => {
const { currentOrg } = useOrganization();
const { data: roles } = useGetOrgRoles(currentOrg?.id || "");
const { mutateAsync: createMutateAsync, isLoading: createIsLoading } = useCreateGroup();
const { mutateAsync: updateMutateAsync, isLoading: updateIsLoading } = useUpdateGroup();
const {
control,
handleSubmit,
reset,
} = useForm<TGroupFormData>({
const { control, handleSubmit, reset } = useForm<TGroupFormData>({
resolver: zodResolver(GroupFormSchema)
});
@@ -74,11 +70,7 @@ export const OrgGroupModal = ({
}
}, [popUp?.group?.data, roles]);
const onGroupModalSubmit = async ({
name,
slug,
role
}: TGroupFormData) => {
const onGroupModalSubmit = async ({ name, slug, role }: TGroupFormData) => {
try {
if (!currentOrg?.id) return;
@@ -116,7 +108,7 @@ export const OrgGroupModal = ({
type: "error"
});
}
}
};
return (
<Modal
@@ -132,15 +124,8 @@ export const OrgGroupModal = ({
control={control}
name="name"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Name"
errorText={error?.message}
isError={Boolean(error)}
>
<Input
{...field}
placeholder="Engineering"
/>
<FormControl label="Name" errorText={error?.message} isError={Boolean(error)}>
<Input {...field} placeholder="Engineering" />
</FormControl>
)}
/>
@@ -148,15 +133,8 @@ export const OrgGroupModal = ({
control={control}
name="slug"
render={({ field, fieldState: { error } }) => (
<FormControl
label="Slug"
errorText={error?.message}
isError={Boolean(error)}
>
<Input
{...field}
placeholder="engineering"
/>
<FormControl label="Slug" errorText={error?.message} isError={Boolean(error)}>
<Input {...field} placeholder="engineering" />
</FormControl>
)}
/>
@@ -206,6 +184,5 @@ export const OrgGroupModal = ({
</form>
</ModalContent>
</Modal>
);
}
};
@@ -5,7 +5,13 @@ import { Tab, TabList, TabPanel, Tabs } from "@app/components/v2";
import { ProjectPermissionActions, ProjectPermissionSub, useWorkspace } from "@app/context";
import { withProjectPermission } from "@app/hoc";
import { GroupsTab, IdentityTab, MemberListTab, ProjectRoleListTab, ServiceTokenTab } from "./components";
import {
GroupsTab,
IdentityTab,
MemberListTab,
ProjectRoleListTab,
ServiceTokenTab
} from "./components";
enum TabSections {
Member = "members",
@@ -18,8 +24,6 @@ enum TabSections {
export const MembersPage = withProjectPermission(
() => {
const { currentWorkspace } = useWorkspace();
console.log("currentWorkspace: ", currentWorkspace);
return (
<div className="container mx-auto flex flex-col justify-between bg-bunker-800 text-white">
<div className="mx-auto mb-6 w-full max-w-7xl py-6 px-6">
@@ -44,7 +48,7 @@ export const MembersPage = withProjectPermission(
{currentWorkspace?.version && currentWorkspace.version > 1 && (
<TabPanel value={TabSections.Groups}>
<motion.div
key="panel-1"
key="panel-groups"
transition={{ duration: 0.15 }}
initial={{ opacity: 0, translateX: 30 }}
animate={{ opacity: 1, translateX: 0 }}