Make encrypted fields editable (#5008)

* fix: data sources update

* fix: default state for custom s3 url

* refactor: move state to parent

* make encrypted fields default enabled for new datasources

* show edit toggle only while editing datasource

* chore: change toggle placement

* chore: replace edit toggle with button

* fix: password reset
This commit is contained in:
vjaris42 2022-12-21 12:33:12 +05:30 committed by GitHub
parent 68393cecb2
commit 307f869ff9
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 87 additions and 15 deletions

View file

@ -27,6 +27,8 @@ const DynamicForm = ({
optionsChanged,
queryName,
}) => {
const [computedProps, setComputedProps] = React.useState({});
// if(schema.properties) todo add empty check
React.useLayoutEffect(() => {
if (!isEditMode || isEmpty(options)) {
@ -35,6 +37,34 @@ const DynamicForm = ({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
React.useEffect(() => {
const { properties } = schema;
if (isEmpty(properties)) return null;
let fields = {};
let encrpytedFieldsProps = {};
const flipComponentDropdown = find(properties, ['type', 'dropdown-component-flip']);
if (flipComponentDropdown) {
const selector = options?.[flipComponentDropdown?.key]?.value;
fields = { ...flipComponentDropdown?.commonFields, ...properties[selector] };
} else {
fields = { ...properties };
}
Object.keys(fields).map((key) => {
const { type, encrypted } = fields[key];
if ((type === 'password' || encrypted) && !(key in computedProps)) {
//Editable encrypted fields only if datasource doesn't exists
encrpytedFieldsProps[key] = {
disabled: !!selectedDataSource?.id,
};
}
});
setComputedProps({ ...computedProps, ...encrpytedFieldsProps });
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [options]);
const getElement = (type) => {
switch (type) {
case 'password':
@ -97,7 +127,7 @@ const DynamicForm = ({
case 'textarea':
return {
type,
placeholder: description,
placeholder: options?.[key]?.encrypted ? '**************' : description,
className: `form-control${handleToggle(controller)}`,
value: options?.[key]?.value,
...(type === 'textarea' && { rows: rows }),
@ -207,6 +237,26 @@ const DynamicForm = ({
return flipComponentDropdown;
}
const handleEncryptedFieldsToggle = (event, field) => {
const isEditing = computedProps[field]['disabled'];
setComputedProps({
...computedProps,
[field]: {
...computedProps[field],
disabled: !isEditing,
},
});
if (isEditing) {
optionchanged(field, '');
} else {
//Send old field value if editing mode disabled for encrypted fields
const newOptions = { ...options };
const oldFieldValue = selectedDataSource?.['options']?.[field];
optionsChanged({ ...newOptions, [field]: oldFieldValue });
}
};
return (
<div className="row">
{Object.keys(obj).map((key) => {
@ -216,14 +266,30 @@ const DynamicForm = ({
return (
<div className={cx('my-2', { 'col-md-12': !className, [className]: !!className })} key={key}>
{label && (
<label
className="form-label"
data-cy={`label-${String(label).toLocaleLowerCase().replace(/\s+/g, '-')}`}
>
{label}
{(type === 'password' || encrypted) && (
<small className="text-green mx-2">
<div className="d-flex align-items-center">
{label && (
<label
className="form-label"
data-cy={`label-${String(label).toLocaleLowerCase().replace(/\s+/g, '-')}`}
>
{label}
</label>
)}
{(type === 'password' || encrypted) && selectedDataSource?.id && (
<div className="mx-1 col">
<button
className="btn btn-sm font-500 color-primary border-1 mb-2 mx-2"
target="_blank"
rel="noreferrer"
onClick={(event) => handleEncryptedFieldsToggle(event, key)}
>
{computedProps?.[key]?.['disabled'] ? 'Edit' : 'Cancel'}
</button>
</div>
)}
{(type === 'password' || encrypted) && (
<div className="col-auto mb-2">
<small className="text-green">
<img
className="mx-2 encrypted-icon"
src="assets/images/icons/padlock.svg"
@ -232,11 +298,12 @@ const DynamicForm = ({
/>
Encrypted
</small>
)}
</label>
)}
</div>
)}
</div>
<Element
{...getElementProps(obj[key])}
{...computedProps[key]}
data-cy={`${String(label).toLocaleLowerCase().replace(/\s+/g, '-')}-text-field`}
/>
</div>

View file

@ -1,7 +1,7 @@
import React from 'react';
export default ({ defaultChecked, onChange, checked = false }) => {
export default ({ defaultChecked, onChange, checked = false, classes = {} }) => {
return (
<label className="form-switch">
<label className={`form-switch ${classes?.wrapper}`}>
<input
className="form-check-input"
checked={checked}

View file

@ -119,7 +119,12 @@ export class DataSourcesService {
const sourceOptions = {};
for (const key of Object.keys(options)) {
sourceOptions[key] = options[key]['value'];
const credentialId = options[key]?.['credential_id'];
if (credentialId) {
sourceOptions[key] = await this.credentialsService.getValue(credentialId);
} else {
sourceOptions[key] = options[key]['value'];
}
}
const service = await this.pluginsHelper.getService(plugin_id, kind);