fix: secret saved indicator on ui for datasource forms (#18531)
## Description Secret saved indicator on ui exists if the datasource field has a `valueExistPath` and server sends back the boolean value for the specific field in `secretExists` key. The UI would appear as follows : #### When the password is saved and there exists a key `valueExistPath` for `Password` field and the value in `secretExists` is true then - When password field is not focused. An overlay indicating the password shows up. <img width="575" alt="Screenshot 2022-11-28 at 8 58 44 PM" src="https://user-images.githubusercontent.com/7565635/204317024-be22127b-adf4-4914-9180-804ebe6b482a.png"> - When the password field is focused. The overlay goes away. <img width="588" alt="Screenshot 2022-11-28 at 8 58 51 PM" src="https://user-images.githubusercontent.com/7565635/204317400-9d601230-5493-40c0-ac66-21112d0d98ca.png"> TL;DR Fixes #14783 Media [Loom Video of 4 sec](https://www.loom.com/share/ba30b9674d754bf4a0c2704eef69008d) ## Type of change - New feature (non-breaking change which adds functionality) ## How Has This Been Tested? - Manual ### Test Plan > Add Testsmith test cases links that relate to this PR ### Issues raised during DP testing > Link issues raised during DP testing for better visiblity and tracking (copy link from comments dropped on this PR) ## Checklist: ### Dev activity - [ ] My code follows the style guidelines of this project - [ ] I have performed a self-review of my own code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] PR is being merged under a feature flag ### QA activity: - [ ] Test plan has been approved by relevant developers - [ ] Test plan has been peer reviewed by QA - [ ] Cypress test cases have been added and approved by either SDET or manual QA - [ ] Organized project review call with relevant stakeholders after Round 1/2 of QA - [ ] Added Test Plan Approved label after reveiwing all Cypress test Co-authored-by: “sneha122” <“sneha@appsmith.com”>
This commit is contained in:
parent
645e35a8e1
commit
276e1e6c4b
|
|
@ -83,6 +83,7 @@ export interface ControlData {
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
staticDependencyPathList?: string[];
|
staticDependencyPathList?: string[];
|
||||||
validator?: (value: string) => { isValid: boolean; message: string };
|
validator?: (value: string) => { isValid: boolean; message: string };
|
||||||
|
isSecretExistsPath?: string;
|
||||||
}
|
}
|
||||||
export type FormConfigType = Omit<ControlData, "configProperty"> & {
|
export type FormConfigType = Omit<ControlData, "configProperty"> & {
|
||||||
configProperty?: string;
|
configProperty?: string;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import React from "react";
|
||||||
import BaseControl, { ControlProps } from "./BaseControl";
|
import BaseControl, { ControlProps } from "./BaseControl";
|
||||||
import { ControlType } from "constants/PropertyControlConstants";
|
import { ControlType } from "constants/PropertyControlConstants";
|
||||||
import { TextInput } from "design-system";
|
import { TextInput } from "design-system";
|
||||||
|
import { AppState } from "@appsmith/reducers";
|
||||||
import { Colors } from "constants/Colors";
|
import { Colors } from "constants/Colors";
|
||||||
import styled from "styled-components";
|
import styled from "styled-components";
|
||||||
import { InputType } from "components/constants";
|
import { InputType } from "components/constants";
|
||||||
|
|
@ -9,7 +10,9 @@ import {
|
||||||
Field,
|
Field,
|
||||||
WrappedFieldMetaProps,
|
WrappedFieldMetaProps,
|
||||||
WrappedFieldInputProps,
|
WrappedFieldInputProps,
|
||||||
|
formValueSelector,
|
||||||
} from "redux-form";
|
} from "redux-form";
|
||||||
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
export const StyledInfo = styled.span`
|
export const StyledInfo = styled.span`
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
|
|
@ -19,42 +22,34 @@ export const StyledInfo = styled.span`
|
||||||
margin-left: 1px;
|
margin-left: 1px;
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export function InputText(props: {
|
const FieldWrapper = styled.div`
|
||||||
label: string;
|
width: 35vw;
|
||||||
value: string;
|
position: relative;
|
||||||
isValid: boolean;
|
`;
|
||||||
subtitle?: string;
|
|
||||||
validationMessage?: string;
|
|
||||||
placeholder?: string;
|
|
||||||
dataType?: string;
|
|
||||||
isRequired?: boolean;
|
|
||||||
name: string;
|
|
||||||
encrypted?: boolean;
|
|
||||||
disabled?: boolean;
|
|
||||||
customStyles?: Record<string, any>;
|
|
||||||
validator?: (value: string) => { isValid: boolean; message: string };
|
|
||||||
}) {
|
|
||||||
const { dataType, disabled, name, placeholder } = props;
|
|
||||||
|
|
||||||
return (
|
const SecretDisplayIndicator = styled.input`
|
||||||
<div data-cy={name} style={{ width: "35vw", ...props.customStyles }}>
|
position: absolute;
|
||||||
<Field
|
top: 0;
|
||||||
component={renderComponent}
|
left: 0;
|
||||||
datatype={dataType}
|
width: 100%;
|
||||||
disabled={disabled || false}
|
height: 100%;
|
||||||
placeholder={placeholder}
|
display: flex;
|
||||||
{...props}
|
align-items: center;
|
||||||
asyncControl
|
padding: 0px var(--ads-spaces-6);
|
||||||
/>
|
z-index: 1;
|
||||||
</div>
|
cursor: text;
|
||||||
);
|
border: none;
|
||||||
}
|
background: none;
|
||||||
|
`;
|
||||||
|
|
||||||
|
const PASSWORD_EXISTS_INDICATOR = "······";
|
||||||
|
|
||||||
function renderComponent(
|
function renderComponent(
|
||||||
props: {
|
props: {
|
||||||
placeholder: string;
|
placeholder: string;
|
||||||
dataType?: InputType;
|
dataType?: InputType;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
reference: any;
|
||||||
validator?: (value: string) => { isValid: boolean; message: string };
|
validator?: (value: string) => { isValid: boolean; message: string };
|
||||||
} & {
|
} & {
|
||||||
meta: Partial<WrappedFieldMetaProps>;
|
meta: Partial<WrappedFieldMetaProps>;
|
||||||
|
|
@ -68,6 +63,7 @@ function renderComponent(
|
||||||
name={props.input?.name}
|
name={props.input?.name}
|
||||||
onChange={props.input.onChange}
|
onChange={props.input.onChange}
|
||||||
placeholder={props.placeholder}
|
placeholder={props.placeholder}
|
||||||
|
ref={props.reference}
|
||||||
value={props.input.value}
|
value={props.input.value}
|
||||||
{...props.input}
|
{...props.input}
|
||||||
validator={props.validator}
|
validator={props.validator}
|
||||||
|
|
@ -75,10 +71,59 @@ function renderComponent(
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class InputTextControl extends BaseControl<InputControlProps> {
|
class InputTextControl extends BaseControl<InputControlProps> {
|
||||||
|
fieldRef: any;
|
||||||
|
|
||||||
|
state = {
|
||||||
|
secretDisplayVisible: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props: InputControlProps) {
|
||||||
|
super(props);
|
||||||
|
this.fieldRef = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
onClickSecretDisplayIndicator = () => {
|
||||||
|
if (!this.state.secretDisplayVisible) return;
|
||||||
|
this.setState({
|
||||||
|
secretDisplayVisible: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (this.fieldRef.current) this.fieldRef.current?.focus();
|
||||||
|
};
|
||||||
|
|
||||||
|
checkForSecretOverlayIndicator = () => {
|
||||||
|
return (
|
||||||
|
this.props.dataType === "PASSWORD" &&
|
||||||
|
this.props.isSecretExistsPath &&
|
||||||
|
this.props.isSecretExistsData
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
onBlur = () => {
|
||||||
|
if (
|
||||||
|
this.checkForSecretOverlayIndicator() &&
|
||||||
|
this.fieldRef.current?.value?.length === 0
|
||||||
|
) {
|
||||||
|
this.setState({
|
||||||
|
secretDisplayVisible: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
if (this.checkForSecretOverlayIndicator()) {
|
||||||
|
this.setState({
|
||||||
|
secretDisplayVisible: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
configProperty,
|
configProperty,
|
||||||
|
customStyles,
|
||||||
dataType,
|
dataType,
|
||||||
disabled,
|
disabled,
|
||||||
encrypted,
|
encrypted,
|
||||||
|
|
@ -92,19 +137,34 @@ class InputTextControl extends BaseControl<InputControlProps> {
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InputText
|
<FieldWrapper data-cy={configProperty} style={customStyles || {}}>
|
||||||
dataType={this.getType(dataType)}
|
{this.state.secretDisplayVisible && (
|
||||||
disabled={disabled}
|
<SecretDisplayIndicator
|
||||||
encrypted={encrypted}
|
onClick={this.onClickSecretDisplayIndicator}
|
||||||
isValid={isValid}
|
onFocus={this.onClickSecretDisplayIndicator}
|
||||||
label={label}
|
type="password"
|
||||||
name={configProperty}
|
value={PASSWORD_EXISTS_INDICATOR}
|
||||||
placeholder={placeholderText}
|
/>
|
||||||
subtitle={subtitle}
|
)}
|
||||||
validationMessage={validationMessage}
|
<Field
|
||||||
validator={validator}
|
asyncControl
|
||||||
value={propertyValue}
|
component={renderComponent}
|
||||||
/>
|
dataType={this.getType(dataType)}
|
||||||
|
disabled={disabled || false}
|
||||||
|
encrypted={encrypted}
|
||||||
|
isValid={isValid}
|
||||||
|
label={label}
|
||||||
|
name={configProperty}
|
||||||
|
onBlur={this.onBlur}
|
||||||
|
onFocus={this.onClickSecretDisplayIndicator}
|
||||||
|
placeholder={this.state.secretDisplayVisible ? "" : placeholderText}
|
||||||
|
reference={this.fieldRef}
|
||||||
|
subtitle={subtitle}
|
||||||
|
validationMessage={validationMessage}
|
||||||
|
validator={validator}
|
||||||
|
value={propertyValue}
|
||||||
|
/>
|
||||||
|
</FieldWrapper>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -145,6 +205,18 @@ export interface InputControlProps extends ControlProps {
|
||||||
encrypted?: boolean;
|
encrypted?: boolean;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
validator?: (value: string) => { isValid: boolean; message: string };
|
validator?: (value: string) => { isValid: boolean; message: string };
|
||||||
|
isSecretExistsData?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default InputTextControl;
|
const mapStateToProps = (state: AppState, props: InputControlProps) => {
|
||||||
|
const valueSelector = formValueSelector(props.formName);
|
||||||
|
let isSecretExistsData;
|
||||||
|
if (props.isSecretExistsPath) {
|
||||||
|
isSecretExistsData = valueSelector(state, props.isSecretExistsPath);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
isSecretExistsData,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(InputTextControl);
|
||||||
|
|
|
||||||
|
|
@ -91,6 +91,7 @@ export interface Basic {
|
||||||
authenticationType: AuthType.basic;
|
authenticationType: AuthType.basic;
|
||||||
username: string;
|
username: string;
|
||||||
password: string;
|
password: string;
|
||||||
|
secretExists?: Record<string, boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ApiKey {
|
export interface ApiKey {
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ export interface DatasourceAuthentication {
|
||||||
bearerToken?: string;
|
bearerToken?: string;
|
||||||
authenticationStatus?: string;
|
authenticationStatus?: string;
|
||||||
authenticationType?: string;
|
authenticationType?: string;
|
||||||
|
secretExists?: Record<string, boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DatasourceColumns {
|
export interface DatasourceColumns {
|
||||||
|
|
|
||||||
|
|
@ -452,15 +452,15 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
return (
|
return (
|
||||||
<section data-cy="section-General" data-replay-id="section-General">
|
<section data-cy="section-General" data-replay-id="section-General">
|
||||||
<FormInputContainer data-replay-id={btoa("url")}>
|
<FormInputContainer data-replay-id={btoa("url")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"url",
|
configProperty: "url",
|
||||||
"URL",
|
label: "URL",
|
||||||
"https://example.com",
|
placeholderText: "https://example.com",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
true,
|
isRequired: true,
|
||||||
this.urlValidator,
|
fieldValidator: this.urlValidator,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer
|
<FormInputContainer
|
||||||
className="t--headers-array"
|
className="t--headers-array"
|
||||||
|
|
@ -502,14 +502,14 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
{formData.isSendSessionEnabled && (
|
{formData.isSendSessionEnabled && (
|
||||||
<FormInputContainer data-replay-id={btoa("sessionSignatureKey")}>
|
<FormInputContainer data-replay-id={btoa("sessionSignatureKey")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"sessionSignatureKey",
|
configProperty: "sessionSignatureKey",
|
||||||
"Session Details Signature Key",
|
label: "Session Details Signature Key",
|
||||||
"",
|
placeholderText: "",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
)}
|
)}
|
||||||
<FormInputContainer data-replay-id={btoa("authType")}>
|
<FormInputContainer data-replay-id={btoa("authType")}>
|
||||||
|
|
@ -591,24 +591,24 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FormInputContainer data-replay-id={btoa("authentication.label")}>
|
<FormInputContainer data-replay-id={btoa("authentication.label")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.label",
|
configProperty: "authentication.label",
|
||||||
"Key",
|
label: "Key",
|
||||||
"api_key",
|
placeholderText: "api_key",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer>
|
<FormInputContainer>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.value",
|
configProperty: "authentication.value",
|
||||||
"Value",
|
label: "Value",
|
||||||
"value",
|
placeholderText: "value",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
true,
|
encrypted: true,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer>
|
<FormInputContainer>
|
||||||
{this.renderDropdownControlViaFormControl(
|
{this.renderDropdownControlViaFormControl(
|
||||||
|
|
@ -633,14 +633,14 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
<FormInputContainer
|
<FormInputContainer
|
||||||
data-replay-id={btoa("authentication.headerPrefix")}
|
data-replay-id={btoa("authentication.headerPrefix")}
|
||||||
>
|
>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.headerPrefix",
|
configProperty: "authentication.headerPrefix",
|
||||||
"Header Prefix",
|
label: "Header Prefix",
|
||||||
"eg: Bearer ",
|
placeholderText: "eg: Bearer ",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
@ -650,14 +650,14 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
renderBearerToken = () => {
|
renderBearerToken = () => {
|
||||||
return (
|
return (
|
||||||
<FormInputContainer data-replay-id={btoa("authentication.bearerToken")}>
|
<FormInputContainer data-replay-id={btoa("authentication.bearerToken")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.bearerToken",
|
configProperty: "authentication.bearerToken",
|
||||||
"Bearer Token",
|
label: "Bearer Token",
|
||||||
"Bearer Token",
|
placeholderText: "Bearer Token",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
true,
|
encrypted: true,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
@ -666,24 +666,25 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FormInputContainer data-replay-id={btoa("authentication.username")}>
|
<FormInputContainer data-replay-id={btoa("authentication.username")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.username",
|
configProperty: "authentication.username",
|
||||||
"Username",
|
label: "Username",
|
||||||
"Username",
|
placeholderText: "Username",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer data-replay-id={btoa("authentication.password")}>
|
<FormInputContainer data-replay-id={btoa("authentication.password")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.password",
|
configProperty: "authentication.password",
|
||||||
"Password",
|
label: "Password",
|
||||||
"Password",
|
placeholderText: "Password",
|
||||||
"PASSWORD",
|
dataType: "PASSWORD",
|
||||||
true,
|
encrypted: true,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
isSecretExistsPath: "authentication.secretExists.password",
|
||||||
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
@ -757,60 +758,61 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
<FormInputContainer
|
<FormInputContainer
|
||||||
data-replay-id={btoa("authentication.headerPrefix")}
|
data-replay-id={btoa("authentication.headerPrefix")}
|
||||||
>
|
>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.headerPrefix",
|
configProperty: "authentication.headerPrefix",
|
||||||
"Header Prefix",
|
label: "Header Prefix",
|
||||||
"eg: Bearer ",
|
placeholderText: "eg: Bearer ",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
)}
|
)}
|
||||||
<FormInputContainer
|
<FormInputContainer
|
||||||
data-replay-id={btoa("authentication.accessTokenUrl")}
|
data-replay-id={btoa("authentication.accessTokenUrl")}
|
||||||
>
|
>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.accessTokenUrl",
|
configProperty: "authentication.accessTokenUrl",
|
||||||
"Access Token URL",
|
label: "Access Token URL",
|
||||||
"https://example.com/login/oauth/access_token",
|
placeholderText: "https://example.com/login/oauth/access_token",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
this.urlValidator,
|
fieldValidator: this.urlValidator,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer data-replay-id={btoa("authentication.clientId")}>
|
<FormInputContainer data-replay-id={btoa("authentication.clientId")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.clientId",
|
configProperty: "authentication.clientId",
|
||||||
"Client ID",
|
label: "Client ID",
|
||||||
"Client ID",
|
placeholderText: "Client ID",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer
|
<FormInputContainer
|
||||||
data-replay-id={btoa("authentication.clientSecret")}
|
data-replay-id={btoa("authentication.clientSecret")}
|
||||||
>
|
>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.clientSecret",
|
configProperty: "authentication.clientSecret",
|
||||||
"Client Secret",
|
label: "Client Secret",
|
||||||
"Client Secret",
|
placeholderText: "Client Secret",
|
||||||
"PASSWORD",
|
dataType: "PASSWORD",
|
||||||
true,
|
encrypted: true,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
isSecretExistsPath: "authentication.secretExists.clientSecret",
|
||||||
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer data-replay-id={btoa("authentication.scopeString")}>
|
<FormInputContainer data-replay-id={btoa("authentication.scopeString")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.scopeString",
|
configProperty: "authentication.scopeString",
|
||||||
"Scope(s)",
|
label: "Scope(s)",
|
||||||
"e.g. read, write",
|
placeholderText: "e.g. read, write",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer
|
<FormInputContainer
|
||||||
data-replay-id={btoa("authentication.isAuthorizationHeader")}
|
data-replay-id={btoa("authentication.isAuthorizationHeader")}
|
||||||
|
|
@ -933,24 +935,24 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<FormInputContainer data-replay-id={btoa("authentication.audience")}>
|
<FormInputContainer data-replay-id={btoa("authentication.audience")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.audience",
|
configProperty: "authentication.audience",
|
||||||
"Audience",
|
label: "Audience",
|
||||||
"https://example.com/oauth/audience",
|
placeholderText: "https://example.com/oauth/audience",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer data-replay-id={btoa("authentication.resource")}>
|
<FormInputContainer data-replay-id={btoa("authentication.resource")}>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.resource",
|
configProperty: "authentication.resource",
|
||||||
"Resource",
|
label: "Resource",
|
||||||
"https://example.com/oauth/resource",
|
placeholderText: "https://example.com/oauth/resource",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
@ -976,14 +978,14 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
<FormInputContainer
|
<FormInputContainer
|
||||||
data-replay-id={btoa("authentication.authorizationUrl")}
|
data-replay-id={btoa("authentication.authorizationUrl")}
|
||||||
>
|
>
|
||||||
{this.renderInputTextControlViaFormControl(
|
{this.renderInputTextControlViaFormControl({
|
||||||
"authentication.authorizationUrl",
|
configProperty: "authentication.authorizationUrl",
|
||||||
"Authorization URL",
|
label: "Authorization URL",
|
||||||
"https://example.com/login/oauth/authorize",
|
placeholderText: "https://example.com/login/oauth/authorize",
|
||||||
"TEXT",
|
dataType: "TEXT",
|
||||||
false,
|
encrypted: false,
|
||||||
false,
|
isRequired: false,
|
||||||
)}
|
})}
|
||||||
</FormInputContainer>
|
</FormInputContainer>
|
||||||
<FormInputContainer>
|
<FormInputContainer>
|
||||||
<div style={{ width: "20vw" }}>
|
<div style={{ width: "20vw" }}>
|
||||||
|
|
@ -1016,15 +1018,25 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
|
|
||||||
// All components in formControls must be rendered via FormControl.
|
// All components in formControls must be rendered via FormControl.
|
||||||
// FormControl is the common wrapper for all formcontrol components and contains common elements i.e. label, subtitle, helpertext
|
// FormControl is the common wrapper for all formcontrol components and contains common elements i.e. label, subtitle, helpertext
|
||||||
renderInputTextControlViaFormControl(
|
renderInputTextControlViaFormControl({
|
||||||
configProperty: string,
|
configProperty,
|
||||||
label: string,
|
dataType,
|
||||||
placeholderText: string,
|
encrypted,
|
||||||
dataType: "TEXT" | "PASSWORD" | "NUMBER",
|
fieldValidator,
|
||||||
encrypted: boolean,
|
isRequired,
|
||||||
isRequired: boolean,
|
isSecretExistsPath,
|
||||||
fieldValidator?: (value: string) => { isValid: boolean; message: string },
|
label,
|
||||||
) {
|
placeholderText,
|
||||||
|
}: {
|
||||||
|
configProperty: string;
|
||||||
|
label: string;
|
||||||
|
placeholderText: string;
|
||||||
|
dataType: "TEXT" | "PASSWORD" | "NUMBER";
|
||||||
|
encrypted: boolean;
|
||||||
|
isRequired: boolean;
|
||||||
|
fieldValidator?: (value: string) => { isValid: boolean; message: string };
|
||||||
|
isSecretExistsPath?: string;
|
||||||
|
}) {
|
||||||
return (
|
return (
|
||||||
<FormControl
|
<FormControl
|
||||||
config={{
|
config={{
|
||||||
|
|
@ -1040,6 +1052,7 @@ class DatasourceRestAPIEditor extends React.Component<
|
||||||
placeholderText: placeholderText,
|
placeholderText: placeholderText,
|
||||||
formName: DATASOURCE_REST_API_FORM,
|
formName: DATASOURCE_REST_API_FORM,
|
||||||
validator: fieldValidator,
|
validator: fieldValidator,
|
||||||
|
isSecretExistsPath,
|
||||||
}}
|
}}
|
||||||
formName={DATASOURCE_REST_API_FORM}
|
formName={DATASOURCE_REST_API_FORM}
|
||||||
multipleConfig={[]}
|
multipleConfig={[]}
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ const formToDatasourceAuthentication = (
|
||||||
authenticationType: AuthType.basic,
|
authenticationType: AuthType.basic,
|
||||||
username: authentication.username,
|
username: authentication.username,
|
||||||
password: authentication.password,
|
password: authentication.password,
|
||||||
|
secretExists: authentication.secretExists,
|
||||||
};
|
};
|
||||||
return basic;
|
return basic;
|
||||||
}
|
}
|
||||||
|
|
@ -224,6 +225,7 @@ const datasourceToFormAuthentication = (
|
||||||
authenticationType: AuthType.basic,
|
authenticationType: AuthType.basic,
|
||||||
username: authentication.username || "",
|
username: authentication.username || "",
|
||||||
password: authentication.password || "",
|
password: authentication.password || "",
|
||||||
|
secretExists: authentication.secretExists,
|
||||||
};
|
};
|
||||||
return basic;
|
return basic;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user