44 *--------------------------------------------------------------------------------------------*/
55
66import { ResourceGroupListStep } from "@microsoft/vscode-azext-azureutils" ;
7- import { AzureWizardPromptStep , nonNullValueAndProp } from "@microsoft/vscode-azext-utils" ;
7+ import { AzureWizardPromptStep } from "@microsoft/vscode-azext-utils" ;
88import { ProgressLocation , window } from "vscode" ;
99import { ext } from "../../../extensionVariables" ;
1010import { localize } from "../../../utils/localize" ;
11- import { validateUtils } from "../../../utils/validateUtils" ;
1211import { ContainerAppNameStep } from "../../createContainerApp/ContainerAppNameStep" ;
1312import { ManagedEnvironmentNameStep } from "../../createManagedEnvironment/ManagedEnvironmentNameStep" ;
1413import { ImageNameStep } from "../../image/imageSource/buildImageInAzure/ImageNameStep" ;
1514import { RegistryNameStep } from "../../image/imageSource/containerRegistry/acr/createAcr/RegistryNameStep" ;
16- import { type DeployWorkspaceProjectContext } from "../DeployWorkspaceProjectContext " ;
15+ import { type DeployWorkspaceProjectInternalContext } from "./deployWorkspaceProjectInternal " ;
1716
18- export class DefaultResourcesNameStep extends AzureWizardPromptStep < DeployWorkspaceProjectContext > {
19- public async prompt ( context : DeployWorkspaceProjectContext ) : Promise < void > {
20- ext . outputChannel . appendLog ( localize ( 'resourceNameUnavailable' ,
21- 'Info: Some container app resources matching the workspace name "{0}" were invalid or unavailable.' ,
22- cleanWorkspaceName ( nonNullValueAndProp ( context . rootFolder , 'name' ) ) )
23- ) ;
24-
25- const resourceBaseName : string = ( await context . ui . showInputBox ( {
17+ export class DefaultResourcesNameStep extends AzureWizardPromptStep < DeployWorkspaceProjectInternalContext > {
18+ public async prompt ( context : DeployWorkspaceProjectInternalContext ) : Promise < void > {
19+ const resourceName : string = ( await context . ui . showInputBox ( {
2620 prompt : localize ( 'resourceBaseNamePrompt' , 'Enter a name for the new container app resource(s).' ) ,
27- validateInput : this . validateInput ,
21+ validateInput : ( name : string ) => this . validateInput ( context , name ) ,
2822 asyncValidationTask : ( name : string ) => this . validateNameAvailability ( context , name )
2923 } ) ) . trim ( ) ;
3024
31- ext . outputChannel . appendLog ( localize ( 'usingResourceName' , 'User provided the new resource name "{0}" as the default for resource creation.' , resourceBaseName ) )
32-
33- ! context . resourceGroup && ( context . newResourceGroupName = resourceBaseName ) ;
34- ! context . managedEnvironment && ( context . newManagedEnvironmentName = resourceBaseName ) ;
35- ! context . containerApp && ( context . newContainerAppName = resourceBaseName ) ;
36- context . imageName = ImageNameStep . getTimestampedImageName ( context . containerApp ?. name || resourceBaseName ) ;
37- }
38-
39- public async configureBeforePrompt ( context : DeployWorkspaceProjectContext ) : Promise < void > {
40- const workspaceName : string = cleanWorkspaceName ( nonNullValueAndProp ( context . rootFolder , 'name' ) ) ;
41- if ( this . validateInput ( workspaceName ) !== undefined ) {
42- context . telemetry . properties . promptDefaultNameReason = 'invalid' ;
43- return ;
44- }
45-
46- if ( ! await this . isWorkspaceNameAvailable ( context , workspaceName ) ) {
47- context . telemetry . properties . promptDefaultNameReason = 'unavailable' ;
48- return ;
49- }
50-
51- if ( ! context . resourceGroup || ! context . managedEnvironment || ! context . registry || ! context . containerApp ) {
52- ext . outputChannel . appendLog ( localize ( 'usingWorkspaceName' , 'Using workspace name "{0}" as the default for remaining resource creation.' , workspaceName ) ) ;
53- }
25+ ext . outputChannel . appendLog ( localize ( 'usingResourceName' , 'User provided the new resource name "{0}" as the default for resource creation.' , resourceName ) )
5426
55- ! context . resourceGroup && ( context . newResourceGroupName = workspaceName ) ;
56- ! context . managedEnvironment && ( context . newManagedEnvironmentName = workspaceName ) ;
57- ! context . registry && ( context . newRegistryName = await RegistryNameStep . tryGenerateRelatedName ( context , workspaceName ) ) ;
58- ! context . containerApp && ( context . newContainerAppName = workspaceName ) ;
59- context . imageName = ImageNameStep . getTimestampedImageName ( context . containerApp ?. name || workspaceName ) ;
27+ ! context . resourceGroup && ( context . newResourceGroupName = resourceName ) ;
28+ ! context . managedEnvironment && ( context . newManagedEnvironmentName = resourceName ) ;
29+ ! context . containerApp && ( context . newContainerAppName = resourceName ) ;
30+ context . imageName = ImageNameStep . getTimestampedImageName ( context . containerApp ?. name || resourceName ) ;
6031 }
6132
62- public shouldPrompt ( context : DeployWorkspaceProjectContext ) : boolean {
33+ public shouldPrompt ( context : DeployWorkspaceProjectInternalContext ) : boolean {
6334 return ( ! context . resourceGroup && ! context . newResourceGroupName ) ||
6435 ( ! context . managedEnvironment && ! context . newManagedEnvironmentName ) ||
65- ( ! context . registry && ! context . newRegistryName ) ||
66- ( ! context . containerApp && ! context . newContainerAppName ) ;
36+ ( ! context . containerApp && ! context . newContainerAppName ) ||
37+ ! context . registry ;
6738 }
6839
69- private validateInput ( name : string = '' ) : string | undefined {
40+ private validateInput ( context : DeployWorkspaceProjectInternalContext , name : string = '' ) : string | undefined {
7041 name = name . trim ( ) ;
7142
72- // No symbols are allowed for ACR - we will strip out any offending characters from the base name, but still need to ensure this version has an appropriate length
73- const nameWithoutSymbols : string = name . replace ( / [ ^ a - z 0 - 9 ] + / g, '' ) ;
74- if ( ! validateUtils . isValidLength ( nameWithoutSymbols , 5 , 20 ) ) {
75- return localize ( 'invalidLength' , 'The alphanumeric portion of the name must be least 5 characters but no more than 20 characters.' ) ;
43+ // ** Sorted from _most_ to _least_ strict naming rules, with priority being most strict character length since that usually gets checked first **
44+ // ** This sorting should help to minimize the possibility of conflicting validate input error messages which could be confusing for users **
45+
46+ if ( ! context . managedEnvironment && ! context . newManagedEnvironmentName ) {
47+ const result = ManagedEnvironmentNameStep . validateInput ( name ) ;
48+ if ( result ) {
49+ return result ;
50+ }
51+ }
52+
53+ if ( ! context . containerApp && ! context . newContainerAppName ) {
54+ const result = ContainerAppNameStep . validateInput ( name ) ;
55+ if ( result ) {
56+ return result ;
57+ }
58+ }
59+
60+ if ( ! context . registry ) { // Skip checking newRegistryName since it gets set every time validateNameAvailability is run
61+ // No symbols are allowed for ACR names
62+ const nameWithoutSymbols : string = name . replace ( / [ ^ a - z 0 - 9 ] + / g, '' ) ;
63+ const result = RegistryNameStep . validateInput ( nameWithoutSymbols ) ;
64+ if ( result ) {
65+ return result ;
66+ }
7667 }
7768
78- // Container app names currently have the strictest name formatting logic at the time of writing this
79- // Todo: https://github.com/microsoft/vscode-azurecontainerapps/issues/603
80- return ContainerAppNameStep . validateInput ( name ) ;
69+ return undefined ;
8170 }
8271
83- protected async validateNameAvailability ( context : DeployWorkspaceProjectContext , name : string ) : Promise < string | undefined > {
72+ protected async validateNameAvailability ( context : DeployWorkspaceProjectInternalContext , name : string ) : Promise < string | undefined > {
8473 return await window . withProgress ( {
8574 location : ProgressLocation . Notification ,
8675 cancellable : false ,
@@ -92,7 +81,6 @@ export class DefaultResourcesNameStep extends AzureWizardPromptStep<DeployWorksp
9281 // Skip check, one already exists so don't need to worry about naming
9382 } else {
9483 context . newRegistryName = await RegistryNameStep . tryGenerateRelatedName ( context , name ) ;
95-
9684 if ( ! context . newRegistryName ) {
9785 return localize ( 'timeoutError' , 'Timed out waiting for registry name to be generated. Please try another name.' ) ;
9886 }
@@ -124,40 +112,4 @@ export class DefaultResourcesNameStep extends AzureWizardPromptStep<DeployWorksp
124112 return undefined ;
125113 } ) ;
126114 }
127-
128- protected async isWorkspaceNameAvailable ( context : DeployWorkspaceProjectContext , workspaceName : string ) : Promise < boolean > {
129- const isAvailable : Record < string , boolean > = { } ;
130-
131- if ( context . resourceGroup || await ResourceGroupListStep . isNameAvailable ( context , workspaceName ) ) {
132- isAvailable [ 'resourceGroup' ] = true ;
133- }
134-
135- if ( context . managedEnvironment || await ManagedEnvironmentNameStep . isNameAvailable ( context , context . resourceGroup ?. name ?? workspaceName , workspaceName ) ) {
136- isAvailable [ 'managedEnvironment' ] = true ;
137- }
138-
139- if ( context . containerApp || await ContainerAppNameStep . isNameAvailable ( context , context . resourceGroup ?. name ?? workspaceName , workspaceName ) ) {
140- isAvailable [ 'containerApp' ] = true ;
141- }
142-
143- return isAvailable [ 'resourceGroup' ] && isAvailable [ 'managedEnvironment' ] && isAvailable [ 'containerApp' ] ;
144- }
145- }
146-
147- export function cleanWorkspaceName ( workspaceName : string ) : string {
148- // Only alphanumeric characters or hyphens
149- let cleanedWorkspaceName : string = workspaceName . toLowerCase ( ) . replace ( / [ ^ a - z 0 - 9 - ] + / g, '' ) ;
150-
151- // Remove any consecutive hyphens
152- cleanedWorkspaceName = cleanedWorkspaceName . replace ( / - + / g, '-' ) ;
153-
154- // Remove any leading or ending hyphens
155- if ( cleanedWorkspaceName . startsWith ( '-' ) ) {
156- cleanedWorkspaceName = cleanedWorkspaceName . slice ( 1 ) ;
157- }
158- if ( cleanedWorkspaceName . endsWith ( '-' ) ) {
159- cleanedWorkspaceName = cleanedWorkspaceName . slice ( 0 , - 1 ) ;
160- }
161-
162- return cleanedWorkspaceName ;
163115}
0 commit comments