1
0
mirror of https://github.com/Infisical/infisical.git synced 2025-03-31 22:09:57 +00:00

Enable users to change the ordering of environments

This commit is contained in:
Daniel Inge
2023-08-16 17:30:50 -04:00
parent 3436e6be0e
commit 29c0d8ab57
6 changed files with 151 additions and 5 deletions
backend/src
frontend/src
hooks/api/workspace
views/Settings/ProjectSettingsPage/components/EnvironmentSection

@ -85,6 +85,43 @@ export const createWorkspaceEnvironment = async (
});
};
/**
* Swaps the ordering of two environments in the database. This is purely for asthetic purposes.
* @param req
* @param res
* @returns
*/
export const reorderWorkspaceEnvironments = async (
req: Request,
res: Response
) => {
const { workspaceId } = req.params;
const { environmentSlug, environmentName, otherEnvironmentSlug, otherEnvironmentName } = req.body;
// atomic update the env to avoid conflict
const workspace = await Workspace.findById(workspaceId).exec();
if (!workspace) {
throw new Error("Failed to create workspace environment");
}
const environmentIndex = workspace.environments.findIndex((env) => env.name === environmentName && env.slug === environmentSlug)
const otherEnvironmentIndex = workspace.environments.findIndex((env) => env.name === otherEnvironmentName && env.slug === otherEnvironmentSlug)
if (environmentIndex === undefined || otherEnvironmentIndex === undefined) {
throw new Error("environment or otherEnvironment couldn't be found")
}
// swap the order of the environments
[workspace.environments[environmentIndex], workspace.environments[otherEnvironmentIndex]] = [workspace.environments[otherEnvironmentIndex], workspace.environments[environmentIndex]]
await workspace.save()
return res.status(200).send({
message: "Successfully reordered environments",
workspace: workspaceId,
});
};
/**
* Rename workspace environment with new name and slug of a workspace with [workspaceId]
* Old slug [oldEnvironmentSlug] must be provided
@ -124,7 +161,7 @@ export const renameWorkspaceEnvironment = async (
if (envIndex === -1) {
throw new Error("Invalid environment given");
}
const oldEnvironment = workspace.environments[envIndex];
workspace.environments[envIndex].name = environmentName;
@ -159,7 +196,7 @@ export const renameWorkspaceEnvironment = async (
{ $set: { "deniedPermissions.$[element].environmentSlug": environmentSlug } },
{ arrayFilters: [{ "element.environmentSlug": oldEnvironmentSlug }] }
);
await EEAuditLogService.createAuditLog(
req.authData,
{
@ -210,7 +247,7 @@ export const deleteWorkspaceEnvironment = async (
if (envIndex === -1) {
throw new Error("Invalid environment given");
}
const oldEnvironment = workspace.environments[envIndex];
workspace.environments.splice(envIndex, 1);

@ -46,6 +46,24 @@ router.put(
environmentController.renameWorkspaceEnvironment
);
router.patch(
"/:workspaceId/environments",
requireAuth({
acceptedAuthModes: [AuthMode.JWT],
}),
requireWorkspaceAuth({
acceptedRoles: [ADMIN, MEMBER],
locationWorkspaceId: "params",
}),
param("workspaceId").exists().trim(),
body("environmentSlug").exists().isString().trim(),
body("environmentName").exists().isString().trim(),
body("otherEnvironmentSlug").exists().isString().trim(),
body("otherEnvironmentName").exists().isString().trim(),
validateRequest,
environmentController.reorderWorkspaceEnvironments
);
router.delete(
"/:workspaceId/environments",
requireAuth({

@ -16,6 +16,7 @@ export {
useGetWorkspaceUsers,
useNameWorkspaceSecrets,
useRenameWorkspace,
useReorderWsEnvironment,
useToggleAutoCapitalization,
useUpdateUserWorkspaceRole,
useUpdateWsEnvironment} from "./queries";

@ -13,6 +13,7 @@ import {
GetWsEnvironmentDTO,
NameWorkspaceSecretsDTO,
RenameWorkspaceDTO,
ReorderEnvironmentsDTO,
ToggleAutoCapitalizationDTO,
UpdateEnvironmentDTO,
Workspace,
@ -244,6 +245,21 @@ export const useCreateWsEnvironment = () => {
});
};
export const useReorderWsEnvironment = () => {
const queryClient = useQueryClient();
return useMutation<{}, {}, ReorderEnvironmentsDTO>({
mutationFn: ({ workspaceID, environmentSlug, environmentName, otherEnvironmentSlug, otherEnvironmentName}) => {
return apiRequest.patch(`/api/v2/workspace/${workspaceID}/environments`, {
environmentSlug, environmentName, otherEnvironmentSlug, otherEnvironmentName
});
},
onSuccess: () => {
queryClient.invalidateQueries(workspaceKeys.getAllUserWorkspace);
}
});
};
export const useUpdateWsEnvironment = () => {
const queryClient = useQueryClient();

@ -46,6 +46,15 @@ export type CreateEnvironmentDTO = {
environmentName: string;
};
export type ReorderEnvironmentsDTO = {
workspaceID: string;
environmentSlug: string;
environmentName: string;
otherEnvironmentSlug: string;
otherEnvironmentName: string;
};
export type UpdateEnvironmentDTO = {
workspaceID: string;
oldEnvironmentSlug: string;

@ -1,6 +1,7 @@
import { faPencil, faXmark } from "@fortawesome/free-solid-svg-icons";
import { faArrowDown,faArrowUp, faPencil, faXmark } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { useNotificationContext } from "@app/components/context/Notifications/NotificationProvider";
import {
EmptyState,
IconButton,
@ -14,6 +15,9 @@ import {
Tr
} from "@app/components/v2";
import { useWorkspace } from "@app/context";
import {
useReorderWsEnvironment
} from "@app/hooks/api";
import { UsePopUpState } from "@app/hooks/usePopUp";
type Props = {
@ -31,6 +35,43 @@ type Props = {
export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
const { currentWorkspace, isLoading } = useWorkspace();
const { createNotification } = useNotificationContext();
const reorderWsEnvironment = useReorderWsEnvironment();
const reorderEnvs = async (moveUp: boolean, name: string, slug: string) => {
try {
if (!currentWorkspace?._id) return;
const indexOfEnv = currentWorkspace.environments.findIndex((env) => env.name === name && env.slug === slug);
// check that this reordering is possible
if (indexOfEnv === 0 && moveUp || indexOfEnv === currentWorkspace.environments.length - 1 && !moveUp) {
return
}
const indexToSwap = moveUp ? indexOfEnv - 1 : indexOfEnv + 1
await reorderWsEnvironment.mutateAsync({
workspaceID: currentWorkspace._id,
environmentSlug: slug,
environmentName: name,
otherEnvironmentSlug: currentWorkspace.environments[indexToSwap].slug,
otherEnvironmentName: currentWorkspace.environments[indexToSwap].name
});
createNotification({
text: "Successfully re-ordered environments",
type: "success"
});
} catch (err) {
console.error(err);
createNotification({
text: "Failed to re-order environments",
type: "error"
});
}
};
return (
<TableContainer>
<Table>
@ -45,11 +86,35 @@ export const EnvironmentTable = ({ handlePopUpOpen }: Props) => {
{isLoading && <TableSkeleton columns={3} innerKey="project-envs" />}
{!isLoading &&
currentWorkspace &&
currentWorkspace.environments.map(({ name, slug }) => (
currentWorkspace.environments.map(({ name, slug }, pos) => (
<Tr key={name}>
<Td>{name}</Td>
<Td>{slug}</Td>
<Td className="flex items-center justify-end">
<IconButton
className="mr-3 py-2"
onClick={() => {
reorderEnvs(false, name, slug)
}}
colorSchema="primary"
variant="plain"
ariaLabel="update"
isDisabled={pos === currentWorkspace.environments.length - 1}
>
<FontAwesomeIcon icon={faArrowDown} />
</IconButton>
<IconButton
className="mr-3 py-2"
onClick={() => {
reorderEnvs(true, name, slug)
}}
colorSchema="primary"
variant="plain"
ariaLabel="update"
isDisabled={pos === 0}
>
<FontAwesomeIcon icon={faArrowUp} />
</IconButton>
<IconButton
className="mr-3 py-2"
onClick={() => {