Skip to content

Commit

Permalink
fix: name dropdown for boxy saml
Browse files Browse the repository at this point in the history
  • Loading branch information
sattvikc committed Jul 11, 2024
1 parent d532b08 commit 77c527a
Show file tree
Hide file tree
Showing 11 changed files with 224 additions and 27 deletions.
2 changes: 1 addition & 1 deletion build/static/js/bundle.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/static/js/bundle.js.map

Large diffs are not rendered by default.

10 changes: 8 additions & 2 deletions src/ui/components/auth/SignInContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,13 +116,19 @@ const SignInContent: React.FC<SignInContentProps> = ({
};

const handleEmailFieldChange = (
e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>
e:
| React.ChangeEvent<HTMLInputElement>
| React.ChangeEvent<HTMLTextAreaElement>
| React.ChangeEvent<HTMLSelectElement>
) => {
setEmail(e.target.value);
};

const handlePasswordFieldChange = (
e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>
e:
| React.ChangeEvent<HTMLInputElement>
| React.ChangeEvent<HTMLTextAreaElement>
| React.ChangeEvent<HTMLSelectElement>
) => {
setPassword(e.target.value);
};
Expand Down
5 changes: 4 additions & 1 deletion src/ui/components/auth/SignInWithApiKeyContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ const SignInWithApiKeyContent = (props: SignInWithApiKeyContentProps) => {
};

const handleApiKeyFieldChange = (
e: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>
e:
| React.ChangeEvent<HTMLInputElement>
| React.ChangeEvent<HTMLTextAreaElement>
| React.ChangeEvent<HTMLSelectElement>
) => {
setApiKey(e.target.value);
};
Expand Down
136 changes: 136 additions & 0 deletions src/ui/components/inputField/InputDropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/* Copyright (c) 2022, VRAI Labs and/or its affiliates. All rights reserved.
*
* This software is licensed under the Apache License, Version 2.0 (the
* "License") as published by the Apache Software Foundation.
*
* You may not use this file except in compliance with the License. You may
* obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
import React, { useCallback, useState } from "react";
import { getImageUrl } from "../../../utils";
import TooltipContainer from "../tooltip/tooltip";

import "./InputField.css";

export type InputDropdownPropTypes = {
name: string;
size?: "small" | "medium";
label?: string;
value?: string | undefined;
options: string[];
placeholder?: string;
error?: string | JSX.Element;
isRequired?: boolean;
hideColon?: boolean;
forceShowError?: boolean;
disabled?: boolean;
prefix?: string;
autofocus?: boolean;
handleChange: (
event:
| React.ChangeEvent<HTMLInputElement>
| React.ChangeEvent<HTMLTextAreaElement>
| React.ChangeEvent<HTMLSelectElement>
) => void;
/** @default "bottom" */
errorPlacement?: "bottom" | "prefix-tooltip";
};

const InputDropdown: React.FC<InputDropdownPropTypes> = (props) => {
const handleChange = props.handleChange;
const { errorPlacement = "bottom" } = props;
const [isFocused, setIsFocused] = useState<boolean>(false);
const [isTouched, setIsTouched] = useState(false);

const onChange = useCallback(
(
event:
| React.ChangeEvent<HTMLInputElement>
| React.ChangeEvent<HTMLTextAreaElement>
| React.ChangeEvent<HTMLSelectElement>
) => {
setIsTouched(true);
handleChange(event);
},
[handleChange]
);

const showError = props.error && (isTouched || props.forceShowError);

return (
<div className="input-field-container">
{props.label && (
<label
htmlFor={props.name}
className="text-small input-label">
{props.label}
{props.isRequired && <span className="text-error input-label-required">*</span>}
{!props.hideColon ? ":" : ""}
</label>
)}
<div
className={`input-field-inset ${isFocused ? "input-field-inset-focused" : ""} ${
showError ? "input-field-inset-error-state" : ""
} ${props.prefix ? "input-field-inset-with-prefix" : ""}`}>
{props.prefix && (
<div
className={`input-field-prefix ${isFocused ? "input-field-prefix-focused" : ""} ${
showError ? "input-field-prefix-error" : ""
}`}>
{props.prefix}
</div>
)}
<select
name={props.name}
id={props.name + "-text"}
onChange={onChange}
value={props.value}
autoFocus={props.autofocus}
onFocus={() => setIsFocused(true)}
onBlur={() => setIsFocused(false)}
className={`text-small text-black input-field ${showError ? "input-field-error-state" : ""} ${
props.size === "small" ? "input-field-small" : ""
}`}>
{props.options.map((option, index) => (
<option
key={index}
value={option}>
{option}
</option>
))}
</select>
</div>
{showError && errorPlacement === "bottom" && (
<div className="input-field-error block-small block-error">
<img
className="input-field-error-icon"
src={getImageUrl("form-field-error-icon.svg")}
alt="Error in field"
/>
<p className="input-field-error-text text-small text-error">{props.error}</p>
</div>
)}
{showError && errorPlacement === "prefix-tooltip" && (
<div className="input-error-prefix-tooltip">
<TooltipContainer
tooltip={props.error}
position="bottom">
<img
className="input-field-error-icon"
src={getImageUrl("form-field-error-icon.svg")}
alt="Error in field"
/>
</TooltipContainer>
</div>
)}
</div>
);
};

export default InputDropdown;
7 changes: 6 additions & 1 deletion src/ui/components/inputField/InputField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,12 @@ export type InputFieldPropTypes = {
disabled?: boolean;
prefix?: string;
autofocus?: boolean;
handleChange: (event: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void;
handleChange: (
event:
| React.ChangeEvent<HTMLInputElement>
| React.ChangeEvent<HTMLTextAreaElement>
| React.ChangeEvent<HTMLSelectElement>
) => void;
/** @default "bottom" */
errorPlacement?: "bottom" | "prefix-tooltip";
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ export const EditPluginPropertyDialog = ({
const command = `curl --location --request PUT '${
// eslint-disable-next-line @typescript-eslint/no-explicit-any
(window as any).connectionURI
}/recipe/multitenancy/tenant' \\
}/recipe/multitenancy/tenant/v2' \\
${commonHeaders.trim()}
--data-raw '{
"tenantId": "${tenantId}",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ export const ClientConfig = ({
const [isDeleteDialogOpen, setIsDeleteDialogOpen] = useState(false);
const handleClientFieldChange = (
name: string,
e: ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>
e: ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement> | React.ChangeEvent<HTMLSelectElement>
) => {
if (e.type === "change") {
setClient({ ...client, [name]: e.target.value });
Expand All @@ -59,7 +59,7 @@ export const ClientConfig = ({

const handleAdditionalConfigChange = (
key: string,
e: ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>
e: ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement> | React.ChangeEvent<HTMLSelectElement>
) => {
const newAdditionalConfig: [string, string | null][] = client.additionalConfig.map(([k, v]) => {
if (k === key) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ export const ProviderInfoForm = ({
});
};

const handleFieldChange = (e: ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => {
const handleFieldChange = (
e: ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement> | React.ChangeEvent<HTMLSelectElement>
) => {
if (e.type === "change") {
setProviderConfigState({ ...providerConfigState, [e.target.name]: e.target.value });
}
Expand Down Expand Up @@ -149,7 +151,7 @@ export const ProviderInfoForm = ({
};

const handleThirdPartyIdSuffixChange = (
e: ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>
e: ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement> | React.ChangeEvent<HTMLSelectElement>
) => {
if (e.type !== "change") {
return;
Expand Down Expand Up @@ -319,8 +321,8 @@ export const ProviderInfoForm = ({
const normalizedScopes = client.scope?.filter((scope) => scope && scope?.trim() !== "") ?? [];
return {
clientId: client.clientId.trim(),
clientType: client.clientType?.trim(),
clientSecret: client.clientSecret?.trim(),
clientType: client.clientType?.trim() || undefined,
clientSecret: client.clientSecret?.trim() || undefined,
scope: normalizedScopes,
additionalConfig: Object.fromEntries(
client.additionalConfig.filter(([key, _]: [string, string | null]) => key.trim().length > 0)
Expand Down Expand Up @@ -481,17 +483,45 @@ export const ProviderInfoForm = ({
minLabelWidth={120}
/>
)}
<ThirdPartyProviderInput
label="Name"
tooltip="The name of the provider."
type="text"
name="name"
error={errorState.name}
forceShowError
value={providerConfigState.name}
minLabelWidth={120}
handleChange={handleFieldChange}
/>
{providerConfigState.thirdPartyId.startsWith("boxy-saml") ? (
<ThirdPartyProviderInput
label="Name"
tooltip="The name of the provider."
type="text"
name="name"
options={[
"Microsoft Entra ID",
"Microsoft AD FS",
"Okta",
"Auth0",
"Google",
"OneLogin",
"PingOne",
"JumpCloud",
"Rippling",
"OpenID",
"SAML",
]}
error={errorState.name}
forceShowError
value={providerConfigState.name}
minLabelWidth={120}
handleChange={handleFieldChange}
/>
) : (
<ThirdPartyProviderInput
label="Name"
tooltip="The name of the provider."
type="text"
name="name"
error={errorState.name}
forceShowError
value={providerConfigState.name}
minLabelWidth={120}
handleChange={handleFieldChange}
/>
)}

<div className="custom-provider-divider" />
<div className="custom-provider-client-config">
<div className="custom-provider-client-config__header">Clients</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,19 @@
* under the License.
*/
import { ReactComponent as InfoIcon } from "../../../../../assets/info-icon.svg";
import InputDropdown from "../../../inputField/InputDropdown";
import InputField, { InputFieldPropTypes } from "../../../inputField/InputField";
import TooltipContainer from "../../../tooltip/tooltip";
import "./thirdPartyProviderInput.scss";

type ThirdPartyProviderInputProps = InputFieldPropTypes & {
options?: string[];
tooltip?: string;
minLabelWidth?: number;
};

export const ThirdPartyProviderInput = (props: ThirdPartyProviderInputProps) => {
const { label, ...rest } = props;
const { label, options, type, ...rest } = props;
return (
<div className="third-party-provider-input-container">
<ThirdPartyProviderInputLabel
Expand All @@ -34,7 +36,17 @@ export const ThirdPartyProviderInput = (props: ThirdPartyProviderInputProps) =>
minLabelWidth={props.minLabelWidth}
/>

<InputField {...rest} />
{options === undefined ? (
<InputField
type={type}
{...rest}
/>
) : (
<InputDropdown
options={options}
{...rest}
/>
)}
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,12 @@ type Props = {
fieldName: "first_name" | "last_name";
label: string;
isEditing: boolean;
onChange: (event: React.ChangeEvent<HTMLInputElement> | React.ChangeEvent<HTMLTextAreaElement>) => void;
onChange: (
event:
| React.ChangeEvent<HTMLInputElement>
| React.ChangeEvent<HTMLTextAreaElement>
| React.ChangeEvent<HTMLSelectElement>
) => void;
};

export const UserDetailNameField: React.FC<Props> = ({ value, fieldName, label, isEditing, onChange }: Props) => {
Expand Down

0 comments on commit 77c527a

Please sign in to comment.