mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-15 20:25:43 +00:00
Merge remote-tracking branch 'origin/main' into misc/terraform-project-group-prereq
This commit is contained in:
@@ -79,7 +79,8 @@ export const eventToNameMap: { [K in EventType]: string } = {
|
||||
[EventType.UPDATE_CERTIFICATE_TEMPLATE_EST_CONFIG]:
|
||||
"Update certificate template EST configuration",
|
||||
[EventType.UPDATE_PROJECT_SLACK_CONFIG]: "Update project slack configuration",
|
||||
[EventType.GET_PROJECT_SLACK_CONFIG]: "Get project slack configuration"
|
||||
[EventType.GET_PROJECT_SLACK_CONFIG]: "Get project slack configuration",
|
||||
[EventType.INTEGRATION_SYNCED]: "Integration sync"
|
||||
};
|
||||
|
||||
export const userAgentTTypeoNameMap: { [K in UserAgentType]: string } = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
export enum ActorType {
|
||||
PLATFORM = "platform",
|
||||
USER = "user",
|
||||
SERVICE = "service",
|
||||
IDENTITY = "identity"
|
||||
@@ -91,5 +92,6 @@ export enum EventType {
|
||||
UPDATE_CERTIFICATE_TEMPLATE_EST_CONFIG = "update-certificate-template-est-config",
|
||||
GET_CERTIFICATE_TEMPLATE_EST_CONFIG = "get-certificate-template-est-config",
|
||||
UPDATE_PROJECT_SLACK_CONFIG = "update-project-slack-config",
|
||||
GET_PROJECT_SLACK_CONFIG = "get-project-slack-config"
|
||||
GET_PROJECT_SLACK_CONFIG = "get-project-slack-config",
|
||||
INTEGRATION_SYNCED = "integration-synced"
|
||||
}
|
||||
|
||||
@@ -1,35 +1,58 @@
|
||||
import { useInfiniteQuery, useQuery } from "@tanstack/react-query";
|
||||
import { useInfiniteQuery, UseInfiniteQueryOptions, useQuery } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { Actor, AuditLog, AuditLogFilters } from "./types";
|
||||
import { Actor, AuditLog, TGetAuditLogsFilter } from "./types";
|
||||
|
||||
export const auditLogKeys = {
|
||||
getAuditLogs: (workspaceId: string | null, filters: AuditLogFilters) =>
|
||||
getAuditLogs: (workspaceId: string | null, filters: TGetAuditLogsFilter) =>
|
||||
[{ workspaceId, filters }, "audit-logs"] as const,
|
||||
getAuditLogActorFilterOpts: (workspaceId: string) =>
|
||||
[{ workspaceId }, "audit-log-actor-filters"] as const
|
||||
};
|
||||
|
||||
export const useGetAuditLogs = (filters: AuditLogFilters, workspaceId: string | null) => {
|
||||
export const useGetAuditLogs = (
|
||||
filters: TGetAuditLogsFilter,
|
||||
projectId: string | null,
|
||||
options: Omit<
|
||||
UseInfiniteQueryOptions<
|
||||
AuditLog[],
|
||||
unknown,
|
||||
AuditLog[],
|
||||
AuditLog[],
|
||||
ReturnType<typeof auditLogKeys.getAuditLogs>
|
||||
>,
|
||||
"queryFn" | "queryKey" | "getNextPageParam"
|
||||
> = {}
|
||||
) => {
|
||||
return useInfiniteQuery({
|
||||
queryKey: auditLogKeys.getAuditLogs(workspaceId, filters),
|
||||
queryKey: auditLogKeys.getAuditLogs(projectId, filters),
|
||||
queryFn: async ({ pageParam }) => {
|
||||
const auditLogEndpoint = workspaceId
|
||||
? `/api/v1/workspace/${workspaceId}/audit-logs`
|
||||
: "/api/v1/organization/audit-logs";
|
||||
const { data } = await apiRequest.get<{ auditLogs: AuditLog[] }>(auditLogEndpoint, {
|
||||
params: {
|
||||
...filters,
|
||||
offset: pageParam,
|
||||
startDate: filters?.startDate?.toISOString(),
|
||||
endDate: filters?.endDate?.toISOString()
|
||||
const { data } = await apiRequest.get<{ auditLogs: AuditLog[] }>(
|
||||
"/api/v1/organization/audit-logs",
|
||||
{
|
||||
params: {
|
||||
...filters,
|
||||
offset: pageParam,
|
||||
startDate: filters?.startDate?.toISOString(),
|
||||
endDate: filters?.endDate?.toISOString(),
|
||||
...(filters.eventMetadata && Object.keys(filters.eventMetadata).length
|
||||
? {
|
||||
eventMetadata: Object.entries(filters.eventMetadata)
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
.join(",")
|
||||
}
|
||||
: {}),
|
||||
...(filters.eventType?.length ? { eventType: filters.eventType.join(",") } : {}),
|
||||
...(projectId ? { projectId } : {})
|
||||
}
|
||||
}
|
||||
});
|
||||
);
|
||||
return data.auditLogs;
|
||||
},
|
||||
getNextPageParam: (lastPage, pages) =>
|
||||
lastPage.length !== 0 ? pages.length * filters.limit : undefined
|
||||
lastPage.length !== 0 ? pages.length * filters.limit : undefined,
|
||||
...options
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,18 @@ import { IdentityTrustedIp } from "../identities/types";
|
||||
import { PkiItemType } from "../pkiCollections/constants";
|
||||
import { ActorType, EventType, UserAgentType } from "./enums";
|
||||
|
||||
export type TGetAuditLogsFilter = {
|
||||
eventType?: EventType[];
|
||||
userAgentType?: UserAgentType;
|
||||
eventMetadata?: Record<string, string>;
|
||||
actorType?: ActorType;
|
||||
projectId?: string;
|
||||
actorId?: string; // user ID format
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
limit: number;
|
||||
};
|
||||
|
||||
interface UserActorMetadata {
|
||||
userId: string;
|
||||
email: string;
|
||||
@@ -33,7 +45,13 @@ export interface IdentityActor {
|
||||
metadata: IdentityActorMetadata;
|
||||
}
|
||||
|
||||
export type Actor = UserActor | ServiceActor | IdentityActor;
|
||||
export interface PlatformActorMetadata {}
|
||||
export interface PlatformActor {
|
||||
type: ActorType.PLATFORM;
|
||||
metadata: PlatformActorMetadata;
|
||||
}
|
||||
|
||||
export type Actor = UserActor | ServiceActor | IdentityActor | PlatformActor;
|
||||
|
||||
interface GetSecretsEvent {
|
||||
type: EventType.GET_SECRETS;
|
||||
@@ -761,6 +779,22 @@ interface GetProjectSlackConfig {
|
||||
};
|
||||
}
|
||||
|
||||
export enum IntegrationSyncedEventTrigger {
|
||||
MANUAL = "manual",
|
||||
AUTO = "auto"
|
||||
}
|
||||
|
||||
interface IntegrationSyncedEvent {
|
||||
type: EventType.INTEGRATION_SYNCED;
|
||||
metadata: {
|
||||
integrationId: string;
|
||||
lastSyncJobId: string;
|
||||
lastUsed: Date;
|
||||
syncMessage: string;
|
||||
isSynced: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export type Event =
|
||||
| GetSecretsEvent
|
||||
| GetSecretEvent
|
||||
@@ -838,7 +872,8 @@ export type Event =
|
||||
| CreateCertificateTemplateEstConfig
|
||||
| GetCertificateTemplateEstConfig
|
||||
| UpdateProjectSlackConfig
|
||||
| GetProjectSlackConfig;
|
||||
| GetProjectSlackConfig
|
||||
| IntegrationSyncedEvent;
|
||||
|
||||
export type AuditLog = {
|
||||
id: string;
|
||||
@@ -851,17 +886,8 @@ export type AuditLog = {
|
||||
userAgentType: UserAgentType;
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
project: {
|
||||
project?: {
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type AuditLogFilters = {
|
||||
eventType?: EventType;
|
||||
userAgentType?: UserAgentType;
|
||||
actor?: string;
|
||||
limit: number;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
};
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export { useGetProjectSecretsDetails } from "./queries";
|
||||
@@ -0,0 +1,261 @@
|
||||
import { useCallback } from "react";
|
||||
import { useQuery, UseQueryOptions } from "@tanstack/react-query";
|
||||
import axios from "axios";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import {
|
||||
DashboardProjectSecretsDetails,
|
||||
DashboardProjectSecretsDetailsResponse,
|
||||
DashboardProjectSecretsOverview,
|
||||
DashboardProjectSecretsOverviewResponse,
|
||||
DashboardSecretsOrderBy,
|
||||
TGetDashboardProjectSecretsDetailsDTO,
|
||||
TGetDashboardProjectSecretsOverviewDTO
|
||||
} from "@app/hooks/api/dashboard/types";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import { mergePersonalSecrets } from "@app/hooks/api/secrets/queries";
|
||||
|
||||
export const dashboardKeys = {
|
||||
all: () => ["dashboard"] as const,
|
||||
getDashboardSecrets: ({
|
||||
projectId,
|
||||
secretPath
|
||||
}: Pick<TGetDashboardProjectSecretsDetailsDTO, "projectId" | "secretPath">) =>
|
||||
[...dashboardKeys.all(), { projectId, secretPath }] as const,
|
||||
getProjectSecretsOverview: ({
|
||||
projectId,
|
||||
secretPath,
|
||||
...params
|
||||
}: TGetDashboardProjectSecretsOverviewDTO) =>
|
||||
[
|
||||
...dashboardKeys.getDashboardSecrets({ projectId, secretPath }),
|
||||
"secrets-overview",
|
||||
params
|
||||
] as const,
|
||||
getProjectSecretsDetails: ({
|
||||
projectId,
|
||||
secretPath,
|
||||
environment,
|
||||
...params
|
||||
}: TGetDashboardProjectSecretsDetailsDTO) =>
|
||||
[
|
||||
...dashboardKeys.getDashboardSecrets({ projectId, secretPath }),
|
||||
environment,
|
||||
"secrets-details",
|
||||
params
|
||||
] as const
|
||||
};
|
||||
|
||||
export const fetchProjectSecretsOverview = async ({
|
||||
includeFolders,
|
||||
includeSecrets,
|
||||
includeDynamicSecrets,
|
||||
environments,
|
||||
...params
|
||||
}: TGetDashboardProjectSecretsOverviewDTO) => {
|
||||
const { data } = await apiRequest.get<DashboardProjectSecretsOverviewResponse>(
|
||||
"/api/v3/dashboard/secrets-overview",
|
||||
{
|
||||
params: {
|
||||
...params,
|
||||
environments: encodeURIComponent(environments.join(",")),
|
||||
includeFolders: includeFolders ? "1" : "",
|
||||
includeSecrets: includeSecrets ? "1" : "",
|
||||
includeDynamicSecrets: includeDynamicSecrets ? "1" : ""
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export const fetchProjectSecretsDetails = async ({
|
||||
includeFolders,
|
||||
includeImports,
|
||||
includeSecrets,
|
||||
includeDynamicSecrets,
|
||||
tags,
|
||||
...params
|
||||
}: TGetDashboardProjectSecretsDetailsDTO) => {
|
||||
const { data } = await apiRequest.get<DashboardProjectSecretsDetailsResponse>(
|
||||
"/api/v3/dashboard/secrets-details",
|
||||
{
|
||||
params: {
|
||||
...params,
|
||||
includeImports: includeImports ? "1" : "",
|
||||
includeFolders: includeFolders ? "1" : "",
|
||||
includeSecrets: includeSecrets ? "1" : "",
|
||||
includeDynamicSecrets: includeDynamicSecrets ? "1" : "",
|
||||
tags: encodeURIComponent(
|
||||
Object.entries(tags)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
.filter(([_, enabled]) => enabled)
|
||||
.map(([tag]) => tag)
|
||||
.join(",")
|
||||
)
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export const useGetProjectSecretsOverview = (
|
||||
{
|
||||
projectId,
|
||||
secretPath,
|
||||
offset = 0,
|
||||
limit = 100,
|
||||
orderBy = DashboardSecretsOrderBy.Name,
|
||||
orderDirection = OrderByDirection.ASC,
|
||||
search = "",
|
||||
includeSecrets,
|
||||
includeFolders,
|
||||
includeDynamicSecrets,
|
||||
environments
|
||||
}: TGetDashboardProjectSecretsOverviewDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
DashboardProjectSecretsOverviewResponse,
|
||||
unknown,
|
||||
DashboardProjectSecretsOverview,
|
||||
ReturnType<typeof dashboardKeys.getProjectSecretsOverview>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
...options,
|
||||
// wait for all values to be available
|
||||
enabled: Boolean(projectId) && (options?.enabled ?? true) && Boolean(environments.length),
|
||||
queryKey: dashboardKeys.getProjectSecretsOverview({
|
||||
secretPath,
|
||||
search,
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
offset,
|
||||
projectId,
|
||||
includeSecrets,
|
||||
includeFolders,
|
||||
includeDynamicSecrets,
|
||||
environments
|
||||
}),
|
||||
queryFn: () =>
|
||||
fetchProjectSecretsOverview({
|
||||
secretPath,
|
||||
search,
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
offset,
|
||||
projectId,
|
||||
includeSecrets,
|
||||
includeFolders,
|
||||
includeDynamicSecrets,
|
||||
environments
|
||||
}),
|
||||
onError: (error) => {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const serverResponse = error.response?.data as { message: string };
|
||||
createNotification({
|
||||
title: "Error fetching secret details",
|
||||
type: "error",
|
||||
text: serverResponse.message
|
||||
});
|
||||
}
|
||||
},
|
||||
select: useCallback((data: Awaited<ReturnType<typeof fetchProjectSecretsOverview>>) => {
|
||||
const { secrets, ...select } = data;
|
||||
|
||||
return {
|
||||
...select,
|
||||
secrets: secrets ? mergePersonalSecrets(secrets) : undefined
|
||||
};
|
||||
}, []),
|
||||
keepPreviousData: true
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetProjectSecretsDetails = (
|
||||
{
|
||||
projectId,
|
||||
secretPath,
|
||||
environment,
|
||||
offset = 0,
|
||||
limit = 100,
|
||||
orderBy = DashboardSecretsOrderBy.Name,
|
||||
orderDirection = OrderByDirection.ASC,
|
||||
search = "",
|
||||
includeSecrets,
|
||||
includeFolders,
|
||||
includeImports,
|
||||
includeDynamicSecrets,
|
||||
tags
|
||||
}: TGetDashboardProjectSecretsDetailsDTO,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
DashboardProjectSecretsDetailsResponse,
|
||||
unknown,
|
||||
DashboardProjectSecretsDetails,
|
||||
ReturnType<typeof dashboardKeys.getProjectSecretsDetails>
|
||||
>,
|
||||
"queryKey" | "queryFn"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
...options,
|
||||
// wait for all values to be available
|
||||
enabled: Boolean(projectId) && (options?.enabled ?? true),
|
||||
queryKey: dashboardKeys.getProjectSecretsDetails({
|
||||
secretPath,
|
||||
search,
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
offset,
|
||||
projectId,
|
||||
environment,
|
||||
includeSecrets,
|
||||
includeFolders,
|
||||
includeImports,
|
||||
includeDynamicSecrets,
|
||||
tags
|
||||
}),
|
||||
queryFn: () =>
|
||||
fetchProjectSecretsDetails({
|
||||
secretPath,
|
||||
search,
|
||||
limit,
|
||||
orderBy,
|
||||
orderDirection,
|
||||
offset,
|
||||
projectId,
|
||||
environment,
|
||||
includeSecrets,
|
||||
includeFolders,
|
||||
includeImports,
|
||||
includeDynamicSecrets,
|
||||
tags
|
||||
}),
|
||||
onError: (error) => {
|
||||
if (axios.isAxiosError(error)) {
|
||||
const serverResponse = error.response?.data as { message: string };
|
||||
createNotification({
|
||||
title: "Error fetching secret details",
|
||||
type: "error",
|
||||
text: serverResponse.message
|
||||
});
|
||||
}
|
||||
},
|
||||
select: useCallback(
|
||||
(data: Awaited<ReturnType<typeof fetchProjectSecretsDetails>>) => ({
|
||||
...data,
|
||||
secrets: data.secrets ? mergePersonalSecrets(data.secrets) : undefined
|
||||
}),
|
||||
[]
|
||||
),
|
||||
keepPreviousData: true
|
||||
});
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
import { TDynamicSecret } from "@app/hooks/api/dynamicSecret/types";
|
||||
import { OrderByDirection } from "@app/hooks/api/generic/types";
|
||||
import { TSecretFolder } from "@app/hooks/api/secretFolders/types";
|
||||
import { TSecretImport } from "@app/hooks/api/secretImports/types";
|
||||
import { SecretV3Raw, SecretV3RawSanitized } from "@app/hooks/api/secrets/types";
|
||||
|
||||
export type DashboardProjectSecretsOverviewResponse = {
|
||||
folders?: (TSecretFolder & { environment: string })[];
|
||||
dynamicSecrets?: (TDynamicSecret & { environment: string })[];
|
||||
secrets?: SecretV3Raw[];
|
||||
totalSecretCount?: number;
|
||||
totalFolderCount?: number;
|
||||
totalDynamicSecretCount?: number;
|
||||
totalCount: number;
|
||||
};
|
||||
|
||||
export type DashboardProjectSecretsDetailsResponse = {
|
||||
imports?: TSecretImport[];
|
||||
folders?: TSecretFolder[];
|
||||
dynamicSecrets?: TDynamicSecret[];
|
||||
secrets?: SecretV3Raw[];
|
||||
totalImportCount?: number;
|
||||
totalFolderCount?: number;
|
||||
totalDynamicSecretCount?: number;
|
||||
totalSecretCount?: number;
|
||||
totalCount: number;
|
||||
};
|
||||
|
||||
export type DashboardProjectSecretsOverview = Omit<
|
||||
DashboardProjectSecretsOverviewResponse,
|
||||
"secrets"
|
||||
> & {
|
||||
secrets?: SecretV3RawSanitized[];
|
||||
};
|
||||
|
||||
export type DashboardProjectSecretsDetails = Omit<
|
||||
DashboardProjectSecretsDetailsResponse,
|
||||
"secrets"
|
||||
> & {
|
||||
secrets?: SecretV3RawSanitized[];
|
||||
};
|
||||
|
||||
export enum DashboardSecretsOrderBy {
|
||||
Name = "name"
|
||||
}
|
||||
|
||||
export type TGetDashboardProjectSecretsOverviewDTO = {
|
||||
projectId: string;
|
||||
secretPath: string;
|
||||
offset?: number;
|
||||
limit?: number;
|
||||
orderBy?: DashboardSecretsOrderBy;
|
||||
orderDirection?: OrderByDirection;
|
||||
search?: string;
|
||||
includeSecrets?: boolean;
|
||||
includeFolders?: boolean;
|
||||
includeDynamicSecrets?: boolean;
|
||||
environments: string[];
|
||||
};
|
||||
|
||||
export type TGetDashboardProjectSecretsDetailsDTO = Omit<
|
||||
TGetDashboardProjectSecretsOverviewDTO,
|
||||
"environments"
|
||||
> & {
|
||||
environment: string;
|
||||
includeImports?: boolean;
|
||||
tags: Record<string, boolean>;
|
||||
};
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { dashboardKeys } from "@app/hooks/api/dashboard/queries";
|
||||
|
||||
import { dynamicSecretKeys } from "./queries";
|
||||
import {
|
||||
@@ -22,6 +23,8 @@ export const useCreateDynamicSecret = () => {
|
||||
return data.dynamicSecret;
|
||||
},
|
||||
onSuccess: (_, { path, environmentSlug, projectSlug }) => {
|
||||
// TODO: optimize but we currently don't pass projectId
|
||||
queryClient.invalidateQueries(dashboardKeys.all());
|
||||
queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectSlug, environmentSlug }));
|
||||
}
|
||||
});
|
||||
@@ -39,6 +42,8 @@ export const useUpdateDynamicSecret = () => {
|
||||
return data.dynamicSecret;
|
||||
},
|
||||
onSuccess: (_, { path, environmentSlug, projectSlug }) => {
|
||||
// TODO: optimize but currently don't pass projectId
|
||||
queryClient.invalidateQueries(dashboardKeys.all());
|
||||
queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectSlug, environmentSlug }));
|
||||
}
|
||||
});
|
||||
@@ -56,6 +61,8 @@ export const useDeleteDynamicSecret = () => {
|
||||
return data.dynamicSecret;
|
||||
},
|
||||
onSuccess: (_, { path, environmentSlug, projectSlug }) => {
|
||||
// TODO: optimize but currently don't pass projectId
|
||||
queryClient.invalidateQueries(dashboardKeys.all());
|
||||
queryClient.invalidateQueries(dynamicSecretKeys.list({ path, projectSlug, environmentSlug }));
|
||||
}
|
||||
});
|
||||
|
||||
@@ -71,6 +71,34 @@ export const useGetDynamicSecretDetails = ({
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetDynamicSecretProviderData = ({
|
||||
tenantId,
|
||||
applicationId,
|
||||
clientSecret,
|
||||
enabled
|
||||
}: {
|
||||
tenantId: string;
|
||||
applicationId: string;
|
||||
clientSecret: string;
|
||||
enabled: boolean
|
||||
}) => {
|
||||
return useQuery({
|
||||
queryKey: ["users"],
|
||||
queryFn: async () => {
|
||||
const { data } = await apiRequest.post<{id:string, email: string, name:string}[]>(
|
||||
"/api/v1/dynamic-secrets/entra-id/users",
|
||||
{
|
||||
tenantId,
|
||||
applicationId,
|
||||
clientSecret
|
||||
}
|
||||
);
|
||||
return data;
|
||||
},
|
||||
enabled
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetDynamicSecretsOfAllEnv = ({
|
||||
path,
|
||||
projectSlug,
|
||||
|
||||
@@ -24,7 +24,8 @@ export enum DynamicSecretProviders {
|
||||
MongoAtlas = "mongo-db-atlas",
|
||||
ElasticSearch = "elastic-search",
|
||||
MongoDB = "mongo-db",
|
||||
RabbitMq = "rabbit-mq"
|
||||
RabbitMq = "rabbit-mq",
|
||||
AzureEntraId = "azure-entra-id"
|
||||
}
|
||||
|
||||
export enum SqlProviders {
|
||||
@@ -177,7 +178,17 @@ export type TDynamicSecretProvider =
|
||||
};
|
||||
ca?: string;
|
||||
};
|
||||
};
|
||||
}
|
||||
| {
|
||||
type: DynamicSecretProviders.AzureEntraId;
|
||||
inputs: {
|
||||
tenantId: string;
|
||||
userId: string;
|
||||
email: string;
|
||||
applicationId: string;
|
||||
clientSecret: string;
|
||||
};
|
||||
};
|
||||
|
||||
export type TCreateDynamicSecretDTO = {
|
||||
projectSlug: string;
|
||||
|
||||
@@ -1 +1,6 @@
|
||||
export { useCreateIntegration, useDeleteIntegration, useGetCloudIntegrations } from "./queries";
|
||||
export {
|
||||
useCreateIntegration,
|
||||
useDeleteIntegration,
|
||||
useGetCloudIntegrations,
|
||||
useGetIntegration
|
||||
} from "./queries";
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useMutation, useQuery, useQueryClient, UseQueryOptions } from "@tanstack/react-query";
|
||||
|
||||
import { createNotification } from "@app/components/notifications";
|
||||
import { apiRequest } from "@app/config/request";
|
||||
|
||||
import { workspaceKeys } from "../workspace";
|
||||
import { TCloudIntegration } from "./types";
|
||||
import { TCloudIntegration, TIntegrationWithEnv } from "./types";
|
||||
|
||||
export const integrationQueryKeys = {
|
||||
getIntegrations: () => ["integrations"] as const
|
||||
getIntegrations: () => ["integrations"] as const,
|
||||
getIntegration: (id: string) => ["integration", id] as const
|
||||
};
|
||||
|
||||
const fetchIntegrations = async () => {
|
||||
@@ -18,6 +19,14 @@ const fetchIntegrations = async () => {
|
||||
return data.integrationOptions;
|
||||
};
|
||||
|
||||
const fetchIntegration = async (id: string) => {
|
||||
const { data } = await apiRequest.get<{ integration: TIntegrationWithEnv }>(
|
||||
`/api/v1/integration/${id}`
|
||||
);
|
||||
|
||||
return data.integration;
|
||||
};
|
||||
|
||||
export const useGetCloudIntegrations = () =>
|
||||
useQuery({
|
||||
queryKey: integrationQueryKeys.getIntegrations(),
|
||||
@@ -128,6 +137,26 @@ export const useDeleteIntegration = () => {
|
||||
});
|
||||
};
|
||||
|
||||
export const useGetIntegration = (
|
||||
integrationId: string,
|
||||
options?: Omit<
|
||||
UseQueryOptions<
|
||||
TIntegrationWithEnv,
|
||||
unknown,
|
||||
TIntegrationWithEnv,
|
||||
ReturnType<typeof integrationQueryKeys.getIntegration>
|
||||
>,
|
||||
"queryFn" | "queryKey"
|
||||
>
|
||||
) => {
|
||||
return useQuery({
|
||||
...options,
|
||||
enabled: Boolean(integrationId && options?.enabled === undefined ? true : options?.enabled),
|
||||
queryKey: integrationQueryKeys.getIntegration(integrationId),
|
||||
queryFn: () => fetchIntegration(integrationId)
|
||||
});
|
||||
};
|
||||
|
||||
export const useSyncIntegration = () => {
|
||||
return useMutation<{}, {}, { id: string; workspaceId: string; lastUsed: string }>({
|
||||
mutationFn: ({ id }) => apiRequest.post(`/api/v1/integration/${id}/sync`),
|
||||
|
||||
@@ -36,14 +36,34 @@ export type TIntegration = {
|
||||
metadata?: {
|
||||
githubVisibility?: string;
|
||||
githubVisibilityRepoIds?: string[];
|
||||
shouldAutoRedeploy?: boolean;
|
||||
secretAWSTag?: {
|
||||
key: string;
|
||||
value: string;
|
||||
}[];
|
||||
|
||||
kmsKeyId?: string;
|
||||
secretSuffix?: string;
|
||||
secretPrefix?: string;
|
||||
syncBehavior?: IntegrationSyncBehavior;
|
||||
mappingBehavior?: IntegrationMappingBehavior;
|
||||
scope: string;
|
||||
org: string;
|
||||
project: string;
|
||||
environment: string;
|
||||
|
||||
shouldDisableDelete?: boolean;
|
||||
shouldMaskSecrets?: boolean;
|
||||
shouldProtectSecrets?: boolean;
|
||||
shouldEnableDelete?: boolean;
|
||||
};
|
||||
};
|
||||
|
||||
export type TIntegrationWithEnv = TIntegration & {
|
||||
environment: {
|
||||
id: string;
|
||||
name: string;
|
||||
slug: string;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { dashboardKeys } from "@app/hooks/api/dashboard/queries";
|
||||
|
||||
import { secretSnapshotKeys } from "../secretSnapshots/queries";
|
||||
import {
|
||||
@@ -124,6 +125,12 @@ export const useCreateFolder = () => {
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { projectId, environment, path }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({
|
||||
projectId,
|
||||
secretPath: path ?? "/"
|
||||
})
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
folderQueryKeys.getSecretFolders({ projectId, environment, path })
|
||||
);
|
||||
@@ -151,6 +158,12 @@ export const useUpdateFolder = () => {
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { projectId, environment, path }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({
|
||||
projectId,
|
||||
secretPath: path ?? "/"
|
||||
})
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
folderQueryKeys.getSecretFolders({ projectId, environment, path })
|
||||
);
|
||||
@@ -179,6 +192,12 @@ export const useDeleteFolder = () => {
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { path = "/", projectId, environment }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({
|
||||
projectId,
|
||||
secretPath: path
|
||||
})
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
folderQueryKeys.getSecretFolders({ projectId, environment, path })
|
||||
);
|
||||
@@ -206,6 +225,12 @@ export const useUpdateFolderBatch = () => {
|
||||
},
|
||||
onSuccess: (_, { projectId, folders }) => {
|
||||
folders.forEach((folder) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({
|
||||
projectId,
|
||||
secretPath: folder.path ?? "/"
|
||||
})
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
folderQueryKeys.getSecretFolders({
|
||||
projectId,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { dashboardKeys } from "@app/hooks/api/dashboard/queries";
|
||||
|
||||
import { secretImportKeys } from "./queries";
|
||||
import {
|
||||
@@ -31,6 +32,9 @@ export const useCreateSecretImport = () => {
|
||||
queryClient.invalidateQueries(
|
||||
secretImportKeys.getSecretImportSecrets({ projectId, environment, path })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId, secretPath: path ?? "/" })
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -55,6 +59,9 @@ export const useUpdateSecretImport = () => {
|
||||
queryClient.invalidateQueries(
|
||||
secretImportKeys.getSecretImportSecrets({ environment, path, projectId })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId, secretPath: path ?? "/" })
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
@@ -93,6 +100,9 @@ export const useDeleteSecretImport = () => {
|
||||
queryClient.invalidateQueries(
|
||||
secretImportKeys.getSecretImportSecrets({ projectId, environment, path })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId, secretPath: path ?? "/" })
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MutationOptions, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
import { apiRequest } from "@app/config/request";
|
||||
import { dashboardKeys } from "@app/hooks/api/dashboard/queries";
|
||||
|
||||
import { secretApprovalRequestKeys } from "../secretApprovalRequest/queries";
|
||||
import { secretSnapshotKeys } from "../secretSnapshots/queries";
|
||||
@@ -44,6 +45,9 @@ export const useCreateSecretV3 = ({
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { workspaceId, environment, secretPath }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
secretKeys.getProjectSecret({ workspaceId, environment, secretPath })
|
||||
);
|
||||
@@ -96,6 +100,9 @@ export const useUpdateSecretV3 = ({
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { workspaceId, environment, secretPath }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
secretKeys.getProjectSecret({ workspaceId, environment, secretPath })
|
||||
);
|
||||
@@ -139,6 +146,9 @@ export const useDeleteSecretV3 = ({
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { workspaceId, environment, secretPath }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
secretKeys.getProjectSecret({ workspaceId, environment, secretPath })
|
||||
);
|
||||
@@ -172,6 +182,9 @@ export const useCreateSecretBatch = ({
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { workspaceId, environment, secretPath }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
secretKeys.getProjectSecret({ workspaceId, environment, secretPath })
|
||||
);
|
||||
@@ -205,6 +218,9 @@ export const useUpdateSecretBatch = ({
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { workspaceId, environment, secretPath }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
secretKeys.getProjectSecret({ workspaceId, environment, secretPath })
|
||||
);
|
||||
@@ -240,6 +256,9 @@ export const useDeleteSecretBatch = ({
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { workspaceId, environment, secretPath }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({ projectId: workspaceId, secretPath })
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
secretKeys.getProjectSecret({ workspaceId, environment, secretPath })
|
||||
);
|
||||
@@ -295,6 +314,12 @@ export const useMoveSecrets = ({
|
||||
return data;
|
||||
},
|
||||
onSuccess: (_, { projectId, sourceEnvironment, sourceSecretPath }) => {
|
||||
queryClient.invalidateQueries(
|
||||
dashboardKeys.getDashboardSecrets({
|
||||
projectId,
|
||||
secretPath: sourceSecretPath
|
||||
})
|
||||
);
|
||||
queryClient.invalidateQueries(
|
||||
secretKeys.getProjectSecret({
|
||||
workspaceId: projectId,
|
||||
|
||||
Reference in New Issue
Block a user