mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 05:28:51 +00:00
feat: updated settings page
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { useMemo } from "react";
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { useRouteContext, useSearch } from "@tanstack/react-router";
|
||||
|
||||
import { fetchOrganizationById, organizationKeys } from "@app/hooks/api/organization/queries";
|
||||
import { useMemo } from "react";
|
||||
|
||||
export const useOrganization = () => {
|
||||
const organizationId = useRouteContext({
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
export { useCreateSubOrganization } from "./mutations";
|
||||
export { useCreateSubOrganization, useUpdateSubOrganization } from "./mutations";
|
||||
export { subOrganizationsQuery } from "./queries";
|
||||
export type {
|
||||
TCreateSubOrganizationDTO,
|
||||
TListSubOrganizationsDTO,
|
||||
TSubOrganization
|
||||
TSubOrganization,
|
||||
TUpdateSubOrganizationDTO
|
||||
} from "./types";
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { subOrganizationsQuery } from "./queries";
|
||||
import { TCreateSubOrganizationDTO, TSubOrganization } from "./types";
|
||||
import { TCreateSubOrganizationDTO, TSubOrganization, TUpdateSubOrganizationDTO } from "./types";
|
||||
|
||||
export const useCreateSubOrganization = () => {
|
||||
const queryClient = useQueryClient();
|
||||
@@ -20,3 +20,19 @@ export const useCreateSubOrganization = () => {
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const useUpdateSubOrganization = () => {
|
||||
const queryClient = useQueryClient();
|
||||
return useMutation({
|
||||
mutationFn: async ({ subOrgId, name }: TUpdateSubOrganizationDTO) => {
|
||||
const { data } = await apiRequest.patch<{ organization: TSubOrganization }>(
|
||||
`/api/v1/sub-organizations/${subOrgId}`,
|
||||
{ name }
|
||||
);
|
||||
return data;
|
||||
},
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: subOrganizationsQuery.allKey() });
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -15,3 +15,8 @@ export type TListSubOrganizationsDTO = {
|
||||
offset?: number;
|
||||
isAccessible?: boolean;
|
||||
};
|
||||
|
||||
export type TUpdateSubOrganizationDTO = {
|
||||
subOrgId: string;
|
||||
name: string;
|
||||
};
|
||||
|
||||
@@ -378,7 +378,7 @@ export const MyProjectView = ({
|
||||
<div className="flex w-full flex-row">
|
||||
<ProjectListToggle value={projectListView} onChange={onProjectListViewChange} />
|
||||
<Input
|
||||
className="h-[2.3rem] bg-mineshaft-800 text-sm placeholder-mineshaft-50 duration-200 focus:bg-mineshaft-700/80"
|
||||
className="h-[2.3rem] bg-mineshaft-800 text-sm placeholder-mineshaft-50/60 duration-200 focus:bg-mineshaft-700/80"
|
||||
containerClassName="w-full ml-2"
|
||||
placeholder="Search by project name..."
|
||||
value={searchFilter}
|
||||
|
||||
+4
-3
@@ -1,15 +1,16 @@
|
||||
import { useOrgPermission } from "@app/context";
|
||||
import { useOrganization, useOrgPermission } from "@app/context";
|
||||
import { OrgMembershipRole } from "@app/helpers/roles";
|
||||
|
||||
import { OrgDeleteSection } from "../OrgDeleteSection";
|
||||
import { OrgIncidentContactsSection } from "../OrgIncidentContactsSection";
|
||||
import { OrgNameChangeSection } from "../OrgNameChangeSection";
|
||||
import { OrgNameChangeSection, SubOrgNameChangeSection } from "../OrgNameChangeSection";
|
||||
|
||||
export const OrgGeneralTab = () => {
|
||||
const { hasOrgRole } = useOrgPermission();
|
||||
const { isSubOrganization } = useOrganization();
|
||||
return (
|
||||
<div className="mb-6 rounded-lg border border-mineshaft-600 bg-mineshaft-900 p-6">
|
||||
<OrgNameChangeSection />
|
||||
{isSubOrganization ? <SubOrgNameChangeSection /> : <OrgNameChangeSection />}
|
||||
<OrgIncidentContactsSection />
|
||||
{hasOrgRole(OrgMembershipRole.Admin) && <OrgDeleteSection />}
|
||||
</div>
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
import { Controller, useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { useQueryClient } from "@tanstack/react-query";
|
||||
import { useNavigate, useRouter } from "@tanstack/react-router";
|
||||
import { z } from "zod";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { OrgPermissionCan } from "@app/components/permissions";
|
||||
import { Button, FormControl, Input } from "@app/components/v2";
|
||||
import {
|
||||
OrgPermissionActions,
|
||||
OrgPermissionSubjects,
|
||||
useOrganization,
|
||||
useOrgPermission
|
||||
} from "@app/context";
|
||||
import { useUpdateSubOrganization } from "@app/hooks/api";
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z
|
||||
.string()
|
||||
.regex(/^[a-zA-Z0-9-]+$/, "Name must only contain alphanumeric characters or hyphens")
|
||||
});
|
||||
|
||||
type FormData = z.infer<typeof formSchema>;
|
||||
|
||||
export const SubOrgNameChangeSection = (): JSX.Element => {
|
||||
const { currentOrg } = useOrganization();
|
||||
const { permission } = useOrgPermission();
|
||||
const navigate = useNavigate();
|
||||
const router = useRouter();
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
const { handleSubmit, control } = useForm<FormData>({
|
||||
resolver: zodResolver(formSchema),
|
||||
defaultValues: {
|
||||
name: currentOrg?.subOrganization?.name || ""
|
||||
}
|
||||
});
|
||||
const { mutateAsync, isPending } = useUpdateSubOrganization();
|
||||
|
||||
const onFormSubmit = async ({ name }: FormData) => {
|
||||
try {
|
||||
await mutateAsync({
|
||||
name,
|
||||
subOrgId: currentOrg.id
|
||||
});
|
||||
|
||||
navigate({ to: "/organization/settings", search: { subOrganization: name } });
|
||||
queryClient.clear();
|
||||
await router.invalidate({ sync: true });
|
||||
createNotification({
|
||||
text: "Successfully updated sub-organization details",
|
||||
type: "success"
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
createNotification({
|
||||
text: "Failed to update sub-organization details",
|
||||
type: "error"
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onFormSubmit)} className="py-4">
|
||||
<div>
|
||||
<h2 className="text-md mb-2 text-mineshaft-100">Organization Name</h2>
|
||||
<Controller
|
||||
defaultValue=""
|
||||
render={({ field, fieldState: { error } }) => (
|
||||
<FormControl isError={Boolean(error)} errorText={error?.message} className="max-w-md">
|
||||
<Input
|
||||
isDisabled={permission.cannot(
|
||||
OrgPermissionActions.Edit,
|
||||
OrgPermissionSubjects.Settings
|
||||
)}
|
||||
placeholder="Acme Corp"
|
||||
{...field}
|
||||
/>
|
||||
</FormControl>
|
||||
)}
|
||||
control={control}
|
||||
name="name"
|
||||
/>
|
||||
</div>
|
||||
<OrgPermissionCan I={OrgPermissionActions.Edit} a={OrgPermissionSubjects.Settings}>
|
||||
{(isAllowed) => (
|
||||
<Button
|
||||
isLoading={isPending}
|
||||
isDisabled={!isAllowed}
|
||||
colorSchema="primary"
|
||||
variant="outline_bg"
|
||||
type="submit"
|
||||
>
|
||||
Save
|
||||
</Button>
|
||||
)}
|
||||
</OrgPermissionCan>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
@@ -1 +1,2 @@
|
||||
export { OrgNameChangeSection } from "./OrgNameChangeSection";
|
||||
export { SubOrgNameChangeSection } from "./SubOrgNameChangeSection";
|
||||
|
||||
Reference in New Issue
Block a user