mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-11 19:28:58 +00:00
misc: filter optimizations
This commit is contained in:
@@ -17,8 +17,21 @@ export const externalMigrationQueryKeys = {
|
||||
vaultNamespaces: () => ["vault-namespaces"],
|
||||
vaultPolicies: (namespace?: string) => ["vault-policies", namespace],
|
||||
vaultMounts: (namespace?: string) => ["vault-mounts", namespace],
|
||||
vaultSecretPaths: (namespace?: string) => ["vault-secret-paths", namespace],
|
||||
vaultKubernetesAuthRoles: (namespace?: string) => ["vault-kubernetes-auth-roles", namespace]
|
||||
vaultAuthMounts: (namespace?: string, authType?: string) => [
|
||||
"vault-auth-mounts",
|
||||
namespace,
|
||||
authType
|
||||
],
|
||||
vaultSecretPaths: (namespace?: string, mountPath?: string) => [
|
||||
"vault-secret-paths",
|
||||
namespace,
|
||||
mountPath
|
||||
],
|
||||
vaultKubernetesAuthRoles: (namespace?: string, mountPath?: string) => [
|
||||
"vault-kubernetes-auth-roles",
|
||||
namespace,
|
||||
mountPath
|
||||
]
|
||||
};
|
||||
|
||||
export const useHasCustomMigrationAvailable = (provider: ExternalMigrationProviders) => {
|
||||
@@ -91,38 +104,71 @@ export const useGetVaultMounts = (enabled = true, namespace?: string) => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetVaultSecretPaths = (enabled = true, namespace?: string) => {
|
||||
export const useGetVaultSecretPaths = (enabled = true, namespace?: string, mountPath?: string) => {
|
||||
return useQuery({
|
||||
queryKey: externalMigrationQueryKeys.vaultSecretPaths(namespace),
|
||||
queryKey: externalMigrationQueryKeys.vaultSecretPaths(namespace, mountPath),
|
||||
queryFn: async () => {
|
||||
if (!namespace || !mountPath) {
|
||||
throw new Error("Both namespace and mountPath are required");
|
||||
}
|
||||
|
||||
const { data } = await apiRequest.get<{
|
||||
secretPaths: string[];
|
||||
}>("/api/v3/external-migration/vault/secret-paths", {
|
||||
params: {
|
||||
namespace
|
||||
namespace,
|
||||
mountPath
|
||||
}
|
||||
});
|
||||
|
||||
return data.secretPaths;
|
||||
},
|
||||
enabled: enabled && !!namespace && !!mountPath
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetVaultAuthMounts = (enabled = true, namespace?: string, authType?: string) => {
|
||||
return useQuery({
|
||||
queryKey: externalMigrationQueryKeys.vaultAuthMounts(namespace, authType),
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.get<{
|
||||
mounts: Array<{ path: string; type: string }>;
|
||||
}>("/api/v3/external-migration/vault/auth-mounts", {
|
||||
params: {
|
||||
namespace,
|
||||
...(authType && { authType })
|
||||
}
|
||||
});
|
||||
|
||||
return data.mounts;
|
||||
},
|
||||
enabled
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetVaultKubernetesAuthRoles = (enabled = true, namespace?: string) => {
|
||||
export const useGetVaultKubernetesAuthRoles = (
|
||||
enabled = true,
|
||||
namespace?: string,
|
||||
mountPath?: string
|
||||
) => {
|
||||
return useQuery({
|
||||
queryKey: externalMigrationQueryKeys.vaultKubernetesAuthRoles(namespace),
|
||||
queryKey: externalMigrationQueryKeys.vaultKubernetesAuthRoles(namespace, mountPath),
|
||||
queryFn: async () => {
|
||||
if (!namespace || !mountPath) {
|
||||
throw new Error("Both namespace and mountPath are required");
|
||||
}
|
||||
|
||||
const { data } = await apiRequest.get<{
|
||||
roles: VaultKubernetesAuthRole[];
|
||||
}>("/api/v3/external-migration/vault/auth-roles/kubernetes", {
|
||||
params: {
|
||||
namespace
|
||||
namespace,
|
||||
mountPath
|
||||
}
|
||||
});
|
||||
|
||||
return data.roles;
|
||||
},
|
||||
enabled
|
||||
enabled: enabled && !!namespace && !!mountPath
|
||||
});
|
||||
};
|
||||
|
||||
+65
-6
@@ -10,6 +10,7 @@ import {
|
||||
ModalContent
|
||||
} from "@app/components/v2";
|
||||
import {
|
||||
useGetVaultAuthMounts,
|
||||
useGetVaultKubernetesAuthRoles,
|
||||
useGetVaultNamespaces
|
||||
} from "@app/hooks/api/migration/queries";
|
||||
@@ -28,21 +29,39 @@ type ContentProps = {
|
||||
|
||||
const Content = ({ onClose, onImport }: ContentProps) => {
|
||||
const [selectedNamespace, setSelectedNamespace] = useState<string | null>(null);
|
||||
const [selectedMountPath, setSelectedMountPath] = useState<string | null>(null);
|
||||
const [selectedRole, setSelectedRole] = useState<VaultKubernetesAuthRole | null>(null);
|
||||
const [shouldFetchRoles, setShouldFetchRoles] = useState(false);
|
||||
const [shouldFetchMounts, setShouldFetchMounts] = useState(false);
|
||||
|
||||
const { data: namespaces, isLoading: isLoadingNamespaces } = useGetVaultNamespaces();
|
||||
const { data: authMounts, isLoading: isLoadingMounts } = useGetVaultAuthMounts(
|
||||
shouldFetchMounts,
|
||||
selectedNamespace ?? undefined,
|
||||
"kubernetes"
|
||||
);
|
||||
const { data: roles, isLoading: isLoadingRoles } = useGetVaultKubernetesAuthRoles(
|
||||
shouldFetchRoles,
|
||||
selectedNamespace ?? undefined
|
||||
selectedNamespace ?? undefined,
|
||||
selectedMountPath ?? undefined
|
||||
);
|
||||
|
||||
// Enable fetching mounts when namespace is selected
|
||||
useEffect(() => {
|
||||
if (selectedNamespace) {
|
||||
setShouldFetchRoles(true);
|
||||
setShouldFetchMounts(true);
|
||||
}
|
||||
}, [selectedNamespace]);
|
||||
|
||||
// Enable fetching roles when both namespace and mount path are selected
|
||||
useEffect(() => {
|
||||
if (selectedNamespace && selectedMountPath) {
|
||||
setShouldFetchRoles(true);
|
||||
} else {
|
||||
setShouldFetchRoles(false);
|
||||
}
|
||||
}, [selectedNamespace, selectedMountPath]);
|
||||
|
||||
const handleImportAndApply = () => {
|
||||
if (!selectedRole) {
|
||||
createNotification({
|
||||
@@ -70,6 +89,7 @@ const Content = ({ onClose, onImport }: ContentProps) => {
|
||||
if (value && !Array.isArray(value)) {
|
||||
const namespace = value as { id: string; name: string };
|
||||
setSelectedNamespace(namespace.name);
|
||||
setSelectedMountPath(null);
|
||||
setSelectedRole(null);
|
||||
}
|
||||
}}
|
||||
@@ -81,7 +101,42 @@ const Content = ({ onClose, onImport }: ContentProps) => {
|
||||
className="w-full"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-mineshaft-400">
|
||||
Select the Vault namespace to fetch available Kubernetes auth roles
|
||||
Select the Vault namespace to fetch available auth mounts
|
||||
</p>
|
||||
</>
|
||||
</FormControl>
|
||||
|
||||
<FormControl
|
||||
label="Auth Engine"
|
||||
className="mb-4"
|
||||
tooltipText="Select the Kubernetes auth engine to narrow down available roles."
|
||||
>
|
||||
<>
|
||||
<FilterableSelect
|
||||
value={
|
||||
selectedMountPath
|
||||
? authMounts?.find((mount) => mount.path === selectedMountPath)
|
||||
: null
|
||||
}
|
||||
onChange={(value) => {
|
||||
if (value && !Array.isArray(value)) {
|
||||
const mount = value as { path: string; type: string };
|
||||
setSelectedMountPath(mount.path.replace(/\/$/, "")); // Remove trailing slash
|
||||
setSelectedRole(null);
|
||||
} else {
|
||||
setSelectedMountPath(null);
|
||||
}
|
||||
}}
|
||||
options={authMounts || []}
|
||||
getOptionValue={(option) => option.path}
|
||||
getOptionLabel={(option) => option.path.replace(/\/$/, "")}
|
||||
isDisabled={isLoadingMounts || !authMounts?.length}
|
||||
placeholder="Select auth engine..."
|
||||
isClearable
|
||||
className="w-full"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-mineshaft-400">
|
||||
Choose a Kubernetes auth engine to filter available roles
|
||||
</p>
|
||||
</>
|
||||
</FormControl>
|
||||
@@ -99,9 +154,13 @@ const Content = ({ onClose, onImport }: ContentProps) => {
|
||||
}}
|
||||
options={roles || []}
|
||||
getOptionValue={(option) => option.name}
|
||||
getOptionLabel={(option) => `${option.name} (${option.mountPath})`}
|
||||
isDisabled={isLoadingRoles || !roles?.length}
|
||||
placeholder="Select a Kubernetes role to load..."
|
||||
getOptionLabel={(option) => option.name}
|
||||
isDisabled={isLoadingRoles || !roles?.length || !selectedMountPath}
|
||||
placeholder={
|
||||
!selectedMountPath
|
||||
? "Select an auth engine first..."
|
||||
: "Select a Kubernetes role to load..."
|
||||
}
|
||||
isClearable
|
||||
className="w-full"
|
||||
/>
|
||||
|
||||
+53
-7
@@ -34,6 +34,7 @@ type ContentProps = {
|
||||
|
||||
const Content = ({ onClose, environment, secretPath, onImport }: ContentProps) => {
|
||||
const [selectedNamespace, setSelectedNamespace] = useState<string | null>(null);
|
||||
const [selectedMountPath, setSelectedMountPath] = useState<string | null>(null);
|
||||
const [selectedPath, setSelectedPath] = useState<string | null>(null);
|
||||
const [shouldFetchPaths, setShouldFetchPaths] = useState(false);
|
||||
const [shouldFetchMounts, setShouldFetchMounts] = useState(false);
|
||||
@@ -41,21 +42,33 @@ const Content = ({ onClose, environment, secretPath, onImport }: ContentProps) =
|
||||
const { data: namespaces, isLoading: isLoadingNamespaces } = useGetVaultNamespaces();
|
||||
const { data: secretPaths, isLoading: isLoadingPaths } = useGetVaultSecretPaths(
|
||||
shouldFetchPaths,
|
||||
selectedNamespace ?? undefined
|
||||
selectedNamespace ?? undefined,
|
||||
selectedMountPath ?? undefined
|
||||
);
|
||||
const { data: mounts, isLoading: isLoadingMounts } = useGetVaultMounts(
|
||||
shouldFetchMounts,
|
||||
selectedNamespace ?? undefined
|
||||
);
|
||||
|
||||
// Enable fetching paths and mounts when namespace is selected
|
||||
// Filter to only show KV mounts
|
||||
const kvMounts = mounts?.filter((mount) => mount.type === "kv" || mount.type.startsWith("kv"));
|
||||
|
||||
// Enable fetching mounts when namespace is selected
|
||||
useEffect(() => {
|
||||
if (selectedNamespace) {
|
||||
setShouldFetchPaths(true);
|
||||
setShouldFetchMounts(true);
|
||||
}
|
||||
}, [selectedNamespace]);
|
||||
|
||||
// Enable fetching paths when both namespace and mount path are selected
|
||||
useEffect(() => {
|
||||
if (selectedNamespace && selectedMountPath) {
|
||||
setShouldFetchPaths(true);
|
||||
} else {
|
||||
setShouldFetchPaths(false);
|
||||
}
|
||||
}, [selectedNamespace, selectedMountPath]);
|
||||
|
||||
const handleImport = () => {
|
||||
if (!selectedPath) {
|
||||
createNotification({ type: "error", text: "Please select a Vault secret path to import" });
|
||||
@@ -111,6 +124,7 @@ const Content = ({ onClose, environment, secretPath, onImport }: ContentProps) =
|
||||
if (value && !Array.isArray(value)) {
|
||||
const namespace = value as { id: string; name: string };
|
||||
setSelectedNamespace(namespace.name);
|
||||
setSelectedMountPath(null);
|
||||
setSelectedPath(null);
|
||||
}
|
||||
}}
|
||||
@@ -122,7 +136,35 @@ const Content = ({ onClose, environment, secretPath, onImport }: ContentProps) =
|
||||
className="w-full"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-mineshaft-400">
|
||||
Select the Vault namespace to fetch available secret paths
|
||||
Select the Vault namespace to fetch available mounts
|
||||
</p>
|
||||
</>
|
||||
</FormControl>
|
||||
|
||||
<FormControl
|
||||
label="Secrets Engine"
|
||||
className="mb-4"
|
||||
tooltipText="Select the KV secrets engine to narrow down secret paths."
|
||||
>
|
||||
<>
|
||||
<FilterableSelect
|
||||
value={kvMounts?.find((mount) => mount.path === selectedMountPath)}
|
||||
onChange={(value) => {
|
||||
if (value && !Array.isArray(value)) {
|
||||
const mount = value as { path: string; type: string; version: string | null };
|
||||
setSelectedMountPath(mount.path.replace(/\/$/, "")); // Remove trailing slash
|
||||
setSelectedPath(null);
|
||||
}
|
||||
}}
|
||||
options={kvMounts || []}
|
||||
getOptionValue={(option) => option.path}
|
||||
getOptionLabel={(option) => option.path.replace(/\/$/, "")}
|
||||
isDisabled={isLoadingMounts || !kvMounts?.length}
|
||||
placeholder="Select secrets engine..."
|
||||
className="w-full"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-mineshaft-400">
|
||||
Choose a KV secrets engine to filter available secret paths
|
||||
</p>
|
||||
</>
|
||||
</FormControl>
|
||||
@@ -141,13 +183,17 @@ const Content = ({ onClose, environment, secretPath, onImport }: ContentProps) =
|
||||
options={(secretPaths || []).map((path) => ({ path }))}
|
||||
getOptionValue={(option) => option.path}
|
||||
getOptionLabel={(option) => option.path}
|
||||
isDisabled={isLoadingPaths || !secretPaths?.length}
|
||||
placeholder="Select a Vault path to import..."
|
||||
isDisabled={isLoadingPaths || !secretPaths?.length || !selectedMountPath}
|
||||
placeholder={
|
||||
!selectedMountPath
|
||||
? "Select a mount path first..."
|
||||
: "Select a Vault path to import..."
|
||||
}
|
||||
isClearable
|
||||
className="w-full"
|
||||
/>
|
||||
<p className="mt-1 text-xs text-mineshaft-400">
|
||||
Choose a secret path from your Vault namespace to import into Infisical
|
||||
Choose a secret path from the selected mount to import into Infisical
|
||||
</p>
|
||||
</>
|
||||
</FormControl>
|
||||
|
||||
Reference in New Issue
Block a user