Tweak removable section UI in web app (#1404)

This commit is contained in:
Leendert de Borst
2025-12-21 15:44:46 +01:00
parent 74b37f137b
commit 254901cfcf
5 changed files with 318 additions and 71 deletions

View File

@@ -30,7 +30,7 @@ import { useVaultMutate } from '@/entrypoints/popup/hooks/useVaultMutate';
import { SKIP_FORM_RESTORE_KEY } from '@/utils/Constants';
import type { Item, ItemField, ItemType, FieldType, Attachment, TotpCode } from '@/utils/dist/core/models/vault';
import { FieldCategories, FieldTypes, ItemTypes, getSystemFieldsForItemType, getOptionalFieldsForItemType, isFieldShownByDefault } from '@/utils/dist/core/models/vault';
import { FieldCategories, FieldTypes, ItemTypes, getSystemFieldsForItemType, getOptionalFieldsForItemType, isFieldShownByDefault, getSystemField, fieldAppliesToType } from '@/utils/dist/core/models/vault';
import { FaviconService } from '@/utils/FaviconService';
import { browser } from '#imports';
@@ -758,26 +758,58 @@ const ItemAddEdit: React.FC = () => {
/**
* Handle item type change from dropdown.
* Clears field values that don't apply to the new item type.
*/
const handleTypeChange = useCallback((newType: ItemType) => {
if (!item) {
return;
}
// When switching FROM Alias type to another type, clear alias and login fields (except URL)
if (!isEditMode && item.ItemType === ItemTypes.Alias && newType !== ItemTypes.Alias) {
const oldType = item.ItemType;
// Clear field values that don't apply to the new type
if (!isEditMode && oldType !== newType) {
setFieldValues(prev => {
const newValues: Record<string, string | string[]> = {};
// Only preserve non-alias and non-login fields, plus login.url
Object.entries(prev).forEach(([key, value]) => {
if (key === 'login.url') {
newValues[key] = value;
} else if (!key.startsWith('alias.') && !key.startsWith('login.')) {
// Check if this field applies to the new type
const systemField = getSystemField(key);
if (systemField) {
// Keep the field only if it applies to the new type
if (fieldAppliesToType(systemField, newType)) {
newValues[key] = value;
}
} else {
// Custom fields are always kept
newValues[key] = value;
}
});
return newValues;
});
// Clear manually added fields that don't apply to new type
setManuallyAddedFields(prev => {
const newSet = new Set<string>();
prev.forEach(fieldKey => {
const systemField = getSystemField(fieldKey);
if (!systemField || fieldAppliesToType(systemField, newType)) {
newSet.add(fieldKey);
}
});
return newSet;
});
// Clear initially visible fields that don't apply to new type
setInitiallyVisibleFields(prev => {
const newSet = new Set<string>();
prev.forEach(fieldKey => {
const systemField = getSystemField(fieldKey);
if (!systemField || fieldAppliesToType(systemField, newType)) {
newSet.add(fieldKey);
}
});
return newSet;
});
}
// Reset alias generated flag, so alias fields will be filled (again) if they are shown by the new type

View File

@@ -7,7 +7,7 @@
<input type="@(_internalShowPassword ? "text" : "password")" id="@Id" autocomplete="off" class="outline-0 shadow-sm bg-gray-50 border border-gray-300 text-gray-900 sm:text-sm rounded-l-lg block w-full p-2.5 pr-16 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white" value="@Value" @oninput="OnInputChanged" placeholder="@Placeholder">
</div>
<div class="flex">
<button type="button" class="px-3 text-gray-500 dark:text-white bg-gray-200 hover:bg-gray-300 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium text-sm dark:bg-gray-600 dark:hover:bg-gray-700 dark:focus:ring-gray-800" @onclick="TogglePasswordVisibility">
<button type="button" class="@GetVisibilityButtonClasses()" @onclick="TogglePasswordVisibility">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
@if (_internalShowPassword)
{
@@ -20,17 +20,20 @@
}
</svg>
</button>
<button type="button" class="px-3 text-gray-500 dark:text-white bg-gray-200 hover:bg-gray-300 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium text-sm border-l border-gray-300 dark:border-gray-700 dark:bg-gray-600 dark:hover:bg-gray-700 dark:focus:ring-gray-800" @onclick="ShowPasswordSettings">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
</button>
<button type="button" class="px-3 text-gray-500 dark:text-white bg-gray-200 hover:bg-gray-300 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium rounded-r-lg text-sm border-l border-gray-300 dark:border-gray-700 dark:bg-gray-600 dark:hover:bg-gray-700 dark:focus:ring-gray-800" @onclick="GeneratePassword">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
</svg>
</button>
@if (ShowGenerateButtons)
{
<button type="button" class="px-3 text-gray-500 dark:text-white bg-gray-200 hover:bg-gray-300 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium text-sm border-l border-gray-300 dark:border-gray-700 dark:bg-gray-600 dark:hover:bg-gray-700 dark:focus:ring-gray-800" @onclick="ShowPasswordSettings">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z"></path>
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z"></path>
</svg>
</button>
<button type="button" class="px-3 text-gray-500 dark:text-white bg-gray-200 hover:bg-gray-300 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium rounded-r-lg text-sm border-l border-gray-300 dark:border-gray-700 dark:bg-gray-600 dark:hover:bg-gray-700 dark:focus:ring-gray-800" @onclick="GeneratePassword">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
</svg>
</button>
}
</div>
</div>
@@ -80,6 +83,13 @@
[Parameter]
public bool ShowPassword { get; set; } = false;
/// <summary>
/// Controls whether the generate and settings buttons are shown.
/// Set to false for fields like CVV or card number that shouldn't be generated.
/// </summary>
[Parameter]
public bool ShowGenerateButtons { get; set; } = true;
/// <summary>
/// Whether the password settings popup is visible.
/// </summary>
@@ -120,6 +130,16 @@
}
}
/// <summary>
/// Gets the CSS classes for the visibility toggle button.
/// When generate buttons are hidden, this button needs rounded-r-lg to be the last button.
/// </summary>
private string GetVisibilityButtonClasses()
{
var baseClasses = "px-3 text-gray-500 dark:text-white bg-gray-200 hover:bg-gray-300 focus:ring-4 focus:outline-none focus:ring-gray-300 font-medium text-sm dark:bg-gray-600 dark:hover:bg-gray-700 dark:focus:ring-gray-800";
return ShowGenerateButtons ? baseClasses : $"{baseClasses} rounded-r-lg";
}
/// <summary>
/// Toggles the password plain text visibility.
/// </summary>

View File

@@ -0,0 +1,55 @@
@using Microsoft.Extensions.Localization
@inject IStringLocalizerFactory LocalizerFactory
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800 relative">
@if (!string.IsNullOrEmpty(Title))
{
<h3 class="mb-4 text-xl font-semibold dark:text-white">@Title</h3>
}
<div class="grid gap-6">
@ChildContent
</div>
@if (CanRemove)
{
<button type="button" @onclick="HandleRemove" @onclick:preventDefault="true"
class="absolute top-3 right-3 text-gray-400 hover:text-red-500 transition-colors" title="@SharedLocalizer["Delete"]">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
}
</div>
@code {
private IStringLocalizer SharedLocalizer => LocalizerFactory.Create("SharedResources", "AliasVault.Client");
/// <summary>
/// Gets or sets the section title.
/// </summary>
[Parameter]
public string Title { get; set; } = string.Empty;
/// <summary>
/// Gets or sets whether the section can be removed.
/// </summary>
[Parameter]
public bool CanRemove { get; set; }
/// <summary>
/// Gets or sets the child content to render inside the section.
/// </summary>
[Parameter]
public RenderFragment? ChildContent { get; set; }
/// <summary>
/// Gets or sets the callback when the remove button is clicked.
/// </summary>
[Parameter]
public EventCallback OnRemove { get; set; }
private async Task HandleRemove()
{
await OnRemove.InvokeAsync();
}
}

View File

@@ -6,7 +6,7 @@
@using TotpGenerator
@using Microsoft.Extensions.Localization
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800 relative">
<div class="flex justify-between">
<div>
<h3 class="mb-4 text-xl font-semibold dark:text-white">@Localizer["TwoFactorAuthenticationTitle"]</h3>
@@ -20,6 +20,15 @@
</div>
}
</div>
@if (CanRemove)
{
<button type="button" @onclick="HandleRemove" @onclick:preventDefault="true"
class="absolute top-3 right-3 text-gray-400 hover:text-red-500 transition-colors" title="@Localizer["Delete"]">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
}
@if ((TotpCodeList.Count == 0 || TotpCodeList.All(t => t.IsDeleted)) && !IsAddFormVisible)
{
@@ -105,6 +114,18 @@
[Parameter]
public EventCallback<List<TotpCode>> TotpCodesChanged { get; set; }
/// <summary>
/// Gets or sets whether the section can be removed.
/// </summary>
[Parameter]
public bool CanRemove { get; set; }
/// <summary>
/// Gets or sets the callback when the remove button is clicked.
/// </summary>
[Parameter]
public EventCallback OnRemove { get; set; }
private bool IsAddFormVisible { get; set; } = false;
private TotpCodeEdit NewTotpCode { get; set; } = new();
private List<Guid> OriginalTotpCodeIds { get; set; } = [];
@@ -206,4 +227,12 @@
await TotpCodesChanged.InvokeAsync(TotpCodeList);
StateHasChanged();
}
/// <summary>
/// Handles the remove section button click.
/// </summary>
private async Task HandleRemove()
{
await OnRemove.InvokeAsync();
}
}

View File

@@ -6,6 +6,7 @@
@inject AliasVault.Client.Services.QuickCreateStateService QuickCreateStateService
@using AliasVault.Client.Services.JsInterop.Models
@using AliasVault.Client.Main.Components.Items
@using AliasVault.Client.Main.Components.Forms
@using Microsoft.Extensions.Localization
@using AliasClientDb
@using AliasClientDb.Models
@@ -65,7 +66,7 @@ else
@if (Show2FA && HasLoginFields())
{
<div class="col-span-1 md:col-span-1 lg:col-span-1">
<TotpCodes TotpCodeList="@Obj.TotpCodes" TotpCodesChanged="HandleTotpCodesChanged" />
<TotpCodes TotpCodeList="@Obj.TotpCodes" TotpCodesChanged="HandleTotpCodesChanged" CanRemove="@CanRemove2FASection()" OnRemove="Remove2FASection" />
</div>
}
@@ -73,22 +74,11 @@ else
@if (ShouldShowField(FieldKey.NotesContent))
{
<div class="col-span-1 md:col-span-1 lg:col-span-1">
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800 relative">
<div class="grid gap-6">
<div class="col-span-6 sm:col-span-3">
<EditFormRow Type="textarea" Id="notes" Label="@Localizer["NotesLabel"]" LabelStyle="EditFormRow.FormLabelStyle.Header" @bind-Value="Obj.Notes"></EditFormRow>
</div>
<RemovableSection CanRemove="@CanRemoveField(FieldKey.NotesContent)" OnRemove="() => RemoveOptionalField(FieldKey.NotesContent)">
<div class="col-span-6 sm:col-span-3">
<EditFormRow Type="textarea" Id="notes" Label="@Localizer["NotesLabel"]" LabelStyle="EditFormRow.FormLabelStyle.Header" @bind-Value="Obj.Notes"></EditFormRow>
</div>
@if (CanRemoveField(FieldKey.NotesContent))
{
<button type="button" @onclick="() => RemoveOptionalField(FieldKey.NotesContent)" @onclick:preventDefault="true"
class="absolute top-3 right-3 text-gray-400 hover:text-red-500 transition-colors" title="@Localizer["RemoveField"]">
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
}
</div>
</RemovableSection>
</div>
}
@@ -96,16 +86,13 @@ else
@if (ShowAttachments)
{
<div class="col-span-1 md:col-span-1 lg:col-span-1">
<div class="p-4 mb-4 bg-white border border-gray-200 rounded-lg shadow-sm 2xl:col-span-2 dark:border-gray-700 sm:p-6 dark:bg-gray-800">
<h3 class="mb-4 text-xl font-semibold dark:text-white">@Localizer["AttachmentsSectionHeader"]</h3>
<div class="grid gap-6">
<div class="col-span-6 sm:col-span-3">
<AttachmentUploader
Attachments="@Obj.Attachments"
AttachmentsChanged="@HandleAttachmentsChanged" />
</div>
<RemovableSection Title="@Localizer["AttachmentsSectionHeader"]" CanRemove="@CanRemoveAttachmentsSection()" OnRemove="RemoveAttachmentsSection">
<div class="col-span-6 sm:col-span-3">
<AttachmentUploader
Attachments="@Obj.Attachments"
AttachmentsChanged="@HandleAttachmentsChanged" />
</div>
</div>
</RemovableSection>
</div>
}
</div>
@@ -300,7 +287,7 @@ else
<EditFormRow Id="cardholder-name" Label="@Localizer["CardholderNameLabel"]" @bind-Value="Obj.CardCardholderName"></EditFormRow>
</div>
<div class="col-span-6">
<EditPasswordFormRow Id="card-number" Label="@Localizer["CardNumberLabel"]" @bind-Value="Obj.CardNumber" ShowPassword="false"></EditPasswordFormRow>
<EditPasswordFormRow Id="card-number" Label="@Localizer["CardNumberLabel"]" @bind-Value="Obj.CardNumber" ShowPassword="false" ShowGenerateButtons="false"></EditPasswordFormRow>
</div>
<div class="col-span-3">
<EditFormRow Id="expiry-month" Label="@Localizer["ExpiryMonthLabel"]" Placeholder="MM" @bind-Value="Obj.CardExpiryMonth"></EditFormRow>
@@ -309,7 +296,7 @@ else
<EditFormRow Id="expiry-year" Label="@Localizer["ExpiryYearLabel"]" Placeholder="YYYY" @bind-Value="Obj.CardExpiryYear"></EditFormRow>
</div>
<div class="col-span-6 sm:col-span-3">
<EditPasswordFormRow Id="card-cvv" Label="@Localizer["CardCvvLabel"]" @bind-Value="Obj.CardCvv" ShowPassword="false"></EditPasswordFormRow>
<EditPasswordFormRow Id="card-cvv" Label="@Localizer["CardCvvLabel"]" @bind-Value="Obj.CardCvv" ShowPassword="false" ShowGenerateButtons="false"></EditPasswordFormRow>
</div>
@if (ShouldShowField(FieldKey.CardPin))
{
@@ -379,8 +366,8 @@ else
HasLoginFields="@HasLoginFields()"
OnAddSystemField="AddOptionalField"
OnAddCustomField="AddCustomField"
OnAdd2FA="() => Show2FA = true"
OnAddAttachments="() => ShowAttachments = true" />
OnAdd2FA="Add2FASection"
OnAddAttachments="AddAttachmentsSection" />
</div>
</div>
</div>
@@ -405,6 +392,8 @@ else
private bool ShowTypeDropdown { get; set; } = false;
private bool Show2FA { get; set; } = false;
private bool ShowAttachments { get; set; } = false;
private bool Show2FAAddedManually { get; set; } = false;
private bool ShowAttachmentsAddedManually { get; set; } = false;
private ItemEdit Obj { get; set; } = new();
private IJSObjectReference? Module;
@@ -560,12 +549,20 @@ else
}
/// <summary>
/// Determines if a field can be removed (was manually added).
/// Determines if a field can be removed (is an optional field).
/// </summary>
private bool CanRemoveField(string fieldKey)
{
// A field can be removed if it was manually added via the + menu
return ManuallyAddedFields.Contains(fieldKey);
// A field can be removed if it's an optional field for the current item type
var fieldDef = SystemFieldRegistry.GetSystemField(fieldKey);
if (fieldDef == null)
{
return false;
}
// Check if it's an optional field (not shown by default)
var config = fieldDef.ApplicableToTypes.GetValueOrDefault(Obj.ItemType);
return config != null && !config.ShowByDefault;
}
/// <summary>
@@ -604,15 +601,128 @@ else
}
/// <summary>
/// Removes an optional field.
/// Removes an optional field (hides it and clears the value).
/// </summary>
private void RemoveOptionalField(string fieldKey)
{
ManuallyAddedFields.Remove(fieldKey);
InitiallyVisibleFields.Remove(fieldKey);
Obj.SetFieldValue(fieldKey, string.Empty);
StateHasChanged();
}
/// <summary>
/// Adds the 2FA section.
/// </summary>
private void Add2FASection()
{
Show2FA = true;
Show2FAAddedManually = true;
// Restore any soft-deleted TOTP codes (undo previous removal)
foreach (var totpCode in Obj.TotpCodes)
{
if (totpCode.IsDeleted)
{
totpCode.IsDeleted = false;
totpCode.UpdatedAt = DateTime.UtcNow;
}
}
StateHasChanged();
}
/// <summary>
/// Removes the 2FA section and marks existing TOTP codes for deletion.
/// </summary>
private void Remove2FASection()
{
Show2FA = false;
Show2FAAddedManually = false;
// Mark all TOTP codes for deletion (soft delete for existing, remove new ones)
foreach (var totpCode in Obj.TotpCodes.ToList())
{
if (totpCode.Id != Guid.Empty)
{
// Existing code - mark for soft delete
totpCode.IsDeleted = true;
totpCode.UpdatedAt = DateTime.UtcNow;
}
else
{
// New code - just remove from list
Obj.TotpCodes.Remove(totpCode);
}
}
StateHasChanged();
}
/// <summary>
/// Checks if the 2FA section can be removed (always true when visible).
/// </summary>
private bool CanRemove2FASection()
{
return true;
}
/// <summary>
/// Adds the attachments section.
/// </summary>
private void AddAttachmentsSection()
{
ShowAttachments = true;
ShowAttachmentsAddedManually = true;
// Restore any soft-deleted attachments (undo previous removal)
foreach (var attachment in Obj.Attachments)
{
if (attachment.IsDeleted)
{
attachment.IsDeleted = false;
attachment.UpdatedAt = DateTime.UtcNow;
}
}
StateHasChanged();
}
/// <summary>
/// Removes the attachments section and marks existing attachments for deletion.
/// </summary>
private void RemoveAttachmentsSection()
{
ShowAttachments = false;
ShowAttachmentsAddedManually = false;
// Mark all attachments for deletion (soft delete for existing, remove new ones)
foreach (var attachment in Obj.Attachments.ToList())
{
if (attachment.Id != Guid.Empty)
{
// Existing attachment - mark for soft delete
attachment.IsDeleted = true;
attachment.UpdatedAt = DateTime.UtcNow;
}
else
{
// New attachment - just remove from list
Obj.Attachments.Remove(attachment);
}
}
StateHasChanged();
}
/// <summary>
/// Checks if the attachments section can be removed (always true when visible).
/// </summary>
private bool CanRemoveAttachmentsSection()
{
return true;
}
/// <summary>
/// Adds a custom field.
/// </summary>
@@ -652,6 +762,7 @@ else
/// <summary>
/// Handles item type change.
/// Clears field values that don't apply to the new item type.
/// </summary>
private async Task HandleItemTypeChange(string newType)
{
@@ -663,25 +774,13 @@ else
var oldType = Obj.ItemType;
Obj.ItemType = newType;
// Clear fields that don't apply to the new type
if (oldType == ItemTypes.Alias && newType != ItemTypes.Alias)
// Clear all system fields that don't apply to the new type
foreach (var fieldDef in SystemFieldRegistry.Fields.Values)
{
// Clear alias fields when switching away from Alias
Obj.AliasFirstName = string.Empty;
Obj.AliasLastName = string.Empty;
Obj.AliasGender = string.Empty;
Obj.AliasBirthDate = string.Empty;
}
if (oldType == ItemTypes.CreditCard && newType != ItemTypes.CreditCard)
{
// Clear card fields when switching away from CreditCard
Obj.CardNumber = string.Empty;
Obj.CardCardholderName = string.Empty;
Obj.CardExpiryMonth = string.Empty;
Obj.CardExpiryYear = string.Empty;
Obj.CardCvv = string.Empty;
Obj.CardPin = string.Empty;
if (!SystemFieldRegistry.FieldAppliesToType(fieldDef, newType))
{
Obj.SetFieldValue(fieldDef.FieldKey, string.Empty);
}
}
// Clear manually added fields that don't apply to new type
@@ -696,6 +795,18 @@ else
ManuallyAddedFields.Remove(fk);
}
// Clear initially visible fields that don't apply to new type
var initialFieldsToRemove = InitiallyVisibleFields
.Where(fk => {
var def = SystemFieldRegistry.GetSystemField(fk);
return def != null && !SystemFieldRegistry.FieldAppliesToType(def, newType);
})
.ToList();
foreach (var fk in initialFieldsToRemove)
{
InitiallyVisibleFields.Remove(fk);
}
// Generate alias for Alias type in create mode
if (newType == ItemTypes.Alias && !EditMode && !HasAliasValues())
{