Skip to content
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

AB#25512193 Add banner about app settings migration #7489

Merged
merged 5 commits into from
Nov 28, 2023
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
14 changes: 11 additions & 3 deletions client-react/src/components/CustomBanner/CustomBanner.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ interface CustomBannerProps {
customIcon?: JSX.Element;
className?: string;
learnMoreLink?: string;
learnMoreText?: string;
learnMoreLinkAriaLabel?: string;
onClickLearnMoreLink?: (e?: any) => any;
onDismiss?: (e?: any) => any;
undocked?: boolean;
onClick?: (e?: any) => any;
Expand All @@ -27,8 +29,10 @@ const CustomBanner: React.FC<CustomBannerProps> = props => {
id,
customIcon,
className: customClassName,
learnMoreText,
learnMoreLink,
learnMoreLinkAriaLabel,
onClickLearnMoreLink,
onDismiss,
undocked,
onClick,
Expand All @@ -55,9 +59,13 @@ const CustomBanner: React.FC<CustomBannerProps> = props => {
{icon ? <span className={messageBannerIconStyle}>{icon}</span> : undefined}
<span>
<span tabIndex={0}>{message}</span>
{learnMoreLink ? (
<Link href={learnMoreLink} target="_blank" aria-label={learnMoreLinkAriaLabel ? learnMoreLinkAriaLabel : t('learnMore')}>
{t('learnMore')}
{learnMoreLink || onClickLearnMoreLink ? (
<Link
href={learnMoreLink}
onClick={onClickLearnMoreLink}
target="_blank"
aria-label={learnMoreLinkAriaLabel ? learnMoreLinkAriaLabel : t('learnMore')}>
{learnMoreText || t('learnMore')}
</Link>
) : (
undefined
Expand Down
5 changes: 5 additions & 0 deletions client-react/src/models/portal-models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ export class Verbs {
public static getStartupInfo = 'get-startup-info';
public static openBlade = 'open-blade';
public static openBlade2 = 'open-blade2';
public static switchMenuItem = 'switch-menu-item';

public static openBladeCollector = 'open-blade-collector'; // Deprecated
public static openBladeCollectorInputs = 'open-blade-collector-inputs'; // Deprecated
Expand Down Expand Up @@ -143,6 +144,10 @@ export interface IOpenBladeInfo<T = any> {
openAsSubJourney?: boolean;
}

export interface ISwitchMenuItemInfo {
menuItemId: string;
}

export interface FrameBladeParams<T> {
id?: string;
feature?: string;
Expand Down
82 changes: 56 additions & 26 deletions client-react/src/pages/app/app-settings/AppSettings.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Formik, FormikProps } from 'formik';
import React, { useContext, useRef, useState } from 'react';
import React, { useContext, useRef, useState, useEffect } from 'react';
import { AppSettingsFormValues } from './AppSettings.types';
import AppSettingsCommandBar from './AppSettingsCommandBar';
import AppSettingsDataLoader from './AppSettingsDataLoader';
Expand All @@ -22,6 +22,7 @@ import { updateWebAppConfigForServiceLinker } from './AppSettings.utils';
import { BladeCloseReason, IBladeResult } from '../../../models/portal-models';
import { SiteStateContext } from '../../../SiteState';
import { Links } from '../../../utils/FwLinks';
import { ExperimentationConstants } from '../../../utils/CommonConstants';

const validate = (values: AppSettingsFormValues | null, t: i18n.TFunction, scenarioChecker: ScenarioService, site: ArmObj<Site>) => {
if (!values) {
Expand Down Expand Up @@ -83,6 +84,7 @@ const AppSettings: React.FC<AppSettingsProps> = props => {
const scenarioChecker = scenarioCheckerRef.current!;
const [showRefreshConfirmDialog, setShowRefreshConfirmDialog] = useState(false);
const [showSaveConfirmDialog, setShowSaveConfirmDialog] = useState(false);
const [showAppSettings, setShowAppSettings] = useState<boolean | undefined>(undefined);

const portalContext = useContext(PortalContext);
const siteStateContext = useContext(SiteStateContext);
Expand Down Expand Up @@ -169,6 +171,23 @@ const AppSettings: React.FC<AppSettingsProps> = props => {
}
};

const onEnvironmentVariablesMenuLinkClick = () => {
portalContext.switchMenuItem({ menuItemId: 'environmentVariables' });
};

useEffect(() => {
let isSubscribed = true;
portalContext.hasFlightEnabled(ExperimentationConstants.TreatmentFlight.showEnvironmentVariables).then(enabled => {
if (isSubscribed) {
setShowAppSettings(!enabled);
}
});

return () => {
isSubscribed = false;
};
}, [portalContext]);

return (
<AppSettingsDataLoader resourceId={resourceId}>
{({ initialFormValues, onSubmit, scaleUpPlan, refreshAppSettings, setInitialValues, asyncData }) => (
Expand Down Expand Up @@ -263,31 +282,42 @@ const AppSettings: React.FC<AppSettingsProps> = props => {
)}
</div>
{initialFormValues ? (
<div className={formStyle}>
<AppSettingsForm
asyncData={asyncData}
tab={props.tab}
onServiceLinkerUpdateClick={(settingName: string) =>
onServiceLinkerUpdateClick(
settingName,
initialFormValues,
setInitialValues,
formProps.values,
formProps.setValues
)
}
onServiceLinkerDeleteClick={(settingName: string) =>
onServiceLinkerDeleteClick(
settingName,
initialFormValues,
setInitialValues,
formProps.values,
formProps.setValues
)
}
{...formProps}
/>
</div>
<>
{showAppSettings === false && (
<CustomBanner
type={MessageBarType.info}
message={t('directToEnvironmentVariablesInfoMessage')}
learnMoreText={t('directToEnvironmentVariablesLink')}
onClickLearnMoreLink={onEnvironmentVariablesMenuLinkClick}
/>
)}
<div className={formStyle}>
<AppSettingsForm
asyncData={asyncData}
tab={props.tab}
showAppSettings={showAppSettings}
onServiceLinkerUpdateClick={(settingName: string) =>
onServiceLinkerUpdateClick(
settingName,
initialFormValues,
setInitialValues,
formProps.values,
formProps.setValues
)
}
onServiceLinkerDeleteClick={(settingName: string) =>
onServiceLinkerDeleteClick(
settingName,
initialFormValues,
setInitialValues,
formProps.values,
formProps.setValues
)
}
{...formProps}
/>
</div>
</>
) : (
<CustomBanner message={t('configLoadFailure')} type={MessageBarType.error} />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ export type AppSettingsFormikPropsCombined = FormikProps<AppSettingsFormValues>
export interface AppSettingsFormProps extends AppSettingsFormikPropsCombined {
asyncData: AppSettingsAsyncData;
tab?: string;
showAppSettings?: boolean;
}

export type LeaseDurationType = 'infinite' | 'fixed';
Expand Down
23 changes: 3 additions & 20 deletions client-react/src/pages/app/app-settings/AppSettingsForm.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Pivot, PivotItem, IPivotItemProps } from '@fluentui/react';
import React, { useRef, useContext, useState, useEffect } from 'react';
import React, { useRef, useContext } from 'react';
import { useTranslation } from 'react-i18next';
import { style } from 'typestyle';
import { AppSettingsFormProps, AppSettingsTabs } from './AppSettings.types';
Expand All @@ -15,27 +15,23 @@ import { ThemeContext } from '../../../ThemeContext';
import { SiteContext } from './Contexts';
import { isWorkflowApp } from '../../../utils/arm-utils';
import { pivotWrapper } from './AppSettings.styles';
import { ExperimentationConstants, OverflowBehavior } from '../../../utils/CommonConstants';
import { OverflowBehavior } from '../../../utils/CommonConstants';
import { errorPagesDirty } from './Sections/ErrorPage';
import ErrorPagePivot from './Sections/ErrorPage';
import { PortalContext } from '../../../PortalContext';

export const settingsWrapper = style({
padding: '5px 20px 5px 0px',
});

const AppSettingsForm: React.FC<AppSettingsFormProps> = props => {
const theme = useContext(ThemeContext);
const { values, initialValues, tab, errors } = props;
const { values, initialValues, tab, errors, showAppSettings } = props;
const site = useContext(SiteContext);
const portalContext = useContext(PortalContext);

const { t } = useTranslation();
const scenarioCheckerRef = useRef(new ScenarioService(t));
const scenarioChecker = scenarioCheckerRef.current!;

const [showAppSettings, setShowAppSettings] = useState(false);

const generalSettingsDirtyCheck = () => {
return generalSettingsDirty(values, initialValues);
};
Expand Down Expand Up @@ -76,19 +72,6 @@ const AppSettingsForm: React.FC<AppSettingsFormProps> = props => {
const showFunctionRuntimeSettings = scenarioChecker.checkScenario(ScenarioIds.showFunctionRuntimeSettings, { site }).status === 'enabled';
const enableCustomErrorPages = scenarioChecker.checkScenario(ScenarioIds.enableCustomErrorPages, { site }).status !== 'disabled';

useEffect(() => {
let isSubscribed = true;
portalContext.hasFlightEnabled(ExperimentationConstants.TreatmentFlight.showEnvironmentVariables).then(enabled => {
if (isSubscribed) {
setShowAppSettings(!enabled);
}
});

return () => {
isSubscribed = false;
};
}, [portalContext]);

return (
<Pivot getTabId={getPivotTabId} defaultSelectedKey={tab} overflowBehavior={OverflowBehavior.menu}>
{showAppSettings ? (
Expand Down
10 changes: 10 additions & 0 deletions client-react/src/portal-communicator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
PortalTheme,
IFeatureInfo,
HighContrastTheme,
ISwitchMenuItemInfo,
} from './models/portal-models';
import { ISubscription } from './models/subscription';
import { darkTheme } from './theme/dark';
Expand Down Expand Up @@ -190,6 +191,15 @@ export default class PortalCommunicator {
});
}

public switchMenuItem(menuItemInfo: ISwitchMenuItemInfo) {
liuqidake marked this conversation as resolved.
Show resolved Hide resolved
const payload: IDataMessage<ISwitchMenuItemInfo> = {
operationId: Guid.newGuid(),
data: menuItemInfo,
};

PortalCommunicator.postMessage(Verbs.switchMenuItem, this.packageData(payload));
}

public openFrameBlade<T, U = any>(bladeInfo: IOpenBladeInfo<FrameBladeParams<U>>): Promise<IBladeResult<T>> {
return this.openBlade(bladeInfo);
}
Expand Down
2 changes: 2 additions & 0 deletions client/src/app/shared/models/portal-resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1476,6 +1476,8 @@ export class PortalResources {
public static platformSettings = 'platformSettings';
public static debugging = 'debugging';
public static modifiedTag = 'modifiedTag';
public static directToEnvironmentVariablesInfoMessage = 'directToEnvironmentVariablesInfoMessage';
public static directToEnvironmentVariablesLink = 'directToEnvironmentVariablesLink';
public static applicationSettings = 'applicationSettings';
public static functionRuntimeSettings = 'functionRuntimeSettings';
public static generalSettings = 'generalSettings';
Expand Down
6 changes: 6 additions & 0 deletions server/Resources/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4568,6 +4568,12 @@ Set to "External URL" to use an API definition that is hosted elsewhere.</value>
<data name="modifiedTag" xml:space="preserve">
<value>(modified)</value>
</data>
<data name="directToEnvironmentVariablesInfoMessage" xml:space="preserve">
<value>View and edit your application settings and connection strings from Environment variables. </value>
</data>
<data name="directToEnvironmentVariablesLink" xml:space="preserve">
<value>Click here to go to Environment Variables menu</value>
</data>
<data name="applicationSettings" xml:space="preserve">
<value>Application settings</value>
</data>
Expand Down