Skip to content

Commit

Permalink
Merge 9cec4ce into f634e3f
Browse files Browse the repository at this point in the history
  • Loading branch information
Allison Gruninger committed Sep 19, 2018
2 parents f634e3f + 9cec4ce commit 4cdf602
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 18 deletions.
25 changes: 23 additions & 2 deletions client/src/app/function/function-new/function-new.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,28 @@

<app-edit-mode-warning [context]="context"></app-edit-mode-warning>

<div *ngIf="functionsInfo" [fnWriteAccess]="context">
<ng-container *ngIf="needsWorkerRuntime">
<div class="runtimeStackTitle">
<img [src]="createCardStyles.other.icon" [style.background-color]="createCardStyles.other.color"/>
<h1>{{ 'functionAppRuntimeStackTitle' | translate }}</h1>
</div>
<div>
<h3>{{ 'functionAppRuntimeStackDescription' | translate }}</h3>
</div>
<div class="search-and-sort">
{{ 'functionRuntimeStackLabel' | translate }}
<drop-down class="tpicker-dropdown"
[options]="possibleRuntimes"
(value)="onRuntimeChanged($event)"
attr.aria-label="{{ 'functionRuntimeStackLabel' | translate }}">
</drop-down>
<button class="custom-button"
(click)="setRuntime()">{{ 'Go' | translate }}
</button>
</div>
</ng-container>

<div *ngIf="functionsInfo && !needsWorkerRuntime" [fnWriteAccess]="context">

<div class="choose">
<h2>{{ 'functionNew_chooseTemplate' | translate }}</h2>
Expand Down Expand Up @@ -46,7 +67,7 @@ <h2>{{ 'functionNew_chooseTemplate' | translate }}</h2>
attr.aria-label="{{'templatePicker_scenario' | translate}}">
</drop-down>

<div *ngIf="runtimeVersion === 'V1'">
<div *ngIf="runtimeVersion === 'V1' && !functionAppLanguage">
{{ 'experimentalLanguageSupport' | translate }}
<slide-toggle class="language-toggle"
[on]="showExperimentalLanguages"
Expand Down
13 changes: 13 additions & 0 deletions client/src/app/function/function-new/function-new.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,19 @@ input.input-error {
padding-bottom:10px;
}

.runtimeStackTitle {
padding-bottom: 15px;
border-bottom: $border;
img {
display: inline-block;
height: 40px;
width: 40px;
margin-right: 15px;
padding: 5px;
float: left;
}
}

drop-down{
display: inline-block;
}
Expand Down
52 changes: 49 additions & 3 deletions client/src/app/function/function-new/function-new.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,19 @@ export class FunctionNewComponent extends FunctionAppContextComponent implements
public allExperimentalLanguages = ['Bash', 'Batch', 'PHP', 'PowerShell', 'Python', 'TypeScript'];
public appSettingsArm: ArmObj<ApplicationSettings>;
public functionAppLanguage: string;
public templates: FunctionTemplate[];
public needsWorkerRuntime: boolean;
public runtime: string;

public possibleRuntimes: DropDownElement<string>[] =
[{
displayLabel: 'C#',
value: 'dotnet',
},
{
displayLabel: 'JavaScript',
value: 'node',
}];

public createCardStyles = {
'blob': { color: '#1E5890', icon: 'image/blob.svg' },
Expand Down Expand Up @@ -172,7 +185,8 @@ export class FunctionNewComponent extends FunctionAppContextComponent implements
this._functionAppService.getRuntimeGeneration(this.context),
this._siteService.getAppSettings(this.context.site.id),
this._functionAppService.getBindingConfig(this.context),
this._functionAppService.getTemplates(this.context));
this._functionAppService.getTemplates(this.context),
this._functionAppService.getWorkerRuntimeRequired(this.context));
})
.do(null, e => {
this._logService.error(LogCategories.functionNew, '/load-functions-cards-failure', e);
Expand All @@ -182,6 +196,8 @@ export class FunctionNewComponent extends FunctionAppContextComponent implements
this.runtimeVersion = tuple[1];
this.appSettingsArm = tuple[2].result;
this.bindings = tuple[3].result.bindings;
this.templates = tuple[4].result;
this.needsWorkerRuntime = tuple[5];

if (this.action && this.functionsInfo && !this.selectedTemplate) {
this.selectedTemplateId = this.action.templateId;
Expand All @@ -190,10 +206,18 @@ export class FunctionNewComponent extends FunctionAppContextComponent implements
if (this.appSettingsArm.properties.hasOwnProperty(Constants.functionsWorkerRuntimeAppSettingsName)) {
const workerRuntime = this.appSettingsArm.properties[Constants.functionsWorkerRuntimeAppSettingsName];
this.functionAppLanguage = WorkerRuntimeLanguages[workerRuntime];
this.allExperimentalLanguages = [];
if (!this.functionAppLanguage) {
// this is if workerRuntime is set, but value is invalid
this.needsWorkerRuntime = true;
} else {
// workerRuntime is valid
this.needsWorkerRuntime = false;
}
}

this._buildCreateCardTemplates(tuple[4].result);
if (!this.needsWorkerRuntime) {
this._buildCreateCardTemplates(this.templates);
}
this._globalStateService.clearBusyState();
});
}
Expand Down Expand Up @@ -351,6 +375,28 @@ export class FunctionNewComponent extends FunctionAppContextComponent implements
this.category = this._translateService.instant('temp_category_all');
}

onRuntimeChanged(runtime: string) {
this.runtime = runtime;
}

setRuntime() {
this._globalStateService.setBusyState();

this.appSettingsArm.properties[Constants.functionsWorkerRuntimeAppSettingsName] = this.runtime;

this._siteService.updateAppSettings(this.context.site.id, this.appSettingsArm)
.do(null, e => {
this._globalStateService.clearBusyState();
this.showComponentError(e);
})
.subscribe(() => {
this.functionAppLanguage = WorkerRuntimeLanguages[this.runtime];
this.needsWorkerRuntime = false;
this._buildCreateCardTemplates(this.templates);
this._globalStateService.clearBusyState();
});
}

switchExperimentalLanguagesOption() {
this.showExperimentalLanguages = !this.showExperimentalLanguages;
this.createCards.forEach(card => {
Expand Down
31 changes: 31 additions & 0 deletions client/src/app/shared/Utilities/runtime-versions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
export class RuntimeVersions {

public static getRuntimeParts(exactRuntime: string) {
return exactRuntime.split('.');
}

public static majorVersion(exactRuntime: string) {
const parts = this.getRuntimeParts(exactRuntime);
if (parts.length > 0) {
return Number(parts[0]);
}
return null;
}

public static minorVersion(exactRuntime: string) {
const parts = this.getRuntimeParts(exactRuntime);
if (parts.length > 2) {
return Number(parts[2]);
}
return null;
}

public static workerRuntimeRequired(exactRuntime: string) {
const majorVersion = this.majorVersion(exactRuntime);
const minorVersion = this.minorVersion(exactRuntime);
if (majorVersion && minorVersion) {
return majorVersion === 2 && minorVersion >= 12050;
}
return false;
}
}
4 changes: 4 additions & 0 deletions client/src/app/shared/models/portal-resources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1299,6 +1299,10 @@
public static swapDiffNotSet = 'swapDiffNotSet';
public static extensionUninstallError = 'extensionUninstallError';
public static v2_preview_label = 'v2_preview_label';
public static functionAppRuntimeStackTitle = 'functionAppRuntimeStackTitle';
public static functionAppRuntimeStackDescription = 'functionAppRuntimeStackDescription';
public static functionRuntimeStackLabel = 'functionRuntimeStackLabel';
public static Go = 'Go';
public static containerACRRegistry = 'containerACRRegistry';
public static containerACRImage = 'containerACRImage';
public static containerACRTag = 'containerACRTag';
Expand Down
13 changes: 13 additions & 0 deletions client/src/app/shared/services/function-app.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import { Templates } from './../../function/embedded/temp-templates';
import { SiteService } from './site.service';
import { ExtensionJobsStatus } from '../models/extension-jobs-status';
import { ExtensionInfo, ExtensionsJson } from 'app/shared/models/extension-info';
import { RuntimeVersions } from 'app/shared/Utilities/runtime-versions';

type Result<T> = Observable<HttpResult<T>>;
@Injectable()
Expand Down Expand Up @@ -586,6 +587,18 @@ export class FunctionAppService {
.map(r => r.json() as HostStatus));
}

getWorkerRuntimeRequired(context: FunctionAppContext): Observable<boolean> {
return this.getFunctionHostStatus(context)
.map(r => {
if (r.isSuccessful) {
if (RuntimeVersions.workerRuntimeRequired(r.result.version)) {
return true;
}
}
return false;
});
}

getLogs(context: FunctionAppContext, fi: FunctionInfo, range?: number, force: boolean = false): Result<string> {
const url = context.urlTemplates.getFunctionLogUrl(fi.name);

Expand Down
13 changes: 12 additions & 1 deletion client/src/app/site/quickstart/quickstart.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,17 @@
</div>

<div *ngIf="!canUseQuickstart" class="no-quickstart">
<h2>**Text telling users to set the worker runtime in app settings**</h2>
<h3>{{ 'functionAppRuntimeStackDescription' | translate }}</h3>
<div class="runtime-set">
{{ 'functionRuntimeStackLabel' | translate }}
<drop-down class="runtime-dropdown"
[options]="possibleRuntimes"
(value)="onRuntimeChanged($event)"
attr.aria-label="{{ 'functionRuntimeStackLabel' | translate }}">
</drop-down>
<button class="custom-button"
(click)="setRuntime()">{{ 'Go' | translate }}
</button>
</div>
</div>
</ng-container>
16 changes: 16 additions & 0 deletions client/src/app/site/quickstart/quickstart.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,22 @@
padding-right: 25px;
}

.runtime-set{
width: 100%;
display: inline-flex;
align-items: center;
padding-bottom: 25px;
padding-top: 10px;
font-size: 12px;
}

.runtime-dropdown{
width: 200px;
height: 23px;
padding-left: 7px;
padding-right: 25px;
}

.form-button {
min-width: 114px;
height: 25px;
Expand Down
61 changes: 49 additions & 12 deletions client/src/app/site/quickstart/quickstart.component.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { workerRuntimeOptions } from './wizard-logic/quickstart-models';
import { devEnvironmentOptions } from 'app/site/quickstart/wizard-logic/quickstart-models';
import { ApplicationSettings } from './../../shared/models/arm/application-settings';
import { devEnvironmentOptions, workerRuntimeOptions } from 'app/site/quickstart/wizard-logic/quickstart-models';
import { SiteService } from './../../shared/services/site.service';
import { SiteTabIds, Constants } from 'app/shared/models/constants';
import { FunctionAppContextComponent } from 'app/shared/components/function-app-context-component';
Expand All @@ -18,6 +18,8 @@ import { UserService } from 'app/shared/services/user.service';
import { Subject } from 'rxjs/Subject';
import { ArmSiteDescriptor } from 'app/shared/resourceDescriptors';
import { Subscription as Subs} from 'app/shared/models/subscription';
import { ArmObj } from 'app/shared/models/arm/arm-obj';
import { DropDownElement } from 'app/shared/models/drop-down-element';

@Component({
selector: 'quickstart',
Expand All @@ -35,6 +37,17 @@ export class QuickstartComponent extends FunctionAppContextComponent implements
public loading = true;
public showDeploymentStep: boolean;
public devEnvironment: devEnvironmentOptions;
public appSettingsArm: ArmObj<ApplicationSettings>;
public runtime: string;
public possibleRuntimes: DropDownElement<string>[] =
[{
displayLabel: 'C#',
value: 'dotnet',
},
{
displayLabel: 'JavaScript',
value: 'node',
}];

private _ngUnsubscribe = new Subject();
private _busyManager: BusyStateScopeManager;
Expand Down Expand Up @@ -98,18 +111,12 @@ export class QuickstartComponent extends FunctionAppContextComponent implements
})
.subscribe(r => {
if (r.isSuccessful) {
const appSettingsArm = r.result;
if (appSettingsArm.properties.hasOwnProperty(Constants.functionsWorkerRuntimeAppSettingsName)) {
const workerRuntimeSetting = appSettingsArm.properties[Constants.functionsWorkerRuntimeAppSettingsName].toLowerCase();
this.appSettingsArm = r.result;
if (this.appSettingsArm.properties.hasOwnProperty(Constants.functionsWorkerRuntimeAppSettingsName)) {
const workerRuntimeSetting = this.appSettingsArm.properties[Constants.functionsWorkerRuntimeAppSettingsName].toLowerCase();

if (this._validWorkerRuntimes.indexOf(workerRuntimeSetting) !== -1) {
this.workerRuntime = workerRuntimeSetting as workerRuntimeOptions;
this.isLinux = ArmUtil.isLinuxApp(this.context.site);
this.isLinuxConsumption = ArmUtil.isLinuxDynamic(this.context.site);

this._setInitalProperties();
this._setQuickstartTitle();
this.canUseQuickstart = true;
this._useValidWorkerRuntime(workerRuntimeSetting);
} else {
this.canUseQuickstart = false;
}
Expand All @@ -128,6 +135,16 @@ export class QuickstartComponent extends FunctionAppContextComponent implements
});
}

private _useValidWorkerRuntime(workerRuntime: string) {
this.workerRuntime = workerRuntime as workerRuntimeOptions;
this.isLinux = ArmUtil.isLinuxApp(this.context.site);
this.isLinuxConsumption = ArmUtil.isLinuxDynamic(this.context.site);

this._setInitalProperties();
this._setQuickstartTitle();
this.canUseQuickstart = true;
}

private _setQuickstartTitle() {
switch (this.workerRuntime) {
case 'dotnet':
Expand Down Expand Up @@ -170,6 +187,26 @@ export class QuickstartComponent extends FunctionAppContextComponent implements
|| this.devEnvironment === 'coretools' && (!this.isLinux || this.isLinux && !this.isLinuxConsumption);
}

onRuntimeChanged(runtime: string) {
this.runtime = runtime;
}

setRuntime() {
this._busyManager.setBusy();

this.appSettingsArm.properties[Constants.functionsWorkerRuntimeAppSettingsName] = this.runtime;

this._siteService.updateAppSettings(this.context.site.id, this.appSettingsArm)
.do(null, e => {
this._busyManager.clearBusy();
this.showComponentError(e);
})
.subscribe(() => {
this._useValidWorkerRuntime(this.runtime);
this._busyManager.clearBusy();
});
}

ngOnDestroy() {
this._ngUnsubscribe.next();
}
Expand Down
12 changes: 12 additions & 0 deletions server/Resources/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -4039,6 +4039,18 @@ Set to "External URL" to use an API definition that is hosted elsewhere.</value>
<data name="v2_preview_label" xml:space="preserve">
<value>~2 (Preview)</value>
</data>
<data name="functionAppRuntimeStackTitle" xml:space="preserve">
<value>Function App runtime stack</value>
</data>
<data name="functionAppRuntimeStackDescription" xml:space="preserve">
<value>Function Apps v2 are now single language. Please set the runtime stack before adding functions to you app.</value>
</data>
<data name="functionRuntimeStackLabel" xml:space="preserve">
<value>Function Runtime stack</value>
</data>
<data name="Go" xml:space="preserve">
<value>Go</value>
</data>
<data name="containerACRRegistry" xml:space="preserve">
<value>Registry</value>
</data>
Expand Down

0 comments on commit 4cdf602

Please sign in to comment.