diff --git a/client/src/app/ctl/config/config-context/config-context.component.css b/client/src/app/ctl/config/config-context/config-context.component.css
new file mode 100644
index 0000000..7318c2c
--- /dev/null
+++ b/client/src/app/ctl/config/config-context/config-context.component.css
@@ -0,0 +1,17 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+.grey-icon {
+ color: grey;
+}
diff --git a/client/src/app/ctl/config/config-context/config-context.component.html b/client/src/app/ctl/config/config-context/config-context.component.html
new file mode 100644
index 0000000..0fb1ec4
--- /dev/null
+++ b/client/src/app/ctl/config/config-context/config-context.component.html
@@ -0,0 +1,36 @@
+
+
+
+ {{context.name}}
+
+
+
+
+
ContextKubeconf:
+
+
+
+
+
Manifest:
+
+
+
+
+
EncryptionConfig:
+
+
+
+
+
ManagementConfiguration:
+
+
+
+
+
+
+
+
+
diff --git a/client/src/app/ctl/config/config-context/config-context.component.spec.ts b/client/src/app/ctl/config/config-context/config-context.component.spec.ts
new file mode 100644
index 0000000..aca76d7
--- /dev/null
+++ b/client/src/app/ctl/config/config-context/config-context.component.spec.ts
@@ -0,0 +1,62 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { ToastrModule } from 'ngx-toastr';
+import { Context } from '../config.models';
+
+import { ConfigContextComponent } from './config-context.component';
+
+describe('ConfigContextComponent', () => {
+ let component: ConfigContextComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ConfigContextComponent ],
+ imports: [
+ BrowserAnimationsModule,
+ MatCardModule,
+ FormsModule,
+ MatInputModule,
+ MatIconModule,
+ MatCheckboxModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ ToastrModule.forRoot()
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ConfigContextComponent);
+ component = fixture.componentInstance;
+
+ component.context = new Context();
+
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/client/src/app/ctl/config/config-context/config-context.component.ts b/client/src/app/ctl/config/config-context/config-context.component.ts
new file mode 100644
index 0000000..0bc5fac
--- /dev/null
+++ b/client/src/app/ctl/config/config-context/config-context.component.ts
@@ -0,0 +1,84 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { Component, OnInit, Input } from '@angular/core';
+import { Context, ContextOptions } from '../config.models';
+import { WebsocketService } from '../../../../services/websocket/websocket.service';
+import { FormControl } from '@angular/forms';
+import { WebsocketMessage } from 'src/services/websocket/websocket.models';
+
+@Component({
+ selector: 'app-config-context',
+ templateUrl: './config-context.component.html',
+ styleUrls: ['./config-context.component.css']
+})
+export class ConfigContextComponent implements OnInit {
+ @Input() context: Context;
+ type = 'ctl';
+ component = 'config';
+
+ locked = true;
+
+ name = new FormControl({value: '', disabled: true});
+ contextKubeconf = new FormControl({value: '', disabled: true});
+ manifest = new FormControl({value: '', disabled: true});
+ managementConfiguration = new FormControl({value: '', disabled: true});
+ encryptionConfig = new FormControl({value: '', disabled: true});
+
+ controlsArray = [this.name, this.contextKubeconf, this.manifest, this.managementConfiguration, this.encryptionConfig];
+
+ constructor(private websocketService: WebsocketService) {}
+
+ ngOnInit(): void {
+ this.name.setValue(this.context.name);
+ this.contextKubeconf.setValue(this.context.contextKubeconf);
+ this.manifest.setValue(this.context.manifest);
+ this.encryptionConfig.setValue(this.context.encryptionConfig);
+ this.managementConfiguration.setValue(this.context.managementConfiguration);
+ }
+
+ toggleLock(): void {
+ for (const control of this.controlsArray) {
+ if (this.locked) {
+ control.enable();
+ } else {
+ control.disable();
+ }
+ }
+
+ this.locked = !this.locked;
+ }
+
+ setContext(): void {
+ const opts: ContextOptions = {
+ Name: this.name.value,
+ Manifest: this.manifest.value,
+ ManagementConfiguration: this.managementConfiguration.value,
+ EncryptionConfig: this.encryptionConfig.value,
+ };
+
+ const msg = new WebsocketMessage(this.type, this.component, 'setContext');
+ msg.data = JSON.parse(JSON.stringify(opts));
+ msg.name = this.name.value;
+
+ this.websocketService.sendMessage(msg);
+ this.toggleLock();
+ }
+
+ useContext(name: string): void {
+ const msg = new WebsocketMessage(this.type, this.component, 'useContext');
+ msg.name = name;
+ this.websocketService.sendMessage(msg);
+ }
+}
diff --git a/client/src/app/ctl/config/config-context/config-context.module.ts b/client/src/app/ctl/config/config-context/config-context.module.ts
new file mode 100644
index 0000000..464f851
--- /dev/null
+++ b/client/src/app/ctl/config/config-context/config-context.module.ts
@@ -0,0 +1,34 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatInputModule } from '@angular/material/input';
+
+
+@NgModule({
+ imports: [
+ FormsModule,
+ MatInputModule,
+ MatCardModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ ],
+ declarations: [
+ ],
+ providers: []
+ })
+ export class ConfigContextModule { }
diff --git a/client/src/app/ctl/config/config-encryption/config-encryption.component.css b/client/src/app/ctl/config/config-encryption/config-encryption.component.css
new file mode 100644
index 0000000..abc1f3f
--- /dev/null
+++ b/client/src/app/ctl/config/config-encryption/config-encryption.component.css
@@ -0,0 +1,17 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+.grey-icon {
+ color: grey;
+}
\ No newline at end of file
diff --git a/client/src/app/ctl/config/config-encryption/config-encryption.component.html b/client/src/app/ctl/config/config-encryption/config-encryption.component.html
new file mode 100644
index 0000000..8a66b53
--- /dev/null
+++ b/client/src/app/ctl/config/config-encryption/config-encryption.component.html
@@ -0,0 +1,39 @@
+
+
+
+ {{config.name}}
+
+
+
+
+
EncryptionKeyPath:
+
+
+
+
+
DecryptionKeyPath:
+
+
+
+
+
+
+
KeySecretName:
+
+
+
+
+
KeySecretNamespace:
+
+
+
+
+
+
+
+
+
+
diff --git a/client/src/app/ctl/config/config-encryption/config-encryption.component.spec.ts b/client/src/app/ctl/config/config-encryption/config-encryption.component.spec.ts
new file mode 100644
index 0000000..c9395d5
--- /dev/null
+++ b/client/src/app/ctl/config/config-encryption/config-encryption.component.spec.ts
@@ -0,0 +1,62 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { ToastrModule } from 'ngx-toastr';
+import { EncryptionConfig } from '../config.models';
+
+import { ConfigEncryptionComponent } from './config-encryption.component';
+
+describe('ConfigEncryptionComponent', () => {
+ let component: ConfigEncryptionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ConfigEncryptionComponent ],
+ imports: [
+ BrowserAnimationsModule,
+ FormsModule,
+ MatCardModule,
+ MatInputModule,
+ MatIconModule,
+ MatCheckboxModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ ToastrModule.forRoot()
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ConfigEncryptionComponent);
+ component = fixture.componentInstance;
+
+ component.config = new EncryptionConfig();
+
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/client/src/app/ctl/config/config-encryption/config-encryption.component.ts b/client/src/app/ctl/config/config-encryption/config-encryption.component.ts
new file mode 100644
index 0000000..7e18471
--- /dev/null
+++ b/client/src/app/ctl/config/config-encryption/config-encryption.component.ts
@@ -0,0 +1,79 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { Component, OnInit, Input } from '@angular/core';
+import { FormControl } from '@angular/forms';
+import { EncryptionConfig, EncryptionConfigOptions } from '../config.models';
+import { WebsocketService } from '../../../../services/websocket/websocket.service';
+import { WebsocketMessage } from '../../../../services/websocket/websocket.models';
+
+@Component({
+ selector: 'app-config-encryption',
+ templateUrl: './config-encryption.component.html',
+ styleUrls: ['./config-encryption.component.css']
+})
+export class ConfigEncryptionComponent implements OnInit {
+ @Input() config: EncryptionConfig;
+ type = 'ctl';
+ component = 'config';
+
+ locked = true;
+ name = new FormControl({value: '', disabled: true});
+ encryptionKeyPath = new FormControl({value: '', disabled: true});
+ decryptionKeyPath = new FormControl({value: '', disabled: true});
+ keySecretName = new FormControl({value: '', disabled: true});
+ keySecretNamespace = new FormControl({value: '', disabled: true});
+
+ controlsArray = [this.encryptionKeyPath, this.decryptionKeyPath, this.keySecretName, this.keySecretNamespace];
+
+ constructor(private websocketService: WebsocketService) {}
+
+ ngOnInit(): void {
+ this.name.setValue(this.config.name);
+ this.encryptionKeyPath.setValue(this.config.encryptionKeyPath);
+ this.decryptionKeyPath.setValue(this.config.decryptionKeyPath);
+ this.keySecretName.setValue(this.config.keySecretName);
+ this.keySecretNamespace.setValue(this.config.keySecretNamespace);
+ }
+
+ toggleLock(): void {
+ for (const control of this.controlsArray) {
+ if (this.locked) {
+ control.enable();
+ } else {
+ control.disable();
+ }
+ }
+
+ this.locked = !this.locked;
+ }
+
+ setEncryptionConfig(): void {
+ const opts: EncryptionConfigOptions = {
+ Name: this.name.value,
+ EncryptionKeyPath: this.encryptionKeyPath.value,
+ DecryptionKeyPath: this.decryptionKeyPath.value,
+ KeySecretName: this.keySecretName.value,
+ KeySecretNamespace: this.keySecretNamespace.value,
+ };
+
+ const msg = new WebsocketMessage(this.type, this.component, 'setEncryptionConfig');
+ msg.data = JSON.parse(JSON.stringify(opts));
+ msg.name = this.name.value;
+
+ this.websocketService.sendMessage(msg);
+ this.toggleLock();
+ }
+
+}
diff --git a/client/src/app/ctl/config/config-encryption/config-encryption.module.ts b/client/src/app/ctl/config/config-encryption/config-encryption.module.ts
new file mode 100644
index 0000000..11f3f95
--- /dev/null
+++ b/client/src/app/ctl/config/config-encryption/config-encryption.module.ts
@@ -0,0 +1,34 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatInputModule } from '@angular/material/input';
+import { MatCardModule } from '@angular/material/card';
+
+
+@NgModule({
+ imports: [
+ FormsModule,
+ MatInputModule,
+ MatCardModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ ],
+ declarations: [
+ ],
+ providers: []
+ })
+ export class ConfigEncryptionModule { }
diff --git a/client/src/app/ctl/config/config-management/config-management.component.css b/client/src/app/ctl/config/config-management/config-management.component.css
new file mode 100644
index 0000000..7318c2c
--- /dev/null
+++ b/client/src/app/ctl/config/config-management/config-management.component.css
@@ -0,0 +1,17 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+.grey-icon {
+ color: grey;
+}
diff --git a/client/src/app/ctl/config/config-management/config-management.component.html b/client/src/app/ctl/config/config-management/config-management.component.html
new file mode 100644
index 0000000..ea47225
--- /dev/null
+++ b/client/src/app/ctl/config/config-management/config-management.component.html
@@ -0,0 +1,36 @@
+
+
+
+ {{config.name}}
+
+
+
+
+ Insecure:
+
+
SystemActionRetries:
+
+
+
+
+
SystemRebootDelay:
+
+
+
+
+
Type:
+
+
+
+
+
+ UseProxy:
+
+
+
+
+
+
diff --git a/client/src/app/ctl/config/config-management/config-management.component.spec.ts b/client/src/app/ctl/config/config-management/config-management.component.spec.ts
new file mode 100644
index 0000000..6fba7d5
--- /dev/null
+++ b/client/src/app/ctl/config/config-management/config-management.component.spec.ts
@@ -0,0 +1,62 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { ToastrModule } from 'ngx-toastr';
+import { ManagementConfig } from '../config.models';
+
+import { ConfigManagementComponent } from './config-management.component';
+
+describe('ConfigManagementComponent', () => {
+ let component: ConfigManagementComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ConfigManagementComponent ],
+ imports: [
+ BrowserAnimationsModule,
+ MatCardModule,
+ FormsModule,
+ MatInputModule,
+ MatIconModule,
+ MatCheckboxModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ ToastrModule.forRoot(),
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ConfigManagementComponent);
+ component = fixture.componentInstance;
+
+ component.config = new ManagementConfig();
+
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/client/src/app/ctl/config/config-management/config-management.component.ts b/client/src/app/ctl/config/config-management/config-management.component.ts
new file mode 100644
index 0000000..7c5f699
--- /dev/null
+++ b/client/src/app/ctl/config/config-management/config-management.component.ts
@@ -0,0 +1,84 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { Component, Input, OnInit } from '@angular/core';
+import { ManagementConfig } from '../config.models';
+import { FormControl, Validators } from '@angular/forms';
+import { WebsocketService } from 'src/services/websocket/websocket.service';
+import { WebsocketMessage } from 'src/services/websocket/websocket.models';
+
+@Component({
+ selector: 'app-config-management',
+ templateUrl: './config-management.component.html',
+ styleUrls: ['./config-management.component.css']
+})
+export class ConfigManagementComponent implements OnInit {
+ @Input() config: ManagementConfig;
+ msgType = 'ctl';
+ component = 'config';
+
+ locked = true;
+
+ name = new FormControl({value: '', disabled: true});
+ insecure = new FormControl({value: false, disabled: true});
+ systemActionRetries = new FormControl({value: '', disabled: true}, Validators.pattern('[0-9]*'));
+ systemRebootDelay = new FormControl({value: '', disabled: true}, Validators.pattern('[0-9]*'));
+ type = new FormControl({value: '', disabled: true});
+ useproxy = new FormControl({value: false, disabled: true});
+
+ controlsArray = [this.name, this.insecure, this.systemRebootDelay, this.systemActionRetries, this.type, this.useproxy];
+
+ constructor(private websocketService: WebsocketService) { }
+
+ ngOnInit(): void {
+ this.name.setValue(this.config.name);
+ this.insecure.setValue(this.config.insecure);
+ this.systemActionRetries.setValue(this.config.systemActionRetries);
+ this.systemRebootDelay.setValue(this.config.systemRebootDelay);
+ this.type.setValue(this.config.type);
+ this.useproxy.setValue(this.config.useproxy);
+ }
+
+ toggleLock(): void {
+ for (const control of this.controlsArray) {
+ if (this.locked) {
+ control.enable();
+ } else {
+ control.disable();
+ }
+ }
+
+ this.locked = !this.locked;
+ }
+
+ setManagementConfig(): void {
+ const msg = new WebsocketMessage(this.msgType, this.component, 'setManagementConfig');
+ msg.name = this.name.value;
+
+ const cfg: ManagementConfig = {
+ name: this.name.value,
+ insecure: this.insecure.value,
+ // TODO(mfuller): need to validate these are numerical values in the form
+ systemActionRetries: +this.systemActionRetries.value,
+ systemRebootDelay: +this.systemRebootDelay.value,
+ type: this.type.value,
+ useproxy: this.useproxy.value
+ };
+
+ msg.data = JSON.parse(JSON.stringify(cfg));
+ this.websocketService.sendMessage(msg);
+ this.toggleLock();
+ }
+
+}
diff --git a/client/src/app/ctl/config/config-management/config-management.module.ts b/client/src/app/ctl/config/config-management/config-management.module.ts
new file mode 100644
index 0000000..e65c8a8
--- /dev/null
+++ b/client/src/app/ctl/config/config-management/config-management.module.ts
@@ -0,0 +1,38 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatInputModule } from '@angular/material/input';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatIconModule } from '@angular/material/icon';
+
+
+@NgModule({
+ imports: [
+ FormsModule,
+ MatInputModule,
+ MatCardModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ MatCheckboxModule,
+ MatIconModule
+ ],
+ declarations: [
+ ],
+ providers: []
+ })
+ export class ConfigManagementModule { }
diff --git a/client/src/app/ctl/config/config-manifest/config-manifest.component.css b/client/src/app/ctl/config/config-manifest/config-manifest.component.css
new file mode 100644
index 0000000..7318c2c
--- /dev/null
+++ b/client/src/app/ctl/config/config-manifest/config-manifest.component.css
@@ -0,0 +1,17 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+.grey-icon {
+ color: grey;
+}
diff --git a/client/src/app/ctl/config/config-manifest/config-manifest.component.html b/client/src/app/ctl/config/config-manifest/config-manifest.component.html
new file mode 100644
index 0000000..5868f7b
--- /dev/null
+++ b/client/src/app/ctl/config/config-manifest/config-manifest.component.html
@@ -0,0 +1,66 @@
+
+
+
+ {{manifest.name}}
+
+
+
+
RepoName:
+
+
+
+
+
URL:
+
+
+
+
+
Branch:
+
+
+
+
+
CommitHash:
+
+
+
+
+
Tag:
+
+
+
+
+
RemoteRef:
+
+
+
+
+
+ Force:
+
+
+ IsPhase:
+
+
SubPath:
+
+
+
+
+
TargetPath:
+
+
+
+
+
MetadataPath:
+
+
+
+
+
+
+
+
+
diff --git a/client/src/app/ctl/config/config-manifest/config-manifest.component.spec.ts b/client/src/app/ctl/config/config-manifest/config-manifest.component.spec.ts
new file mode 100644
index 0000000..d3b4d3c
--- /dev/null
+++ b/client/src/app/ctl/config/config-manifest/config-manifest.component.spec.ts
@@ -0,0 +1,68 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatIconModule } from '@angular/material/icon';
+import { MatInputModule } from '@angular/material/input';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { ToastrModule } from 'ngx-toastr';
+import { CtlManifest, Manifest, RepoCheckout, Repository } from '../config.models';
+
+import { ConfigManifestComponent } from './config-manifest.component';
+
+describe('ConfigManifestComponent', () => {
+ let component: ConfigManifestComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ConfigManifestComponent ],
+ imports: [
+ BrowserAnimationsModule,
+ MatCardModule,
+ FormsModule,
+ MatInputModule,
+ MatIconModule,
+ MatCheckboxModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ ToastrModule.forRoot()
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ConfigManifestComponent);
+ component = fixture.componentInstance;
+
+ component.manifest = new Manifest();
+ component.manifest.manifest = new CtlManifest();
+ const repoName = 'fakerepo';
+ component.manifest.manifest.phaseRepositoryName = repoName;
+ component.manifest.manifest.repositories = {};
+ component.manifest.manifest.repositories[repoName] = new Repository();
+ component.manifest.manifest.repositories[repoName].checkout = new RepoCheckout();
+
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/client/src/app/ctl/config/config-manifest/config-manifest.component.ts b/client/src/app/ctl/config/config-manifest/config-manifest.component.ts
new file mode 100644
index 0000000..0302b44
--- /dev/null
+++ b/client/src/app/ctl/config/config-manifest/config-manifest.component.ts
@@ -0,0 +1,127 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { Component, Input, OnInit } from '@angular/core';
+import { Manifest, ManifestOptions, Repository } from '../config.models';
+import { FormControl } from '@angular/forms';
+import { WebsocketService } from 'src/services/websocket/websocket.service';
+import { WebsocketMessage } from 'src/services/websocket/websocket.models';
+
+
+@Component({
+ selector: 'app-config-manifest',
+ templateUrl: './config-manifest.component.html',
+ styleUrls: ['./config-manifest.component.css']
+})
+export class ConfigManifestComponent implements OnInit {
+ @Input() manifest: Manifest;
+
+ type = 'ctl';
+ component = 'config';
+
+ locked = true;
+ Name = new FormControl({value: '', disabled: true});
+ RepoName = new FormControl({value: '', disabled: true});
+ URL = new FormControl({value: '', disabled: true});
+ Branch = new FormControl({value: '', disabled: true});
+ CommitHash = new FormControl({value: '', disabled: true});
+ Tag = new FormControl({value: '', disabled: true});
+ RemoteRef = new FormControl({value: '', disabled: true});
+ Force = new FormControl({value: false, disabled: true});
+ IsPhase = new FormControl({value: false, disabled: true});
+ SubPath = new FormControl({value: '', disabled: true});
+ TargetPath = new FormControl({value: '', disabled: true});
+ MetadataPath = new FormControl({value: '', disabled: true});
+
+ controlsArray = [
+ this.Name,
+ this.RepoName,
+ this.URL,
+ this.Branch,
+ this.CommitHash,
+ this.Tag,
+ this.RemoteRef,
+ this.Force,
+ this.IsPhase,
+ this.SubPath,
+ this.TargetPath,
+ this.MetadataPath
+ ];
+
+ constructor(private websocketService: WebsocketService) { }
+
+ ngOnInit(): void {
+ this.Name.setValue(this.manifest.name);
+
+ // TODO(mfuller): not sure yet how to handle multiple repositories,
+ // so for now, I'm just showing the phase repository (primary)
+ const repoName = this.manifest.manifest.phaseRepositoryName;
+ this.RepoName.setValue(repoName);
+ const primaryRepo: Repository = this.manifest.manifest.repositories[repoName];
+ this.URL.setValue(primaryRepo.url);
+ this.Branch.setValue(primaryRepo.checkout.branch);
+ this.CommitHash.setValue(primaryRepo.checkout.commitHash);
+ this.Tag.setValue(primaryRepo.checkout.tag);
+ this.RemoteRef.setValue(primaryRepo.checkout.remoteRef);
+ this.Force.setValue(primaryRepo.checkout.force);
+ // TODO(mfuller): this value doesn't come from the config file, but if set to true,
+ // it appears to set the phaseRepositoryName key, and since that's
+ // the only repo I'm showing, set to true for now
+ this.IsPhase.setValue(true);
+ this.SubPath.setValue(this.manifest.manifest.subPath);
+ this.TargetPath.setValue(this.manifest.manifest.targetPath);
+ this.MetadataPath.setValue(this.manifest.manifest.metadataPath);
+ }
+
+ toggleLock(): void {
+ for (const control of this.controlsArray) {
+ if (this.locked) {
+ control.enable();
+ } else {
+ control.disable();
+ }
+ }
+
+ this.locked = !this.locked;
+ }
+
+ setManifest(): void {
+ const msg = new WebsocketMessage(this.type, this.component, 'setManifest');
+ msg.name = this.manifest.name;
+
+ // TODO(mfuller): since "Force" and "IsPhase" can only be set by passing in
+ // CLI flags rather than passing in values, there doesn't appear to be a way
+ // to unset them once they're true without manually editing the config file.
+ // Open a bug for this? Or is this intentional? I may have to write a custom
+ // setter to set the value directly in the Config struct
+ const opts: ManifestOptions = {
+ Name: this.Name.value,
+ RepoName: this.RepoName.value,
+ URL: this.URL.value,
+ Branch: this.Branch.value,
+ CommitHash: this.CommitHash.value,
+ Tag: this.Tag.value,
+ RemoteRef: this.RemoteRef.value,
+ Force: this.Force.value,
+ IsPhase: this.IsPhase.value,
+ SubPath: this.SubPath.value,
+ TargetPath: this.TargetPath.value,
+ MetadataPath: this.MetadataPath.value
+ };
+
+ msg.data = JSON.parse(JSON.stringify(opts));
+ this.websocketService.sendMessage(msg);
+ this.toggleLock();
+ }
+}
diff --git a/client/src/app/ctl/config/config-manifest/config-manifest.module.ts b/client/src/app/ctl/config/config-manifest/config-manifest.module.ts
new file mode 100644
index 0000000..fcf3a69
--- /dev/null
+++ b/client/src/app/ctl/config/config-manifest/config-manifest.module.ts
@@ -0,0 +1,36 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+import { NgModule } from '@angular/core';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { MatButtonModule } from '@angular/material/button';
+import { MatCardModule } from '@angular/material/card';
+import { MatCheckboxModule } from '@angular/material/checkbox';
+import { MatInputModule } from '@angular/material/input';
+
+
+@NgModule({
+ imports: [
+ FormsModule,
+ MatInputModule,
+ MatCardModule,
+ MatButtonModule,
+ ReactiveFormsModule,
+ MatCheckboxModule
+ ],
+ declarations: [
+ ],
+ providers: []
+ })
+ export class ConfigManifestModule { }
diff --git a/client/src/app/ctl/config/config.component.css b/client/src/app/ctl/config/config.component.css
new file mode 100644
index 0000000..396bd76
--- /dev/null
+++ b/client/src/app/ctl/config/config.component.css
@@ -0,0 +1,17 @@
+/*
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+*/
+
+.grey-icon {
+ color: grey;
+}
diff --git a/client/src/app/ctl/config/config.component.html b/client/src/app/ctl/config/config.component.html
index e1367b0..18d7f13 100755
--- a/client/src/app/ctl/config/config.component.html
+++ b/client/src/app/ctl/config/config.component.html
@@ -1 +1,26 @@
-