Skip to content

Commit

Permalink
Merge pull request #7519 from NipuniBhagya/master
Browse files Browse the repository at this point in the history
Improve AI feature banners to match the feature status
  • Loading branch information
NipuniBhagya authored Feb 7, 2025
2 parents 4cffe68 + 0439079 commit 0b7fb85
Show file tree
Hide file tree
Showing 13 changed files with 153 additions and 55 deletions.
12 changes: 12 additions & 0 deletions .changeset/bright-falcons-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@wso2is/console": patch
"@wso2is/admin.applications.v1": patch
"@wso2is/admin.branding.ai.v1": patch
"@wso2is/admin.feature-gate.v1": patch
"@wso2is/admin.login-flow.ai.v1": patch
"@wso2is/common.ai.v1": patch
"@wso2is/i18n": patch
"@wso2is/admin.push-providers.v1": patch
---

Improve AI feature banners
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,39 @@
}
},
{% endif %}
{% if console.ai is defined %}
"ai": {
"disabledFeatures": [
{% if console.ai.disabled_features is defined %}
{% for feature in console.ai.disabled_features %}
"{{ feature }}"{{ "," if not loop.last }}
{% endfor %}
{% endif %}
],
"enabled": {% if console.ai.enabled is defined %} {{ console.ai.enabled }},
{% else %}
{% if ai_services.key is defined and ai_services.key|length > 0 %} true,
{% else %} false,
{% endif %}
{% endif %}
"scopes": {
{% if console.ai.scopes is defined %}
{% for operation, scopes in console.ai.scopes.items() %}
"{{ operation }}": [
{% for scope in scopes %}
"{{ scope }}"{{ "," if not loop.last }}
{% endfor %}
]{{ "," if not loop.last }}
{% endfor %}
{% else %}
"create": [],
"read": [],
"update": [],
"delete": []
{% endif %}
}
},
{% endif %}
{% if console.analytics.enabled is defined %}
"analytics": {
"disabledFeatures": [
Expand Down
11 changes: 10 additions & 1 deletion apps/console/src/public/deployment.config.json
Original file line number Diff line number Diff line change
Expand Up @@ -323,7 +323,16 @@
"ai": {
"disabledFeatures": [],
"enabled": false,
"featureFlags": [],
"featureFlags": [
{
"feature": "ai.application.loginFlow.banner",
"flag": ""
},
{
"feature": "ai.branding.banner",
"flag": ""
}
],
"scopes": {
"create": [],
"delete": [],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* under the License.
*/

import Chip from "@oxygen-ui/react/Chip";
import Link from "@oxygen-ui/react/Link";
import { PaletteIcon } from "@oxygen-ui/react-icons";
import { ApplicationTabComponentsFilter } from
Expand All @@ -26,9 +25,10 @@ import { history } from "@wso2is/admin.core.v1/helpers/history";
import { UIConfigInterface } from "@wso2is/admin.core.v1/models/config";
import { AppState } from "@wso2is/admin.core.v1/store";
import { ApplicationTabIDs, applicationConfig } from "@wso2is/admin.extensions.v1";
import { FeatureStatusLabel } from "@wso2is/admin.feature-gate.v1/models/feature-status";
import FeatureFlagLabel from "@wso2is/admin.feature-gate.v1/components/feature-flag-label";
import FeatureFlagConstants from "@wso2is/admin.feature-gate.v1/constants/feature-flag-constants";
import { OrganizationType } from "@wso2is/admin.organizations.v1/constants";
import { TestableComponentInterface } from "@wso2is/core/models";
import { FeatureFlagsInterface, TestableComponentInterface } from "@wso2is/core/models";
import { URLUtils } from "@wso2is/core/utils";
import { Field, Form } from "@wso2is/form";
import {
Expand Down Expand Up @@ -182,14 +182,15 @@ export const GeneralDetailsForm: FunctionComponent<GeneralDetailsFormPopsInterfa
const { getLink } = useDocumentation();

const UIConfig: UIConfigInterface = useSelector((state: AppState) => state?.config?.ui);
const brandingFeatureFlagsConfig: FeatureFlagsInterface[] = UIConfig?.features?.applications?.featureFlags;
const orgType: OrganizationType = useSelector((state: AppState) => state?.organization?.organizationType);

const [ isDiscoverable, setDiscoverability ] = useState<boolean>(discoverability);

const [ isMyAccountEnabled, setMyAccountStatus ] = useState<boolean>(AppConstants.DEFAULT_MY_ACCOUNT_STATUS);
const [ isM2MApplication, setM2MApplication ] = useState<boolean>(false);

const isSubOrg: boolean = window[ "AppUtils" ].getConfig().organizationName;
const orgType: OrganizationType = useSelector((state: AppState) => state?.organization?.organizationType);
const isSubOrganizationType: boolean = orgType === OrganizationType.SUBORGANIZATION;

const {
Expand Down Expand Up @@ -591,10 +592,13 @@ export const GeneralDetailsForm: FunctionComponent<GeneralDetailsFormPopsInterfa
<>
<Heading as="h4">
{ t("applications:forms.generalDetails.sections.branding.title") }
<Chip
size="small"
label={ t(FeatureStatusLabel.BETA) }
className="oxygen-chip-beta mb-1 ml-2"
<FeatureFlagLabel
featureFlags={ brandingFeatureFlagsConfig }
featureKey={
FeatureFlagConstants.FEATURE_FLAG_KEY_MAP
.APPLICATION_EDIT_BRANDING_LINK
}
type="chip"
/>
</Heading>
<PaletteIcon fill="#ff7300" /> &nbsp;
Expand Down
36 changes: 24 additions & 12 deletions features/admin.branding.ai.v1/components/branding-ai-banner.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
* Copyright (c) 2024-2025, 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
Expand All @@ -19,20 +19,23 @@
import SendOutlinedIcon from "@mui/icons-material/SendOutlined";
import { Collapse } from "@mui/material";
import Box from "@oxygen-ui/react/Box";
import Chip from "@oxygen-ui/react/Chip";
import CircularProgress from "@oxygen-ui/react/CircularProgress";
import IconButton from "@oxygen-ui/react/IconButton";
import TextField from "@oxygen-ui/react/TextField";
import Typography from "@oxygen-ui/react/Typography";
import { FeatureStatusLabel } from "@wso2is/admin.feature-gate.v1/models/feature-status";
import { AppState } from "@wso2is/admin.core.v1/store";
import FeatureFlagLabel from "@wso2is/admin.feature-gate.v1/components/feature-flag-label";
import FeatureFlagConstants from "@wso2is/admin.feature-gate.v1/constants/feature-flag-constants";
import AIBanner from "@wso2is/common.ai.v1/components/ai-banner";
import AIBannerTall from "@wso2is/common.ai.v1/components/ai-banner-tall";
import { FeatureAccessConfigInterface } from "@wso2is/core/models";
import {
DocumentationLink,
useDocumentation
} from "@wso2is/react-components";
import React, { FunctionComponent, PropsWithChildren, ReactElement, useState } from "react";
import { Trans, useTranslation } from "react-i18next";
import { useSelector } from "react-redux";
import useAIBrandingPreference from "../hooks/use-ai-branding-preference";
import useGenerateAIBrandingPreference, { GenerateAIBrandingPreferenceFunc }
from "../hooks/use-generate-ai-branding-preference";
Expand All @@ -55,6 +58,10 @@ const BrandingAIBanner: FunctionComponent<PropsWithChildren<BrandingAIBannerProp

const { getLink } = useDocumentation();

const aiFeatureConfig: FeatureAccessConfigInterface = useSelector(
(state: AppState) => state.config.ui.features?.ai);
const isAIFeautureEnabled: boolean = aiFeatureConfig?.enabled;

const {
bannerState,
isGeneratingBranding,
Expand Down Expand Up @@ -93,18 +100,23 @@ const BrandingAIBanner: FunctionComponent<PropsWithChildren<BrandingAIBannerProp
<Collapse in={ bannerState === BannerState.FULL }>
<AIBanner
title={ t("branding:ai.banner.full.heading") }
description={ t("branding:ai.banner.full.subHeading") }
description={
isAIFeautureEnabled
? t("branding:ai.banner.full.subHeading")
: t("ai:subscribeToAI")
}
aiText={ t("branding:ai.title") }
actionButtonText={ t("branding:ai.banner.full.button") }
onActionButtonClick={ handleExpandClick }
titleLabel={ (
<Chip
size="small"
label={ t(FeatureStatusLabel.BETA) }
className="oxygen-chip-beta mb-1 ml-2"
<FeatureFlagLabel
featureFlags={ aiFeatureConfig?.featureFlags }
featureKey={ FeatureFlagConstants.FEATURE_FLAG_KEY_MAP.AI_BRANDING_BANNER }
type="chip"
/>
) }
readonly={ readonly }
hideAction={ !isAIFeautureEnabled }
/>
</Collapse>
<Collapse in={ bannerState === BannerState.INPUT || bannerState === BannerState.COLLAPSED }>
Expand All @@ -124,10 +136,10 @@ const BrandingAIBanner: FunctionComponent<PropsWithChildren<BrandingAIBannerProp
) }
aiText={ t("branding:ai.title") }
titleLabel={ (
<Chip
size="small"
label={ t(FeatureStatusLabel.BETA) }
className="oxygen-chip-beta mb-1 ml-2"
<FeatureFlagLabel
featureFlags={ aiFeatureConfig?.featureFlags }
featureKey={ FeatureFlagConstants.FEATURE_FLAG_KEY_MAP.AI_BRANDING_BANNER }
type="chip"
/>
) }
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,11 @@ class FeatureFlagConstants {
ACTIONS_TYPES_PRE_REGISTRATION: "actions.types.list.preRegistration",
ACTIONS_TYPES_PRE_UPDATE_PASSWORD: "actions.types.list.preUpdatePassword",
ACTIONS_TYPES_PRE_UPDATE_PROFILE: "actions.types.list.preUpdateProfile",
AI_APPLICATION_LOGIN_FLOW_BANNER: "ai.application.loginFlow.banner",
AI_BRANDING_BANNER: "ai.branding.banner",
APPLICATIONS: "application",
APPLICATION_BRANDING_TEXT: "branding.stylesAndText.application.text",
APPLICATION_EDIT_BRANDING_LINK: "applications.edit.general.branding",
APPLICATION_TEMPLATES: "applications.templates",
BRANDING: "branding",
BRANDING_STYLES_AND_TEXT_TITLE: "branding.stylesAndText.application.title",
Expand All @@ -46,6 +49,8 @@ class FeatureFlagConstants {
LOGIN_AND_REGISTRATION_ORGANIZATION_DISCOVERY: "loginAndRegistration.organizationSettings.discovery",
LOGIN_AND_REGISTRATION_ORGANIZATION_IMPERSONATION: "loginAndRegistration.organizationSettings.impersonation",
ORGANIZATION_BRANDING_TEXT: "branding.stylesAndText.organization.text",
PUSH_PROVIDERS: "pushProviders",
PUSH_PROVIDER_TEMPLATES: "pushProviders.templates",
SMS_TEMPLATES: "smsTemplates",
USER_ROLES: "userRoles"
};
Expand Down
37 changes: 23 additions & 14 deletions features/admin.login-flow.ai.v1/components/login-flow-ai-banner.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2024, WSO2 LLC. (https://www.wso2.com).
* Copyright (c) 2024-2025, 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
Expand Down Expand Up @@ -28,16 +28,16 @@ import Box from "@oxygen-ui/react/Box";
import Button from "@oxygen-ui/react/Button";
import Card from "@oxygen-ui/react/Card";
import CardContent from "@oxygen-ui/react/CardContent";
import Chip from "@oxygen-ui/react/Chip";
import Grid from "@oxygen-ui/react/Grid";
import TextField from "@oxygen-ui/react/TextField";
import Typography from "@oxygen-ui/react/Typography";
import { FeatureAccessConfigInterface, useRequiredScopes } from "@wso2is/access-control";
import { useRequiredScopes } from "@wso2is/access-control";
import { AppState } from "@wso2is/admin.core.v1/store";
import { FeatureStatusLabel } from "@wso2is/admin.feature-gate.v1/models/feature-status";
import FeatureFlagLabel from "@wso2is/admin.feature-gate.v1/components/feature-flag-label";
import FeatureFlagConstants from "@wso2is/admin.feature-gate.v1/constants/feature-flag-constants";
import AIBanner from "@wso2is/common.ai.v1/components/ai-banner";
import AIBannerTall from "@wso2is/common.ai.v1/components/ai-banner-tall";
import { AlertLevels, IdentifiableComponentInterface } from "@wso2is/core/models";
import { AlertLevels, FeatureAccessConfigInterface, IdentifiableComponentInterface } from "@wso2is/core/models";
import { addAlert } from "@wso2is/core/store";
import { ConfirmationModal, DocumentationLink, useDocumentation } from "@wso2is/react-components";
import React, { FunctionComponent, ReactElement, useState } from "react";
Expand All @@ -64,6 +64,9 @@ const LoginFlowAIBanner: FunctionComponent<IdentifiableComponentInterface> = (

const applicationsFeatureConfig: FeatureAccessConfigInterface =
useSelector((state: AppState) => state.config.ui.features.applications);
const aiFeatureConfig: FeatureAccessConfigInterface = useSelector(
(state: AppState) => state.config.ui.features?.ai);

const hasApplicationUpdatePermissions: boolean = useRequiredScopes(applicationsFeatureConfig?.scopes?.update);

const dispatch: Dispatch = useDispatch();
Expand Down Expand Up @@ -91,6 +94,8 @@ const LoginFlowAIBanner: FunctionComponent<IdentifiableComponentInterface> = (
const [ showReplaceConfirmationModal, setShowReplaceConfirmationModal ] = useState<boolean>(false);
const [ replacingPrompt, setReplacingPrompt ] = useState<string>("");

const isAIFeautureEnabled: boolean = aiFeatureConfig?.enabled;

/**
* Handles the click event of the expand button.
*/
Expand Down Expand Up @@ -175,17 +180,21 @@ const LoginFlowAIBanner: FunctionComponent<IdentifiableComponentInterface> = (
<Collapse in={ bannerState === BannerState.FULL }>
<AIBanner
title={ t("ai:aiLoginFlow.banner.full.heading") }
description={ t("ai:aiLoginFlow.banner.full.subheading") }
description={ isAIFeautureEnabled
? t("ai:aiLoginFlow.banner.full.subheading")
: t("ai:subscribeToAI")
}
aiText={ t("ai:aiLoginFlow.title") }
actionButtonText={ t("ai:aiLoginFlow.banner.full.button") }
onActionButtonClick={ handleExpandClick }
titleLabel={ (
<Chip
size="small"
label={ t(FeatureStatusLabel.BETA) }
className="oxygen-chip-beta mb-1 ml-2"
<FeatureFlagLabel
featureFlags={ aiFeatureConfig?.featureFlags }
featureKey={ FeatureFlagConstants.FEATURE_FLAG_KEY_MAP.AI_APPLICATION_LOGIN_FLOW_BANNER }
type="chip"
/>
) }
hideAction={ !isAIFeautureEnabled }
/>
</Collapse>
<Collapse in={ bannerState === BannerState.INPUT || bannerState === BannerState.COLLAPSED }>
Expand All @@ -206,10 +215,10 @@ const LoginFlowAIBanner: FunctionComponent<IdentifiableComponentInterface> = (
) }
aiText={ t("ai:aiLoginFlow.title") }
titleLabel={ (
<Chip
size="small"
label={ t(FeatureStatusLabel.BETA) }
className="oxygen-chip-beta mb-1 ml-2"
<FeatureFlagLabel
featureFlags={ aiFeatureConfig?.featureFlags }
featureKey={ FeatureFlagConstants.FEATURE_FLAG_KEY_MAP.AI_APPLICATION_LOGIN_FLOW_BANNER }
type="chip"
/>
) }
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@

.push-provider-template-ribbon {
border-radius: 0;
position: absolute;
right: 0;
position: relative;
right: -23px;
font-size: .8em;
height: 24px;
width: 75px;
Expand All @@ -55,10 +55,6 @@
align-items: center;
padding: 10px;

.push-provider-template-name-label{
margin-right: 40px;
}

.push-provider-template-image-container {
min-height: 35px;
min-width: 35px;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,18 +65,19 @@ const PushProviderCard: FunctionComponent<PushProviderCardPropsInterface> = ({
const { t } = useTranslation();

const pushProviderFeatureFlagsConfig: FeatureFlagsInterface[] = useSelector(
(state: AppState) => state.config.ui.features.pushProviders.featureFlags
(state: AppState) => state.config.ui.features.pushProviders?.featureFlags
);

const featureFlag: string = useFeatureFlag(FeatureFlagConstants.FEATURE_FLAG_KEY_MAP.APPLICATION_TEMPLATES,
const featureFlag: string = useFeatureFlag(FeatureFlagConstants.FEATURE_FLAG_KEY_MAP.PUSH_PROVIDER_TEMPLATES,
pushProviderFeatureFlagsConfig
);

const featureStatus: PushProviderTemplateFeatureStatus = useMemo(() => {
if (!template?.customAttributes
|| !Array.isArray(template?.customAttributes)
|| template?.customAttributes.length === 0) {
return false;

return null;
}

const property: CustomAttributeInterface = template?.customAttributes?.find(
Expand All @@ -88,7 +89,7 @@ const PushProviderCard: FunctionComponent<PushProviderCardPropsInterface> = ({
return property?.value as PushProviderTemplateFeatureStatus;
}

return property?.value;
return null;
}, [ template ]);

const resolveRibbonLabel = (featureStatus: PushProviderTemplateFeatureStatus): string => {
Expand Down
Loading

0 comments on commit 0b7fb85

Please sign in to comment.