Add new password custom field type (#2186)

This commit is contained in:
Leendert de Borst
2026-06-18 09:45:30 +02:00
committed by Leendert de Borst
parent 9dcdca4966
commit 043b241cf0
11 changed files with 138 additions and 45 deletions

View File

@@ -323,6 +323,7 @@ const AddFieldMenu: React.FC<AddFieldMenuProps> = ({
className="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:text-white"
>
<option value="Text">{t('itemTypes.fieldTypes.text')}</option>
<option value="Password">{t('itemTypes.fieldTypes.password')}</option>
<option value="Hidden">{t('itemTypes.fieldTypes.hidden')}</option>
<option value="Email">{t('itemTypes.fieldTypes.email')}</option>
<option value="URL">{t('itemTypes.fieldTypes.url')}</option>

View File

@@ -23,6 +23,7 @@ import { FieldTypes } from '@/utils/dist/core/models/vault';
import EditableFieldLabel from './EditableFieldLabel';
import { FormInput } from './FormInput';
import HiddenField from './HiddenField';
import PasswordField from './PasswordField';
/**
* Custom field definition type
@@ -85,7 +86,18 @@ const SortableCustomField: React.FC<ISortableCustomFieldProps> = ({
);
}
if (field.isHidden || field.fieldType === FieldTypes.Hidden || field.fieldType === FieldTypes.Password) {
if (field.fieldType === FieldTypes.Password) {
return (
<PasswordField
id={field.tempId}
label=""
value={value}
onChange={onValueChange}
/>
);
}
if (field.isHidden || field.fieldType === FieldTypes.Hidden) {
return (
<HiddenField
id={field.tempId}

View File

@@ -260,6 +260,7 @@
"fieldType": "Field Type",
"fieldTypes": {
"text": "Text",
"password": "Password",
"hidden": "Hidden (masked text)",
"email": "Email",
"url": "URL",

View File

@@ -109,6 +109,7 @@ const getSectionIcon = (key: string): keyof typeof MaterialIcons.glyphMap => {
*/
const FIELD_TYPE_OPTIONS: { value: FieldType; labelKey: string }[] = [
{ value: 'Text', labelKey: 'itemTypes.fieldTypes.text' },
{ value: 'Password', labelKey: 'itemTypes.fieldTypes.password' },
{ value: 'Hidden', labelKey: 'itemTypes.fieldTypes.hidden' },
{ value: 'Email', labelKey: 'itemTypes.fieldTypes.email' },
{ value: 'URL', labelKey: 'itemTypes.fieldTypes.url' },

View File

@@ -12,6 +12,7 @@ import { HapticsUtility } from '@/utils/HapticsUtility';
import { useColors } from '@/hooks/useColorScheme';
import { AdvancedPasswordField } from './AdvancedPasswordField';
import { EditableFieldLabel } from './EditableFieldLabel';
import { FormField } from './FormField';
import { HiddenField } from './HiddenField';
@@ -66,7 +67,17 @@ const CustomFieldItem: React.FC<CustomFieldItemProps> = ({
);
}
if (field.isHidden || field.fieldType === FieldTypes.Hidden || field.fieldType === FieldTypes.Password) {
if (field.fieldType === FieldTypes.Password) {
return (
<AdvancedPasswordField
value={value}
onChangeText={onValueChange}
label=""
/>
);
}
if (field.isHidden || field.fieldType === FieldTypes.Hidden) {
return (
<HiddenField
value={value}

View File

@@ -360,6 +360,7 @@
"enterFieldName": "Enter field name",
"fieldTypes": {
"text": "Text",
"password": "Password",
"hidden": "Hidden",
"email": "Email",
"url": "URL",

View File

@@ -272,7 +272,7 @@
/* End PBXFileReference section */
/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */
CEE9098F2DA548C7008D568F /* PBXFileSystemSynchronizedBuildFileExceptionSet */ = {
CEE9098F2DA548C7008D568F /* Exceptions for "Autofill" folder in "Autofill" target */ = {
isa = PBXFileSystemSynchronizedBuildFileExceptionSet;
membershipExceptions = (
Info.plist,
@@ -282,13 +282,84 @@
/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */
/* Begin PBXFileSystemSynchronizedRootGroup section */
CE59C7602E4F47FD0024A246 /* AliasVaultUITests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = AliasVaultUITests; sourceTree = "<group>"; };
CE77825E2EA1822400A75E6F /* VaultUtils */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultUtils; sourceTree = "<group>"; };
CEE480882DBE86DC00F4A367 /* VaultStoreKit */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultStoreKit; sourceTree = "<group>"; };
CEE480972DBE86DD00F4A367 /* VaultStoreKitTests */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultStoreKitTests; sourceTree = "<group>"; };
CEE4816B2DBE8AC800F4A367 /* VaultUI */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultUI; sourceTree = "<group>"; };
CEE482AB2DBE8EFE00F4A367 /* VaultModels */ = {isa = PBXFileSystemSynchronizedRootGroup; explicitFileTypes = {}; explicitFolders = (); path = VaultModels; sourceTree = "<group>"; };
CEE909812DA548C7008D568F /* Autofill */ = {isa = PBXFileSystemSynchronizedRootGroup; exceptions = (CEE9098F2DA548C7008D568F /* PBXFileSystemSynchronizedBuildFileExceptionSet */, ); explicitFileTypes = {}; explicitFolders = (); path = Autofill; sourceTree = "<group>"; };
CE59C7602E4F47FD0024A246 /* AliasVaultUITests */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
explicitFileTypes = {
};
explicitFolders = (
);
path = AliasVaultUITests;
sourceTree = "<group>";
};
CE77825E2EA1822400A75E6F /* VaultUtils */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
explicitFileTypes = {
};
explicitFolders = (
);
path = VaultUtils;
sourceTree = "<group>";
};
CEE480882DBE86DC00F4A367 /* VaultStoreKit */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
explicitFileTypes = {
};
explicitFolders = (
);
path = VaultStoreKit;
sourceTree = "<group>";
};
CEE480972DBE86DD00F4A367 /* VaultStoreKitTests */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
explicitFileTypes = {
};
explicitFolders = (
);
path = VaultStoreKitTests;
sourceTree = "<group>";
};
CEE4816B2DBE8AC800F4A367 /* VaultUI */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
explicitFileTypes = {
};
explicitFolders = (
);
path = VaultUI;
sourceTree = "<group>";
};
CEE482AB2DBE8EFE00F4A367 /* VaultModels */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
);
explicitFileTypes = {
};
explicitFolders = (
);
path = VaultModels;
sourceTree = "<group>";
};
CEE909812DA548C7008D568F /* Autofill */ = {
isa = PBXFileSystemSynchronizedRootGroup;
exceptions = (
CEE9098F2DA548C7008D568F /* Exceptions for "Autofill" folder in "Autofill" target */,
);
explicitFileTypes = {
};
explicitFolders = (
);
path = Autofill;
sourceTree = "<group>";
};
/* End PBXFileSystemSynchronizedRootGroup section */
/* Begin PBXFrameworksBuildPhase section */
@@ -448,7 +519,7 @@
path = Generated;
sourceTree = "<group>";
};
6114AD0A31612EA499210371 = {
6114AD0A31612EA499210371 /* */ = {
isa = PBXGroup;
children = (
8F8258CE46969A87661E0302 /* RustCore.swift */,
@@ -484,7 +555,7 @@
832341AE1AAA6A7D00B99B32 /* Libraries */,
D65327D7A22EEC0BE12398D9 /* Pods */,
83CBBA001A601CBA00E9B192 /* Products */,
6114AD0A31612EA499210371,
6114AD0A31612EA499210371 /* */,
CE5212B62F0C061800F4C835 /* Recovered References */,
3AD00C41DD88E219A26C2E41 /* RustCoreFramework */,
);
@@ -1655,7 +1726,10 @@
"$(inherited)",
"-DRCT_REMOVE_LEGACY_ARCH=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
@@ -1718,7 +1792,10 @@
"$(inherited)",
"-DRCT_REMOVE_LEGACY_ARCH=1",
);
OTHER_LDFLAGS = "$(inherited) ";
OTHER_LDFLAGS = (
"$(inherited)",
" ",
);
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
SDKROOT = iphoneos;
SWIFT_ENABLE_EXPLICIT_MODULES = NO;

View File

@@ -2108,28 +2108,6 @@ PODS:
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- RNCMaskedView (0.3.2):
- hermes-engine
- RCTRequired
- RCTTypeSafety
- React-Core
- React-Core-prebuilt
- React-debug
- React-Fabric
- React-featureflags
- React-graphics
- React-ImageManager
- React-jsi
- React-NativeModulesApple
- React-RCTFabric
- React-renderercss
- React-rendererdebug
- React-utils
- ReactCodegen
- ReactCommon/turbomodule/bridging
- ReactCommon/turbomodule/core
- ReactNativeDependencies
- Yoga
- RNGestureHandler (2.31.2):
- hermes-engine
- RCTRequired
@@ -2509,7 +2487,6 @@ DEPENDENCIES:
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- ReactNativeDependencies (from `../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCMaskedView (from `../node_modules/@react-native-masked-view/masked-view`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
- RNReanimated (from `../node_modules/react-native-reanimated`)
- RNScreens (from `../node_modules/react-native-screens`)
@@ -2749,8 +2726,6 @@ EXTERNAL SOURCES:
:podspec: "../node_modules/react-native/third-party-podspecs/ReactNativeDependencies.podspec"
RNCAsyncStorage:
:path: "../node_modules/@react-native-async-storage/async-storage"
RNCMaskedView:
:path: "../node_modules/@react-native-masked-view/masked-view"
RNGestureHandler:
:path: "../node_modules/react-native-gesture-handler"
RNReanimated:
@@ -2793,7 +2768,7 @@ SPEC CHECKSUMS:
ExpoUI: b8da9e23eb4cef30e4797bc6de102a9178e6cd2b
ExpoWebBrowser: 6e3d90e3fe1952d21a8494872b1e1a485cd50e2f
FBLazyVector: 24e62c765683b8d89006a88a2c8f5cf019f0074d
hermes-engine: f684a01742a30bb5d7332da47aa184074d8ae9b4
hermes-engine: a384bd37273f335daf0965c0fd0aa46f197e0175
Macaw: 7af8ea57aa2cab35b4a52a45e6f85eea753ea9ae
OpenSSL-Universal: 6082b0bf950e5636fe0d78def171184e2b3899c2
RCTDeprecation: a4c521821fab57cbb125b36effe84d897d0dfa12
@@ -2804,7 +2779,7 @@ SPEC CHECKSUMS:
React: e2dc35338068bbd299c66f043ae0d7f25de8499e
React-callinvoker: 28b25d21b124c26cebaea713ba7d801b9351dc48
React-Core: 02ed7d2ffb70437bdf2aba074a13078a7b0b9ff0
React-Core-prebuilt: 43e26cf5ff020a09ab026c6f6277ad013fa0044f
React-Core-prebuilt: b87f4cdecb2229f7d0943644cef9a084d433983d
React-CoreModules: b3a5a42dadcde3b5d47b325bd912eb2ced89e146
React-cxxreact: fe8f88dda044e5905e99a00f41b7a874c3908716
React-debug: 92944dc4d89f56d640e75498266cbde557a48189
@@ -2874,9 +2849,8 @@ SPEC CHECKSUMS:
ReactAppDependencyProvider: 25c9c516839be2c5e3d3344f95dc7da5f7e63fc2
ReactCodegen: 8538eb1bd61031ede1dadd7d725ee1d42dbdceaa
ReactCommon: 7dfc3250793bf36cf221096ff59e1179e13eef7f
ReactNativeDependencies: 2c0483134df7ac059c1f1c484b4fbf6a40451fb5
ReactNativeDependencies: b8c3edb93459c2b4531665273e0e904ab3c12ba2
RNCAsyncStorage: 2ad919e88b8bc2cd80e8697ce66d04d006743283
RNCMaskedView: eb2b2e538afa907f05a5848a1a1ac26092e6fec9
RNGestureHandler: 2ff61eac036eaf89f6818bf4ed9c39771a17d134
RNReanimated: f735b1747a7a93bda7ca102c6d37a3cf54b6d5e8
RNScreens: 991cc417cd396602a6cf59a42139e5a9d91462a9

View File

@@ -32,13 +32,23 @@
</textarea>
</div>
}
else if (customField.IsHidden || customField.FieldType == FieldType.Hidden || customField.FieldType == FieldType.Password)
else if (customField.FieldType == FieldType.Password)
{
<EditPasswordFormRow
Id="@($"custom-{customField.TempId ?? customField.FieldKey}")"
Label=""
@bind-Value="customField.Value"
ShowPassword="false"/>
ShowPassword="false"
ShowGenerateButtons="true"/>
}
else if (customField.IsHidden || customField.FieldType == FieldType.Hidden)
{
<EditPasswordFormRow
Id="@($"custom-{customField.TempId ?? customField.FieldKey}")"
Label=""
@bind-Value="customField.Value"
ShowPassword="false"
ShowGenerateButtons="false"/>
}
else
{

View File

@@ -116,6 +116,7 @@
<select @bind="CustomFieldType"
class="w-full px-3 py-2 border border-gray-300 dark:border-gray-600 rounded-md shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 dark:bg-gray-700 dark:text-white">
<option value="Text">@Localizer["FieldTypeText"]</option>
<option value="Password">@Localizer["FieldTypePassword"]</option>
<option value="Hidden">@Localizer["FieldTypeHidden"]</option>
<option value="Email">@Localizer["FieldTypeEmail"]</option>
<option value="URL">@Localizer["FieldTypeUrl"]</option>

View File

@@ -113,6 +113,10 @@
<value>Text</value>
<comment>Text field type option</comment>
</data>
<data name="FieldTypePassword">
<value>Password</value>
<comment>Password field type option</comment>
</data>
<data name="FieldTypeHidden">
<value>Hidden</value>
<comment>Hidden field type option</comment>