Merge pull request #45 from MycroftAI/test

Ability to show and apply Pantacor software updates
pull/57/head
Chris Veilleux 2021-02-17 16:20:02 -06:00 committed by GitHub
commit 3813c24529
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 178 additions and 36 deletions

View File

@ -28,6 +28,7 @@ const routes: Routes = [
{ path: 'dashboard', component: DashboardComponent, resolve: {account: AccountResolverService} },
{ path: 'maintenance', component: MaintenancePageComponent},
{ path: '', redirectTo: '/dashboard', pathMatch: 'full'},
{ path: 'pair', redirectTo: '/devices/add', pathMatch: 'full'},
{ path: '**', component: PageNotFoundComponent }
];

View File

@ -31,6 +31,7 @@ const deviceUrl = '/api/devices';
const geographyUrl = 'api/geographies';
const pairingCodeUrl = '/api/pairing-code';
const preferencesUrl = '/api/preferences';
const softwareUpdateUrl = '/api/software-update';
const voicesUrl = '/api/voices';
const wakeWordUrl = '/api/wake-words';
@ -100,4 +101,8 @@ export class DeviceService {
getWakeWords() {
return this.http.get<DeviceAttribute[]>(wakeWordUrl);
}
applySoftwareUpdate(pantacorUpdateId: string) {
return this.http.patch<any>(softwareUpdateUrl, {deploymentId: pantacorUpdateId});
}
}

View File

@ -11,13 +11,18 @@
[value]="getPlatform(device)"
>
</account-display-field>
<account-display-field
<account-display-field *ngIf="device.platform === 'mycroft_mark_1'"
[label]="'Enclosure Version'"
[value]="device.enclosureVersion"
>
</account-display-field>
<account-display-field *ngIf="device.platform === 'mycroft_mark_2'"
[label]="'Hardware Version'"
[value]="device.enclosureVersion"
>
</account-display-field>
<account-display-field
[label]="'Core Version'"
[label]="'Mycroft Version'"
[value]="device.coreVersion"
>
</account-display-field>
@ -26,6 +31,14 @@
[value]="device.pantacorConfig.ipAddress"
>
</account-display-field>
<button
mat-flat-button
*ngIf="device.pantacorConfig.autoUpdate === false" (click)="applySoftwareUpdate()"
fxFlex
[disabled]="softwareUpdateDisabled"
>
{{softwareUpdateText}}
</button>
</mat-card-content>
</mat-tab>

View File

@ -1,6 +1,14 @@
@import "~@angular/material/theming";
@import 'mycroft-colors';
@import 'components/buttons';
mat-tab-group {
mat-card-content {
margin-top: 32px;
height: 180px;
button {
@include action-button-primary;
background-color: mat-color($mycroft-accent, 'A100');
}
}
}

View File

@ -17,10 +17,13 @@ and limitations under the License.
***************************************************************************** */
import { Component, Input, OnInit } from '@angular/core';
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
import { faInfoCircle, faCog, faMapMarkerAlt } from '@fortawesome/free-solid-svg-icons';
import { Device } from '@account/models/device.model';
import { DeviceService } from '@account/http/device.service';
import { SnackbarComponent } from 'shared';
@Component({
selector: 'account-device-info',
@ -38,10 +41,22 @@ export class DeviceDisplayComponent implements OnInit {
public infoIcon = faInfoCircle;
public configIcon = faCog;
public locationIcon = faMapMarkerAlt;
public softwareUpdateText: string;
public softwareUpdateDisabled: boolean;
constructor() { }
constructor(
private deviceService: DeviceService,
private snackbar: MatSnackBar
) { }
ngOnInit() {
if (!this.device.pantacorUpdateId) {
this.softwareUpdateText = 'NO UPDATES AVAILABLE';
this.softwareUpdateDisabled = true;
} else {
this.softwareUpdateText = 'APPLY SOFTWARE UPDATE';
this.softwareUpdateDisabled = false;
}
}
getPlatform(device: Device) {
@ -49,4 +64,29 @@ export class DeviceDisplayComponent implements OnInit {
return knownPlatform ? knownPlatform.displayName : device.platform;
}
openErrorSnackbar() {
const config = new MatSnackBarConfig();
config.data = {type: 'error', message: 'An error occurred, device will not be updated.'};
this.snackbar.openFromComponent(SnackbarComponent, config);
}
openSuccessSnackbar() {
const config = new MatSnackBarConfig();
config.duration = 3000;
config.data = {type: 'success', message: 'The update will be applied to your device momentarily'};
this.snackbar.openFromComponent(SnackbarComponent, config);
}
applySoftwareUpdate() {
this.deviceService.applySoftwareUpdate(this.device.pantacorUpdateId).subscribe(
() => {
this.openSuccessSnackbar();
this.softwareUpdateText = 'NO UPDATES AVAILABLE';
this.softwareUpdateDisabled = true;
},
() => { this.openErrorSnackbar(); }
);
}
}

View File

@ -37,9 +37,17 @@
<account-geography-card [geoForm]="deviceForm" [required]="true"></account-geography-card>
<account-voice-card [voiceForm]="deviceForm"></account-voice-card>
<account-wake-word-card [wakeWordForm]="deviceForm"></account-wake-word-card>
<account-software-release-card [softwareReleaseForm]="deviceForm"></account-software-release-card>
<account-software-update-card [softwareUpdateForm]="deviceForm"></account-software-update-card>
<account-ssh-card [sshForm]="deviceForm"></account-ssh-card>
<account-software-release-card
*ngIf="pantacorId"
[softwareReleaseForm]="deviceForm"
>
</account-software-release-card>
<account-software-update-card
*ngIf="pantacorId"
[softwareUpdateForm]="deviceForm"
>
</account-software-update-card>
<account-ssh-card *ngIf="pantacorId" [sshForm]="deviceForm"></account-ssh-card>
</mat-card-content>
<mat-card-actions *ngIf=!addDevice align="right">

View File

@ -27,6 +27,7 @@ import { FormGroup } from '@angular/forms';
export class DeviceEditCardComponent implements OnInit {
@Input() deviceForm: FormGroup;
@Input() addDevice = false;
@Input() pantacorId: string;
@Output() saveChanges = new EventEmitter<boolean>();
constructor() { }

View File

@ -2,6 +2,7 @@
*ngIf="device$ | async"
[deviceForm]="deviceForm"
[addDevice]="false"
[pantacorId]="pantacorId"
(saveChanges)="onExit($event)"
>
</account-device-edit-card>

View File

@ -38,6 +38,7 @@ export class DeviceEditComponent implements OnInit {
public deviceForm: FormGroup;
private deviceId: string;
public device$ = new Observable<Device>();
public pantacorId: string;
private snackbarConfig = new MatSnackBarConfig();
constructor(
@ -57,6 +58,7 @@ export class DeviceEditComponent implements OnInit {
switchMap((params: ParamMap) => this.deviceService.getDevice(params.get('deviceId'))),
tap((device) => {
this.deviceId = device.id;
this.pantacorId = device.pantacorConfig.pantacorId;
this.buildDeviceForm(device);
})
);

View File

@ -6,7 +6,7 @@
fxLayoutAlign="start center"
routerLink="/devices/add"
>
<img src="../assets/generic-device-icon-blue.svg">
<img src="../assets/generic-device-icon-white.svg">
<span fxFlex class="mat-h2">ADD DEVICE</span>
<fa-icon class="mat-h2" [icon]="addIcon"></fa-icon>
</div>
@ -49,9 +49,6 @@
<button mat-flat-button color="warn" (click)="onRemove(device, i)">
REMOVE
</button>
<button mat-flat-button color="accent" [disabled]="true" (click)="onRemove(device, i)">
UPDATE
</button>
</mat-card-actions>
</mat-card>
</div>

View File

@ -22,7 +22,7 @@
}
img {
height: 32px;
height: 48px;
margin-left: 16px;
margin-right: 16px;
}

View File

@ -95,6 +95,6 @@ export class DeviceListComponent implements OnInit {
getDeviceIcon(device: Device) {
const knownPlatform = this.platforms[device.platform];
return knownPlatform ? knownPlatform.icon : '../assets/generic-device-icon-white.svg';
return knownPlatform ? knownPlatform.icon : '../assets/generic-device-icon-blue.svg';
}
}

View File

@ -40,4 +40,5 @@ export interface Device {
voice: Voice;
wakeWord: WakeWord;
pantacorConfig: PantacorConfig;
pantacorUpdateId: string;
}

View File

@ -17,7 +17,7 @@ and limitations under the License.
***************************************************************************** */
export interface PantacorConfig {
autoUpdate: string;
autoUpdate: boolean;
ipAddress: string;
pantacorId: string;
sshPublicKey: string;

View File

@ -1,10 +1,18 @@
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="60" height="60" fill="#22A7F0"/>
<rect x="19" y="11" width="22" height="38" rx="8" fill="white"/>
<rect x="16.5" y="8.5" width="27" height="43" rx="9.5" stroke="white"/>
<line x1="30" y1="38" x2="30" y2="22" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<line x1="33" y1="35" x2="33" y2="25" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<line x1="24" y1="32" x2="24" y2="28" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<line x1="27" y1="35" x2="27" y2="25" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<line x1="36" y1="32" x2="36" y2="28" stroke="#22A7F0" stroke-width="2" stroke-linecap="round"/>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 60 60" style="enable-background:new 0 0 60 60;" xml:space="preserve">
<style type="text/css">
.st0{fill:#5B6984;}
.st1{fill:none;stroke:#5B6984;}
.st2{fill:none;stroke:#FFFFFF;stroke-width:2;stroke-linecap:round;}
</style>
<path class="st0" d="M49,27v6c0,4.4-3.6,8-8,8H19c-4.4,0-8-3.6-8-8v-6c0-4.4,3.6-8,8-8h22C45.4,19,49,22.6,49,27z"/>
<path class="st1" d="M51.5,26v8c0,5.2-4.3,9.5-9.5,9.5H18c-5.2,0-9.5-4.3-9.5-9.5v-8c0-5.2,4.3-9.5,9.5-9.5h24
C47.2,16.5,51.5,20.8,51.5,26z"/>
<line class="st2" x1="30" y1="38" x2="30" y2="22"/>
<line class="st2" x1="33" y1="35" x2="33" y2="25"/>
<line class="st2" x1="24" y1="32" x2="24" y2="28"/>
<line class="st2" x1="27" y1="35" x2="27" y2="25"/>
<line class="st2" x1="36" y1="32" x2="36" y2="28"/>
</svg>

Before

Width:  |  Height:  |  Size: 771 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,10 +1,18 @@
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="60" height="60" fill="white"/>
<rect x="19" y="11" width="22" height="38" rx="8" fill="#5B6984"/>
<rect x="16.5" y="8.5" width="27" height="43" rx="9.5" stroke="#5B6984"/>
<line x1="30" y1="38" x2="30" y2="22" stroke="white" stroke-width="2" stroke-linecap="round"/>
<line x1="33" y1="35" x2="33" y2="25" stroke="white" stroke-width="2" stroke-linecap="round"/>
<line x1="24" y1="32" x2="24" y2="28" stroke="white" stroke-width="2" stroke-linecap="round"/>
<line x1="27" y1="35" x2="27" y2="25" stroke="white" stroke-width="2" stroke-linecap="round"/>
<line x1="36" y1="32" x2="36" y2="28" stroke="white" stroke-width="2" stroke-linecap="round"/>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 60 60" style="enable-background:new 0 0 60 60;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:none;stroke:#FFFFFF;}
.st2{fill:#FFFFFF;stroke:#5B6984;stroke-width:2;stroke-linecap:round;}
</style>
<path class="st0" d="M49,27v6c0,4.4-3.6,8-8,8H19c-4.4,0-8-3.6-8-8v-6c0-4.4,3.6-8,8-8h22C45.4,19,49,22.6,49,27z"/>
<path class="st1" d="M51.5,26v8c0,5.2-4.3,9.5-9.5,9.5H18c-5.2,0-9.5-4.3-9.5-9.5v-8c0-5.2,4.3-9.5,9.5-9.5h24
C47.2,16.5,51.5,20.8,51.5,26z"/>
<line class="st2" x1="30" y1="38" x2="30" y2="22"/>
<line class="st2" x1="33" y1="35" x2="33" y2="25"/>
<line class="st2" x1="24" y1="32" x2="24" y2="28"/>
<line class="st2" x1="27" y1="35" x2="27" y2="25"/>
<line class="st2" x1="36" y1="32" x2="36" y2="28"/>
</svg>

Before

Width:  |  Height:  |  Size: 763 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -1,6 +1,55 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19.52 29.8869C19.4771 30.5082 19.3766 31.1241 19.22 31.7269C19.2264 31.7532 19.2264 31.7806 19.22 31.8069C19.0677 32.3492 18.8874 32.8832 18.68 33.4069C18.57 33.6669 18.43 33.9369 18.29 34.1969C18.1326 34.4505 17.9554 34.6913 17.76 34.9169C17.5849 35.1432 17.3676 35.3334 17.12 35.4769C16.8678 35.6114 16.5858 35.6802 16.3 35.6769H3.53C3.24706 35.683 2.96756 35.614 2.72 35.4769C2.46971 35.3332 2.2491 35.1432 2.07 34.9169C1.88106 34.6909 1.71052 34.4501 1.56 34.1969C1.4 33.9369 1.28 33.6669 1.16 33.4069C1.02759 33.1247 0.914004 32.8341 0.820001 32.5369C0.820001 32.5369 0.700001 32.1169 0.650001 31.8969C0.650001 31.8369 0.43 30.7269 0.39 30.1369C0.0600003 25.3569 0 11.2269 0 11.2269C0 5.42689 3.17 0.00689305 9.88 0.00689305C11.2703 -0.0466351 12.655 0.212137 13.9321 0.764182C15.2092 1.31623 16.3464 2.14751 17.26 3.19689C18.9775 5.33145 19.8781 8.00826 19.8 10.7469C19.8 10.7469 19.89 25.1869 19.52 29.8869Z" transform="translate(10 2)" stroke="#6C7A89" stroke-width="0.75" stroke-linejoin="round"/>
<path d="M13.8432 19.94C13.8432 19.53 13.8432 19.11 13.8432 18.69V9.77C13.8432 9.62333 13.8432 9.47667 13.8432 9.33C13.8432 4.4 12.9932 0 7.00319 0C0.81319 0 0.00318953 4.47 0.00318953 9.45V19.06C0.00318953 19.49 0.00318953 19.93 0.00318953 20.35C-0.0288053 22.0015 0.180056 23.6488 0.623189 25.24C1.34319 27.77 3.15319 29.53 6.84319 29.59C12.8432 29.69 13.7332 25.01 13.7832 19.96L13.8432 19.94Z" transform="translate(13.0469 5.1167)" fill="#6C7A89"/>
<path d="M0.380812 1.96426C0.323184 1.96438 0.266283 1.9514 0.214414 1.92628C0.162545 1.90117 0.117067 1.86459 0.0814202 1.81931C0.0457737 1.77403 0.0208922 1.72123 0.00865958 1.66492C-0.00357306 1.6086 -0.00283688 1.55025 0.010812 1.49426C0.122676 1.06626 0.373284 0.687426 0.723414 0.417047C1.07354 0.146667 1.50344 0 1.94581 0C2.38819 0 2.81808 0.146667 3.16821 0.417047C3.51834 0.687426 3.76895 1.06626 3.88081 1.49426C3.89446 1.55025 3.8952 1.6086 3.88296 1.66492C3.87073 1.72123 3.84585 1.77403 3.8102 1.81931C3.77456 1.86459 3.72908 1.90117 3.67721 1.92628C3.62534 1.9514 3.56844 1.96438 3.51081 1.96426C3.42466 1.96216 3.34163 1.93158 3.27469 1.87731C3.20775 1.82303 3.16067 1.74812 3.14081 1.66426C3.072 1.40106 2.91787 1.1681 2.70255 1.00184C2.48722 0.835573 2.22286 0.745385 1.95081 0.745385C1.67877 0.745385 1.4144 0.835573 1.19908 1.00184C0.983753 1.1681 0.829625 1.40106 0.760812 1.66426C0.74095 1.74812 0.693873 1.82303 0.626934 1.87731C0.559995 1.93158 0.476964 1.96216 0.390812 1.96426H0.380812Z" transform="translate(14.4189 15.1528)" fill="white"/>
<path d="M0.380812 1.96426C0.323184 1.96438 0.266282 1.9514 0.214413 1.92628C0.162544 1.90117 0.117066 1.86459 0.0814196 1.81931C0.0457732 1.77403 0.0208927 1.72123 0.00866002 1.66492C-0.00357263 1.6086 -0.0028374 1.55025 0.0108115 1.49426C0.122675 1.06626 0.373284 0.687426 0.723414 0.417047C1.07354 0.146667 1.50344 0 1.94581 0C2.38819 0 2.81808 0.146667 3.16821 0.417047C3.51834 0.687426 3.76895 1.06626 3.88081 1.49426C3.89446 1.55025 3.8952 1.6086 3.88296 1.66492C3.87073 1.72123 3.84585 1.77403 3.8102 1.81931C3.77456 1.86459 3.72908 1.90117 3.67721 1.92628C3.62534 1.9514 3.56844 1.96438 3.51081 1.96426C3.42466 1.96216 3.34163 1.93158 3.27469 1.87731C3.20775 1.82303 3.16067 1.74812 3.14081 1.66426C3.072 1.40106 2.91787 1.1681 2.70255 1.00184C2.48722 0.835573 2.22286 0.745385 1.95081 0.745385C1.67877 0.745385 1.4144 0.835573 1.19908 1.00184C0.983753 1.1681 0.829625 1.40106 0.760812 1.66426C0.74095 1.74812 0.693872 1.82303 0.626933 1.87731C0.559994 1.93158 0.476965 1.96216 0.390813 1.96426H0.380812Z" transform="translate(21.6191 15.1528)" fill="white"/>
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 24.1.2, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 59.8 59.8" style="enable-background:new 0 0 59.8 59.8;" xml:space="preserve">
<style type="text/css">
.st0{fill:none;stroke:#5B6984;stroke-width:1.2057;}
.st1{fill:none;stroke:#5B6984;stroke-width:0.9546;}
.st2{fill:#5B6984;}
.st3{fill:none;stroke:#FFFFFF;stroke-width:2.2255;stroke-linecap:round;}
</style>
<path class="st0" d="M45.3,50.6H14.7c-2.9,0-5.2-2.3-5.2-5.2V14.8c0-2.9,2.3-5.2,5.2-5.2h30.6c2.9,0,5.2,2.3,5.2,5.2v30.6
C50.5,48.3,48.2,50.6,45.3,50.6z"/>
<path class="st1" d="M45.3,35.3H14.7c-2.9,0-5.2-2.3-5.2-5.2V14.8c0-2.9,2.3-5.2,5.2-5.2h30.6c2.9,0,5.2,2.3,5.2,5.2v15.3
C50.5,33,48.2,35.3,45.3,35.3z"/>
<path class="st2" d="M44,33.7H16c-2.3,0-4.1-1.8-4.1-4.1V15.9c0-2.3,1.8-4.1,4.1-4.1H44c2.3,0,4.1,1.8,4.1,4.1v13.7
C48.1,31.9,46.2,33.7,44,33.7z"/>
<g>
<circle class="st2" cx="14" cy="39.1" r="0.9"/>
<circle class="st2" cx="17.5" cy="39.1" r="0.9"/>
<circle class="st2" cx="14" cy="45.2" r="0.9"/>
<circle class="st2" cx="17.5" cy="45.2" r="0.9"/>
<circle class="st2" cx="15.8" cy="42.2" r="0.9"/>
<circle class="st2" cx="19.3" cy="42.2" r="0.9"/>
<circle class="st2" cx="21.1" cy="39.1" r="0.9"/>
<circle class="st2" cx="21.1" cy="45.2" r="0.9"/>
<circle class="st2" cx="22.8" cy="42.2" r="0.9"/>
<circle class="st2" cx="24.6" cy="39.1" r="0.9"/>
<circle class="st2" cx="24.6" cy="45.2" r="0.9"/>
<circle class="st2" cx="26.4" cy="42.2" r="0.9"/>
<circle class="st2" cx="28.1" cy="39.1" r="0.9"/>
<circle class="st2" cx="28.1" cy="45.2" r="0.9"/>
<circle class="st2" cx="29.9" cy="42.2" r="0.9"/>
<circle class="st2" cx="31.7" cy="39.1" r="0.9"/>
<circle class="st2" cx="31.7" cy="45.2" r="0.9"/>
<circle class="st2" cx="33.4" cy="42.2" r="0.9"/>
<circle class="st2" cx="35.2" cy="39.1" r="0.9"/>
<circle class="st2" cx="35.2" cy="45.2" r="0.9"/>
<circle class="st2" cx="37" cy="42.2" r="0.9"/>
<circle class="st2" cx="38.7" cy="39.1" r="0.9"/>
<circle class="st2" cx="38.7" cy="45.2" r="0.9"/>
<circle class="st2" cx="40.5" cy="42.2" r="0.9"/>
<circle class="st2" cx="42.3" cy="39.1" r="0.9"/>
<circle class="st2" cx="42.3" cy="45.2" r="0.9"/>
<circle class="st2" cx="44" cy="42.2" r="0.9"/>
<circle class="st2" cx="45.8" cy="39.1" r="0.9"/>
<circle class="st2" cx="45.8" cy="45.2" r="0.9"/>
</g>
<g>
<line class="st3" x1="30" y1="31.6" x2="30" y2="13.8"/>
<line class="st3" x1="33.3" y1="28.3" x2="33.3" y2="17.2"/>
<line class="st3" x1="23.3" y1="25" x2="23.3" y2="20.5"/>
<line class="st3" x1="26.7" y1="28.3" x2="26.7" y2="17.2"/>
<line class="st3" x1="36.7" y1="25" x2="36.7" y2="20.5"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB