diff --git a/src/components/CreateInternalResourceDialog.tsx b/src/components/CreateInternalResourceDialog.tsx index 16179f8a..44ed12a5 100644 --- a/src/components/CreateInternalResourceDialog.tsx +++ b/src/components/CreateInternalResourceDialog.tsx @@ -89,7 +89,9 @@ export default function CreateInternalResourceDialog({ // mode: z.enum(["host", "cidr", "port"]), mode: z.enum(["host", "cidr"]), destination: z.string().min(1), - siteId: z.int().positive(t("createInternalResourceDialogPleaseSelectSite")), + siteId: z + .int() + .positive(t("createInternalResourceDialogPleaseSelectSite")), // protocol: z.enum(["tcp", "udp"]), // proxyPort: z.int() // .positive() @@ -101,25 +103,31 @@ export default function CreateInternalResourceDialog({ // .max(65535, t("createInternalResourceDialogDestinationPortMax")) // .nullish(), alias: z.string().nullish(), - roles: z.array( - z.object({ - id: z.string(), - text: z.string() - }) - ).optional(), - users: z.array( - z.object({ - id: z.string(), - text: z.string() - }) - ).optional(), - clients: z.array( - z.object({ - id: z.string(), - text: z.string() - }) - ).optional() - }) + roles: z + .array( + z.object({ + id: z.string(), + text: z.string() + }) + ) + .optional(), + users: z + .array( + z.object({ + id: z.string(), + text: z.string() + }) + ) + .optional(), + clients: z + .array( + z.object({ + id: z.string(), + text: z.string() + }) + ) + .optional() + }); // .refine( // (data) => { // if (data.mode === "port") { @@ -159,12 +167,24 @@ export default function CreateInternalResourceDialog({ type FormData = z.infer; - const [allRoles, setAllRoles] = useState<{ id: string; text: string }[]>([]); - const [allUsers, setAllUsers] = useState<{ id: string; text: string }[]>([]); - const [allClients, setAllClients] = useState<{ id: string; text: string }[]>([]); - const [activeRolesTagIndex, setActiveRolesTagIndex] = useState(null); - const [activeUsersTagIndex, setActiveUsersTagIndex] = useState(null); - const [activeClientsTagIndex, setActiveClientsTagIndex] = useState(null); + const [allRoles, setAllRoles] = useState<{ id: string; text: string }[]>( + [] + ); + const [allUsers, setAllUsers] = useState<{ id: string; text: string }[]>( + [] + ); + const [allClients, setAllClients] = useState< + { id: string; text: string }[] + >([]); + const [activeRolesTagIndex, setActiveRolesTagIndex] = useState< + number | null + >(null); + const [activeUsersTagIndex, setActiveUsersTagIndex] = useState< + number | null + >(null); + const [activeClientsTagIndex, setActiveClientsTagIndex] = useState< + number | null + >(null); const [hasMachineClients, setHasMachineClients] = useState(false); const availableSites = sites.filter( @@ -211,11 +231,18 @@ export default function CreateInternalResourceDialog({ useEffect(() => { const fetchRolesUsersAndClients = async () => { try { - const [rolesResponse, usersResponse, clientsResponse] = await Promise.all([ - api.get>(`/org/${orgId}/roles`), - api.get>(`/org/${orgId}/users`), - api.get>(`/org/${orgId}/clients?filter=machine&limit=1000`) - ]); + const [rolesResponse, usersResponse, clientsResponse] = + await Promise.all([ + api.get>( + `/org/${orgId}/roles` + ), + api.get>( + `/org/${orgId}/users` + ), + api.get>( + `/org/${orgId}/clients?filter=machine&limit=1000` + ) + ]); setAllRoles( rolesResponse.data.data.roles @@ -243,7 +270,10 @@ export default function CreateInternalResourceDialog({ setAllClients(machineClients); setHasMachineClients(machineClients.length > 0); } catch (error) { - console.error("Error fetching roles, users, and clients:", error); + console.error( + "Error fetching roles, users, and clients:", + error + ); } }; @@ -265,10 +295,19 @@ export default function CreateInternalResourceDialog({ // destinationPort: data.mode === "port" ? data.destinationPort : undefined, destination: data.destination, enabled: true, - alias: data.alias && typeof data.alias === "string" && data.alias.trim() ? data.alias : undefined, - roleIds: data.roles ? data.roles.map((r) => parseInt(r.id)) : [], + alias: + data.alias && + typeof data.alias === "string" && + data.alias.trim() + ? data.alias + : undefined, + roleIds: data.roles + ? data.roles.map((r) => parseInt(r.id)) + : [], userIds: data.users ? data.users.map((u) => u.id) : [], - clientIds: data.clients ? data.clients.map((c) => parseInt(c.id)) : [] + clientIds: data.clients + ? data.clients.map((c) => parseInt(c.id)) + : [] } ); @@ -295,7 +334,9 @@ export default function CreateInternalResourceDialog({ toast({ title: t("createInternalResourceDialogSuccess"), - description: t("createInternalResourceDialogInternalResourceCreatedSuccessfully"), + description: t( + "createInternalResourceDialogInternalResourceCreatedSuccessfully" + ), variant: "default" }); @@ -307,7 +348,9 @@ export default function CreateInternalResourceDialog({ title: t("createInternalResourceDialogError"), description: formatAxiosError( error, - t("createInternalResourceDialogFailedToCreateInternalResource") + t( + "createInternalResourceDialogFailedToCreateInternalResource" + ) ), variant: "destructive" }); @@ -321,13 +364,19 @@ export default function CreateInternalResourceDialog({ - {t("createInternalResourceDialogNoSitesAvailable")} + + {t("createInternalResourceDialogNoSitesAvailable")} + - {t("createInternalResourceDialogNoSitesAvailableDescription")} + {t( + "createInternalResourceDialogNoSitesAvailableDescription" + )} - + @@ -338,9 +387,13 @@ export default function CreateInternalResourceDialog({ - {t("createInternalResourceDialogCreateClientResource")} + + {t("createInternalResourceDialogCreateClientResource")} + - {t("createInternalResourceDialogCreateClientResourceDescription")} + {t( + "createInternalResourceDialogCreateClientResourceDescription" + )} @@ -353,7 +406,9 @@ export default function CreateInternalResourceDialog({ {/* Resource Properties Form */}

- {t("createInternalResourceDialogResourceProperties")} + {t( + "createInternalResourceDialogResourceProperties" + )}

( - {t("createInternalResourceDialogName")} + + {t( + "createInternalResourceDialogName" + )} + @@ -375,7 +434,11 @@ export default function CreateInternalResourceDialog({ name="siteId" render={({ field }) => ( - {t("createInternalResourceDialogSite")} + + {t( + "createInternalResourceDialogSite" + )} + @@ -384,43 +447,71 @@ export default function CreateInternalResourceDialog({ role="combobox" className={cn( "w-full justify-between", - !field.value && "text-muted-foreground" + !field.value && + "text-muted-foreground" )} > {field.value ? availableSites.find( - (site) => site.siteId === field.value + ( + site + ) => + site.siteId === + field.value )?.name - : t("createInternalResourceDialogSelectSite")} + : t( + "createInternalResourceDialogSelectSite" + )} - + - {t("createInternalResourceDialogNoSitesFound")} + + {t( + "createInternalResourceDialogNoSitesFound" + )} + - {availableSites.map((site) => ( - { - field.onChange(site.siteId); - }} - > - - {site.name} - - ))} + {availableSites.map( + ( + site + ) => ( + { + field.onChange( + site.siteId + ); + }} + > + + { + site.name + } + + ) + )} @@ -431,14 +522,20 @@ export default function CreateInternalResourceDialog({ )} /> - ( - {t("createInternalResourceDialogMode")} + + {t( + "createInternalResourceDialogMode" + )} + )} /> -{/* + {/* {mode === "port" && ( <>
@@ -521,7 +626,9 @@ export default function CreateInternalResourceDialog({ {/* Target Configuration Form */}

- {t("createInternalResourceDialogTargetConfiguration")} + {t( + "createInternalResourceDialogTargetConfiguration" + )}

( - {t("createInternalResourceDialogDestination")} + {t( + "createInternalResourceDialogDestination" + )} - {mode === "host" && t("createInternalResourceDialogDestinationHostDescription")} - {mode === "cidr" && t("createInternalResourceDialogDestinationCidrDescription")} + {mode === "host" && + t( + "createInternalResourceDialogDestinationHostDescription" + )} + {mode === "cidr" && + t( + "createInternalResourceDialogDestinationCidrDescription" + )} {/* {mode === "port" && t("createInternalResourceDialogDestinationIPDescription")} */} @@ -584,12 +699,23 @@ export default function CreateInternalResourceDialog({ name="alias" render={({ field }) => ( - {t("createInternalResourceDialogAlias")} + + {t( + "createInternalResourceDialogAlias" + )} + - + - {t("createInternalResourceDialogAliasDescription")} + {t( + "createInternalResourceDialogAliasDescription" + )} @@ -609,31 +735,53 @@ export default function CreateInternalResourceDialog({ name="roles" render={({ field }) => ( - {t("roles")} + + {t("roles")} + { form.setValue( "roles", - newRoles as [Tag, ...Tag[]] + newRoles as [ + Tag, + ...Tag[] + ] ); }} - enableAutocomplete={true} - autocompleteOptions={allRoles} + enableAutocomplete={ + true + } + autocompleteOptions={ + allRoles + } allowDuplicates={false} - restrictTagsToAutocompleteOptions={true} + restrictTagsToAutocompleteOptions={ + true + } sortTags={true} /> - {t("resourceRoleDescription")} + {t( + "resourceRoleDescription" + )} )} @@ -643,25 +791,45 @@ export default function CreateInternalResourceDialog({ name="users" render={({ field }) => ( - {t("users")} + + {t("users")} + { form.setValue( "users", - newUsers as [Tag, ...Tag[]] + newUsers as [ + Tag, + ...Tag[] + ] ); }} - enableAutocomplete={true} - autocompleteOptions={allUsers} + enableAutocomplete={ + true + } + autocompleteOptions={ + allUsers + } allowDuplicates={false} - restrictTagsToAutocompleteOptions={true} + restrictTagsToAutocompleteOptions={ + true + } sortTags={true} /> @@ -675,31 +843,62 @@ export default function CreateInternalResourceDialog({ name="clients" render={({ field }) => ( - {t("clients")} + + {t("clients")} + { + tags={ + form.getValues() + .clients || + [] + } + setTags={( + newClients + ) => { form.setValue( "clients", - newClients as [Tag, ...Tag[]] + newClients as [ + Tag, + ...Tag[] + ] ); }} - enableAutocomplete={true} - autocompleteOptions={allClients} - allowDuplicates={false} - restrictTagsToAutocompleteOptions={true} + enableAutocomplete={ + true + } + autocompleteOptions={ + allClients + } + allowDuplicates={ + false + } + restrictTagsToAutocompleteOptions={ + true + } sortTags={true} /> - {t("resourceClientDescription") || "Machine clients that can access this resource"} + {t( + "resourceClientDescription" + ) || + "Machine clients that can access this resource"} )} diff --git a/src/components/EditInternalResourceDialog.tsx b/src/components/EditInternalResourceDialog.tsx index b575dc61..2eea4bb0 100644 --- a/src/components/EditInternalResourceDialog.tsx +++ b/src/components/EditInternalResourceDialog.tsx @@ -81,32 +81,41 @@ export default function EditInternalResourceDialog({ const [isSubmitting, setIsSubmitting] = useState(false); const formSchema = z.object({ - name: z.string().min(1, t("editInternalResourceDialogNameRequired")).max(255, t("editInternalResourceDialogNameMaxLength")), + name: z + .string() + .min(1, t("editInternalResourceDialogNameRequired")) + .max(255, t("editInternalResourceDialogNameMaxLength")), mode: z.enum(["host", "cidr", "port"]), // protocol: z.enum(["tcp", "udp"]).nullish(), // proxyPort: z.int().positive().min(1, t("editInternalResourceDialogProxyPortMin")).max(65535, t("editInternalResourceDialogProxyPortMax")).nullish(), destination: z.string().min(1), // destinationPort: z.int().positive().min(1, t("editInternalResourceDialogDestinationPortMin")).max(65535, t("editInternalResourceDialogDestinationPortMax")).nullish(), alias: z.string().nullish(), - roles: z.array( - z.object({ - id: z.string(), - text: z.string() - }) - ).optional(), - users: z.array( - z.object({ - id: z.string(), - text: z.string() - }) - ).optional(), - clients: z.array( - z.object({ - id: z.string(), - text: z.string() - }) - ).optional() - }) + roles: z + .array( + z.object({ + id: z.string(), + text: z.string() + }) + ) + .optional(), + users: z + .array( + z.object({ + id: z.string(), + text: z.string() + }) + ) + .optional(), + clients: z + .array( + z.object({ + id: z.string(), + text: z.string() + }) + ) + .optional() + }); // .refine( // (data) => { // if (data.mode === "port") { @@ -146,12 +155,24 @@ export default function EditInternalResourceDialog({ type FormData = z.infer; - const [allRoles, setAllRoles] = useState<{ id: string; text: string }[]>([]); - const [allUsers, setAllUsers] = useState<{ id: string; text: string }[]>([]); - const [allClients, setAllClients] = useState<{ id: string; text: string }[]>([]); - const [activeRolesTagIndex, setActiveRolesTagIndex] = useState(null); - const [activeUsersTagIndex, setActiveUsersTagIndex] = useState(null); - const [activeClientsTagIndex, setActiveClientsTagIndex] = useState(null); + const [allRoles, setAllRoles] = useState<{ id: string; text: string }[]>( + [] + ); + const [allUsers, setAllUsers] = useState<{ id: string; text: string }[]>( + [] + ); + const [allClients, setAllClients] = useState< + { id: string; text: string }[] + >([]); + const [activeRolesTagIndex, setActiveRolesTagIndex] = useState< + number | null + >(null); + const [activeUsersTagIndex, setActiveUsersTagIndex] = useState< + number | null + >(null); + const [activeClientsTagIndex, setActiveClientsTagIndex] = useState< + number | null + >(null); const [loadingRolesUsers, setLoadingRolesUsers] = useState(false); const [hasMachineClients, setHasMachineClients] = useState(false); @@ -183,22 +204,30 @@ export default function EditInternalResourceDialog({ resourceUsersResponse, clientsResponse ] = await Promise.all([ - api.get>(`/org/${orgId}/roles`), + api.get>( + `/org/${orgId}/roles` + ), api.get>( `/site-resource/${resource.id}/roles` ), - api.get>(`/org/${orgId}/users`), + api.get>( + `/org/${orgId}/users` + ), api.get>( `/site-resource/${resource.id}/users` ), - api.get>(`/org/${orgId}/clients?filter=machine&limit=1000`) + api.get>( + `/org/${orgId}/clients?filter=machine&limit=1000` + ) ]); - let resourceClientsResponse: AxiosResponse>; + let resourceClientsResponse: AxiosResponse< + AxiosResponse + >; try { - resourceClientsResponse = await api.get>( - `/site-resource/${resource.id}/clients` - ); + resourceClientsResponse = await api.get< + AxiosResponse + >(`/site-resource/${resource.id}/clients`); } catch { resourceClientsResponse = { data: { @@ -255,16 +284,21 @@ export default function EditInternalResourceDialog({ })); setAllClients(machineClients); - - const existingClients = resourceClientsResponse.data.data.clients.map((c: { clientId: number; name: string }) => ({ - id: c.clientId.toString(), - text: c.name - })); + + const existingClients = + resourceClientsResponse.data.data.clients.map( + (c: { clientId: number; name: string }) => ({ + id: c.clientId.toString(), + text: c.name + }) + ); form.setValue("clients", existingClients); // Show clients tag input if there are machine clients OR existing client access - setHasMachineClients(machineClients.length > 0 || existingClients.length > 0); + setHasMachineClients( + machineClients.length > 0 || existingClients.length > 0 + ); } catch (error) { console.error("Error fetching roles, users, and clients:", error); } finally { @@ -295,18 +329,26 @@ export default function EditInternalResourceDialog({ setIsSubmitting(true); try { // Update the site resource - await api.post(`/org/${orgId}/site/${resource.siteId}/resource/${resource.id}`, { - name: data.name, - mode: data.mode, - // protocol: data.mode === "port" ? data.protocol : null, - // proxyPort: data.mode === "port" ? data.proxyPort : null, - // destinationPort: data.mode === "port" ? data.destinationPort : null, - destination: data.destination, - alias: data.alias && typeof data.alias === "string" && data.alias.trim() ? data.alias : null, - roleIds: (data.roles || []).map((r) => parseInt(r.id)), - userIds: (data.users || []).map((u) => u.id), - clientIds: (data.clients || []).map((c) => parseInt(c.id)) - }); + await api.post( + `/org/${orgId}/site/${resource.siteId}/resource/${resource.id}`, + { + name: data.name, + mode: data.mode, + // protocol: data.mode === "port" ? data.protocol : null, + // proxyPort: data.mode === "port" ? data.proxyPort : null, + // destinationPort: data.mode === "port" ? data.destinationPort : null, + destination: data.destination, + alias: + data.alias && + typeof data.alias === "string" && + data.alias.trim() + ? data.alias + : null, + roleIds: (data.roles || []).map((r) => parseInt(r.id)), + userIds: (data.users || []).map((u) => u.id), + clientIds: (data.clients || []).map((c) => parseInt(c.id)) + } + ); // Update roles, users, and clients // await Promise.all([ @@ -323,7 +365,9 @@ export default function EditInternalResourceDialog({ toast({ title: t("editInternalResourceDialogSuccess"), - description: t("editInternalResourceDialogInternalResourceUpdatedSuccessfully"), + description: t( + "editInternalResourceDialogInternalResourceUpdatedSuccessfully" + ), variant: "default" }); @@ -333,7 +377,12 @@ export default function EditInternalResourceDialog({ console.error("Error updating internal resource:", error); toast({ title: t("editInternalResourceDialogError"), - description: formatAxiosError(error, t("editInternalResourceDialogFailedToUpdateInternalResource")), + description: formatAxiosError( + error, + t( + "editInternalResourceDialogFailedToUpdateInternalResource" + ) + ), variant: "destructive" }); } finally { @@ -345,24 +394,41 @@ export default function EditInternalResourceDialog({ - {t("editInternalResourceDialogEditClientResource")} + + {t("editInternalResourceDialogEditClientResource")} + - {t("editInternalResourceDialogUpdateResourceProperties", { resourceName: resource.name })} + {t( + "editInternalResourceDialogUpdateResourceProperties", + { resourceName: resource.name } + )}
- + {/* Resource Properties Form */}
-

{t("editInternalResourceDialogResourceProperties")}

+

+ {t( + "editInternalResourceDialogResourceProperties" + )} +

( - {t("editInternalResourceDialogName")} + + {t( + "editInternalResourceDialogName" + )} + @@ -376,9 +442,15 @@ export default function EditInternalResourceDialog({ name="mode" render={({ field }) => ( - {t("editInternalResourceDialogMode")} + + {t( + "editInternalResourceDialogMode" + )} + @@ -448,20 +528,34 @@ export default function EditInternalResourceDialog({ {/* Target Configuration Form */}
-

{t("editInternalResourceDialogTargetConfiguration")}

+

+ {t( + "editInternalResourceDialogTargetConfiguration" + )} +

( - {t("editInternalResourceDialogDestination")} + + {t( + "editInternalResourceDialogDestination" + )} + - {mode === "host" && t("editInternalResourceDialogDestinationHostDescription")} - {mode === "cidr" && t("editInternalResourceDialogDestinationCidrDescription")} + {mode === "host" && + t( + "editInternalResourceDialogDestinationHostDescription" + )} + {mode === "cidr" && + t( + "editInternalResourceDialogDestinationCidrDescription" + )} {/* {mode === "port" && t("editInternalResourceDialogDestinationIPDescription")} */} @@ -499,12 +593,23 @@ export default function EditInternalResourceDialog({ name="alias" render={({ field }) => ( - {t("editInternalResourceDialogAlias")} + + {t( + "editInternalResourceDialogAlias" + )} + - + - {t("editInternalResourceDialogAliasDescription")} + {t( + "editInternalResourceDialogAliasDescription" + )} @@ -529,31 +634,57 @@ export default function EditInternalResourceDialog({ name="roles" render={({ field }) => ( - {t("roles")} + + {t("roles")} + { + tags={ + form.getValues() + .roles || [] + } + setTags={( + newRoles + ) => { form.setValue( "roles", - newRoles as [Tag, ...Tag[]] + newRoles as [ + Tag, + ...Tag[] + ] ); }} - enableAutocomplete={true} - autocompleteOptions={allRoles} - allowDuplicates={false} - restrictTagsToAutocompleteOptions={true} + enableAutocomplete={ + true + } + autocompleteOptions={ + allRoles + } + allowDuplicates={ + false + } + restrictTagsToAutocompleteOptions={ + true + } sortTags={true} /> - {t("resourceRoleDescription")} + {t( + "resourceRoleDescription" + )} )} @@ -563,25 +694,49 @@ export default function EditInternalResourceDialog({ name="users" render={({ field }) => ( - {t("users")} + + {t("users")} + { + setTags={( + newUsers + ) => { form.setValue( "users", - newUsers as [Tag, ...Tag[]] + newUsers as [ + Tag, + ...Tag[] + ] ); }} - enableAutocomplete={true} - autocompleteOptions={allUsers} - allowDuplicates={false} - restrictTagsToAutocompleteOptions={true} + enableAutocomplete={ + true + } + autocompleteOptions={ + allUsers + } + allowDuplicates={ + false + } + restrictTagsToAutocompleteOptions={ + true + } sortTags={true} /> @@ -589,42 +744,73 @@ export default function EditInternalResourceDialog({ )} /> - {hasMachineClients && ( - ( - - {t("clients")} - - { - form.setValue( - "clients", - newClients as [Tag, ...Tag[]] - ); - }} - enableAutocomplete={true} - autocompleteOptions={allClients} - allowDuplicates={false} - restrictTagsToAutocompleteOptions={true} - sortTags={true} - /> - - - - {t("resourceClientDescription") || "Machine clients that can access this resource"} - - - )} - /> - )} + {hasMachineClients && ( + ( + + + {t("clients")} + + + { + form.setValue( + "clients", + newClients as [ + Tag, + ...Tag[] + ] + ); + }} + enableAutocomplete={ + true + } + autocompleteOptions={ + allClients + } + allowDuplicates={ + false + } + restrictTagsToAutocompleteOptions={ + true + } + sortTags={true} + /> + + + + {t( + "resourceClientDescription" + ) || + "Machine clients that can access this resource"} + + + )} + /> + )}
)}
@@ -645,7 +831,7 @@ export default function EditInternalResourceDialog({ disabled={isSubmitting} loading={isSubmitting} > - {t("editInternalResourceDialogSaveResource")} + {t("editInternalResourceDialogSaveResource")}