diff --git a/.changeset/silver-beans-rule.md b/.changeset/silver-beans-rule.md
new file mode 100644
index 00000000000..bb5108c04c7
--- /dev/null
+++ b/.changeset/silver-beans-rule.md
@@ -0,0 +1,5 @@
+---
+"@wso2is/console": patch
+---
+
+Move Multi Attribute Login connector to Login & Registration
diff --git a/apps/console/src/extensions/configs/server-configuration.tsx b/apps/console/src/extensions/configs/server-configuration.tsx
index 9cc06102a43..ff72e53a27c 100644
--- a/apps/console/src/extensions/configs/server-configuration.tsx
+++ b/apps/console/src/extensions/configs/server-configuration.tsx
@@ -64,9 +64,11 @@ export const serverConfigurationConfig: ServerConfigurationConfig = {
],
connectorToggleName: {},
connectorsToHide: [
- "analytics-engine",
- "elastic-analytics-engine",
- "pii-controller"
+ ServerConfigurationsConstants.WSO2_ANALYTICS_ENGINE_CONNECTOR_CATEGORY_ID,
+ ServerConfigurationsConstants.ELK_ANALYTICS_CONNECTOR_ID,
+ ServerConfigurationsConstants.LITE_USER_REGISTRATION_CONNECTOR_ID,
+ ServerConfigurationsConstants.MULTI_ATTRIBUTE_LOGIN_CONNECTOR_ID,
+ ServerConfigurationsConstants.CONSENT_INFO_CONNECTOR_ID
],
connectorsToShow: [ "all" ],
customConnectors: [
diff --git a/apps/console/src/features/core/configs/routes.tsx b/apps/console/src/features/core/configs/routes.tsx
index f13b2124c87..7a401b40141 100644
--- a/apps/console/src/features/core/configs/routes.tsx
+++ b/apps/console/src/features/core/configs/routes.tsx
@@ -20,7 +20,11 @@ import {
ArrowRightToBracketPencilIcon,
BoltIcon,
EnvelopeGearIcon,
+ EnvelopeIcon,
HierarchyIcon,
+ LightbulbOnIcon,
+ LinearNodesIcon,
+ UserCircleDotIcon,
UserGroupIcon
} from "@oxygen-ui/react-icons";
import { RouteInterface } from "@wso2is/core/models";
@@ -124,17 +128,6 @@ export const getAppViewRoutes = (useExtendedRoutes: boolean = false): RouteInter
protected: true,
showOnSidePanel: true
},
- {
- component: lazy(() => import("../../server-configurations/pages/governance-connectors")),
- exact: true,
- icon: null,
- id: "governanceConnectors",
- name: "console:manage.features.sidePanel.governanceConnectors",
- order: 11,
- path: AppConstants.getPaths().get("GOVERNANCE_CONNECTORS"),
- protected: true,
- showOnSidePanel: false
- },
{
category: "console:develop.features.sidePanel.categories.application",
children: [
@@ -351,7 +344,7 @@ export const getAppViewRoutes = (useExtendedRoutes: boolean = false): RouteInter
component: lazy(() => import("../../oidc-scopes/pages/oidc-scopes")),
exact: true,
icon: {
- icon: getSidePanelIcons().scopes
+ icon:
},
id: "oidcScopes",
name: "console:develop.features.sidePanel.oidcScopes",
@@ -458,7 +451,7 @@ export const getAppViewRoutes = (useExtendedRoutes: boolean = false): RouteInter
import("../../../features/email-management/" + "pages/email-customization")
),
exact: true,
- icon: { icon: getSidePanelIcons().emailTemplates },
+ icon: { icon: },
id: "communication-management",
name: "Email",
order: 14,
@@ -876,7 +869,7 @@ export const getAppViewRoutes = (useExtendedRoutes: boolean = false): RouteInter
featureStatus: "BETA",
featureStatusLabel: "common:beta",
icon: {
- icon: getSidePanelIcons().insights
+ icon:
},
id: "insights",
name: "Insights",
@@ -894,7 +887,7 @@ export const getAppViewRoutes = (useExtendedRoutes: boolean = false): RouteInter
),
exact: true,
icon: {
- icon: getSidePanelIcons().insights
+ icon:
},
id: "analytics",
name: "Analytics",
@@ -990,6 +983,18 @@ export const getAppViewRoutes = (useExtendedRoutes: boolean = false): RouteInter
path: AppConstants.getPaths().get("GOVERNANCE_CONNECTORS"),
protected: true,
showOnSidePanel: false
+ },
+ {
+ component: lazy(() => import("../../server-configurations/pages/multi-attribute-login-edit")),
+ exact: true,
+ icon: null,
+ id: "multiAttributeLogin",
+ name: "console:manage.features.governanceConnectors.connectorCategories.accountManagement." +
+ "connectors.multiattributeLoginHandler.friendlyName",
+ order: 999,
+ path: AppConstants.getPaths().get("MULTI_ATTRIBUTE_LOGIN"),
+ protected: true,
+ showOnSidePanel: false
}
]),
"id"
diff --git a/apps/console/src/features/core/constants/app-constants.ts b/apps/console/src/features/core/constants/app-constants.ts
index 3833350b65e..267a7b8dd35 100644
--- a/apps/console/src/features/core/constants/app-constants.ts
+++ b/apps/console/src/features/core/constants/app-constants.ts
@@ -333,6 +333,7 @@ export class AppConstants {
[ "ROLE_EDIT", `${ AppConstants.getAdminViewBasePath() }/roles/:id` ],
[ "ROOT", "/" ],
[ "GOVERNANCE_CONNECTORS", `${AppConstants.getAdminViewBasePath()}/governance-connectors/:id` ],
+ [ "MULTI_ATTRIBUTE_LOGIN", `${AppConstants.getAdminViewBasePath()}/multi-attribute-login` ],
[ "UNAUTHORIZED", `${AppConstants.getMainViewBasePath()}/unauthorized` ],
[ "USERS", `${AppConstants.getAdminViewBasePath()}/users` ],
[ "USER_EDIT", `${AppConstants.getAdminViewBasePath()}/users/:id` ],
diff --git a/apps/console/src/features/core/utils/route-utils.ts b/apps/console/src/features/core/utils/route-utils.ts
index a6db94f30cd..fcee481f0f6 100644
--- a/apps/console/src/features/core/utils/route-utils.ts
+++ b/apps/console/src/features/core/utils/route-utils.ts
@@ -18,6 +18,7 @@
import {
BuildingGearIcon,
+ DatabaseDocumentIcon,
PaletteIcon,
SquareUserIcon
} from "@oxygen-ui/react-icons";
@@ -262,7 +263,7 @@ export class RouteUtils {
};
const userAttributesAndStores: Omit = {
- icon: BuildingGearIcon,
+ icon: DatabaseDocumentIcon,
id: "userAttributesAndStores",
name: "User Attributes & Stores"
};
@@ -315,7 +316,8 @@ export class RouteUtils {
AppConstants.getPaths().get("LOGIN_AND_REGISTRATION"),
AppConstants.getPaths().get("USERNAME_VALIDATION_EDIT"),
AppConstants.getPaths().get("ALTERNATIVE_LOGIN_IDENTIFIER_EDIT"),
- AppConstants.getPaths().get("ADMIN_ADVISORY_BANNER_EDIT")
+ AppConstants.getPaths().get("ADMIN_ADVISORY_BANNER_EDIT"),
+ AppConstants.getPaths().get("MULTI_ATTRIBUTE_LOGIN")
];
const CategoryMappedRoutes: Omit[] = [
@@ -370,16 +372,19 @@ export class RouteUtils {
{
category: manage,
id: "userStores",
+ order: 2,
parent: userAttributesAndStores
},
{
category: manage,
id: "attributeDialects",
+ order: 1,
parent: userAttributesAndStores
},
{
category: manage,
id: "oidcScopes",
+ order: 3,
parent: userAttributesAndStores
},
{
diff --git a/apps/console/src/features/server-configurations/components/governance-connectors/dynamic-governance-connector.tsx b/apps/console/src/features/server-configurations/components/governance-connectors/dynamic-governance-connector.tsx
index 9889b679297..7c029f31417 100644
--- a/apps/console/src/features/server-configurations/components/governance-connectors/dynamic-governance-connector.tsx
+++ b/apps/console/src/features/server-configurations/components/governance-connectors/dynamic-governance-connector.tsx
@@ -129,7 +129,7 @@ export const DynamicGovernanceConnector: FunctionComponent {
dispatch(
addAlert({
description: t(
"console:manage.features.governanceConnectors.notifications." +
"updateConnector.success.description",
- { name: connector.friendlyName }
+ { name: connector?.friendlyName }
),
level: AlertLevels.SUCCESS,
message: t(
@@ -197,15 +197,15 @@ export const DynamicGovernanceConnector: FunctionComponent
serverConfigurationConfig.connectorPropertiesToShow.includes(property.name)
|| serverConfigurationConfig.connectorPropertiesToShow
.includes(ServerConfigurationsConstants.ALL)))
} }
- form={ kebabCase(connector.friendlyName) + "-form" }
+ form={ kebabCase(connector?.friendlyName) + "-form" }
initialValues={ getConnectorInitialValues(connector) }
- data-testid={ `${ testId }-${ connector.name }-form` }
+ data-testid={ `${ testId }-${ connector?.name }-form` }
isSubmitting={ isSubmitting }
/>
);
@@ -245,7 +245,7 @@ export const DynamicGovernanceConnector: FunctionComponent
{
diff --git a/apps/console/src/features/server-configurations/pages/connector-listing-page.tsx b/apps/console/src/features/server-configurations/pages/connector-listing-page.tsx
index 6f7a5c69766..a37f37b338a 100644
--- a/apps/console/src/features/server-configurations/pages/connector-listing-page.tsx
+++ b/apps/console/src/features/server-configurations/pages/connector-listing-page.tsx
@@ -36,6 +36,7 @@ import { I18n } from "@wso2is/i18n";
import { PageLayout } from "@wso2is/react-components";
import { AxiosError } from "axios";
import camelCase from "lodash-es/camelCase";
+import lowerCase from "lodash-es/lowerCase";
import React, { FunctionComponent, MutableRefObject, ReactElement, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useDispatch, useSelector } from "react-redux";
@@ -320,6 +321,10 @@ export const ConnectorListingPage: FunctionComponent {
+ history.push(AppConstants.getPaths().get("MULTI_ATTRIBUTE_LOGIN"));
+ };
+
/**
* Get connector categories which generate the connector forms dynamically.
*/
@@ -387,6 +392,11 @@ export const ConnectorListingPage: FunctionComponent
-
-
+ <>
+
+
+
+
+ }
+ header={
+ t("console:manage.features.governanceConnectors." +
+ "connectorCategories.accountManagement.connectors." +
+ "multiattributeLoginHandler.friendlyName")
+ }
+ onPrimaryActionClick={ handleMultiAttributeLoginAction }
+ primaryAction={ t("common:configure") }
+ />
+
+ >
) : (
<>
diff --git a/apps/console/src/features/server-configurations/pages/governance-connectors.tsx b/apps/console/src/features/server-configurations/pages/governance-connectors.tsx
index c75904d246a..99394c06a8a 100644
--- a/apps/console/src/features/server-configurations/pages/governance-connectors.tsx
+++ b/apps/console/src/features/server-configurations/pages/governance-connectors.tsx
@@ -31,7 +31,7 @@ import { Grid, Menu, Rail, Ref, Sticky } from "semantic-ui-react";
import { serverConfigurationConfig } from "../../../extensions";
import { AppConstants, AppState, FeatureConfigInterface, UIConstants, history } from "../../core";
import { OrganizationUtils } from "../../organizations/utils";
-import { getConnectorCategory } from "../api";
+import { getConnectorCategory } from "../api/governance-connectors";
import { DynamicGovernanceConnector } from "../components";
import { ServerConfigurationsConstants } from "../constants";
import { GovernanceConnectorCategoryInterface, GovernanceConnectorInterface } from "../models";
@@ -206,7 +206,7 @@ export const GovernanceConnectorsPage: FunctionComponent
diff --git a/apps/console/src/features/server-configurations/pages/multi-attribute-login-edit.tsx b/apps/console/src/features/server-configurations/pages/multi-attribute-login-edit.tsx
new file mode 100644
index 00000000000..519ad64fd54
--- /dev/null
+++ b/apps/console/src/features/server-configurations/pages/multi-attribute-login-edit.tsx
@@ -0,0 +1,185 @@
+/**
+ * Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
+ *
+ * WSO2 LLC. licenses this file to you under the Apache License,
+ * Version 2.0 (the "License"); 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 { hasRequiredScopes } from "@wso2is/core/helpers";
+import { AlertLevels, TestableComponentInterface } from "@wso2is/core/models";
+import { addAlert } from "@wso2is/core/store";
+import { ContentLoader, PageLayout } from "@wso2is/react-components";
+import { AxiosError } from "axios";
+import React, { FunctionComponent, MutableRefObject, ReactElement, useEffect, useRef, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { useDispatch, useSelector } from "react-redux";
+import { Dispatch } from "redux";
+import { Grid, Ref } from "semantic-ui-react";
+import { AppConstants, AppState, FeatureConfigInterface, history } from "../../core";
+import { getConnectorDetails } from "../api/governance-connectors";
+import { DynamicGovernanceConnector } from "../components/governance-connectors/dynamic-governance-connector";
+import { ServerConfigurationsConstants } from "../constants/server-configurations-constants";
+import { GovernanceConnectorInterface } from "../models/governance-connectors";
+
+/**
+ * Props for the Server Configurations page.
+ */
+type GovernanceConnectorsPageInterface = TestableComponentInterface;
+
+/**
+ * Multi Attribute Login connector edit page.
+ *
+ * @param props - Props injected to the component.
+ * @returns Multi Attribute Login connector edit page.
+ */
+export const MultiAttributeLoginEdit: FunctionComponent = (
+ props: GovernanceConnectorsPageInterface
+): ReactElement => {
+ const { [ "data-testid" ]: testId } = props;
+
+ const dispatch: Dispatch = useDispatch();
+ const pageContextRef: MutableRefObject = useRef(null);
+
+ const { t } = useTranslation();
+
+ const featureConfig: FeatureConfigInterface = useSelector((state: AppState) => state.config.ui.features);
+ const allowedScopes: string = useSelector((state: AppState) => state?.auth?.allowedScopes);
+ const categoryId: string = ServerConfigurationsConstants.ACCOUNT_MANAGEMENT_CATEGORY_ID;
+ const connectorId: string = ServerConfigurationsConstants.MULTI_ATTRIBUTE_LOGIN_CONNECTOR_ID;
+
+ const [ connector, setConnector ] = useState(undefined);
+ const [ isConnectorRequestLoading, setConnectorRequestLoading ] = useState(false);
+
+ useEffect(() => {
+ // If Governance Connector read permission is not available, prevent from trying to load the connectors.
+ if (!hasRequiredScopes(featureConfig?.governanceConnectors,
+ featureConfig?.governanceConnectors?.scopes?.read,
+ allowedScopes)) {
+
+ return;
+ }
+
+ loadConnectorDetails();
+ }, []);
+
+ /**
+ * Load multi attribute login connector.
+ */
+ const loadConnectorDetails = () => {
+
+ setConnectorRequestLoading(true);
+
+ getConnectorDetails(
+ categoryId,
+ connectorId
+ )
+ .then((response: GovernanceConnectorInterface) => {
+ response.categoryId = categoryId;
+ setConnector(response);
+ })
+ .catch((error: AxiosError) => {
+ if (error.response && error.response.data && error.response.data.detail) {
+ dispatch(
+ addAlert({
+ description: t(
+ "console:manage.features.governanceConnectors.notifications." +
+ "getConnector.error.description",
+ { description: error.response.data.description }
+ ),
+ level: AlertLevels.ERROR,
+ message: t(
+ "console:manage.features.governanceConnectors.notifications." +
+ "getConnector.error.message"
+ )
+ })
+ );
+ } else {
+ // Generic error message
+ dispatch(
+ addAlert({
+ description: t(
+ "console:manage.features.governanceConnectors.notifications." +
+ "getConnector.genericError.description"
+ ),
+ level: AlertLevels.ERROR,
+ message: t(
+ "console:manage.features.governanceConnectors.notifications." +
+ "getConnector.genericError.message"
+ )
+ })
+ );
+ }
+ })
+ .finally(() => {
+ setConnectorRequestLoading(false);
+ });
+ };
+
+ const onBackButtonClick = (): void => {
+ history.push(AppConstants.getPaths().get("LOGIN_AND_REGISTRATION"));
+ };
+
+ if (isConnectorRequestLoading && !connector) {
+ return ;
+ }
+
+ return (
+ onBackButtonClick(),
+ text: t("console:manage.features.governanceConnectors.goBackLoginAndRegistration")
+ } }
+ data-testid={ `${testId}-page-layout` }
+ >
+ [
+
+
+
+
+
+ loadConnectorDetails() }
+ />
+
+
+
+
+
+ ]
+
+ );
+};
+
+/**
+ * Default props for the component.
+ */
+MultiAttributeLoginEdit.defaultProps = {
+ "data-testid": "multi-attribute-login-edit"
+};
+
+/**
+ * A default export was added to support React.lazy.
+ * TODO: Change this to a named export once react starts supporting named exports for code splitting.
+ * @see {@link https://reactjs.org/docs/code-splitting.html#reactlazy}
+ */
+export default MultiAttributeLoginEdit;