Skip to content

Commit a314888

Browse files
authored
Merge pull request #857 from raheeliftikhar5/generic-oauth
Added Generic OAuth
2 parents 447ecf3 + a92a113 commit a314888

File tree

12 files changed

+596
-141
lines changed

12 files changed

+596
-141
lines changed

client/packages/lowcoder-design/src/components/iconSelect/index.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,7 @@ export const IconSelect = (props: {
398398
visible={visible}
399399
setVisible={setVisible}
400400
trigger="click"
401-
leftOffset={-96}
401+
leftOffset={-30}
402402
searchKeywords={props.searchKeywords}
403403
/>
404404
);

client/packages/lowcoder/src/comps/controls/iconControl.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ const Wrapper = styled.div`
7070
}
7171
`;
7272

73-
const IconPicker = (props: {
73+
export const IconPicker = (props: {
7474
value: string;
7575
onChange: (value: string) => void;
7676
label?: ReactNode;

client/packages/lowcoder/src/comps/generators/uiCompBuilder.tsx

+26-23
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,6 @@ export function HidableView(props: {
5454
}
5555
}
5656

57-
export function ExtendedComponentView(props: {
58-
children: JSX.Element | React.ReactNode;
59-
className: string;
60-
dataTestId: string;
61-
}) {
62-
if (!props.className && !props.dataTestId) {
63-
return <>{props.children}</>;
64-
}
65-
66-
return (
67-
<div className={props.className} data-testid={props.dataTestId} style={{ width: "100%", height: "100%", margin: "0px", padding: "0px" }}>
68-
{props.children}
69-
</div>
70-
);
71-
}
72-
7357
export function ExtendedPropertyView<
7458
ChildrenCompMap extends Record<string, Comp<unknown>>,
7559
>(props: {
@@ -196,7 +180,13 @@ export class UICompBuilder<
196180
}
197181

198182
override getView(): ViewReturn {
199-
return (<div ref={this.ref} style={{height:"100%",width:"100%",margin:0,padding:0}}><UIView comp={this} viewFn={builder.viewFn} /></div>);
183+
return (
184+
<UIView
185+
innerRef={this.ref}
186+
comp={this}
187+
viewFn={builder.viewFn}
188+
/>
189+
);
200190
}
201191

202192
override getPropertyView(): ReactNode {
@@ -223,7 +213,11 @@ export const DisabledContext = React.createContext<boolean>(false);
223213
/**
224214
* Guaranteed to be in a react component, so that react hooks can be used internally
225215
*/
226-
function UIView(props: { comp: any; viewFn: any }) {
216+
function UIView(props: {
217+
innerRef: React.RefObject<HTMLDivElement>;
218+
comp: any;
219+
viewFn: any;
220+
}) {
227221
const comp = props.comp;
228222

229223
const childrenProps = childrenToProps(comp.children);
@@ -243,13 +237,22 @@ function UIView(props: { comp: any; viewFn: any }) {
243237
//END ADD BY FRED
244238

245239
return (
246-
<ExtendedComponentView
240+
<div
241+
ref={props.innerRef}
247242
className={childrenProps.className as string}
248-
dataTestId={childrenProps.dataTestId as string}
249-
>
243+
data-testid={childrenProps.dataTestId as string}
244+
style={{
245+
width: "100%",
246+
height: "100%",
247+
margin: "0px",
248+
padding: "0px",
249+
}}>
250250
<HidableView hidden={childrenProps.hidden as boolean}>
251-
{props.viewFn(childrenProps, comp.dispatch)}
251+
{props.viewFn(
252+
childrenProps,
253+
comp.dispatch
254+
)}
252255
</HidableView>
253-
</ExtendedComponentView>
256+
</div>
254257
);
255258
}

client/packages/lowcoder/src/constants/authConstants.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -90,9 +90,9 @@ export const AuthRoutes: Array<{ path: string; component: React.ComponentType<an
9090
{ path: ORG_AUTH_REGISTER_URL, component: UserRegister },
9191
];
9292

93-
export type ServerAuthType = "GOOGLE" | "GITHUB" | "FORM" | "KEYCLOAK" | "ORY";
93+
export type ServerAuthType = "GOOGLE" | "GITHUB" | "FORM" | "KEYCLOAK" | "ORY" | "GENERIC";
9494

95-
export type ServerAuthTypeInfoValueType = { logo: string; isOAuth2?: boolean };
95+
export type ServerAuthTypeInfoValueType = { logo?: string; isOAuth2?: boolean };
9696
export const ServerAuthTypeInfo: { [key in ServerAuthType]?: ServerAuthTypeInfoValueType } = {
9797
GOOGLE: {
9898
logo: GoogleLoginIcon,
@@ -110,6 +110,10 @@ export const ServerAuthTypeInfo: { [key in ServerAuthType]?: ServerAuthTypeInfoV
110110
logo: OryLoginIcon,
111111
isOAuth2: true
112112
},
113+
GENERIC: {
114+
logo: undefined,
115+
isOAuth2: true
116+
},
113117
FORM: { logo: EmailLoginIcon },
114118
};
115119

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
import { useMemo, useState } from "react";
2+
import { messageInstance, CloseEyeIcon } from "lowcoder-design";
3+
import { trans } from "i18n";
4+
import {
5+
FormStyled,
6+
PasswordLabel
7+
} from "../styledComponents";
8+
import { default as Form } from "antd/es/form";
9+
import { default as Input } from "antd/es/input";
10+
import { default as Tooltip } from "antd/es/tooltip";
11+
import IdSourceApi, { ConfigItem } from "api/idSourceApi";
12+
import { validateResponse } from "api/apiUtils";
13+
import { authConfig, AuthType, clientIdandSecretConfig, ItemType } from "../idSourceConstants";
14+
import _ from "lodash";
15+
import Flex from "antd/es/flex";
16+
import Button from "antd/es/button";
17+
18+
type GeneralOAuthFormProp = {
19+
authType: AuthType,
20+
onSave: () => void;
21+
onCancel: () => void;
22+
};
23+
24+
function GeneralOAuthForm(props: GeneralOAuthFormProp) {
25+
const {
26+
authType,
27+
onSave,
28+
onCancel,
29+
} = props;
30+
const [form1] = Form.useForm();
31+
const [saveLoading, setSaveLoading] = useState(false);
32+
33+
function saveAuthProvider(values: ConfigItem) {
34+
setSaveLoading(true);
35+
const config = {
36+
...values,
37+
authType,
38+
enableRegister: true,
39+
}
40+
IdSourceApi.saveConfig(config)
41+
.then((resp) => {
42+
if (validateResponse(resp)) {
43+
messageInstance.success(trans("idSource.saveSuccess"));
44+
}
45+
})
46+
.catch((e) => messageInstance.error(e.message))
47+
.finally(() => {
48+
setSaveLoading(false);
49+
onSave();
50+
});
51+
}
52+
53+
const handleSave = () => {
54+
form1.validateFields().then(values => {
55+
console.log(values);
56+
saveAuthProvider(values);
57+
});
58+
}
59+
60+
function handleCancel() {
61+
onCancel();
62+
}
63+
64+
const authConfigForm = useMemo(() => {
65+
if(!authConfig[authType]) return clientIdandSecretConfig;
66+
return authConfig[authType].form;
67+
}, [authType])
68+
69+
return (
70+
<FormStyled
71+
form={form1}
72+
name="general"
73+
layout="vertical"
74+
style={{ maxWidth: '100%' }}
75+
autoComplete="off"
76+
>
77+
{Object.entries(authConfigForm).map(([key, value]) => {
78+
const valueObject = _.isObject(value) ? (value as ItemType) : false;
79+
const required = true;
80+
const label = valueObject ? valueObject.label : value;
81+
const tip = valueObject && valueObject.tip;
82+
const isPassword = valueObject && valueObject.isPassword;
83+
return (
84+
<div key={key}>
85+
<Form.Item
86+
key={key}
87+
name={key}
88+
rules={[
89+
{
90+
required,
91+
message: trans("idSource.formPlaceholder", {
92+
label,
93+
}),
94+
},
95+
]}
96+
label={
97+
isPassword ? (
98+
<PasswordLabel>
99+
<span>{label}:</span>
100+
<CloseEyeIcon />
101+
</PasswordLabel>
102+
) : (
103+
<Tooltip title={tip}>
104+
<span className={tip ? "has-tip" : ""}>{label}</span>:
105+
</Tooltip>
106+
)
107+
}
108+
>
109+
{isPassword ? (
110+
<Input
111+
type={"password"}
112+
placeholder={trans("idSource.encryptedServer")}
113+
autoComplete={"one-time-code"}
114+
/>
115+
) : (
116+
<Input
117+
placeholder={trans("idSource.formPlaceholder", {
118+
label,
119+
})}
120+
/>
121+
)}
122+
</Form.Item>
123+
</div>
124+
);
125+
})}
126+
<Flex justify="end" gap={'8px'}>
127+
<Button
128+
type="default"
129+
style={{margin: 0}}
130+
onClick={handleCancel}
131+
>
132+
Cancel
133+
</Button>
134+
<Button
135+
type="primary"
136+
style={{margin: 0}}
137+
onClick={handleSave}
138+
loading={saveLoading}
139+
>
140+
Save
141+
</Button>
142+
</Flex>
143+
</FormStyled>
144+
);
145+
}
146+
147+
export default GeneralOAuthForm;

0 commit comments

Comments
 (0)