fix(studio): hide secret visibility controls in pipeline edit forms (#51010)

## Problem

Pipeline edit forms hide stored credentials but still show visibility
controls beside their placeholders. The controls suggest that the stored
secret can be revealed.

## Solution

- Hide visibility controls in edit mode for ClickHouse, Snowflake,
DuckLake, and Analytics Bucket secret fields.
- Keep the controls available when creating a destination, with
accessible labels for the DuckLake and Analytics Bucket controls.

| Before | After |
| --- | --- |
| <img width="1024" height="196" alt="CleanShot 2026-09-29 at 16 48
56@2x"
src="https://github.com/user-attachments/assets/a9da9a32-ab17-4c07-abf3-dfa88b8c6475"
/> | <img width="1024" height="168" alt="CleanShot 2026-09-29 at 16 47
23@2x"
src="https://github.com/user-attachments/assets/fddeb880-cd23-4752-ae73-8f27348c647f"
/> |

## To test

1. Open **Database → Pipelines** and edit a destination of each type:
ClickHouse, Snowflake, DuckLake with custom parameters, and Analytics
Bucket. Check that the hidden secret fields have no eye button.
2. Start creating each destination and check that its secret fields
still offer a working visibility control.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

## Summary

* **Improvements**
* Secret fields in replication destination forms remain masked when
editing an existing destination, and their visibility controls are
hidden. When creating a destination, supported secret fields can be
revealed.
* **Accessibility**
* Catalog-token visibility controls now use dynamic, descriptive labels.
DuckLake catalog URL and S3 secret-key reveal controls also have
descriptive labels.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Danny White authored and GitHub committed 2026-09-30 09:55:45 +10:00
1 parent 6b7c91a773
commit 68d5011514
4 files changed
+61 -43

No files matched your search

@@ -303,6 +303,7 @@ export const AnalyticsBucketFields = ({
<div className="flex items-center justify-center">
<Button
className="w-7"
aria-label={showCatalogToken ? 'Hide catalog token' : 'Show catalog token'}
icon={showCatalogToken ? <Eye /> : <EyeOff />}
onClick={() => setShowCatalogToken(!showCatalogToken)}
/>
@@ -408,18 +409,23 @@ export const AnalyticsBucketFields = ({
<FormControl>
<Input
{...field}
type={showSecretAccessKey ? 'text' : 'password'}
type={showSecretAccessKey && !editMode ? 'text' : 'password'}
value={field.value ?? ''}
placeholder={
editMode ? STORED_SECRET_PLACEHOLDER : 'Provide the secret access key'
}
/>
</FormControl>
<Button
icon={showSecretAccessKey ? <Eye /> : <EyeOff />}
className="w-7 absolute right-1 top-[4px]"
onClick={() => setShowSecretAccessKey(!showSecretAccessKey)}
/>
{!editMode && (
<Button
aria-label={
showSecretAccessKey ? 'Hide secret access key' : 'Show secret access key'
}
icon={showSecretAccessKey ? <Eye /> : <EyeOff />}
className="w-7 absolute right-1 top-[4px]"
onClick={() => setShowSecretAccessKey(!showSecretAccessKey)}
/>
)}
</FormItemLayout>
)}
/>
@@ -83,26 +83,28 @@ export const ClickHouseFields = ({
labelOptional="Optional"
description={
editMode
? 'Enter a new password to replace the stored one. The eye button shows only what you enter.'
? 'Enter a new password to replace the stored one.'
: 'Leave blank if the ClickHouse user has no password.'
}
>
<FormControl>
<PasswordInput
value={field.value ?? ''}
type={showPassword ? 'text' : 'password'}
type={showPassword && !editMode ? 'text' : 'password'}
placeholder={editMode ? STORED_SECRET_PLACEHOLDER : undefined}
onChange={(event) => field.onChange(event.target.value)}
actions={
<div className="flex items-center justify-center">
<Button
className="w-7"
title={passwordVisibilityLabel}
aria-label={passwordVisibilityLabel}
icon={showPassword ? <Eye /> : <EyeOff />}
onClick={() => setShowPassword(!showPassword)}
/>
</div>
!editMode && (
<div className="flex items-center justify-center">
<Button
className="w-7"
title={passwordVisibilityLabel}
aria-label={passwordVisibilityLabel}
icon={showPassword ? <Eye /> : <EyeOff />}
onClick={() => setShowPassword(!showPassword)}
/>
</div>
)
}
/>
</FormControl>
@@ -405,7 +405,7 @@ const DuckLakeCustomFields = ({
<FormControl>
<PasswordInput
value={field.value ?? ''}
type={showCatalogUrl ? 'text' : 'password'}
type={showCatalogUrl && !editMode ? 'text' : 'password'}
placeholder={
editMode
? STORED_SECRET_PLACEHOLDER
@@ -413,13 +413,16 @@ const DuckLakeCustomFields = ({
}
onChange={(event) => field.onChange(event.target.value)}
actions={
<div className="flex items-center justify-center">
<Button
className="w-7"
icon={showCatalogUrl ? <Eye /> : <EyeOff />}
onClick={() => setShowCatalogUrl(!showCatalogUrl)}
/>
</div>
!editMode && (
<div className="flex items-center justify-center">
<Button
className="w-7"
aria-label={showCatalogUrl ? 'Hide catalog URL' : 'Show catalog URL'}
icon={showCatalogUrl ? <Eye /> : <EyeOff />}
onClick={() => setShowCatalogUrl(!showCatalogUrl)}
/>
</div>
)
}
/>
</FormControl>
@@ -520,16 +523,21 @@ const DuckLakeCustomFields = ({
<FormControl>
<Input
{...field}
type={showSecretAccessKey ? 'text' : 'password'}
type={showSecretAccessKey && !editMode ? 'text' : 'password'}
placeholder={editMode ? STORED_SECRET_PLACEHOLDER : 'my-secret-key'}
value={field.value ?? ''}
/>
</FormControl>
<Button
icon={showSecretAccessKey ? <Eye /> : <EyeOff />}
className="w-7 absolute right-6 top-[4px]"
onClick={() => setShowSecretAccessKey(!showSecretAccessKey)}
/>
{!editMode && (
<Button
aria-label={
showSecretAccessKey ? 'Hide secret access key' : 'Show secret access key'
}
icon={showSecretAccessKey ? <Eye /> : <EyeOff />}
className="w-7 absolute right-6 top-[4px]"
onClick={() => setShowSecretAccessKey(!showSecretAccessKey)}
/>
)}
</FormItemLayout>
)}
/>
@@ -239,21 +239,23 @@ export const SnowflakeFields = ({
<FormControl>
<PasswordInput
value={field.value ?? ''}
type={showPrivateKeyPassphrase ? 'text' : 'password'}
type={showPrivateKeyPassphrase && !editMode ? 'text' : 'password'}
placeholder={editMode ? STORED_SECRET_PLACEHOLDER : undefined}
onChange={(event) => field.onChange(event.target.value)}
actions={
<div className="flex items-center justify-center">
<Button
className="w-7"
title={showPrivateKeyPassphrase ? 'Hide passphrase' : 'Show passphrase'}
aria-label={
showPrivateKeyPassphrase ? 'Hide passphrase' : 'Show passphrase'
}
icon={showPrivateKeyPassphrase ? <Eye /> : <EyeOff />}
onClick={() => setShowPrivateKeyPassphrase(!showPrivateKeyPassphrase)}
/>
</div>
!editMode && (
<div className="flex items-center justify-center">
<Button
className="w-7"
title={showPrivateKeyPassphrase ? 'Hide passphrase' : 'Show passphrase'}
aria-label={
showPrivateKeyPassphrase ? 'Hide passphrase' : 'Show passphrase'
}
icon={showPrivateKeyPassphrase ? <Eye /> : <EyeOff />}
onClick={() => setShowPrivateKeyPassphrase(!showPrivateKeyPassphrase)}
/>
</div>
)
}
/>
</FormControl>