mirror of
https://github.com/hashicorp/vault.git
synced 2025-08-06 06:37:02 +02:00
[UI] Ember Data Migration - Form Type Updates (#31011)
* updates type handling for forms * fixes validation in aws and ssh config forms * fixes issue with missing sync destination name
This commit is contained in:
parent
43c3aa37b9
commit
a6ab9bed1d
@ -56,7 +56,6 @@ export default class ConfigureWif extends Component<Args> {
|
|||||||
@service declare readonly version: VersionService;
|
@service declare readonly version: VersionService;
|
||||||
@service declare readonly flashMessages: FlashMessageService;
|
@service declare readonly flashMessages: FlashMessageService;
|
||||||
|
|
||||||
@tracked accessType = 'account'; // for community users they will not be able to change this. for enterprise users, they will have the option to select "wif".
|
|
||||||
@tracked errorMessage = '';
|
@tracked errorMessage = '';
|
||||||
@tracked invalidFormAlert = '';
|
@tracked invalidFormAlert = '';
|
||||||
@tracked saveIssuerWarning = '';
|
@tracked saveIssuerWarning = '';
|
||||||
@ -68,7 +67,7 @@ export default class ConfigureWif extends Component<Args> {
|
|||||||
constructor(owner: Owner, args: Args) {
|
constructor(owner: Owner, args: Args) {
|
||||||
super(owner, args);
|
super(owner, args);
|
||||||
// the following checks are only relevant to existing enterprise configurations
|
// the following checks are only relevant to existing enterprise configurations
|
||||||
const { isNew, isWifPluginConfigured, isAccountPluginConfigured } = this.args.configForm;
|
const { isNew, data, isWifPluginConfigured, isAccountPluginConfigured } = this.args.configForm;
|
||||||
|
|
||||||
if (this.version.isEnterprise && !isNew) {
|
if (this.version.isEnterprise && !isNew) {
|
||||||
assert(
|
assert(
|
||||||
@ -83,7 +82,7 @@ export default class ConfigureWif extends Component<Args> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// cache the issuer to check if it has been changed later
|
// cache the issuer to check if it has been changed later
|
||||||
this.originalIssuer = this.args.configForm.data['issuer'] as string | undefined;
|
this.originalIssuer = data.issuer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@action continueSubmitForm() {
|
@action continueSubmitForm() {
|
||||||
@ -105,7 +104,7 @@ export default class ConfigureWif extends Component<Args> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.originalIssuer !== data['issuer']) {
|
if (this.originalIssuer !== data.issuer) {
|
||||||
// if the issuer has changed show modal with warning that the config will change
|
// if the issuer has changed show modal with warning that the config will change
|
||||||
// if the modal is shown, the user has to click confirm to continue saving
|
// if the modal is shown, the user has to click confirm to continue saving
|
||||||
this.saveIssuerWarning = `You are updating the global issuer config. This will overwrite Vault's current issuer ${
|
this.saveIssuerWarning = `You are updating the global issuer config. This will overwrite Vault's current issuer ${
|
||||||
@ -178,19 +177,19 @@ export default class ConfigureWif extends Component<Args> {
|
|||||||
@action
|
@action
|
||||||
onChangeAccessType(accessType: 'account' | 'wif') {
|
onChangeAccessType(accessType: 'account' | 'wif') {
|
||||||
const { configForm, type } = this.args;
|
const { configForm, type } = this.args;
|
||||||
configForm['accessType'] = accessType;
|
configForm.accessType = accessType;
|
||||||
|
|
||||||
if (accessType === 'account') {
|
if (accessType === 'account') {
|
||||||
// reset all "wif" attributes that are mutually exclusive with "account" attributes
|
// reset all "wif" attributes that are mutually exclusive with "account" attributes
|
||||||
// these attributes are the same for each engine
|
// these attributes are the same for each engine
|
||||||
configForm['identityTokenAudience'] = configForm['identityTokenTtl'] = undefined;
|
configForm.data.identityTokenAudience = configForm.data.identityTokenTtl = undefined;
|
||||||
} else if (accessType === 'wif') {
|
} else if (accessType === 'wif') {
|
||||||
// reset all "account" attributes that are mutually exclusive with "wif" attributes
|
// reset all "account" attributes that are mutually exclusive with "wif" attributes
|
||||||
// these attributes are different for each engine
|
// these attributes are different for each engine
|
||||||
if (type === 'azure') {
|
if (type === 'azure') {
|
||||||
configForm['clientSecret'] = undefined;
|
(configForm as AzureConfigForm).data.clientSecret = undefined;
|
||||||
} else if (type === 'aws') {
|
} else if (type === 'aws') {
|
||||||
configForm['accessKey'] = undefined;
|
(configForm as AwsConfigForm).data.accessKey = undefined;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,7 @@ import { Validations } from 'vault/vault/app-types';
|
|||||||
|
|
||||||
type CustomMessageFormData = Partial<CreateCustomMessageRequest>;
|
type CustomMessageFormData = Partial<CreateCustomMessageRequest>;
|
||||||
|
|
||||||
export default class CustomMessageForm extends Form {
|
export default class CustomMessageForm extends Form<CustomMessageFormData> {
|
||||||
declare data: CustomMessageFormData;
|
|
||||||
|
|
||||||
formFields = [
|
formFields = [
|
||||||
new FormField('authenticated', undefined, {
|
new FormField('authenticated', undefined, {
|
||||||
label: 'Where should we display this message?',
|
label: 'Where should we display this message?',
|
||||||
|
@ -13,14 +13,13 @@ export type FormOptions = {
|
|||||||
isNew?: boolean;
|
isNew?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Form {
|
export default class Form<T extends object> {
|
||||||
[key: string]: unknown; // Add an index signature to allow dynamic property assignment for set shim
|
declare data: T;
|
||||||
declare data: Record<string, unknown>;
|
|
||||||
declare validations: Validations;
|
declare validations: Validations;
|
||||||
declare isNew: boolean;
|
declare isNew: boolean;
|
||||||
|
|
||||||
constructor(data = {}, options: FormOptions = {}, validations?: Validations) {
|
constructor(data: Partial<T> = {}, options: FormOptions = {}, validations?: Validations) {
|
||||||
this.data = { ...data };
|
this.data = { ...data } as T;
|
||||||
this.isNew = options.isNew || false;
|
this.isNew = options.isNew || false;
|
||||||
// typically this would be defined on the subclass
|
// typically this would be defined on the subclass
|
||||||
// if validations are conditional, it may be preferable to define them during instantiation
|
// if validations are conditional, it may be preferable to define them during instantiation
|
||||||
@ -31,16 +30,20 @@ export default class Form {
|
|||||||
// this allows for form field properties to be accessed directly on the class rather than form.data.someField
|
// this allows for form field properties to be accessed directly on the class rather than form.data.someField
|
||||||
const proxyTarget = (target: this, prop: string) => {
|
const proxyTarget = (target: this, prop: string) => {
|
||||||
// check if the property that is being accessed is a form field
|
// check if the property that is being accessed is a form field
|
||||||
const formFields = Array.isArray(target['formFields']) ? target['formFields'] : [];
|
const { formFields, formFieldGroups } = target as {
|
||||||
|
formFields?: FormField[];
|
||||||
|
formFieldGroups?: FormFieldGroup[];
|
||||||
|
};
|
||||||
|
const fields = Array.isArray(formFields) ? formFields : [];
|
||||||
// in the case of formFieldGroups we need extract the fields out into a flat array
|
// in the case of formFieldGroups we need extract the fields out into a flat array
|
||||||
const formGroupFields = Array.isArray(target['formFieldGroups'])
|
const groupFields = Array.isArray(formFieldGroups)
|
||||||
? target['formFieldGroups'].reduce((arr: FormField[], group: FormFieldGroup) => {
|
? formFieldGroups.reduce((arr: FormField[], group) => {
|
||||||
const values = Object.values(group)[0] || [];
|
const values = Object.values(group)[0] || [];
|
||||||
return [...arr, ...values];
|
return [...arr, ...values];
|
||||||
}, [])
|
}, [])
|
||||||
: [];
|
: [];
|
||||||
// combine the formFields and formGroupFields into a single array
|
// combine the formFields and formGroupFields into a single array
|
||||||
const allFields = [...formFields, ...formGroupFields];
|
const allFields = [...fields, ...groupFields];
|
||||||
const formDataKeys = allFields.map((field) => field.name) || [];
|
const formDataKeys = allFields.map((field) => field.name) || [];
|
||||||
// if the property is a form field return the data object as the target, otherwise return the original target (this)
|
// if the property is a form field return the data object as the target, otherwise return the original target (this)
|
||||||
// account for nested form data properties like 'config.maxLeaseTtl' when accessing the object like this.config
|
// account for nested form data properties like 'config.maxLeaseTtl' when accessing the object like this.config
|
||||||
|
@ -9,13 +9,14 @@ import FormFieldGroup from 'vault/utils/forms/field-group';
|
|||||||
import { regions } from 'vault/helpers/aws-regions';
|
import { regions } from 'vault/helpers/aws-regions';
|
||||||
|
|
||||||
import type { Validations } from 'vault/app-types';
|
import type { Validations } from 'vault/app-types';
|
||||||
|
import type { AwsConfigFormData } from 'vault/secrets/engine';
|
||||||
|
|
||||||
export default class AwsConfigForm extends WifConfigForm {
|
export default class AwsConfigForm extends WifConfigForm<AwsConfigFormData> {
|
||||||
validations: Validations = {
|
validations: Validations = {
|
||||||
lease: [
|
lease: [
|
||||||
{
|
{
|
||||||
validator(form: AwsConfigForm) {
|
validator(data: AwsConfigForm['data']) {
|
||||||
const { lease, leaseMax } = form;
|
const { lease, leaseMax } = data;
|
||||||
return (lease && leaseMax) || (!lease && !leaseMax) ? true : false;
|
return (lease && leaseMax) || (!lease && !leaseMax) ? true : false;
|
||||||
},
|
},
|
||||||
message: 'Lease TTL and Max Lease TTL are both required if one of them is set.',
|
message: 'Lease TTL and Max Lease TTL are both required if one of them is set.',
|
||||||
@ -24,7 +25,7 @@ export default class AwsConfigForm extends WifConfigForm {
|
|||||||
};
|
};
|
||||||
|
|
||||||
get isAccountPluginConfigured() {
|
get isAccountPluginConfigured() {
|
||||||
return !!this.data['accessKey'];
|
return !!this.data.accessKey;
|
||||||
}
|
}
|
||||||
|
|
||||||
get isWifPluginConfigured() {
|
get isWifPluginConfigured() {
|
||||||
|
@ -7,7 +7,9 @@ import WifConfigForm from './wif-config';
|
|||||||
import FormField from 'vault/utils/forms/field';
|
import FormField from 'vault/utils/forms/field';
|
||||||
import FormFieldGroup from 'vault/utils/forms/field-group';
|
import FormFieldGroup from 'vault/utils/forms/field-group';
|
||||||
|
|
||||||
export default class AzureConfigForm extends WifConfigForm {
|
import type { AzureConfigFormData } from 'vault/vault/secrets/engine';
|
||||||
|
|
||||||
|
export default class AzureConfigForm extends WifConfigForm<AzureConfigFormData> {
|
||||||
// the "clientSecret" param is not checked because it's never returned by the API.
|
// the "clientSecret" param is not checked because it's never returned by the API.
|
||||||
// thus we can never say for sure if the account accessType has been configured so we always return false
|
// thus we can never say for sure if the account accessType has been configured so we always return false
|
||||||
isAccountPluginConfigured = false;
|
isAccountPluginConfigured = false;
|
||||||
|
@ -13,8 +13,7 @@ import { tracked } from '@glimmer/tracking';
|
|||||||
import type { SecretsEngineFormData } from 'vault/secrets/engine';
|
import type { SecretsEngineFormData } from 'vault/secrets/engine';
|
||||||
import type { Validations } from 'vault/app-types';
|
import type { Validations } from 'vault/app-types';
|
||||||
|
|
||||||
export default class SecretsEngineForm extends Form {
|
export default class SecretsEngineForm extends Form<SecretsEngineFormData> {
|
||||||
declare data: Partial<SecretsEngineFormData>;
|
|
||||||
@tracked declare type: string;
|
@tracked declare type: string;
|
||||||
|
|
||||||
validations: Validations = {
|
validations: Validations = {
|
||||||
@ -179,6 +178,7 @@ export default class SecretsEngineForm extends Form {
|
|||||||
...this.data,
|
...this.data,
|
||||||
config: {
|
config: {
|
||||||
...(config || {}),
|
...(config || {}),
|
||||||
|
forceNoCache: config?.forceNoCache ?? false,
|
||||||
listingVisibility: config?.listingVisibility ? 'unauth' : 'hidden',
|
listingVisibility: config?.listingVisibility ? 'unauth' : 'hidden',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -7,7 +7,9 @@ import WifConfigForm from './wif-config';
|
|||||||
import FormField from 'vault/utils/forms/field';
|
import FormField from 'vault/utils/forms/field';
|
||||||
import FormFieldGroup from 'vault/utils/forms/field-group';
|
import FormFieldGroup from 'vault/utils/forms/field-group';
|
||||||
|
|
||||||
export default class AzureConfigForm extends WifConfigForm {
|
import type { GcpConfigFormData } from 'vault/secrets/engine';
|
||||||
|
|
||||||
|
export default class AzureConfigForm extends WifConfigForm<GcpConfigFormData> {
|
||||||
// the "credentials" param is not checked for "isAccountPluginConfigured" because it's never return by the API
|
// the "credentials" param is not checked for "isAccountPluginConfigured" because it's never return by the API
|
||||||
// additionally credentials can be set via GOOGLE_APPLICATION_CREDENTIALS env var so we cannot call it a required field in the ui.
|
// additionally credentials can be set via GOOGLE_APPLICATION_CREDENTIALS env var so we cannot call it a required field in the ui.
|
||||||
// thus we can never say for sure if the account accessType has been configured so we always return false
|
// thus we can never say for sure if the account accessType has been configured so we always return false
|
||||||
|
@ -9,14 +9,12 @@ import FormField from 'vault/utils/forms/field';
|
|||||||
import type { Validations } from 'vault/app-types';
|
import type { Validations } from 'vault/app-types';
|
||||||
import type { SshConfigureCaRequest } from '@hashicorp/vault-client-typescript';
|
import type { SshConfigureCaRequest } from '@hashicorp/vault-client-typescript';
|
||||||
|
|
||||||
export default class SshConfigForm extends Form {
|
export default class SshConfigForm extends Form<SshConfigureCaRequest> {
|
||||||
declare data: Partial<SshConfigureCaRequest>;
|
|
||||||
|
|
||||||
validations: Validations = {
|
validations: Validations = {
|
||||||
generateSigningKey: [
|
generateSigningKey: [
|
||||||
{
|
{
|
||||||
validator(form: SshConfigForm) {
|
validator(data: SshConfigForm['data']) {
|
||||||
const { publicKey, privateKey, generateSigningKey } = form;
|
const { publicKey, privateKey, generateSigningKey } = data;
|
||||||
// if generateSigningKey is false, both public and private keys are required
|
// if generateSigningKey is false, both public and private keys are required
|
||||||
if (!generateSigningKey && (!publicKey || !privateKey)) {
|
if (!generateSigningKey && (!publicKey || !privateKey)) {
|
||||||
return false;
|
return false;
|
||||||
@ -28,8 +26,8 @@ export default class SshConfigForm extends Form {
|
|||||||
],
|
],
|
||||||
publicKey: [
|
publicKey: [
|
||||||
{
|
{
|
||||||
validator(form: SshConfigForm) {
|
validator(data: SshConfigForm['data']) {
|
||||||
const { publicKey, privateKey } = form;
|
const { publicKey, privateKey } = data;
|
||||||
// regardless of generateSigningKey, if one key is set they both need to be set.
|
// regardless of generateSigningKey, if one key is set they both need to be set.
|
||||||
return publicKey || privateKey ? !!(publicKey && privateKey) : true;
|
return publicKey || privateKey ? !!(publicKey && privateKey) : true;
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,7 @@ import Form from 'vault/forms/form';
|
|||||||
import FormField from 'vault/utils/forms/field';
|
import FormField from 'vault/utils/forms/field';
|
||||||
import { tracked } from '@glimmer/tracking';
|
import { tracked } from '@glimmer/tracking';
|
||||||
|
|
||||||
export default class WifConfigForm extends Form {
|
export default class WifConfigForm<T extends object> extends Form<T> {
|
||||||
// for community users they will not be able to change this. for enterprise users, they will have the option to select "wif".
|
// for community users they will not be able to change this. for enterprise users, they will have the option to select "wif".
|
||||||
@tracked accessType: 'account' | 'wif' = 'account';
|
@tracked accessType: 'account' | 'wif' = 'account';
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ import { commonFields, getPayload } from './shared';
|
|||||||
|
|
||||||
import type { SystemWriteSyncDestinationsAwsSmNameRequest } from '@hashicorp/vault-client-typescript';
|
import type { SystemWriteSyncDestinationsAwsSmNameRequest } from '@hashicorp/vault-client-typescript';
|
||||||
|
|
||||||
type AwsSmFormData = Partial<SystemWriteSyncDestinationsAwsSmNameRequest>;
|
type AwsSmFormData = SystemWriteSyncDestinationsAwsSmNameRequest & {
|
||||||
|
name: string;
|
||||||
export default class AwsSmForm extends Form {
|
};
|
||||||
declare data: AwsSmFormData;
|
|
||||||
|
|
||||||
|
export default class AwsSmForm extends Form<AwsSmFormData> {
|
||||||
formFieldGroups = [
|
formFieldGroups = [
|
||||||
new FormFieldGroup('default', [
|
new FormFieldGroup('default', [
|
||||||
commonFields.name,
|
commonFields.name,
|
||||||
@ -59,6 +59,7 @@ export default class AwsSmForm extends Form {
|
|||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
const formState = super.toJSON();
|
const formState = super.toJSON();
|
||||||
return { ...formState, data: getPayload('aws-sm', this.data, this.isNew) };
|
const data = getPayload<AwsSmFormData>('aws-sm', this.data, this.isNew);
|
||||||
|
return { ...formState, data };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ import { commonFields, getPayload } from './shared';
|
|||||||
|
|
||||||
import type { SystemWriteSyncDestinationsAzureKvNameRequest } from '@hashicorp/vault-client-typescript';
|
import type { SystemWriteSyncDestinationsAzureKvNameRequest } from '@hashicorp/vault-client-typescript';
|
||||||
|
|
||||||
type AzureKvFormData = Partial<SystemWriteSyncDestinationsAzureKvNameRequest>;
|
type AzureKvFormData = SystemWriteSyncDestinationsAzureKvNameRequest & {
|
||||||
|
name: string;
|
||||||
export default class AzureKvForm extends Form {
|
};
|
||||||
declare data: AzureKvFormData;
|
|
||||||
|
|
||||||
|
export default class AzureKvForm extends Form<AzureKvFormData> {
|
||||||
formFieldGroups = [
|
formFieldGroups = [
|
||||||
new FormFieldGroup('default', [
|
new FormFieldGroup('default', [
|
||||||
commonFields.name,
|
commonFields.name,
|
||||||
@ -57,6 +57,7 @@ export default class AzureKvForm extends Form {
|
|||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
const formState = super.toJSON();
|
const formState = super.toJSON();
|
||||||
return { ...formState, data: getPayload('azure-kv', this.data, this.isNew) };
|
const data = getPayload<AzureKvFormData>('azure-kv', this.data, this.isNew);
|
||||||
|
return { ...formState, data };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ import { commonFields, getPayload } from './shared';
|
|||||||
|
|
||||||
import type { SystemWriteSyncDestinationsGcpSmNameRequest } from '@hashicorp/vault-client-typescript';
|
import type { SystemWriteSyncDestinationsGcpSmNameRequest } from '@hashicorp/vault-client-typescript';
|
||||||
|
|
||||||
type GcpSmFormData = Partial<SystemWriteSyncDestinationsGcpSmNameRequest>;
|
type GcpSmFormData = SystemWriteSyncDestinationsGcpSmNameRequest & {
|
||||||
|
name: string;
|
||||||
export default class GcpSmForm extends Form {
|
};
|
||||||
declare data: GcpSmFormData;
|
|
||||||
|
|
||||||
|
export default class GcpSmForm extends Form<GcpSmFormData> {
|
||||||
formFieldGroups = [
|
formFieldGroups = [
|
||||||
new FormFieldGroup('default', [
|
new FormFieldGroup('default', [
|
||||||
commonFields.name,
|
commonFields.name,
|
||||||
@ -42,6 +42,7 @@ export default class GcpSmForm extends Form {
|
|||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
const formState = super.toJSON();
|
const formState = super.toJSON();
|
||||||
return { ...formState, data: getPayload('gcp-sm', this.data, this.isNew) };
|
const data = getPayload<GcpSmFormData>('gcp-sm', this.data, this.isNew);
|
||||||
|
return { ...formState, data };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,11 +10,11 @@ import { commonFields, getPayload } from './shared';
|
|||||||
|
|
||||||
import type { SystemWriteSyncDestinationsGhNameRequest } from '@hashicorp/vault-client-typescript';
|
import type { SystemWriteSyncDestinationsGhNameRequest } from '@hashicorp/vault-client-typescript';
|
||||||
|
|
||||||
type GhFormData = Partial<SystemWriteSyncDestinationsGhNameRequest>;
|
type GhFormData = SystemWriteSyncDestinationsGhNameRequest & {
|
||||||
|
name: string;
|
||||||
export default class GcpSmForm extends Form {
|
};
|
||||||
declare data: GhFormData;
|
|
||||||
|
|
||||||
|
export default class GcpSmForm extends Form<GhFormData> {
|
||||||
formFieldGroups = [
|
formFieldGroups = [
|
||||||
new FormFieldGroup('default', [
|
new FormFieldGroup('default', [
|
||||||
commonFields.name,
|
commonFields.name,
|
||||||
@ -42,6 +42,7 @@ export default class GcpSmForm extends Form {
|
|||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
const formState = super.toJSON();
|
const formState = super.toJSON();
|
||||||
return { ...formState, data: getPayload('gh', this.data, this.isNew) };
|
const data = getPayload<GhFormData>('gh', this.data, this.isNew);
|
||||||
|
return { ...formState, data };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,26 +45,27 @@ export const commonFields = {
|
|||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
export function getPayload(type: DestinationType, data: Record<string, unknown>, isNew: boolean) {
|
export function getPayload<T>(type: DestinationType, data: T, isNew: boolean) {
|
||||||
const { maskedParams, readonlyParams } = findDestination(type);
|
const { maskedParams, readonlyParams } = findDestination(type);
|
||||||
const payload = { ...data };
|
const payload: T = { ...data };
|
||||||
|
|
||||||
// the server returns ****** for sensitive fields
|
// the server returns ****** for sensitive fields
|
||||||
// these are represented as maskedParams in the sync-destinations helper
|
// these are represented as maskedParams in the sync-destinations helper
|
||||||
// when editing, remove these fields from the payload if they haven't been changed
|
// when editing, remove these fields from the payload if they haven't been changed
|
||||||
if (!isNew) {
|
if (!isNew) {
|
||||||
maskedParams.forEach((maskedParam) => {
|
maskedParams.forEach((maskedParam) => {
|
||||||
const value = (payload[maskedParam] as string) || '';
|
const key = maskedParam as keyof T;
|
||||||
|
const value = (payload[key] as string) || '';
|
||||||
// if the value is asterisks, remove it from the payload
|
// if the value is asterisks, remove it from the payload
|
||||||
if (value.match(/^\*+$/)) {
|
if (value.match(/^\*+$/)) {
|
||||||
delete payload[maskedParam];
|
delete payload[key];
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// to preserve the original Ember Data payload structure, remove fields that are not editable
|
// to preserve the original Ember Data payload structure, remove fields that are not editable
|
||||||
// since editing is disabled in the form the value will not change so this is mostly to satisfy existing test conditions
|
// since editing is disabled in the form the value will not change so this is mostly to satisfy existing test conditions
|
||||||
readonlyParams.forEach((readonlyParam) => {
|
readonlyParams.forEach((readonlyParam) => {
|
||||||
delete payload[readonlyParam];
|
delete payload[readonlyParam as keyof T];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,11 +10,11 @@ import { commonFields, getPayload } from './shared';
|
|||||||
|
|
||||||
import type { SystemWriteSyncDestinationsVercelProjectNameRequest } from '@hashicorp/vault-client-typescript';
|
import type { SystemWriteSyncDestinationsVercelProjectNameRequest } from '@hashicorp/vault-client-typescript';
|
||||||
|
|
||||||
type VercelProjectFormData = Partial<SystemWriteSyncDestinationsVercelProjectNameRequest>;
|
type VercelProjectFormData = SystemWriteSyncDestinationsVercelProjectNameRequest & {
|
||||||
|
name: string;
|
||||||
export default class GcpSmForm extends Form {
|
};
|
||||||
declare data: VercelProjectFormData;
|
|
||||||
|
|
||||||
|
export default class VercelProjectForm extends Form<VercelProjectFormData> {
|
||||||
formFieldGroups = [
|
formFieldGroups = [
|
||||||
new FormFieldGroup('default', [
|
new FormFieldGroup('default', [
|
||||||
commonFields.name,
|
commonFields.name,
|
||||||
@ -45,6 +45,7 @@ export default class GcpSmForm extends Form {
|
|||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
const formState = super.toJSON();
|
const formState = super.toJSON();
|
||||||
return { ...formState, data: getPayload('vercel-project', this.data, this.isNew) };
|
const data = getPayload<VercelProjectFormData>('vercel-project', this.data, this.isNew);
|
||||||
|
return { ...formState, data };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ export default class VaultClusterSettingsMountSecretBackendRoute extends Route {
|
|||||||
kvConfig: {
|
kvConfig: {
|
||||||
maxVersions: 0,
|
maxVersions: 0,
|
||||||
casRequired: false,
|
casRequired: false,
|
||||||
deleteVersionAfter: 0,
|
deleteVersionAfter: undefined,
|
||||||
},
|
},
|
||||||
options: { version: 2 },
|
options: { version: 2 },
|
||||||
};
|
};
|
||||||
|
@ -39,15 +39,17 @@ export default class DestinationsCreateForm extends Component<Args> {
|
|||||||
super(owner, args);
|
super(owner, args);
|
||||||
// cache initial custom tags value to compare against updates
|
// cache initial custom tags value to compare against updates
|
||||||
// tags that are removed when editing need to be added to the payload
|
// tags that are removed when editing need to be added to the payload
|
||||||
if (args.form['customTags']) {
|
// cast type here since not all types have customTags
|
||||||
this.initialCustomTags = { ...args.form['customTags'] };
|
const { customTags } = args.form.data as unknown as Record<string, unknown>;
|
||||||
|
if (customTags) {
|
||||||
|
this.initialCustomTags = { ...customTags };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get header() {
|
get header() {
|
||||||
const { type, form } = this.args;
|
const { type, form } = this.args;
|
||||||
const { name: typeDisplayName } = findDestination(type);
|
const { name: typeDisplayName } = findDestination(type);
|
||||||
const { name } = form;
|
const { name } = form.data;
|
||||||
|
|
||||||
return form.isNew
|
return form.isNew
|
||||||
? {
|
? {
|
||||||
@ -87,18 +89,18 @@ export default class DestinationsCreateForm extends Component<Args> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
diffCustomTags(customTags?: Record<string, string>) {
|
diffCustomTags(payload: Record<string, unknown>) {
|
||||||
// if tags were removed we need to add them to the payload
|
// if tags were removed we need to add them to the payload
|
||||||
const { form } = this.args;
|
const { isNew } = this.args.form;
|
||||||
if (!form.isNew && customTags && this.initialCustomTags) {
|
const { customTags } = payload;
|
||||||
|
if (!isNew && customTags && this.initialCustomTags) {
|
||||||
// compare the new and old keys of customTags object to determine which need to be removed
|
// compare the new and old keys of customTags object to determine which need to be removed
|
||||||
const oldKeys = Object.keys(this.initialCustomTags).filter((k) => !Object.keys(customTags).includes(k));
|
const oldKeys = Object.keys(this.initialCustomTags).filter((k) => !Object.keys(customTags).includes(k));
|
||||||
// add tagsToRemove to the payload if there is a diff
|
// add tagsToRemove to the payload if there is a diff
|
||||||
if (oldKeys.length > 0) {
|
if (oldKeys.length > 0) {
|
||||||
return { tagsToRemove: oldKeys };
|
payload['tagsToRemove'] = oldKeys;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
save = task(
|
save = task(
|
||||||
@ -109,21 +111,18 @@ export default class DestinationsCreateForm extends Component<Args> {
|
|||||||
this.modelValidations = null;
|
this.modelValidations = null;
|
||||||
|
|
||||||
const { form, type } = this.args;
|
const { form, type } = this.args;
|
||||||
|
const { name } = form.data;
|
||||||
const { isValid, state, invalidFormMessage, data } = form.toJSON();
|
const { isValid, state, invalidFormMessage, data } = form.toJSON();
|
||||||
const name = form['name'] as string;
|
|
||||||
|
|
||||||
this.modelValidations = isValid ? null : state;
|
this.modelValidations = isValid ? null : state;
|
||||||
this.invalidFormMessage = isValid ? '' : invalidFormMessage;
|
this.invalidFormMessage = isValid ? '' : invalidFormMessage;
|
||||||
|
|
||||||
if (isValid) {
|
if (isValid) {
|
||||||
try {
|
try {
|
||||||
const { tagsToRemove } = this.diffCustomTags(data['customTags'] as Record<string, string>);
|
const payload = data as unknown as Record<string, unknown>;
|
||||||
if (tagsToRemove) {
|
this.diffCustomTags(payload);
|
||||||
data['tagsToRemove'] = tagsToRemove;
|
const method = apiMethodResolver(form.isNew ? 'write' : 'patch', type);
|
||||||
}
|
await this.api.sys[method](name, payload);
|
||||||
|
|
||||||
const method = apiMethodResolver(form.isNew ? 'write' : 'patch', this.args.type);
|
|
||||||
await this.api.sys[method](name, data);
|
|
||||||
|
|
||||||
this.router.transitionTo('vault.cluster.sync.secrets.destinations.destination.details', type, name);
|
this.router.transitionTo('vault.cluster.sync.secrets.destinations.destination.details', type, name);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
24
ui/types/vault/secrets/engine.d.ts
vendored
24
ui/types/vault/secrets/engine.d.ts
vendored
@ -3,13 +3,19 @@
|
|||||||
* SPDX-License-Identifier: BUSL-1.1
|
* SPDX-License-Identifier: BUSL-1.1
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { MountsEnableSecretsEngineRequest } from '@hashicorp/vault-client-typescript';
|
import type {
|
||||||
|
MountsEnableSecretsEngineRequest,
|
||||||
|
AwsConfigureRootIamCredentialsRequest,
|
||||||
|
AwsConfigureLeaseRequest,
|
||||||
|
AzureConfigureRequest,
|
||||||
|
GoogleCloudConfigureRequest,
|
||||||
|
} from '@hashicorp/vault-client-typescript';
|
||||||
|
|
||||||
export type EngineConfig = {
|
export type EngineConfig = {
|
||||||
forceNoCache: boolean;
|
forceNoCache?: boolean;
|
||||||
listingVisibility: string;
|
listingVisibility?: string | boolean;
|
||||||
defaultLeaseTtl: number;
|
defaultLeaseTtl?: number;
|
||||||
maxLeaseTtl: number;
|
maxLeaseTtl?: number;
|
||||||
allowedManagedKeys?: string[];
|
allowedManagedKeys?: string[];
|
||||||
auditNonHmacRequestKeys?: string[];
|
auditNonHmacRequestKeys?: string[];
|
||||||
auditNonHmacResponseKeys?: string[];
|
auditNonHmacResponseKeys?: string[];
|
||||||
@ -91,3 +97,11 @@ export type SecretsEngineFormData = MountsEnableSecretsEngineRequest & {
|
|||||||
deleteVersionAfter?: string;
|
deleteVersionAfter?: string;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Issuer = {
|
||||||
|
issuer?: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type AwsConfigFormData = AwsConfigureRootIamCredentialsRequest & AwsConfigureLeaseRequest & Issuer;
|
||||||
|
export type AzureConfigFormData = AzureConfigureRequest & Issuer;
|
||||||
|
export type GcpConfigFormData = GoogleCloudConfigureRequest & Issuer;
|
||||||
|
Loading…
Reference in New Issue
Block a user