From fe862c8fee02a9f07a25e35c761660f83ab9ee61 Mon Sep 17 00:00:00 2001 From: GeoffCoxMSFT Date: Wed, 23 Jun 2021 11:41:33 -0700 Subject: [PATCH] Added recommended OS --- .../src/components/azureProvisionDialog.tsx | 79 +++++++++++++++---- .../azurePublish/src/components/util.ts | 40 ++++++++++ 2 files changed, 102 insertions(+), 17 deletions(-) diff --git a/extensions/azurePublish/src/components/azureProvisionDialog.tsx b/extensions/azurePublish/src/components/azureProvisionDialog.tsx index f0fcbc83bf..400e9dc403 100644 --- a/extensions/azurePublish/src/components/azureProvisionDialog.tsx +++ b/extensions/azurePublish/src/components/azureProvisionDialog.tsx @@ -9,6 +9,7 @@ import { DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button' import { logOut, usePublishApi, + useProjectApi, getTenants, getARMTokenForTenant, useLocalStorage, @@ -61,7 +62,7 @@ import { getResourceGroups, } from './api'; import { ChooseResourcesList } from './ChooseResourcesList'; -import { getExistResources, removePlaceholder, decodeToken, defaultExtensionState } from './util'; +import { getExistResources, removePlaceholder, decodeToken, defaultExtensionState, parseRuntimeKey } from './util'; import { ResourceGroupPicker } from './ResourceGroupPicker'; import { ChooseProvisionAction } from './ChooseProvisionAction'; @@ -134,11 +135,7 @@ const LearnMoreLink = styled(Link)` `; const appOSChoiceGroupStyles = { - flexContainer: { display: 'flex', flexDirection: 'row' }, -}; - -const appOSChoiceGroupOptionStyles = { - root: { marginLeft: '8px' }, + flexContainer: { display: 'flex', flexDirection: 'row', alignItems: 'center' }, }; const PageTypes = { @@ -291,6 +288,7 @@ const getLogoutNotificationSettings = (description: string, type: Notification[' ), }; }; + const getDefaultFormData = (currentProfile, defaults) => { return { creationType: defaults.creationType ?? 'create', @@ -307,11 +305,9 @@ const getDefaultFormData = (currentProfile, defaults) => { }; }; -const defaultAppServiceOperatingSystem = 'windows'; - export const AzureProvisionDialog: React.FC = () => { const { - currentProjectId, + currentProjectId: getCurrentProjectId, publishConfig, startProvision, closeDialog, @@ -327,12 +323,44 @@ export const AzureProvisionDialog: React.FC = () => { setTenantId, } = usePublishApi(); + const { projectCollection } = useProjectApi(); + + const currentProjectId = getCurrentProjectId(); + const telemetryClient = useTelemetryClient(); const { setItem, getItem, clearAll } = useLocalStorage(); // set type of publish - azurePublish or azureFunctionsPublish const publishType = getType(); const profileName = getName(); + + const getPreferredAppServiceOS = () => { + const project = projectCollection.find((project) => project.projectId === currentProjectId); + const runtimeKey = project?.setting.runtime.key; + if (runtimeKey) { + const { runtimeLanguage, runtimeType } = parseRuntimeKey(runtimeKey); + + switch (runtimeLanguage) { + case 'dotnet': + return 'windows'; + case 'js': + switch (runtimeType) { + case 'webapp': + return 'linux'; + case 'function': + return 'windows'; + default: + return 'windows'; + } + break; + default: + return 'windows'; + } + } else { + return 'windows'; + } + }; + const currentConfig = removePlaceholder(publishConfig); const extensionState = { ...defaultExtensionState, ...getItem(profileName) }; @@ -349,7 +377,10 @@ export const AzureProvisionDialog: React.FC = () => { const [luisLocations, setLuisLocations] = useState([]); const [extensionResourceOptions, setExtensionResourceOptions] = useState([]); - const [formData, setFormData] = useState(getDefaultFormData(currentConfig, extensionState)); + const preferredAppServiceOS = useMemo(getPreferredAppServiceOS, [currentProjectId, projectCollection]); + const [formData, setFormData] = useState( + getDefaultFormData(currentConfig, { ...extensionState, appServiceOperatingSystem: preferredAppServiceOS }) + ); const [isLoading, setIsLoading] = useState(true); const [loadingErrorMessage, setLoadingErrorMessage] = useState(); @@ -570,7 +601,7 @@ export const AzureProvisionDialog: React.FC = () => { const getResources = async () => { try { - const resources = await getResourceList(currentProjectId(), publishType); + const resources = await getResourceList(currentProjectId, publishType); setExtensionResourceOptions(resources); } catch (err) { // todo: how do we handle API errors in this component @@ -861,10 +892,24 @@ export const AzureProvisionDialog: React.FC = () => { ); }; - const appServiceOSOptions: IChoiceGroupOption[] = [ - { key: 'windows', text: 'Windows' }, - { key: 'linux', text: 'Linux', styles: appOSChoiceGroupOptionStyles }, - ]; + const getAppServiceOSOptions = useCallback((): IChoiceGroupOption[] => { + return [ + { + key: 'windows', + text: preferredAppServiceOS === 'windows' ? formatMessage('Windows (Recommended)') : formatMessage('Windows'), + styles: { + root: { marginTop: '4px' }, + }, + }, + { + key: 'linux', + text: preferredAppServiceOS === 'linux' ? formatMessage('Linux (Recommended)') : formatMessage('Linux'), + styles: { + root: { marginTop: '4px', marginLeft: '8px' }, + }, + }, + ]; + }, [preferredAppServiceOS]); const PageFormConfig = ( { { updateFormData('appServiceOperatingSystem', o.key as string); diff --git a/extensions/azurePublish/src/components/util.ts b/extensions/azurePublish/src/components/util.ts index 9aba7ad5d7..b38ca1110f 100644 --- a/extensions/azurePublish/src/components/util.ts +++ b/extensions/azurePublish/src/components/util.ts @@ -72,3 +72,43 @@ export const defaultExtensionState = { requiredResources: [], creationType: 'create', }; + +// Note: parseRuntimeKey is cut-and-pasted from skills because importing it from @bfc/shared adds a crypto dependency that the UI doesn't have. + +/** + * Returns true if the runtime key is adaptive; false otherwise. + * Example adaptive runtime keys: 'adaptive-runtime-dotnet-webapp' or 'adaptive-runtime-node-functions' + * Example older adaptive runtime keys: 'csharp-azurewebapp-v2' + */ +const isUsingAdaptiveRuntimeKey = (runtimeKey?: string): boolean => + runtimeKey === 'csharp-azurewebapp-v2' || !!runtimeKey?.startsWith('adaptive-runtime-'); + +/** + * Parses the runtime key + * Example adaptive runtime keys: 'adaptive-runtime-dotnet-webapp' or 'adaptive-runtime-node-functions' + * Example older adaptive runtime keys: 'csharp-azurewebapp-v2' + * @returns If the runtime is adaptive and the parsed runtime language and type + * @default { isUsingAdaptiveRuntime: false, runtimeLanguage: 'dotnet', runtimeType: 'webapp'} + */ +export const parseRuntimeKey = ( + runtimeKey?: string +): { isUsingAdaptiveRuntime: boolean; runtimeLanguage?: string; runtimeType?: string } => { + const isAdaptive = isUsingAdaptiveRuntimeKey(runtimeKey); + + if (runtimeKey && isAdaptive) { + const parts = runtimeKey?.split('-'); + if (parts.length === 4) { + return { + isUsingAdaptiveRuntime: isAdaptive, + runtimeLanguage: parts[2], + runtimeType: parts[3], + }; + } + } + + return { + isUsingAdaptiveRuntime: isAdaptive, + runtimeLanguage: 'dotnet', + runtimeType: 'webapp', + }; +};