Skip to content

Update auth flow #1253

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Nov 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion client/packages/lowcoder-design/src/components/tacoInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -331,12 +331,14 @@ const FormInput = (props: {
check: (value: string) => boolean;
};
formName?: string;
onBlur?: () => void;
onChange?: (value: string, valid: boolean) => void;
className?: string;
inputRef?: Ref<InputRef>;
msg?: string;
defaultValue?: string;
}) => {
const { mustFill, checkRule, label, placeholder, onChange, formName, className, inputRef } =
const { mustFill, checkRule, label, placeholder, onBlur, onChange, formName, className, inputRef, defaultValue } =
props;
const [valueValid, setValueValid] = useState(true);
return (
Expand All @@ -350,6 +352,7 @@ const FormInput = (props: {
ref={inputRef}
name={formName}
placeholder={placeholder}
defaultValue={defaultValue}
onChange={(e) => {
let valid = true;
if (checkRule) {
Expand All @@ -358,6 +361,7 @@ const FormInput = (props: {
}
onChange && onChange(e.target.value, valid);
}}
onBlur={() => onBlur?.()}
/>
</FormInputFiled>
);
Expand Down
5 changes: 5 additions & 0 deletions client/packages/lowcoder/src/api/applicationApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,7 @@ class ApplicationApi extends Api {
static publicToMarketplaceURL = (applicationId: string) => `/applications/${applicationId}/public-to-marketplace`;
static getMarketplaceAppURL = (applicationId: string) => `/applications/${applicationId}/view_marketplace`;
static setAppEditingStateURL = (applicationId: string) => `/applications/editState/${applicationId}`;
static serverSettingsURL = () => `/serverSettings`;

static fetchHomeData(request: HomeDataPayload): AxiosPromise<HomeDataResponse> {
return Api.get(ApplicationApi.fetchHomeDataURL, request);
Expand Down Expand Up @@ -240,6 +241,10 @@ class ApplicationApi extends Api {
editingFinished,
});
}

static fetchServerSettings(): AxiosPromise<any> {
return Api.get(ApplicationApi.serverSettingsURL());
}
}

export default ApplicationApi;
4 changes: 2 additions & 2 deletions client/packages/lowcoder/src/api/idSourceApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ class IdSourceApi extends Api {
return Api.post(IdSourceApi.saveConfigURL, request);
}

static deleteConfig(id: string): AxiosPromise<ApiResponse> {
return Api.delete(IdSourceApi.deleteConfigURL(id));
static deleteConfig(id: string, deleteConfig?: boolean): AxiosPromise<ApiResponse> {
return Api.delete(IdSourceApi.deleteConfigURL(id), {delete: deleteConfig});
}

static syncManual(authType: string): AxiosPromise<ApiResponse> {
Expand Down
4 changes: 4 additions & 0 deletions client/packages/lowcoder/src/api/orgApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export class OrgApi extends Api {
static deleteOrgURL = (orgId: string) => `/organizations/${orgId}`;
static updateOrgURL = (orgId: string) => `/organizations/${orgId}/update`;
static fetchUsage = (orgId: string) => `/organizations/${orgId}/api-usage`;
static fetchOrgsByEmailURL = (email: string) => `organizations/byuser/${email}`;

static createGroup(request: { name: string }): AxiosPromise<GenericApiResponse<OrgGroup>> {
return Api.post(OrgApi.createGroupURL, request);
Expand Down Expand Up @@ -141,6 +142,9 @@ export class OrgApi extends Api {
return Api.get(OrgApi.fetchUsage(orgId), { lastMonthOnly: true });
}

static fetchOrgsByEmail(email: string): AxiosPromise<ApiResponse> {
return Api.get(OrgApi.fetchOrgsByEmailURL(email));
}
}

export default OrgApi;
9 changes: 8 additions & 1 deletion client/packages/lowcoder/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
ADMIN_APP_URL,
ORG_AUTH_FORGOT_PASSWORD_URL,
ORG_AUTH_RESET_PASSWORD_URL,
ADMIN_AUTH_URL,
} from "constants/routesURL";
import React from "react";
import { createRoot } from "react-dom/client";
Expand Down Expand Up @@ -55,7 +56,7 @@ import { getBrandingConfig } from "./redux/selectors/configSelectors";
import { buildMaterialPreviewURL } from "./util/materialUtils";
import GlobalInstances from 'components/GlobalInstances';
// import posthog from 'posthog-js'
import { fetchHomeData } from "./redux/reduxActions/applicationActions";
import { fetchHomeData, fetchServerSettingsAction } from "./redux/reduxActions/applicationActions";
import { getNpmPackageMeta } from "./comps/utils/remote";
import { packageMetaReadyAction, setLowcoderCompsLoading } from "./redux/reduxActions/npmPluginActions";

Expand Down Expand Up @@ -94,6 +95,7 @@ type AppIndexProps = {
fetchHomeData: (currentUserAnonymous?: boolean | undefined) => void;
fetchLowcoderCompVersions: () => void;
getCurrentUser: () => void;
fetchServerSettings: () => void;
favicon: string;
brandName: string;
uiLanguage: string;
Expand All @@ -102,6 +104,7 @@ type AppIndexProps = {
class AppIndex extends React.Component<AppIndexProps, any> {
componentDidMount() {
this.props.getCurrentUser();
this.props.fetchServerSettings();
// if (!this.props.currentUserAnonymous) {
// this.props.fetchHomeData(this.props.currentUserAnonymous);
// }
Expand Down Expand Up @@ -337,6 +340,7 @@ class AppIndex extends React.Component<AppIndexProps, any> {
// component={ApplicationListPage}
component={LazyApplicationHome}
/>
<LazyRoute exact path={ADMIN_AUTH_URL} component={LazyUserAuthComp} />
<LazyRoute path={USER_AUTH_URL} component={LazyUserAuthComp} />
<LazyRoute
path={ORG_AUTH_LOGIN_URL}
Expand Down Expand Up @@ -437,6 +441,9 @@ const mapDispatchToProps = (dispatch: any) => ({
dispatch(setLowcoderCompsLoading(false));
}
},
fetchServerSettings: () => {
dispatch(fetchServerSettingsAction());
}
});

const AppIndexWithProps = connect(mapStateToProps, mapDispatchToProps)(AppIndex);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,8 @@ export const ReduxActionTypes = {
FETCH_ALL_MARKETPLACE_APPS: "FETCH_ALL_MARKETPLACE_APPS",
FETCH_ALL_MARKETPLACE_APPS_SUCCESS: "FETCH_ALL_MARKETPLACE_APPS_SUCCESS",
SET_APP_EDITING_STATE: "SET_APP_EDITING_STATE",
FETCH_SERVER_SETTINGS: "FETCH_SERVER_SETTINGS",
FETCH_SERVER_SETTINGS_SUCCESS: "FETCH_SERVER_SETTINGS_SUCCESS",

/* user profile */
SET_USER_PROFILE_SETTING_MODAL_VISIBLE: "SET_USER_PROFILE_SETTING_MODAL_VISIBLE",
Expand Down
1 change: 1 addition & 0 deletions client/packages/lowcoder/src/constants/routesURL.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { UserGuideLocationState } from "pages/tutorials/tutorialsConstant";
import { DatasourceType } from "@lowcoder-ee/constants/queryConstants";

export const BASE_URL = "/";
export const ADMIN_AUTH_URL = "/admin/login";
export const USER_AUTH_URL = "/user/auth";
export const USER_PROFILE_URL = "/user/profile";
export const NEWS_URL = "/news";
Expand Down
11 changes: 8 additions & 3 deletions client/packages/lowcoder/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3008,7 +3008,11 @@ export const en = {
"resetSuccessDesc": "Password Reset Succeeded. The New Password is: {password}",
"resetLostPasswordSuccess": "Password Reset Succeeded. Please login again.",
"copyPassword": "Copy Password",
"poweredByLowcoder": "Powered by: Lowcoder.cloud"
"poweredByLowcoder": "Powered by: Lowcoder.cloud",
"continue": "Continue",
"enterPassword": "Enter your password",
"selectAuthProvider": "Select Authentication Provider",
"selectWorkspace": "Select your workspace",
},
"preLoad": {
"jsLibraryHelpText": "Add JavaScript Libraries to Your Current Application via URL Addresses. lodash, day.js, uuid, numbro are Built into the System for Immediate Use. JavaScript Libraries are Loaded Before the Application is Initialized, Which Can Have an Impact on Application Performance.",
Expand Down Expand Up @@ -3542,12 +3546,13 @@ export const en = {
"formSelectPlaceholder": "Please Select the {label}",
"saveSuccess": "Saved Successfully",
"dangerLabel": "Danger Zone",
"dangerTip": "Disabling This ID Provider May Result in Some Users Being Unable to Log In. Proceed With Caution.",
"dangerTip": "Disabling or Deleting This ID Provider May Result in Some Users Being Unable to Log In. Proceed With Caution.",
"lastEnabledConfig": "You can't disable/delete config as this is the only enabled configuration.",
"disable": "Disable",
"disableSuccess": "Disabled Successfully",
"encryptedServer": "-------- Encrypted on the Server Side --------",
"disableTip": "Tips",
"disableContent": "Disabling This ID Provider May Result in Some Users Being Unable to Log In. Are You Sure to Proceed?",
"disableContent": "{action} This ID Provider May Result in Some Users Being Unable to Log In. Are You Sure to Proceed?",
"manualTip": "",
"lockTip": "The Content is Locked. To Make Changes, Please Click the {icon} to Unlock.",
"lockModalContent": "Changing the 'ID Attribute' Field Can Have Significant Impacts on User Identification. Please Confirm That You Understand the Implications of This Change Before Proceeding.",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,42 +4,73 @@ import { trans } from "i18n";
import { useState } from "react";
import { validateResponse } from "api/apiUtils";
import IdSourceApi from "api/idSourceApi";
import { DangerIcon, CustomModal } from "lowcoder-design";
import { CustomModal } from "lowcoder-design";
import history from "util/history";
import { OAUTH_PROVIDER_SETTING } from "constants/routesURL";
import { messageInstance } from "lowcoder-design/src/components/GlobalInstances";
import Flex from "antd/es/flex";
import Alert from "antd/es/alert";

export const DeleteConfig = (props: { id: string }) => {
export const DeleteConfig = (props: {
id: string,
allowDelete?: boolean,
allowDisable?: boolean,
isLastEnabledConfig?: boolean,
}) => {
const [disableLoading, setDisableLoading] = useState(false);
const [deleteLoading, setDeleteLoading] = useState(false);
const handleDelete = () => {

const handleDelete = (deleteConfig?: boolean) => {
const setLoading = deleteConfig ? setDeleteLoading : setDisableLoading;
const action = deleteConfig ? trans("delete") : trans("idSource.disable");
CustomModal.confirm({
title: trans("idSource.disableTip"),
content: trans("idSource.disableContent"),
content: trans("idSource.disableContent", {action}),
onConfirm: () => {
setDeleteLoading(true);
IdSourceApi.deleteConfig(props.id)
.then((resp) => {
if (validateResponse(resp)) {
messageInstance.success(trans("idSource.disableSuccess"), 0.8, () =>
setLoading(true);
IdSourceApi.deleteConfig(props.id, deleteConfig)
.then((resp) => {
if (validateResponse(resp)) {
const successMsg = deleteConfig ? trans("home.deleteSuccessMsg") : trans("idSource.disableSuccess");
messageInstance.success(successMsg, 0.8, () =>
history.push(OAUTH_PROVIDER_SETTING)
);
}
})
.catch((e) => messageInstance.error(e.message))
.finally(() => setDeleteLoading(false));
.finally(() => setLoading(false));
},
});
};
return (
<DeleteWrapper>
<div>{trans("idSource.dangerLabel")}</div>
<div className="danger-tip">
<DangerIcon />
{trans("idSource.dangerTip")}
</div>
<Button loading={deleteLoading} onClick={() => handleDelete()}>
{trans("idSource.disable")}
</Button>
<h4>{trans("idSource.dangerLabel")}</h4>
<Alert
className="danger-tip"
description={trans("idSource.dangerTip")}
type="warning"
showIcon
/>
{props.isLastEnabledConfig && (
<Alert
className="danger-tip"
description={trans("idSource.lastEnabledConfig")}
type="warning"
showIcon
/>
)}
<Flex gap={8}>
{props.allowDisable && (
<Button danger disabled={props.isLastEnabledConfig} loading={disableLoading} onClick={() => handleDelete()}>
{trans("idSource.disable")}
</Button>
)}
{props.allowDelete && (
<Button type="primary" danger disabled={props.isLastEnabledConfig} loading={deleteLoading} onClick={() => handleDelete(true)}>
{trans("delete")}
</Button>
)}
</Flex>
</DeleteWrapper>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,22 @@ import { sourceMappingKeys } from "../OAuthForms/GenericOAuthForm";
import Flex from "antd/es/flex";

type IdSourceDetailProps = {
location: Location & { state: ConfigItem };
location: Location & { state: { config: ConfigItem, totalEnabledConfigs: number }};
};

export const IdSourceDetail = (props: IdSourceDetailProps) => {
const configDetail = props.location.state;
const {
config: configDetail,
totalEnabledConfigs,
} = props.location.state;
const [form] = useForm();
const [lock, setLock] = useState(() => {
const config = props.location.state;
const { config } = props.location.state;
return !config.ifLocal;
});
const [saveLoading, setSaveLoading] = useState(false);
const [saveDisable, setSaveDisable] = useState(() => {
const config = props.location.state;
const { config } = props.location.state;
if (
(config.authType === AuthType.Form && !config.enable) ||
(!config.ifLocal && !config.enable)
Expand Down Expand Up @@ -321,12 +324,15 @@ export const IdSourceDetail = (props: IdSourceDetailProps) => {
<Manual type={configDetail.authType} />
</>
)}
{configDetail.enable && (
<>
<Divider />
<DeleteConfig id={configDetail.id} />
</>
)}
<>
<Divider />
<DeleteConfig
id={configDetail.id}
allowDelete={configDetail.authType !== AuthType.Form}
allowDisable={configDetail.enable}
isLastEnabledConfig={totalEnabledConfigs === 1 && configDetail.enable}
/>
</>
</Content>
</DetailContainer>
);
Expand Down
6 changes: 3 additions & 3 deletions client/packages/lowcoder/src/pages/setting/idSource/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import { FreeTypes } from "pages/setting/idSource/idSourceConstants";
import { messageInstance, AddIcon } from "lowcoder-design";
import { currentOrgAdmin } from "../../../util/permissionUtils";
import CreateModal from "./createModal";
import _ from "lodash";
import { HelpText } from "components/HelpText";
import { IconControlView } from "@lowcoder-ee/comps/controls/iconControl";

Expand All @@ -42,6 +41,7 @@ export const IdSourceList = (props: any) => {
const config = useSelector(selectSystemConfig);
const { currentOrgId} = user;
const [configs, setConfigs] = useState<ConfigItem[]>([]);
const [enabledConfigs, setEnabledConfigs] = useState<ConfigItem[]>([]);
const [fetching, setFetching] = useState(false);
const [modalVisible, setModalVisible] = useState(false);
const enableEnterpriseLogin = useSelector(selectSystemConfig)?.featureFlag?.enableEnterpriseLogin;
Expand Down Expand Up @@ -76,8 +76,8 @@ export const IdSourceList = (props: any) => {
let res: ConfigItem[] = resp.data.data.filter((item: ConfigItem) =>
IdSource.includes(item.authType)
);
// res = _.uniqBy(res, 'authType');
setConfigs(res);
setEnabledConfigs(res.filter(item => item.enable));
}
})
.catch((e) => {
Expand Down Expand Up @@ -126,7 +126,7 @@ export const IdSourceList = (props: any) => {
}
history.push({
pathname: OAUTH_PROVIDER_DETAIL,
state: record,
state: { config: record, totalEnabledConfigs: enabledConfigs.length },
});
},
})}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -258,35 +258,16 @@ export const DeleteWrapper = styled.div`
line-height: 19px;

.danger-tip {
height: 32px;
padding: 0 16px 0 8px;
margin: 5px 0 8px 0;
background: #fff3f1;
max-width: 440px;
padding: 8px 16px;
margin: 5px 0 12px 0;
border-radius: 4px;
display: inline-flex;
align-items: center;

svg {
margin-right: 8px;
}
}

.ant-btn {
min-width: 84px;
display: block;
padding: 4px 8px;
background: #fef4f4;
border: 1px solid #fccdcd;
font-size: 13px;
color: #f73131;

&:hover,
&.ant-btn-loading {
background: #feecec;
}

${btnLoadingCss}
}
`;

export const StatusSpan = styled.span`
Expand Down
Loading
Loading