import { WebSiteManagementModels } from '@azure/arm-appservice' ; import { AppSettingsTreeItem , AppSettingTreeItem , deleteSite , DeploymentsTreeItem , DeploymentTreeItem , getFile , LogFilesTreeItem , ParsedSite , SiteFilesTreeItem } from 'vscode-azureappservice' ; import { AzExtParentTreeItem , AzExtTreeItem , IActionContext , TreeItemIconPath } from 'vscode-azureextensionui' ; import { runFromPackageKey } from '../constants' ; import { IParsedHostJson , parseHostJson } from '../funcConfig/host' ; import { FuncVersion , latestGAVersion , tryParseFuncVersion } from '../FuncVersion' ; import { envUtils } from '../utils/envUtils' ; import { nonNullValue } from '../utils/nonNull' ; import { treeUtils } from '../utils/treeUtils' ; import { ApplicationSettings , FuncHostRequest , IProjectTreeItem } from './IProjectTreeItem' ; import { matchesAnyPart , ProjectResource , ProjectSource } from './projectContextValues' ; import { RemoteFunctionsTreeItem } from './remoteProject/RemoteFunctionsTreeItem' ; export abstract class SlotTreeItemBase extends AzExtParentTreeItem implements IProjectTreeItem { public logStreamPath : string = '' ; public readonly appSettingsTreeItem : AppSettingsTreeItem ; public deploymentsNode : DeploymentsTreeItem | undefined ; public readonly source : ProjectSource = ProjectSource . Remote ; public site : ParsedSite ; public abstract readonly contextValue : string ; public abstract readonly label : string ; private _functionsTreeItem : RemoteFunctionsTreeItem | undefined ; private readonly _logFilesTreeItem : LogFilesTreeItem ; private readonly _siteFilesTreeItem : SiteFilesTreeItem ; private _cachedVersion : FuncVersion | undefined ; private _cachedHostJson : IParsedHostJson | undefined ; private _cachedIsConsumption : boolean | undefined ; public constructor ( parent , site ) { super ( parent ) ; this . site = site ; this . appSettingsTreeItem = new AppSettingsTreeItem ( this , site ) ; this . _siteFilesTreeItem = new SiteFilesTreeItem ( this , site , true ) ; this . _logFilesTreeItem = new LogFilesTreeItem ( this , site ) ; const valuesToMask = [ site . siteName , site . slotName , site . defaultHostName , site . resourceGroup , site . planName , site . planResourceGroup , site . kuduHostName , site . gitUrl , site . rawSite . repositorySiteName , ... ( site . rawSite . hostNames || [ ] ) , ... ( site . rawSite . enabledHostNames || [ ] ) ] ; for ( const v of valuesToMask ) { if ( v ) { this . valuesToMask . push ( v ) ; } } } public get logStreamLabel ( ) : string { return this . site . fullName ; } public get id ( ) : string { return this . site . id ; } public async getHostRequest ( ) { return { url : this . site . defaultHostUrl } ; } public get description ( ) : string | undefined { return this . _state ?. toLowerCase ( ) !== 'running' ? this . _state : undefined ; } public get iconPath ( ) : TreeItemIconPath { return treeUtils . getIconPath ( this . contextValue ) ; } private get _state ( ) : string | undefined { return this . site . rawSite . state ; } public hasMoreChildrenImpl ( ) { return false ; } /**
     * NOTE: We need to be extra careful in this method because it blocks many core scenarios (e.g. deploy) if the tree item is listed as invalid
     */ public async refreshImpl ( context ) { this . _cachedVersion = undefined ; this . _cachedHostJson = undefined ; this . _cachedIsConsumption = undefined ; const client = await this . site . createClient ( context ) ; this . site = new ParsedSite ( nonNullValue ( await client . getSite ( ) , 'site' ) , this . subscription ) ; } public async getVersion ( context ) { let result = this . _cachedVersion ; if ( result === undefined ) { let version ; try { const client = await this . site . createClient ( context ) ; const appSettings = await client . listApplicationSettings ( ) ; version = tryParseFuncVersion ( appSettings . properties && appSettings . properties . FUNCTIONS_EXTENSION_VERSION ) ; } catch { } result = version || latestGAVersion ; this . _cachedVersion = result ; } return result ; } public async getHostJson ( context ) { let result = this . _cachedHostJson ; if ( ! result ) { let data ; try { data = JSON . parse ( ( await getFile ( context , this . site , 'site/wwwroot/host.json' ) ) . data ) ; } catch { } const version = await this . getVersion ( context ) ; result = parseHostJson ( data , version ) ; this . _cachedHostJson = result ; } return result ; } public async getApplicationSettings ( context ) { const client = await this . site . createClient ( context ) ; const appSettings = await client . listApplicationSettings ( ) ; return appSettings . properties || { } ; } public async setApplicationSetting ( context , key , value ) { const client = await this . site . createClient ( context ) ; const settings = await client . listApplicationSettings ( ) ; if ( ! settings . properties ) { settings . properties = { } ; } settings . properties [ key ] = value ; await client . updateApplicationSettings ( settings ) ; } public async getIsConsumption ( context ) { let result = this . _cachedIsConsumption ; if ( result === undefined ) { try { const client = await this . site . createClient ( context ) ; result = await client . getIsConsumption ( context ) ; } catch { result = true ; } this . _cachedIsConsumption = result ; } return result ; } public async loadMoreChildrenImpl ( _clearCache , context ) { const client = await this . site . createClient ( context ) ; const siteConfig = await client . getSiteConfig ( ) ; const sourceControl = await client . getSourceControl ( ) ; this . deploymentsNode = new DeploymentsTreeItem ( this , this . site , siteConfig , sourceControl ) ; if ( ! this . _functionsTreeItem ) { this . _functionsTreeItem = await RemoteFunctionsTreeItem . createFunctionsTreeItem ( context , this ) ; } return [ this . _functionsTreeItem , this . appSettingsTreeItem , this . _siteFilesTreeItem , this . _logFilesTreeItem , this . deploymentsNode ] ; } public async pickTreeItemImpl ( expectedContextValues ) { for ( const expectedContextValue of expectedContextValues ) { switch ( expectedContextValue ) { case AppSettingsTreeItem . contextValue : case AppSettingTreeItem . contextValue : return this . appSettingsTreeItem ; case DeploymentsTreeItem . contextValueConnected : case DeploymentsTreeItem . contextValueUnconnected : case DeploymentTreeItem . contextValue : return this . deploymentsNode ; default : if ( typeof expectedContextValue === 'string' ) { if ( DeploymentTreeItem . contextValue . test ( expectedContextValue ) ) { return this . deploymentsNode ; } } else if ( matchesAnyPart ( expectedContextValue , ProjectResource . Functions , ProjectResource . Function ) ) { return this . _functionsTreeItem ; } } } return undefined ; } public compareChildrenImpl ( ) { return 0 ; } public async isReadOnly ( context ) { const client = await this . site . createClient ( context ) ; const appSettings = await client . listApplicationSettings ( ) ; return [ runFromPackageKey , 'WEBSITE_RUN_FROM_ZIP' ] . some ( key => appSettings . properties && envUtils . isEnvironmentVariableSet ( appSettings . properties [ key ] ) ) ; } public async deleteTreeItemImpl ( context ) { await deleteSite ( context , this . site ) ; } }