feat: ui changes for input template

This commit is contained in:
=
2025-05-28 16:09:12 +05:30
parent 93d7c812e7
commit 8e3559828f
27 changed files with 800 additions and 90 deletions

View File

@@ -13,6 +13,7 @@ export type TDynamicSecret = {
status?: DynamicSecretStatus;
statusDetails?: string;
maxTTL: string;
usernameTemplate?: string | null;
metadata?: { key: string; value: string }[];
};
@@ -272,6 +273,7 @@ export type TCreateDynamicSecretDTO = {
environmentSlug: string;
name: string;
metadata?: { key: string; value: string }[];
usernameTemplate?: string;
};
export type TUpdateDynamicSecretDTO = {
@@ -285,6 +287,7 @@ export type TUpdateDynamicSecretDTO = {
defaultTTL?: string;
maxTTL?: string | null;
inputs?: unknown;
usernameTemplate?: string | null;
};
};

View File

@@ -53,7 +53,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -93,7 +94,8 @@ export const AwsElastiCacheInputForm = ({
"UserId": "{{username}}"
}`
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -104,10 +106,13 @@ export const AwsElastiCacheInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.AwsElastiCache, inputs: provider },
@@ -116,7 +121,9 @@ export const AwsElastiCacheInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -270,6 +277,25 @@ export const AwsElastiCacheInputForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify ElastiCache Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="provider.creationStatement"

View File

@@ -42,7 +42,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -70,7 +71,8 @@ export const AwsIamInputForm = ({
} = useForm<TForm>({
resolver: zodResolver(formSchema),
defaultValues: {
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -81,12 +83,14 @@ export const AwsIamInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.AwsIam, inputs: provider },
maxTTL,
@@ -94,7 +98,9 @@ export const AwsIamInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -300,6 +306,25 @@ export const AwsIamInputForm = ({
</FormControl>
)}
/>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
{!isSingleEnvironmentMode && (
<Controller
control={control}

View File

@@ -55,7 +55,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -93,7 +94,8 @@ export const CassandraInputForm = ({
resolver: zodResolver(formSchema),
defaultValues: {
provider: getSqlStatements(),
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -104,11 +106,13 @@ export const CassandraInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Cassandra, inputs: provider },
@@ -117,7 +121,9 @@ export const CassandraInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -298,6 +304,25 @@ export const CassandraInputForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify CQL Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="provider.creationStatement"

View File

@@ -76,7 +76,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -113,7 +114,8 @@ export const ElasticSearchInputForm = ({
roles: ["superuser"],
port: 443
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -124,10 +126,12 @@ export const ElasticSearchInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.ElasticSearch, inputs: provider },
@@ -136,7 +140,9 @@ export const ElasticSearchInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -418,6 +424,25 @@ export const ElasticSearchInputForm = ({
)}
/>
</div>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
{!isSingleEnvironmentMode && (
<Controller
control={control}

View File

@@ -79,7 +79,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -120,7 +121,8 @@ export const LdapInputForm = ({
rollbackLdif: "",
credentialType: CredentialType.Dynamic
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -133,10 +135,13 @@ export const LdapInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Ldap, inputs: provider },
@@ -145,6 +150,8 @@ export const LdapInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate,
environmentSlug: environment.slug
});
onCompleted();
@@ -413,6 +420,25 @@ export const LdapInputForm = ({
)}
</div>
</div>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
</div>
</div>
</div>

View File

@@ -66,7 +66,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -114,7 +115,8 @@ export const MongoAtlasInputForm = ({
provider: {
roles: [{ databaseName: "", roleName: "" }]
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -135,10 +137,13 @@ export const MongoAtlasInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.MongoAtlas, inputs: provider },
@@ -147,7 +152,9 @@ export const MongoAtlasInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -312,7 +319,7 @@ export const MongoAtlasInputForm = ({
label="Role"
className="text-xs text-mineshaft-400"
tooltipClassName="max-w-md whitespace-pre-line"
tooltipText={`Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.
tooltipText={`Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.
Built-in: atlasAdmin, backup, clusterMonitor, dbAdmin, dbAdminAnyDatabase, enableSharding, read, readAnyDatabase, readWrite, readWriteAnyDatabase.`}
/>
)}
@@ -362,6 +369,26 @@ export const MongoAtlasInputForm = ({
<AccordionItem value="advance-section">
<AccordionTrigger>Advanced</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
tooltipText="randomUsername: Function used to generate random username"
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
<FormLabel
label="Scopes"
isOptional

View File

@@ -56,7 +56,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -89,7 +90,8 @@ export const MongoDBDatabaseInputForm = ({
provider: {
roles: [{ roleName: "readWrite" }]
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -105,10 +107,13 @@ export const MongoDBDatabaseInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: {
@@ -124,7 +129,9 @@ export const MongoDBDatabaseInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -272,7 +279,7 @@ export const MongoDBDatabaseInputForm = ({
<FormLabel
label="Roles"
tooltipClassName="max-w-md whitespace-pre-line"
tooltipText={`Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.
tooltipText={`Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.
Built-in: atlasAdmin, backup, clusterMonitor, dbAdmin, dbAdminAnyDatabase, enableSharding, read, readAnyDatabase, readWrite, readWriteAnyDatabase.`}
/>
<div className="mb-3 mt-1 flex flex-col space-y-2">
@@ -340,6 +347,25 @@ export const MongoDBDatabaseInputForm = ({
)}
/>
</div>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
{!isSingleEnvironmentMode && (
<Controller
control={control}

View File

@@ -60,7 +60,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -102,7 +103,8 @@ export const RabbitMqInputForm = ({
},
tags: []
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -113,10 +115,13 @@ export const RabbitMqInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.RabbitMq, inputs: provider },
@@ -125,7 +130,9 @@ export const RabbitMqInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -424,6 +431,25 @@ export const RabbitMqInputForm = ({
)}
/>
</div>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
{!isSingleEnvironmentMode && (
<Controller
control={control}

View File

@@ -53,7 +53,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -87,7 +88,8 @@ export const RedisInputForm = ({
creationStatement: "ACL SETUSER {{username}} on >{{password}} ~* &* +@all",
revocationStatement: "ACL DELUSER {{username}}"
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -98,11 +100,13 @@ export const RedisInputForm = ({
maxTTL,
provider,
defaultTTL,
usernameTemplate,
environment
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Redis, inputs: provider },
maxTTL,
@@ -110,7 +114,9 @@ export const RedisInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -265,6 +271,26 @@ export const RedisInputForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify Redis Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
tooltipText="randomUsername: Function used to generate random username"
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="provider.creationStatement"

View File

@@ -51,7 +51,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -88,7 +89,8 @@ sp_role 'grant', 'mon_role', '{{username}}';`,
revocationStatement: `sp_dropuser '{{username}}';
sp_droplogin '{{username}}';`
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -99,11 +101,13 @@ sp_droplogin '{{username}}';`
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SapAse, inputs: provider },
maxTTL,
@@ -111,7 +115,9 @@ sp_droplogin '{{username}}';`
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -262,6 +268,26 @@ sp_droplogin '{{username}}';`
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify SQL Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
tooltipText="randomUsername: Function used to generate random username"
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="provider.creationStatement"

View File

@@ -53,7 +53,8 @@ const formSchema = z.object({
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
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()
});
type TForm = z.infer<typeof formSchema>;
@@ -88,7 +89,8 @@ GRANT "MONITORING" TO {{username}};`,
DROP USER {{username}};`,
renewStatement: "ALTER USER {{username}} VALID UNTIL '{{expiration}}';"
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -96,6 +98,7 @@ DROP USER {{username}};`,
const handleCreateDynamicSecret = async ({
name,
usernameTemplate,
maxTTL,
provider,
defaultTTL,
@@ -104,6 +107,7 @@ DROP USER {{username}};`,
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SapHana, inputs: provider },
maxTTL,
@@ -111,6 +115,8 @@ DROP USER {{username}};`,
path: secretPath,
defaultTTL,
projectSlug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate,
environmentSlug: environment.slug
});
onCompleted();
@@ -263,6 +269,26 @@ DROP USER {{username}};`,
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify SQL Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
tooltipText="randomUsername: Function used to generate random username"
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="provider.creationStatement"

View File

@@ -57,7 +57,8 @@ const formSchema = z.object({
.trim()
.min(1)
.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()
});
type TForm = z.infer<typeof formSchema>;
@@ -91,7 +92,8 @@ export const SnowflakeInputForm = ({
revocationStatement: "DROP USER {{username}};",
renewStatement: "ALTER USER {{username}} SET DAYS_TO_EXPIRY = {{expiration}};"
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -102,11 +104,13 @@ export const SnowflakeInputForm = ({
maxTTL,
provider,
defaultTTL,
environment
environment,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.Snowflake, inputs: provider },
maxTTL,
@@ -114,7 +118,9 @@ export const SnowflakeInputForm = ({
path: secretPath,
defaultTTL,
projectSlug,
environmentSlug: environment.slug
environmentSlug: environment.slug,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch (err) {
@@ -266,6 +272,26 @@ export const SnowflakeInputForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify SQL Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
tooltipText="randomUsername: Function used to generate random username"
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="provider.creationStatement"

View File

@@ -96,7 +96,8 @@ const formSchema = z.object({
value: z.string().trim().default("")
})
.array()
.optional()
.optional(),
usernameTemplate: z.string().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -191,7 +192,8 @@ export const SqlDatabaseInputForm = ({
allowedSymbols: "-_.~!*"
}
},
environment: isSingleEnvironmentMode ? environments[0] : undefined
environment: isSingleEnvironmentMode ? environments[0] : undefined,
usernameTemplate: "{{randomUsername}}"
}
});
@@ -204,11 +206,13 @@ export const SqlDatabaseInputForm = ({
provider,
defaultTTL,
environment,
metadata
metadata,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (createDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await createDynamicSecret.mutateAsync({
provider: { type: DynamicSecretProviders.SqlDatabase, inputs: provider },
@@ -218,7 +222,9 @@ export const SqlDatabaseInputForm = ({
defaultTTL,
projectSlug,
environmentSlug: environment.slug,
metadata
metadata,
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? undefined : usernameTemplate
});
onCompleted();
} catch {
@@ -474,6 +480,26 @@ export const SqlDatabaseInputForm = ({
Creation, Revocation & Renew Statements (optional)
</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
tooltipText="randomUsername: Function used to generate random username"
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
placeholder="{{randomUsername}}"
/>
</FormControl>
)}
/>
<div className="mb-4 text-sm text-mineshaft-300">
Customize SQL statements for managing database user lifecycle
</div>

View File

@@ -56,7 +56,8 @@ const formSchema = z.object({
newName: z
.string()
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -85,6 +86,7 @@ export const EditDynamicSecretAwsElastiCacheProviderForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -93,9 +95,16 @@ export const EditDynamicSecretAwsElastiCacheProviderForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -106,7 +115,8 @@ export const EditDynamicSecretAwsElastiCacheProviderForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -261,6 +271,24 @@ export const EditDynamicSecretAwsElastiCacheProviderForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify ElastiCache Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="inputs.creationStatement"

View File

@@ -46,7 +46,8 @@ const formSchema = z.object({
newName: z
.string()
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -75,6 +76,7 @@ export const EditDynamicSecretAwsIamForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -83,9 +85,16 @@ export const EditDynamicSecretAwsIamForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -96,7 +105,8 @@ export const EditDynamicSecretAwsIamForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -297,6 +307,24 @@ export const EditDynamicSecretAwsIamForm = ({
</FormControl>
)}
/>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
</div>
</div>
<div className="mt-4 flex items-center space-x-4">

View File

@@ -58,7 +58,8 @@ const formSchema = z.object({
newName: z
.string()
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -89,15 +90,23 @@ export const EditDynamicSecretCassandraForm = ({
newName: dynamicSecret.name,
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
},
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}"
}
});
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -108,7 +117,8 @@ export const EditDynamicSecretCassandraForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -292,6 +302,24 @@ export const EditDynamicSecretCassandraForm = ({
<AccordionItem value="modify-sql-statement">
<AccordionTrigger>Modify CQL Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="inputs.creationStatement"

View File

@@ -76,7 +76,8 @@ const formSchema = z.object({
newName: z
.string()
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -107,6 +108,7 @@ export const EditDynamicSecretElasticSearchForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -115,9 +117,16 @@ export const EditDynamicSecretElasticSearchForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -128,7 +137,8 @@ export const EditDynamicSecretElasticSearchForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -390,7 +400,6 @@ export const EditDynamicSecretElasticSearchForm = ({
</Button>
</div>
</div>
<div>
<Controller
control={control}
@@ -410,6 +419,24 @@ export const EditDynamicSecretElasticSearchForm = ({
)}
/>
</div>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
</div>
</div>
</div>

View File

@@ -70,7 +70,8 @@ const formSchema = z.object({
newName: z
.string()
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -101,6 +102,7 @@ export const EditDynamicSecretLdapForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -110,9 +112,17 @@ export const EditDynamicSecretLdapForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const selectedCredentialType = watch("inputs.credentialType");
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -123,7 +133,8 @@ export const EditDynamicSecretLdapForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -329,6 +340,24 @@ export const EditDynamicSecretLdapForm = ({
)}
/>
)}
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
</div>
<div className="mt-4 flex items-center space-x-4">
<Button type="submit" isLoading={isSubmitting}>

View File

@@ -69,7 +69,8 @@ const formSchema = z.object({
newName: z
.string()
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -115,6 +116,7 @@ export const EditDynamicSecretMongoAtlasForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -133,9 +135,17 @@ export const EditDynamicSecretMongoAtlasForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -146,7 +156,8 @@ export const EditDynamicSecretMongoAtlasForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -312,7 +323,7 @@ export const EditDynamicSecretMongoAtlasForm = ({
label="Role"
className="text-xs text-mineshaft-400"
tooltipClassName="max-w-md whitespace-pre-line"
tooltipText={`Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.
tooltipText={`Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.
Built-in: atlasAdmin, backup, clusterMonitor, dbAdmin, dbAdminAnyDatabase, enableSharding, read, readAnyDatabase, readWrite, readWriteAnyDatabase.`}
/>
)}
@@ -362,6 +373,24 @@ export const EditDynamicSecretMongoAtlasForm = ({
<AccordionItem value="advance-section">
<AccordionTrigger>Advanced</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
<FormLabel
label="Scopes"
isOptional

View File

@@ -52,7 +52,8 @@ const formSchema = z.object({
newName: z
.string()
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -83,6 +84,7 @@ export const EditDynamicSecretMongoDBForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"]),
roles: (dynamicSecret.inputs as { roles: string[] }).roles?.map((roleName) => ({
@@ -99,9 +101,17 @@ export const EditDynamicSecretMongoDBForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -116,6 +126,8 @@ export const EditDynamicSecretMongoDBForm = ({
port: inputs?.port ? inputs.port : undefined,
roles: inputs?.roles?.map((el) => el.roleName)
},
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate,
newName: newName === dynamicSecret.name ? undefined : newName
}
});
@@ -265,7 +277,7 @@ export const EditDynamicSecretMongoDBForm = ({
<FormLabel
label="Roles"
tooltipClassName="max-w-md whitespace-pre-line"
tooltipText={`Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.
tooltipText={`Human-readable label that identifies a group of privileges assigned to a database user. This value can either be a built-in role or a custom role.
Built-in: atlasAdmin, backup, clusterMonitor, dbAdmin, dbAdminAnyDatabase, enableSharding, read, readAnyDatabase, readWrite, readWriteAnyDatabase.`}
/>
<div className="mb-3 mt-1 flex flex-col space-y-2">
@@ -333,6 +345,26 @@ export const EditDynamicSecretMongoDBForm = ({
)}
/>
</div>
<div>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
</div>
</div>
</div>
<div className="mt-4 flex items-center space-x-4">

View File

@@ -50,7 +50,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
newName: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
newName: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -80,6 +81,7 @@ export const EditDynamicSecretRabbitMqForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -88,9 +90,17 @@ export const EditDynamicSecretRabbitMqForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -101,7 +111,8 @@ export const EditDynamicSecretRabbitMqForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -405,6 +416,26 @@ export const EditDynamicSecretRabbitMqForm = ({
)}
/>
</div>
<div>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
</div>
</div>
</div>
</div>

View File

@@ -57,7 +57,8 @@ const formSchema = z.object({
newName: z
.string()
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -86,6 +87,7 @@ export const EditDynamicSecretRedisProviderForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -94,9 +96,16 @@ export const EditDynamicSecretRedisProviderForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -104,6 +113,8 @@ export const EditDynamicSecretRedisProviderForm = ({
projectSlug,
environmentSlug: environment,
data: {
usernameTemplate:
!usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate,
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
@@ -262,6 +273,24 @@ export const EditDynamicSecretRedisProviderForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify Redis Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="inputs.creationStatement"

View File

@@ -40,6 +40,7 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
usernameTemplate: z.string().trim().nullable().optional(),
maxTTL: z
.string()
.optional()
@@ -81,6 +82,7 @@ export const EditDynamicSecretSapAseForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -89,9 +91,17 @@ export const EditDynamicSecretSapAseForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -102,7 +112,8 @@ export const EditDynamicSecretSapAseForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -272,6 +283,24 @@ export const EditDynamicSecretSapAseForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify SQL Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="inputs.creationStatement"

View File

@@ -52,7 +52,8 @@ const formSchema = z.object({
if (valMs > 24 * 60 * 60 * 1000)
ctx.addIssue({ code: z.ZodIssueCode.custom, message: "TTL must be less than a day" });
}),
newName: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase")
newName: z.string().refine((val) => val.toLowerCase() === val, "Must be lowercase"),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -81,6 +82,7 @@ export const EditDynamicSecretSapHanaForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -89,9 +91,17 @@ export const EditDynamicSecretSapHanaForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
try {
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
@@ -102,7 +112,8 @@ export const EditDynamicSecretSapHanaForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -259,6 +270,24 @@ export const EditDynamicSecretSapHanaForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify SQL Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="inputs.creationStatement"

View File

@@ -56,7 +56,8 @@ const formSchema = z.object({
.string()
.trim()
.min(1)
.refine((val) => val.toLowerCase() === val, "Must be lowercase")
.refine((val) => val.toLowerCase() === val, "Must be lowercase"),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -85,6 +86,7 @@ export const EditDynamicSecretSnowflakeForm = ({
defaultTTL: dynamicSecret.defaultTTL,
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"])
}
@@ -93,10 +95,17 @@ export const EditDynamicSecretSnowflakeForm = ({
const updateDynamicSecret = useUpdateDynamicSecret();
const handleUpdateDynamicSecret = async ({ inputs, maxTTL, defaultTTL, newName }: TForm) => {
const handleUpdateDynamicSecret = async ({
inputs,
maxTTL,
defaultTTL,
newName,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
@@ -106,7 +115,8 @@ export const EditDynamicSecretSnowflakeForm = ({
maxTTL: maxTTL || undefined,
defaultTTL,
inputs,
newName: newName === dynamicSecret.name ? undefined : newName
newName: newName === dynamicSecret.name ? undefined : newName,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -262,6 +272,24 @@ export const EditDynamicSecretSnowflakeForm = ({
<AccordionItem value="advance-statements">
<AccordionTrigger>Modify SQL Statements</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
<Controller
control={control}
name="inputs.creationStatement"

View File

@@ -97,7 +97,8 @@ const formSchema = z.object({
value: z.string().trim().default("")
})
.array()
.optional()
.optional(),
usernameTemplate: z.string().trim().nullable().optional()
});
type TForm = z.infer<typeof formSchema>;
@@ -139,6 +140,7 @@ export const EditDynamicSecretSqlProviderForm = ({
maxTTL: dynamicSecret.maxTTL,
newName: dynamicSecret.name,
metadata: dynamicSecret.metadata,
usernameTemplate: dynamicSecret?.usernameTemplate || "{{randomUsername}}",
inputs: {
...(dynamicSecret.inputs as TForm["inputs"]),
passwordRequirements:
@@ -161,11 +163,13 @@ export const EditDynamicSecretSqlProviderForm = ({
maxTTL,
defaultTTL,
newName,
metadata
metadata,
usernameTemplate
}: TForm) => {
// wait till previous request is finished
if (updateDynamicSecret.isPending) return;
try {
const isDefaultUsernameTemplate = usernameTemplate === "{{randomUsername}}";
await updateDynamicSecret.mutateAsync({
name: dynamicSecret.name,
path: secretPath,
@@ -179,7 +183,8 @@ export const EditDynamicSecretSqlProviderForm = ({
gatewayId: isGatewayInActive ? null : inputs.gatewayId
},
newName: newName === dynamicSecret.name ? undefined : newName,
metadata
metadata,
usernameTemplate: !usernameTemplate || isDefaultUsernameTemplate ? null : usernameTemplate
}
});
onClose();
@@ -427,6 +432,25 @@ export const EditDynamicSecretSqlProviderForm = ({
Creation, Revocation & Renew Statements (optional)
</AccordionTrigger>
<AccordionContent>
<Controller
control={control}
name="usernameTemplate"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Username Template"
isError={Boolean(error?.message)}
errorText={error?.message}
helperText="randomUsername: Function used to generate random username"
>
<Input
{...field}
value={field.value || undefined}
className="border-mineshaft-600 bg-mineshaft-900 text-sm"
/>
</FormControl>
)}
/>
<div className="mb-4 text-sm text-mineshaft-300">
Customize SQL statements for managing database user lifecycle
</div>