mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-10-07 05:27:48 +00:00
Moved tags to aws iam provider inputs
This commit is contained in:
@@ -1,21 +0,0 @@
|
|||||||
import { Knex } from "knex";
|
|
||||||
|
|
||||||
import { TableName } from "../schemas";
|
|
||||||
|
|
||||||
export async function up(knex: Knex): Promise<void> {
|
|
||||||
const hasCol = await knex.schema.hasColumn(TableName.DynamicSecret, "tags");
|
|
||||||
if (!hasCol) {
|
|
||||||
await knex.schema.alterTable(TableName.DynamicSecret, (t) => {
|
|
||||||
t.jsonb("tags").nullable();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function down(knex: Knex): Promise<void> {
|
|
||||||
const hasCol = await knex.schema.hasColumn(TableName.DynamicSecret, "tags");
|
|
||||||
if (hasCol) {
|
|
||||||
await knex.schema.alterTable(TableName.DynamicSecret, (t) => {
|
|
||||||
t.dropColumn("tags");
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -29,8 +29,7 @@ export const DynamicSecretsSchema = z.object({
|
|||||||
encryptedInput: zodBuffer,
|
encryptedInput: zodBuffer,
|
||||||
projectGatewayId: z.string().uuid().nullable().optional(),
|
projectGatewayId: z.string().uuid().nullable().optional(),
|
||||||
gatewayId: z.string().uuid().nullable().optional(),
|
gatewayId: z.string().uuid().nullable().optional(),
|
||||||
usernameTemplate: z.string().nullable().optional(),
|
usernameTemplate: z.string().nullable().optional()
|
||||||
tags: z.unknown().nullable().optional()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TDynamicSecrets = z.infer<typeof DynamicSecretsSchema>;
|
export type TDynamicSecrets = z.infer<typeof DynamicSecretsSchema>;
|
||||||
|
|||||||
@@ -80,7 +80,6 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1),
|
environmentSlug: z.string().describe(DYNAMIC_SECRETS.CREATE.environmentSlug).min(1),
|
||||||
name: slugSchema({ min: 1, max: 64, field: "Name" }).describe(DYNAMIC_SECRETS.CREATE.name),
|
name: slugSchema({ min: 1, max: 64, field: "Name" }).describe(DYNAMIC_SECRETS.CREATE.name),
|
||||||
metadata: ResourceMetadataSchema.optional(),
|
metadata: ResourceMetadataSchema.optional(),
|
||||||
tags: ResourceMetadataSchema.optional(),
|
|
||||||
usernameTemplate: userTemplateSchema.optional()
|
usernameTemplate: userTemplateSchema.optional()
|
||||||
}),
|
}),
|
||||||
response: {
|
response: {
|
||||||
@@ -147,7 +146,6 @@ export const registerDynamicSecretRouter = async (server: FastifyZodProvider) =>
|
|||||||
.nullable(),
|
.nullable(),
|
||||||
newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional(),
|
newName: z.string().describe(DYNAMIC_SECRETS.UPDATE.newName).optional(),
|
||||||
metadata: ResourceMetadataSchema.optional(),
|
metadata: ResourceMetadataSchema.optional(),
|
||||||
tags: ResourceMetadataSchema.optional(),
|
|
||||||
usernameTemplate: userTemplateSchema.nullable().optional()
|
usernameTemplate: userTemplateSchema.nullable().optional()
|
||||||
})
|
})
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -166,7 +166,6 @@ export const dynamicSecretLeaseServiceFactory = ({
|
|||||||
usernameTemplate: dynamicSecretCfg.usernameTemplate,
|
usernameTemplate: dynamicSecretCfg.usernameTemplate,
|
||||||
identity,
|
identity,
|
||||||
metadata: { projectId },
|
metadata: { projectId },
|
||||||
tags: dynamicSecretCfg.tags as Record<string, string>[] | undefined,
|
|
||||||
config
|
config
|
||||||
});
|
});
|
||||||
} catch (error: unknown) {
|
} catch (error: unknown) {
|
||||||
|
|||||||
@@ -79,7 +79,6 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
defaultTTL,
|
defaultTTL,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
metadata,
|
metadata,
|
||||||
tags,
|
|
||||||
usernameTemplate
|
usernameTemplate
|
||||||
}: TCreateDynamicSecretDTO) => {
|
}: TCreateDynamicSecretDTO) => {
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
@@ -166,8 +165,7 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
folderId: folder.id,
|
folderId: folder.id,
|
||||||
name,
|
name,
|
||||||
gatewayId: selectedGatewayId,
|
gatewayId: selectedGatewayId,
|
||||||
usernameTemplate,
|
usernameTemplate
|
||||||
tags: JSON.stringify(tags)
|
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
@@ -204,9 +202,10 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
actorOrgId,
|
actorOrgId,
|
||||||
actorAuthMethod,
|
actorAuthMethod,
|
||||||
metadata,
|
metadata,
|
||||||
tags,
|
|
||||||
usernameTemplate
|
usernameTemplate
|
||||||
}: TUpdateDynamicSecretDTO) => {
|
}: TUpdateDynamicSecretDTO) => {
|
||||||
|
console.log({ inputs });
|
||||||
|
|
||||||
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
const project = await projectDAL.findProjectBySlug(projectSlug, actorOrgId);
|
||||||
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
if (!project) throw new NotFoundError({ message: `Project with slug '${projectSlug}' not found` });
|
||||||
|
|
||||||
@@ -318,8 +317,7 @@ export const dynamicSecretServiceFactory = ({
|
|||||||
name: newName ?? name,
|
name: newName ?? name,
|
||||||
status: null,
|
status: null,
|
||||||
gatewayId: selectedGatewayId,
|
gatewayId: selectedGatewayId,
|
||||||
usernameTemplate,
|
usernameTemplate
|
||||||
tags: JSON.stringify(tags)
|
|
||||||
},
|
},
|
||||||
tx
|
tx
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -23,7 +23,6 @@ export type TCreateDynamicSecretDTO = {
|
|||||||
projectSlug: string;
|
projectSlug: string;
|
||||||
metadata?: ResourceMetadataDTO;
|
metadata?: ResourceMetadataDTO;
|
||||||
usernameTemplate?: string | null;
|
usernameTemplate?: string | null;
|
||||||
tags?: ResourceMetadataDTO;
|
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
export type TUpdateDynamicSecretDTO = {
|
export type TUpdateDynamicSecretDTO = {
|
||||||
@@ -36,7 +35,6 @@ export type TUpdateDynamicSecretDTO = {
|
|||||||
inputs?: TProvider["inputs"];
|
inputs?: TProvider["inputs"];
|
||||||
projectSlug: string;
|
projectSlug: string;
|
||||||
metadata?: ResourceMetadataDTO;
|
metadata?: ResourceMetadataDTO;
|
||||||
tags?: ResourceMetadataDTO;
|
|
||||||
usernameTemplate?: string | null;
|
usernameTemplate?: string | null;
|
||||||
} & Omit<TProjectPermission, "projectId">;
|
} & Omit<TProjectPermission, "projectId">;
|
||||||
|
|
||||||
|
|||||||
@@ -119,20 +119,20 @@ export const AwsIamProvider = (): TDynamicProviderFns => {
|
|||||||
identity?: {
|
identity?: {
|
||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
tags?: Record<string, string>[];
|
|
||||||
metadata: { projectId: string };
|
metadata: { projectId: string };
|
||||||
}) => {
|
}) => {
|
||||||
const { inputs, usernameTemplate, metadata, identity, tags } = data;
|
const { inputs, usernameTemplate, metadata, identity } = data;
|
||||||
|
|
||||||
const providerInputs = await validateProviderInputs(inputs);
|
const providerInputs = await validateProviderInputs(inputs);
|
||||||
|
console.log({ providerInputs, inputs });
|
||||||
const client = await $getClient(providerInputs, metadata.projectId);
|
const client = await $getClient(providerInputs, metadata.projectId);
|
||||||
|
|
||||||
const username = generateUsername(usernameTemplate, identity);
|
const username = generateUsername(usernameTemplate, identity);
|
||||||
const { policyArns, userGroups, policyDocument, awsPath, permissionBoundaryPolicyArn } = providerInputs;
|
const { policyArns, userGroups, policyDocument, awsPath, permissionBoundaryPolicyArn } = providerInputs;
|
||||||
const awsTags = [{ Key: "createdBy", Value: "infisical-dynamic-secret" }];
|
const awsTags = [{ Key: "createdBy", Value: "infisical-dynamic-secret" }];
|
||||||
|
|
||||||
if (tags && Array.isArray(tags)) {
|
if (providerInputs.tags && Array.isArray(providerInputs.tags)) {
|
||||||
const additionalTags = tags.map((tag) => ({
|
const additionalTags = providerInputs.tags.map((tag) => ({
|
||||||
Key: tag.key,
|
Key: tag.key,
|
||||||
Value: tag.value
|
Value: tag.value
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import RE2 from "re2";
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
import { CharacterType, characterValidator } from "@app/lib/validator/validate-string";
|
import { CharacterType, characterValidator } from "@app/lib/validator/validate-string";
|
||||||
|
import { ResourceMetadataSchema } from "@app/services/resource-metadata/resource-metadata-schema";
|
||||||
|
|
||||||
import { TDynamicSecretLeaseConfig } from "../../dynamic-secret-lease/dynamic-secret-lease-types";
|
import { TDynamicSecretLeaseConfig } from "../../dynamic-secret-lease/dynamic-secret-lease-types";
|
||||||
|
|
||||||
@@ -207,7 +208,8 @@ export const DynamicSecretAwsIamSchema = z.preprocess(
|
|||||||
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
||||||
policyDocument: z.string().trim().optional(),
|
policyDocument: z.string().trim().optional(),
|
||||||
userGroups: z.string().trim().optional(),
|
userGroups: z.string().trim().optional(),
|
||||||
policyArns: z.string().trim().optional()
|
policyArns: z.string().trim().optional(),
|
||||||
|
tags: ResourceMetadataSchema.optional()
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
method: z.literal(AwsIamAuthType.AssumeRole),
|
method: z.literal(AwsIamAuthType.AssumeRole),
|
||||||
@@ -217,7 +219,8 @@ export const DynamicSecretAwsIamSchema = z.preprocess(
|
|||||||
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
||||||
policyDocument: z.string().trim().optional(),
|
policyDocument: z.string().trim().optional(),
|
||||||
userGroups: z.string().trim().optional(),
|
userGroups: z.string().trim().optional(),
|
||||||
policyArns: z.string().trim().optional()
|
policyArns: z.string().trim().optional(),
|
||||||
|
tags: ResourceMetadataSchema.optional()
|
||||||
})
|
})
|
||||||
])
|
])
|
||||||
);
|
);
|
||||||
@@ -525,7 +528,6 @@ export type TDynamicProviderFns = {
|
|||||||
name: string;
|
name: string;
|
||||||
};
|
};
|
||||||
metadata: { projectId: string };
|
metadata: { projectId: string };
|
||||||
tags?: Record<string, string>[];
|
|
||||||
config?: TDynamicSecretLeaseConfig;
|
config?: TDynamicSecretLeaseConfig;
|
||||||
}) => Promise<{ entityId: string; data: unknown }>;
|
}) => Promise<{ entityId: string; data: unknown }>;
|
||||||
validateConnection: (inputs: unknown, metadata: { projectId: string }) => Promise<boolean>;
|
validateConnection: (inputs: unknown, metadata: { projectId: string }) => Promise<boolean>;
|
||||||
|
|||||||
+17
-15
@@ -34,7 +34,12 @@ const formSchema = z.object({
|
|||||||
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
||||||
policyDocument: z.string().trim().optional(),
|
policyDocument: z.string().trim().optional(),
|
||||||
userGroups: z.string().trim().optional(),
|
userGroups: z.string().trim().optional(),
|
||||||
policyArns: z.string().trim().optional()
|
policyArns: z.string().trim().optional(),
|
||||||
|
tags: z
|
||||||
|
.array(
|
||||||
|
z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) })
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
method: z.literal(DynamicSecretAwsIamAuth.AssumeRole),
|
method: z.literal(DynamicSecretAwsIamAuth.AssumeRole),
|
||||||
@@ -44,7 +49,12 @@ const formSchema = z.object({
|
|||||||
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
||||||
policyDocument: z.string().trim().optional(),
|
policyDocument: z.string().trim().optional(),
|
||||||
userGroups: z.string().trim().optional(),
|
userGroups: z.string().trim().optional(),
|
||||||
policyArns: z.string().trim().optional()
|
policyArns: z.string().trim().optional(),
|
||||||
|
tags: z
|
||||||
|
.array(
|
||||||
|
z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) })
|
||||||
|
)
|
||||||
|
.optional()
|
||||||
})
|
})
|
||||||
]),
|
]),
|
||||||
defaultTTL: z.string().superRefine((val, ctx) => {
|
defaultTTL: z.string().superRefine((val, ctx) => {
|
||||||
@@ -69,12 +79,7 @@ const formSchema = z.object({
|
|||||||
}),
|
}),
|
||||||
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
|
name: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
|
||||||
environment: z.object({ name: z.string(), slug: z.string() }),
|
environment: z.object({ name: z.string(), slug: z.string() }),
|
||||||
usernameTemplate: z.string().nullable().optional(),
|
usernameTemplate: z.string().nullable().optional()
|
||||||
tags: z
|
|
||||||
.array(
|
|
||||||
z.object({ key: z.string().trim().min(1).max(128), value: z.string().trim().min(1).max(256) })
|
|
||||||
)
|
|
||||||
.optional()
|
|
||||||
});
|
});
|
||||||
type TForm = z.infer<typeof formSchema>;
|
type TForm = z.infer<typeof formSchema>;
|
||||||
|
|
||||||
@@ -107,8 +112,7 @@ export const AwsIamInputForm = ({
|
|||||||
usernameTemplate: "{{randomUsername}}",
|
usernameTemplate: "{{randomUsername}}",
|
||||||
provider: {
|
provider: {
|
||||||
method: DynamicSecretAwsIamAuth.AssumeRole
|
method: DynamicSecretAwsIamAuth.AssumeRole
|
||||||
},
|
}
|
||||||
tags: []
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -121,8 +125,7 @@ export const AwsIamInputForm = ({
|
|||||||
provider,
|
provider,
|
||||||
defaultTTL,
|
defaultTTL,
|
||||||
environment,
|
environment,
|
||||||
usernameTemplate,
|
usernameTemplate
|
||||||
tags
|
|
||||||
}: TForm) => {
|
}: TForm) => {
|
||||||
// wait till previous request is finished
|
// wait till previous request is finished
|
||||||
if (createDynamicSecret.isPending) return;
|
if (createDynamicSecret.isPending) return;
|
||||||
@@ -138,8 +141,7 @@ export const AwsIamInputForm = ({
|
|||||||
projectSlug,
|
projectSlug,
|
||||||
environmentSlug: environment.slug,
|
environmentSlug: environment.slug,
|
||||||
usernameTemplate:
|
usernameTemplate:
|
||||||
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate,
|
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
|
||||||
tags
|
|
||||||
});
|
});
|
||||||
onCompleted();
|
onCompleted();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -408,7 +410,7 @@ export const AwsIamInputForm = ({
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<MetadataForm control={control} name="tags" isValueRequired />
|
<MetadataForm control={control} name="provider.tags" title="Tags" isValueRequired />
|
||||||
{!isSingleEnvironmentMode && (
|
{!isSingleEnvironmentMode && (
|
||||||
<Controller
|
<Controller
|
||||||
control={control}
|
control={control}
|
||||||
|
|||||||
+11
-11
@@ -23,7 +23,10 @@ const formSchema = z.object({
|
|||||||
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
||||||
policyDocument: z.string().trim().optional(),
|
policyDocument: z.string().trim().optional(),
|
||||||
userGroups: z.string().trim().optional(),
|
userGroups: z.string().trim().optional(),
|
||||||
policyArns: z.string().trim().optional()
|
policyArns: z.string().trim().optional(),
|
||||||
|
tags: z
|
||||||
|
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
|
||||||
|
.optional(),
|
||||||
}),
|
}),
|
||||||
z.object({
|
z.object({
|
||||||
method: z.literal(DynamicSecretAwsIamAuth.AssumeRole),
|
method: z.literal(DynamicSecretAwsIamAuth.AssumeRole),
|
||||||
@@ -33,7 +36,10 @@ const formSchema = z.object({
|
|||||||
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
permissionBoundaryPolicyArn: z.string().trim().optional(),
|
||||||
policyDocument: z.string().trim().optional(),
|
policyDocument: z.string().trim().optional(),
|
||||||
userGroups: z.string().trim().optional(),
|
userGroups: z.string().trim().optional(),
|
||||||
policyArns: z.string().trim().optional()
|
policyArns: z.string().trim().optional(),
|
||||||
|
tags: z
|
||||||
|
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
|
||||||
|
.optional()
|
||||||
})
|
})
|
||||||
]),
|
]),
|
||||||
defaultTTL: z.string().superRefine((val, ctx) => {
|
defaultTTL: z.string().superRefine((val, ctx) => {
|
||||||
@@ -58,9 +64,6 @@ const formSchema = z.object({
|
|||||||
})
|
})
|
||||||
.nullable(),
|
.nullable(),
|
||||||
newName: slugSchema().optional(),
|
newName: slugSchema().optional(),
|
||||||
tags: z
|
|
||||||
.array(z.object({ key: z.string().trim().min(1), value: z.string().trim().min(1) }))
|
|
||||||
.optional(),
|
|
||||||
usernameTemplate: z.string().trim().nullable().optional()
|
usernameTemplate: z.string().trim().nullable().optional()
|
||||||
});
|
});
|
||||||
type TForm = z.infer<typeof formSchema>;
|
type TForm = z.infer<typeof formSchema>;
|
||||||
@@ -95,7 +98,6 @@ export const EditDynamicSecretAwsIamForm = ({
|
|||||||
inputs: {
|
inputs: {
|
||||||
...(dynamicSecret.inputs as TForm["inputs"])
|
...(dynamicSecret.inputs as TForm["inputs"])
|
||||||
},
|
},
|
||||||
tags: dynamicSecret.tags
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
const isAccessKeyMethod = watch("inputs.method") === DynamicSecretAwsIamAuth.AccessKey;
|
const isAccessKeyMethod = watch("inputs.method") === DynamicSecretAwsIamAuth.AccessKey;
|
||||||
@@ -107,8 +109,7 @@ export const EditDynamicSecretAwsIamForm = ({
|
|||||||
maxTTL,
|
maxTTL,
|
||||||
defaultTTL,
|
defaultTTL,
|
||||||
newName,
|
newName,
|
||||||
usernameTemplate,
|
usernameTemplate
|
||||||
tags
|
|
||||||
}: TForm) => {
|
}: TForm) => {
|
||||||
// wait till previous request is finished
|
// wait till previous request is finished
|
||||||
if (updateDynamicSecret.isPending) return;
|
if (updateDynamicSecret.isPending) return;
|
||||||
@@ -125,8 +126,7 @@ export const EditDynamicSecretAwsIamForm = ({
|
|||||||
inputs,
|
inputs,
|
||||||
newName: newName === dynamicSecret.name ? undefined : newName,
|
newName: newName === dynamicSecret.name ? undefined : newName,
|
||||||
usernameTemplate:
|
usernameTemplate:
|
||||||
!usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate,
|
!usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
|
||||||
tags
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
onClose();
|
onClose();
|
||||||
@@ -389,7 +389,7 @@ export const EditDynamicSecretAwsIamForm = ({
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<MetadataForm control={control} name="tags" isValueRequired />
|
<MetadataForm control={control} name="inputs.tags" title="Tags" isValueRequired />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-4 flex items-center space-x-4">
|
<div className="mt-4 flex items-center space-x-4">
|
||||||
|
|||||||
+3
-1
@@ -7,10 +7,12 @@ import { FormControl, FormLabel, IconButton, Input } from "@app/components/v2";
|
|||||||
export const MetadataForm = ({
|
export const MetadataForm = ({
|
||||||
control,
|
control,
|
||||||
name = "metadata",
|
name = "metadata",
|
||||||
|
title = "Metadata",
|
||||||
isValueRequired = false
|
isValueRequired = false
|
||||||
}: {
|
}: {
|
||||||
control: Control<any>;
|
control: Control<any>;
|
||||||
name?: string;
|
name?: string;
|
||||||
|
title?: string;
|
||||||
isValueRequired?: boolean;
|
isValueRequired?: boolean;
|
||||||
}) => {
|
}) => {
|
||||||
const metadataFormFields = useFieldArray({
|
const metadataFormFields = useFieldArray({
|
||||||
@@ -19,7 +21,7 @@ export const MetadataForm = ({
|
|||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FormControl label={name.charAt(0).toUpperCase() + name.slice(1)}>
|
<FormControl label={title}>
|
||||||
<div className="flex flex-col space-y-2">
|
<div className="flex flex-col space-y-2">
|
||||||
{metadataFormFields.fields.map(({ id: metadataFieldId }, i) => (
|
{metadataFormFields.fields.map(({ id: metadataFieldId }, i) => (
|
||||||
<div key={metadataFieldId} className="flex items-end space-x-2">
|
<div key={metadataFieldId} className="flex items-end space-x-2">
|
||||||
|
|||||||
Reference in New Issue
Block a user