mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
better subscriptions
This commit is contained in:
committed by
Aiden McClelland
parent
7a144b4d25
commit
2086367407
@@ -24,7 +24,6 @@
|
|||||||
"@ionic/angular": "^5.6.0",
|
"@ionic/angular": "^5.6.0",
|
||||||
"@ionic/storage": "^3.0.0",
|
"@ionic/storage": "^3.0.0",
|
||||||
"@ionic/storage-angular": "^3.0.0",
|
"@ionic/storage-angular": "^3.0.0",
|
||||||
"@ngrx/component": "^11.1.1",
|
|
||||||
"@start9labs/emver": "^0.1.4",
|
"@start9labs/emver": "^0.1.4",
|
||||||
"ajv": "^6.12.6",
|
"ajv": "^6.12.6",
|
||||||
"angularx-qrcode": "^11.0.0",
|
"angularx-qrcode": "^11.0.0",
|
||||||
|
|||||||
@@ -5,6 +5,6 @@
|
|||||||
{{ params.title }}
|
{{ params.title }}
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</div>
|
</div>
|
||||||
<div class="long-message" [innerHTML]="params.notes | markdown"></div>
|
<div class="long-message" [innerHTML]="params.message | markdown"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ import { Loadable } from '../loadable'
|
|||||||
})
|
})
|
||||||
export class AlertComponent implements OnInit, Loadable {
|
export class AlertComponent implements OnInit, Loadable {
|
||||||
@Input() params: {
|
@Input() params: {
|
||||||
alert: string
|
|
||||||
title: string
|
title: string
|
||||||
|
message: string
|
||||||
titleColor: string
|
titleColor: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,17 +1,17 @@
|
|||||||
<div *ngIf="!(loading$ | ngrxPush) && !params.skipCompletionDialogue" class="slide-content">
|
<div *ngIf="!(loading$ | async) && !params.skipCompletionDialogue" class="slide-content">
|
||||||
<div style="margin-top: 25px;">
|
<div style="margin-top: 25px;">
|
||||||
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
|
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
|
||||||
<ion-label [color]="$color$ | ngrxPush" style="font-size: xx-large; font-weight: bold;">
|
<ion-label [color]="color$ | async" style="font-size: xx-large; font-weight: bold;">
|
||||||
{{successText}}
|
{{ successText }}
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</div>
|
</div>
|
||||||
<div class="long-message">
|
<div class="long-message">
|
||||||
{{summary}}
|
{{ summary }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="loading$ | ngrxPush" class="center-spinner">
|
<div *ngIf="loading$ | async" class="center-spinner">
|
||||||
<ion-spinner color="warning" name="lines"></ion-spinner>
|
<ion-spinner color="warning" name="lines"></ion-spinner>
|
||||||
<ion-label class="long-message">{{label}}</ion-label>
|
<ion-label class="long-message">{{label}}</ion-label>
|
||||||
</div>
|
</div>
|
||||||
@@ -1,42 +1,41 @@
|
|||||||
<div>
|
<div *ngIf="loading$ | async" class="center-spinner">
|
||||||
<div *ngIf="!(loading$ | ngrxPush)" class="slide-content">
|
<ion-spinner color="warning" name="lines"></ion-spinner>
|
||||||
<div style="margin-top: 25px;">
|
<ion-label class="long-message">Checking for installed services which depend on {{ params.title }}...</ion-label>
|
||||||
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
|
</div>
|
||||||
<ion-label color="warning" style="font-size: xx-large; font-weight: bold;"
|
|
||||||
*ngIf="hasDependentViolation">
|
|
||||||
WARNING
|
|
||||||
</ion-label>
|
|
||||||
<ion-label color="success" style="font-size: x-large; font-weight: bold; text-transform: capitalize;"
|
|
||||||
*ngIf="!hasDependentViolation">
|
|
||||||
READY
|
|
||||||
</ion-label>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div *ngIf="longMessage" class="long-message" >
|
<div *ngIf="!(loading$ | async)" class="slide-content">
|
||||||
{{longMessage}}
|
<div style="margin-top: 25px;">
|
||||||
</div>
|
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
|
||||||
<div style="margin: 25px 0px;">
|
<ion-label color="warning" style="font-size: xx-large; font-weight: bold;"
|
||||||
<div style="border-width: 0px 0px 1px 0px; font-size: unset; text-align: left; font-weight: bold; margin-left: 13px; border-style: solid; border-color: var(--ion-color-light-tint);"
|
*ngIf="hasDependentViolation">
|
||||||
*ngIf="hasDependentViolation"
|
WARNING
|
||||||
>
|
</ion-label>
|
||||||
<ion-text color="warning">Will Stop</ion-text>
|
<ion-label color="success" style="font-size: x-large; font-weight: bold; text-transform: capitalize;"
|
||||||
</div>
|
*ngIf="!hasDependentViolation">
|
||||||
<ion-item
|
READY
|
||||||
style="--ion-item-background: rgb(0,0,0,0); margin-top: 5px"
|
</ion-label>
|
||||||
*ngFor="let dep of dependentBreakages"
|
</div>
|
||||||
>
|
|
||||||
<ion-avatar style="position: relative; height: 4vh; width: 4vh" slot="start">
|
<div *ngIf="longMessage" class="long-message" >
|
||||||
<img [src]="dep.iconURL" />
|
{{ longMessage }}
|
||||||
</ion-avatar>
|
</div>
|
||||||
<ion-label>
|
<div style="margin: 25px 0px;">
|
||||||
<h5>{{dep.title}}</h5>
|
<div style="border-width: 0px 0px 1px 0px; font-size: unset; text-align: left; font-weight: bold; margin-left: 13px; border-style: solid; border-color: var(--ion-color-light-tint);"
|
||||||
</ion-label>
|
*ngIf="hasDependentViolation"
|
||||||
</ion-item>
|
>
|
||||||
|
<ion-text color="warning">Will Stop</ion-text>
|
||||||
</div>
|
</div>
|
||||||
|
<ion-item
|
||||||
|
style="--ion-item-background: rgb(0,0,0,0); margin-top: 5px"
|
||||||
|
*ngFor="let dep of dependentBreakages | keyvalue"
|
||||||
|
>
|
||||||
|
<ion-avatar style="position: relative; height: 4vh; width: 4vh" slot="start">
|
||||||
|
<img [src]="dep.value.iconURL" />
|
||||||
|
</ion-avatar>
|
||||||
|
<ion-label>
|
||||||
|
<h5>{{ dep.value.title }}</h5>
|
||||||
|
</ion-label>
|
||||||
|
</ion-item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="loading$ | ngrxPush" class="center-spinner">
|
|
||||||
<ion-spinner color="warning" name="lines"></ion-spinner>
|
|
||||||
<ion-label class="long-message">Checking for installed services which depend on {{params.title}}...</ion-label>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
<ion-toolbar>
|
<ion-toolbar>
|
||||||
<ion-label class="toolbar-label text-ellipses">
|
<ion-label class="toolbar-label text-ellipses">
|
||||||
<h1 class="toolbar-title">{{ params.toolbar.title }}</h1>
|
<h1 class="toolbar-title">{{ params.toolbar.title }}</h1>
|
||||||
<h3 style="font-size: large; font-style: italic">{{params.toolbar.action}} <ion-text style="font-size: medium;" color="medium">{{ params.toolbar.version | displayEmver }}</ion-text></h3>
|
<h3 style="font-size: large; font-style: italic">{{ params.toolbar.action }} <ion-text style="font-size: medium;" color="medium">{{ params.toolbar.version | displayEmver }}</ion-text></h3>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-toolbar>
|
</ion-toolbar>
|
||||||
</ion-header>
|
</ion-header>
|
||||||
@@ -11,14 +11,13 @@
|
|||||||
<ion-slides *ngIf="!error" id="slide-show" style="--bullet-background: white" pager="false">
|
<ion-slides *ngIf="!error" id="slide-show" style="--bullet-background: white" pager="false">
|
||||||
<ion-slide *ngFor="let def of params.slideDefinitions">
|
<ion-slide *ngFor="let def of params.slideDefinitions">
|
||||||
<!-- We can pass [transitions]="transitions" into the component if logic within the component needs to trigger a transition (not just bottom bar) -->
|
<!-- We can pass [transitions]="transitions" into the component if logic within the component needs to trigger a transition (not just bottom bar) -->
|
||||||
<dependencies #components *ngIf="def.slide.selector === 'dependencies'" [params]="def.slide.params"></dependencies>
|
<alert #components *ngIf="def.slide.selector === 'alert'" [params]="def.slide.params" style="width: 100%;"></alert>
|
||||||
<notes #components *ngIf="def.slide.selector === 'notes'" [params]="def.slide.params" style="width: 100%;"></notes>
|
<notes #components *ngIf="def.slide.selector === 'notes'" [params]="def.slide.params" style="width: 100%;"></notes>
|
||||||
<dependents #components *ngIf="def.slide.selector === 'dependents'" [params]="def.slide.params" [transitions]="transitions"></dependents>
|
<dependents #components *ngIf="def.slide.selector === 'dependents'" [params]="def.slide.params" [transitions]="transitions"></dependents>
|
||||||
<complete #components *ngIf="def.slide.selector === 'complete'" [params]="def.slide.params" [transitions]="transitions"></complete>
|
<complete #components *ngIf="def.slide.selector === 'complete'" [params]="def.slide.params" [transitions]="transitions"></complete>
|
||||||
</ion-slide>
|
</ion-slide>
|
||||||
</ion-slides>
|
</ion-slides>
|
||||||
|
|
||||||
|
|
||||||
<div *ngIf="error" class="slide-content">
|
<div *ngIf="error" class="slide-content">
|
||||||
<div style="margin-top: 25px;">
|
<div style="margin-top: 25px;">
|
||||||
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
|
<div style="margin: 15px; display: flex; justify-content: center; align-items: center;">
|
||||||
@@ -27,7 +26,7 @@
|
|||||||
</ion-label>
|
</ion-label>
|
||||||
</div>
|
</div>
|
||||||
<div class="long-message">
|
<div class="long-message">
|
||||||
{{error}}
|
{{ error }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -38,24 +37,27 @@
|
|||||||
<ng-container *ngIf="!initializing && !error">
|
<ng-container *ngIf="!initializing && !error">
|
||||||
|
|
||||||
<!-- cancel button if loading/not loading -->
|
<!-- cancel button if loading/not loading -->
|
||||||
<ion-button slot="start" *ngIf="v.loading && v.bar.cancel.whileLoading as cancel" (click)="transitions.cancel()" class="toolbar-button" fill="outline" color="medium">
|
<ion-button slot="start" *ngIf="(currentSlide.loading$ | async) && currentBottomBar.cancel.whileLoading as cancel" (click)="transitions.cancel()" class="toolbar-button" fill="outline" color="medium">
|
||||||
<ion-text *ngIf="cancel.text" [class.smaller-text]="cancel.text > 16">{{cancel.text}}</ion-text>
|
<ion-text *ngIf="cancel.text" [class.smaller-text]="cancel.text > 16">{{ cancel.text }}</ion-text>
|
||||||
<ion-icon *ngIf="!cancel.text" name="close-outline"></ion-icon>
|
<ion-icon *ngIf="!cancel.text" name="close-outline"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-button slot="start" *ngIf="!v.loading && v.bar.cancel.afterLoading as cancel" (click)="transitions.cancel()" class="toolbar-button" fill="outline" color="medium">
|
<ion-button slot="start" *ngIf="!(currentSlide.loading$ | async) && currentBottomBar.cancel.afterLoading as cancel" (click)="transitions.cancel()" class="toolbar-button" fill="outline" color="medium">
|
||||||
<ion-text *ngIf="cancel.text" [class.smaller-text]="cancel.text > 16">{{cancel.text}}</ion-text>
|
<ion-text *ngIf="cancel.text" [class.smaller-text]="cancel.text > 16">{{ cancel.text }}</ion-text>
|
||||||
<ion-icon *ngIf="!cancel.text" name="close-outline"></ion-icon>
|
<ion-icon *ngIf="!cancel.text" name="close-outline"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|
||||||
<!-- next button -->
|
<!-- next/finish buttons -->
|
||||||
<ion-button slot="end" *ngIf="!v.loading && v.bar.next as next" (click)="transitions.next()" fill="outline" class="toolbar-button" color="primary">
|
<ng-container *ngIf="!(currentSlide.loading$ | async)">
|
||||||
<ion-text [class.smaller-text]="next.length > 16">{{next}}</ion-text>
|
<!-- next -->
|
||||||
</ion-button>
|
<ion-button slot="end" *ngIf="currentBottomBar.next as next" (click)="transitions.next()" fill="outline" class="toolbar-button" color="primary">
|
||||||
|
<ion-text [class.smaller-text]="next.length > 16">{{ next }}</ion-text>
|
||||||
|
</ion-button>
|
||||||
|
|
||||||
<!-- finish button -->
|
<!-- finish -->
|
||||||
<ion-button slot="end" *ngIf="!v.loading && v.bar.finish as finish" (click)="transitions.final()" fill="outline" class="toolbar-button" color="primary">
|
<ion-button slot="end" *ngIf="currentBottomBar.finish as finish" (click)="transitions.final()" fill="outline" class="toolbar-button" color="primary">
|
||||||
<ion-text [class.smaller-text]="finish.length > 16">{{finish}}</ion-text>
|
<ion-text [class.smaller-text]="finish.length > 16">{{ finish }}</ion-text>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
</ng-container>
|
</ng-container>
|
||||||
<ng-container *ngIf="error">
|
<ng-container *ngIf="error">
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import { Injectable } from '@angular/core'
|
import { Injectable } from '@angular/core'
|
||||||
import { InstalledPackageDataEntry } from 'src/app/services/patch-db/data-model'
|
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||||
import { Breakages } from 'src/app/services/api/api-types'
|
import { Breakages } from 'src/app/services/api/api-types'
|
||||||
import { exists } from 'src/app/util/misc.util'
|
import { exists } from 'src/app/util/misc.util'
|
||||||
import { ApiService } from '../../services/api/api.service'
|
import { ApiService } from '../../services/api/api.service'
|
||||||
import { InstallWizardComponent, SlideDefinition, TopbarParams } from './install-wizard.component'
|
import { InstallWizardComponent, SlideDefinition, TopbarParams } from './install-wizard.component'
|
||||||
import { WizardAction } from './wizard-types'
|
|
||||||
|
|
||||||
@Injectable({ providedIn: 'root' })
|
@Injectable({ providedIn: 'root' })
|
||||||
export class WizardBaker {
|
export class WizardBaker {
|
||||||
@@ -17,10 +16,6 @@ export class WizardBaker {
|
|||||||
}): InstallWizardComponent['params'] {
|
}): InstallWizardComponent['params'] {
|
||||||
const { id, title, version, installAlert } = values
|
const { id, title, version, installAlert } = values
|
||||||
|
|
||||||
validate(id, exists, 'missing id')
|
|
||||||
validate(title, exists, 'missing title')
|
|
||||||
validate(version, exists, 'missing version')
|
|
||||||
|
|
||||||
const action = 'install'
|
const action = 'install'
|
||||||
const toolbar: TopbarParams = { action, title, version }
|
const toolbar: TopbarParams = { action, title, version }
|
||||||
|
|
||||||
@@ -29,8 +24,8 @@ export class WizardBaker {
|
|||||||
slide: {
|
slide: {
|
||||||
selector: 'alert',
|
selector: 'alert',
|
||||||
params: {
|
params: {
|
||||||
alert: installAlert,
|
|
||||||
title: 'Warning',
|
title: 'Warning',
|
||||||
|
message: installAlert,
|
||||||
titleColor: 'warning',
|
titleColor: 'warning',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -62,10 +57,6 @@ export class WizardBaker {
|
|||||||
}): InstallWizardComponent['params'] {
|
}): InstallWizardComponent['params'] {
|
||||||
const { id, title, version, installAlert } = values
|
const { id, title, version, installAlert } = values
|
||||||
|
|
||||||
validate(id, exists, 'missing id')
|
|
||||||
validate(title, exists, 'missing title')
|
|
||||||
validate(version, exists, 'missing version')
|
|
||||||
|
|
||||||
const action = 'update'
|
const action = 'update'
|
||||||
const toolbar: TopbarParams = { action, title, version }
|
const toolbar: TopbarParams = { action, title, version }
|
||||||
|
|
||||||
@@ -74,8 +65,8 @@ export class WizardBaker {
|
|||||||
slide: {
|
slide: {
|
||||||
selector: 'alert',
|
selector: 'alert',
|
||||||
params: {
|
params: {
|
||||||
alert: installAlert,
|
|
||||||
title: 'Warning',
|
title: 'Warning',
|
||||||
|
message: installAlert,
|
||||||
titleColor: 'warning',
|
titleColor: 'warning',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -166,10 +157,6 @@ export class WizardBaker {
|
|||||||
}): InstallWizardComponent['params'] {
|
}): InstallWizardComponent['params'] {
|
||||||
const { id, title, version, installAlert } = values
|
const { id, title, version, installAlert } = values
|
||||||
|
|
||||||
validate(id, exists, 'missing id')
|
|
||||||
validate(title, exists, 'missing title')
|
|
||||||
validate(version, exists, 'missing version')
|
|
||||||
|
|
||||||
const action = 'downgrade'
|
const action = 'downgrade'
|
||||||
const toolbar: TopbarParams = { action, title, version }
|
const toolbar: TopbarParams = { action, title, version }
|
||||||
|
|
||||||
@@ -178,8 +165,8 @@ export class WizardBaker {
|
|||||||
slide: {
|
slide: {
|
||||||
selector: 'alert',
|
selector: 'alert',
|
||||||
params: {
|
params: {
|
||||||
alert: installAlert,
|
|
||||||
title: 'Warning',
|
title: 'Warning',
|
||||||
|
message: installAlert,
|
||||||
titleColor: 'warning',
|
titleColor: 'warning',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -222,11 +209,7 @@ export class WizardBaker {
|
|||||||
}): InstallWizardComponent['params'] {
|
}): InstallWizardComponent['params'] {
|
||||||
const { id, title, version, uninstallAlert } = values
|
const { id, title, version, uninstallAlert } = values
|
||||||
|
|
||||||
validate(id, exists, 'missing id')
|
const action = 'uninstall'
|
||||||
validate(title, exists, 'missing title')
|
|
||||||
validate(version, exists, 'missing version')
|
|
||||||
|
|
||||||
const action = 'uninstall' as WizardAction
|
|
||||||
const toolbar: TopbarParams = { action, title, version }
|
const toolbar: TopbarParams = { action, title, version }
|
||||||
|
|
||||||
const slideDefinitions: SlideDefinition[] = [
|
const slideDefinitions: SlideDefinition[] = [
|
||||||
@@ -234,8 +217,8 @@ export class WizardBaker {
|
|||||||
slide: {
|
slide: {
|
||||||
selector: 'alert',
|
selector: 'alert',
|
||||||
params: {
|
params: {
|
||||||
alert: uninstallAlert || defaultUninstallationWarning(title),
|
|
||||||
title: 'Warning',
|
title: 'Warning',
|
||||||
|
message: uninstallAlert || defaultUninstallWarning(title),
|
||||||
titleColor: 'warning',
|
titleColor: 'warning',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -248,7 +231,7 @@ export class WizardBaker {
|
|||||||
action,
|
action,
|
||||||
verb: 'uninstalling',
|
verb: 'uninstalling',
|
||||||
title,
|
title,
|
||||||
fetchBreakages: () => this.apiService.dryRemovePackage({ id }).then(breakages => breakages ),
|
fetchBreakages: () => this.apiService.dryRemovePackage({ id }).then(breakages => breakages),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
bottomBar: { cancel: { whileLoading: { }, afterLoading: { text: 'Cancel' } }, next: 'Uninstall' },
|
bottomBar: { cancel: { whileLoading: { }, afterLoading: { text: 'Cancel' } }, next: 'Uninstall' },
|
||||||
@@ -274,10 +257,6 @@ export class WizardBaker {
|
|||||||
}): InstallWizardComponent['params'] {
|
}): InstallWizardComponent['params'] {
|
||||||
const { breakages, title, version } = values
|
const { breakages, title, version } = values
|
||||||
|
|
||||||
validate(breakages, t => !!t && Array.isArray(t), 'missing breakages')
|
|
||||||
validate(title, exists, 'missing title')
|
|
||||||
validate(version, exists, 'missing version')
|
|
||||||
|
|
||||||
const action = 'stop'
|
const action = 'stop'
|
||||||
const toolbar: TopbarParams = { action, title, version }
|
const toolbar: TopbarParams = { action, title, version }
|
||||||
|
|
||||||
@@ -298,7 +277,7 @@ export class WizardBaker {
|
|||||||
return { toolbar, slideDefinitions }
|
return { toolbar, slideDefinitions }
|
||||||
}
|
}
|
||||||
|
|
||||||
configure (values: { breakages: Breakages, pkg: InstalledPackageDataEntry }): InstallWizardComponent['params'] {
|
configure (values: { breakages: Breakages, pkg: PackageDataEntry }): InstallWizardComponent['params'] {
|
||||||
const { breakages, pkg } = values
|
const { breakages, pkg } = values
|
||||||
const { title, version } = pkg.manifest
|
const { title, version } = pkg.manifest
|
||||||
const action = 'configure'
|
const action = 'configure'
|
||||||
@@ -321,12 +300,4 @@ export class WizardBaker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function validate<T> (t: T, test: (t: T) => Boolean, desc: string) {
|
const defaultUninstallWarning = serviceName => `Uninstalling ${ serviceName } will result in the deletion of its data.`
|
||||||
if (!test(t)) {
|
|
||||||
console.error('failed validation', desc, t)
|
|
||||||
throw new Error(desc)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const defaultUninstallationWarning = serviceName => `Uninstalling ${ serviceName } will result in the deletion of its data.`
|
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
<p
|
<p
|
||||||
[style.color]="'var(--ion-color-' + color + ')'"
|
[style.color]="'var(--ion-color-' + rendering.color + ')'"
|
||||||
[style.font-size]="size"
|
[style.font-size]="size"
|
||||||
[style.font-style]="style"
|
[style.font-style]="style"
|
||||||
[style.font-weight]="weight"
|
[style.font-weight]="weight"
|
||||||
>
|
>
|
||||||
{{ display }}
|
{{ rendering.display }}
|
||||||
<ion-spinner *ngIf="showDots" class="dots dots-small" name="dots" [color]="color"></ion-spinner>
|
<ion-spinner *ngIf="rendering.showDots" class="dots dots-small" name="dots" [color]="color"></ion-spinner>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import { Component, Input } from '@angular/core'
|
import { Component, Input } from '@angular/core'
|
||||||
import { combineLatest } from 'rxjs'
|
import { PkgStatusRendering } from 'src/app/services/pkg-status-rendering.service'
|
||||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
|
||||||
import { renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'status',
|
selector: 'status',
|
||||||
@@ -9,36 +7,9 @@ import { renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
|||||||
styleUrls: ['./status.component.scss'],
|
styleUrls: ['./status.component.scss'],
|
||||||
})
|
})
|
||||||
export class StatusComponent {
|
export class StatusComponent {
|
||||||
@Input() pkgId: string
|
@Input() rendering: PkgStatusRendering
|
||||||
@Input() size?: 'small' | 'medium' | 'large' = 'large'
|
@Input() size?: 'small' | 'medium' | 'large' = 'large'
|
||||||
@Input() style?: string = 'regular'
|
@Input() style?: string = 'regular'
|
||||||
@Input() weight?: string = 'normal'
|
@Input() weight?: string = 'normal'
|
||||||
display = ''
|
|
||||||
color = ''
|
|
||||||
showDots = false
|
|
||||||
subs = []
|
|
||||||
|
|
||||||
constructor (
|
|
||||||
private readonly patch: PatchDbModel,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit () {
|
|
||||||
this.subs = [
|
|
||||||
combineLatest([
|
|
||||||
this.patch.watch$('package-data', this.pkgId, 'state'),
|
|
||||||
this.patch.watch$('package-data', this.pkgId, 'installed', 'status'),
|
|
||||||
])
|
|
||||||
.subscribe(([state, status]) => {
|
|
||||||
const { display, color, showDots } = renderPkgStatus(state, status)
|
|
||||||
this.display = display
|
|
||||||
this.color = color
|
|
||||||
this.showDots = showDots
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnDestroy () {
|
|
||||||
this.subs.forEach(sub => sub.unsubscribe())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ import { MarkdownPipe } from '../pipes/markdown.pipe'
|
|||||||
import { AnnotationStatusPipe } from '../pipes/annotation-status.pipe'
|
import { AnnotationStatusPipe } from '../pipes/annotation-status.pipe'
|
||||||
import { TruncateCenterPipe, TruncateEndPipe } from '../pipes/truncate.pipe'
|
import { TruncateCenterPipe, TruncateEndPipe } from '../pipes/truncate.pipe'
|
||||||
import { MaskPipe } from '../pipes/mask.pipe'
|
import { MaskPipe } from '../pipes/mask.pipe'
|
||||||
import { DisplayBulbPipe } from '../pipes/display-bulb.pipe'
|
import { HasUiPipe, LaunchablePipe } from '../pipes/ui.pipe'
|
||||||
import { HasUiPipe, LaunchablePipe, ManifestPipe } from '../pipes/ui.pipe'
|
|
||||||
import { EmptyPipe } from '../pipes/empty.pipe'
|
import { EmptyPipe } from '../pipes/empty.pipe'
|
||||||
import { StatusPipe } from '../pipes/status.pipe'
|
import { StatusPipe } from '../pipes/status.pipe'
|
||||||
import { NotificationColorPipe } from '../pipes/notification-color.pipe'
|
import { NotificationColorPipe } from '../pipes/notification-color.pipe'
|
||||||
import { ReactiveComponentModule } from '@ngrx/component'
|
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
@@ -24,18 +22,14 @@ import { ReactiveComponentModule } from '@ngrx/component'
|
|||||||
TruncateCenterPipe,
|
TruncateCenterPipe,
|
||||||
TruncateEndPipe,
|
TruncateEndPipe,
|
||||||
MaskPipe,
|
MaskPipe,
|
||||||
DisplayBulbPipe,
|
|
||||||
EmverDisplayPipe,
|
EmverDisplayPipe,
|
||||||
HasUiPipe,
|
HasUiPipe,
|
||||||
LaunchablePipe,
|
LaunchablePipe,
|
||||||
ManifestPipe,
|
|
||||||
EmptyPipe,
|
EmptyPipe,
|
||||||
StatusPipe,
|
StatusPipe,
|
||||||
NotificationColorPipe,
|
NotificationColorPipe,
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [],
|
||||||
ReactiveComponentModule,
|
|
||||||
],
|
|
||||||
exports: [
|
exports: [
|
||||||
EmverComparesPipe,
|
EmverComparesPipe,
|
||||||
EmverSatisfiesPipe,
|
EmverSatisfiesPipe,
|
||||||
@@ -46,15 +40,12 @@ import { ReactiveComponentModule } from '@ngrx/component'
|
|||||||
TruncateEndPipe,
|
TruncateEndPipe,
|
||||||
TruncateCenterPipe,
|
TruncateCenterPipe,
|
||||||
MaskPipe,
|
MaskPipe,
|
||||||
DisplayBulbPipe,
|
|
||||||
EmverDisplayPipe,
|
EmverDisplayPipe,
|
||||||
HasUiPipe,
|
HasUiPipe,
|
||||||
LaunchablePipe,
|
LaunchablePipe,
|
||||||
ManifestPipe,
|
|
||||||
EmptyPipe,
|
EmptyPipe,
|
||||||
StatusPipe,
|
StatusPipe,
|
||||||
NotificationColorPipe,
|
NotificationColorPipe,
|
||||||
ReactiveComponentModule,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class SharingModule { }
|
export class SharingModule { }
|
||||||
@@ -8,15 +8,15 @@
|
|||||||
</ion-header>
|
</ion-header>
|
||||||
|
|
||||||
<ion-content class="ion-padding-top">
|
<ion-content class="ion-padding-top">
|
||||||
<ng-container *ngIf="patch.data['server-info'][pkgId]?.installed as installed">
|
<ng-container *ngIf="patch.data['package-data'][pkgId] as pkg">
|
||||||
<ion-item-group>
|
<ion-item-group>
|
||||||
<ion-item button *ngFor="let action of installed.manifest.actions | keyvalue: asIsOrder" (click)="handleAction(installed, action)" >
|
<ion-item button *ngFor="let action of pkg.manifest.actions | keyvalue: asIsOrder" (click)="handleAction(pkg, action)" >
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<h2><ion-text color="primary">{{ action.value.name }}</ion-text><ion-icon *ngIf="!(action.value['allowed-statuses'] | includes: installed.status.main.status)" color="danger" name="close-outline"></ion-icon></h2>
|
<h2><ion-text color="primary">{{ action.value.name }}</ion-text><ion-icon *ngIf="!(action.value['allowed-statuses'] | includes: pkg.installed.status.main.status)" color="danger" name="close-outline"></ion-icon></h2>
|
||||||
<p><ion-text color="dark">{{ action.value.description }}</ion-text></p>
|
<p><ion-text color="dark">{{ action.value.description }}</ion-text></p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item button (click)="uninstall(installed.manifest)" >
|
<ion-item button (click)="uninstall(pkg.manifest)" >
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<h2><ion-text color="primary">Uninstall</ion-text></h2>
|
<h2><ion-text color="primary">Uninstall</ion-text></h2>
|
||||||
<p><ion-text color="dark">This will uninstall the service from your Embassy and delete all data permanently.</ion-text></p>
|
<p><ion-text color="dark">This will uninstall the service from your Embassy and delete all data permanently.</ion-text></p>
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { AlertController, IonContent, ModalController, NavController } from '@io
|
|||||||
import { LoaderService } from 'src/app/services/loader.service'
|
import { LoaderService } from 'src/app/services/loader.service'
|
||||||
import { HttpErrorResponse } from '@angular/common/http'
|
import { HttpErrorResponse } from '@angular/common/http'
|
||||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||||
import { Action, InstalledPackageDataEntry, Manifest, PackageMainStatus } from 'src/app/services/patch-db/data-model'
|
import { Action, Manifest, PackageDataEntry, PackageMainStatus } from 'src/app/services/patch-db/data-model'
|
||||||
import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component'
|
import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component'
|
||||||
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
||||||
import { Subscription } from 'rxjs'
|
import { Subscription } from 'rxjs'
|
||||||
@@ -44,8 +44,8 @@ export class AppActionsPage {
|
|||||||
this.subs.forEach(sub => sub.unsubscribe())
|
this.subs.forEach(sub => sub.unsubscribe())
|
||||||
}
|
}
|
||||||
|
|
||||||
async handleAction (pkg: InstalledPackageDataEntry, action: { key: string, value: Action }) {
|
async handleAction (pkg: PackageDataEntry, action: { key: string, value: Action }) {
|
||||||
if ((action.value['allowed-statuses'] as PackageMainStatus[]).includes(pkg.status.main.status)) {
|
if ((action.value['allowed-statuses'] as PackageMainStatus[]).includes(pkg.installed.status.main.status)) {
|
||||||
const alert = await this.alertCtrl.create({
|
const alert = await this.alertCtrl.create({
|
||||||
header: 'Confirm',
|
header: 'Confirm',
|
||||||
message: `Are you sure you want to execute action "${action.value.name}"? ${action.value.warning || ''}`,
|
message: `Are you sure you want to execute action "${action.value.name}"? ${action.value.warning || ''}`,
|
||||||
|
|||||||
@@ -35,7 +35,7 @@
|
|||||||
|
|
||||||
<ng-container *ngIf="pkg">
|
<ng-container *ngIf="pkg">
|
||||||
<!-- @TODO make sure this is how to determine if pkg is in needs_config -->
|
<!-- @TODO make sure this is how to determine if pkg is in needs_config -->
|
||||||
<ng-container *ngIf="pkg.manifest.config && !pkg.status.configured && !edited">
|
<ng-container *ngIf="pkg.manifest.config && !pkg.installed.status.configured && !edited">
|
||||||
<ion-item class="notifier-item">
|
<ion-item class="notifier-item">
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<h2 style="display: flex; align-items: center; margin-bottom: 3px;">
|
<h2 style="display: flex; align-items: center; margin-bottom: 3px;">
|
||||||
@@ -91,7 +91,7 @@
|
|||||||
|
|
||||||
<!-- save button, always show -->
|
<!-- save button, always show -->
|
||||||
<ion-button
|
<ion-button
|
||||||
[disabled]="invalid || (!edited && !added && !pkg.status.configured )"
|
[disabled]="invalid || (!edited && !added && !pkg.installed.status.configured )"
|
||||||
fill="outline"
|
fill="outline"
|
||||||
expand="block"
|
expand="block"
|
||||||
style="margin: 10px"
|
style="margin: 10px"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import { wizardModal } from 'src/app/components/install-wizard/install-wizard.co
|
|||||||
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
||||||
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
import { ConfigSpec } from 'src/app/pkg-config/config-types'
|
||||||
import { ConfigCursor } from 'src/app/pkg-config/config-cursor'
|
import { ConfigCursor } from 'src/app/pkg-config/config-cursor'
|
||||||
import { InstalledPackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
import { PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
||||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -26,7 +26,7 @@ export class AppConfigPage {
|
|||||||
|
|
||||||
loadingText: string | undefined
|
loadingText: string | undefined
|
||||||
|
|
||||||
pkg: InstalledPackageDataEntry
|
pkg: PackageDataEntry
|
||||||
hasConfig = false
|
hasConfig = false
|
||||||
|
|
||||||
mocalShowing = false
|
mocalShowing = false
|
||||||
@@ -82,7 +82,7 @@ export class AppConfigPage {
|
|||||||
this.navCtrl.back()
|
this.navCtrl.back()
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
this.patch.watch$('package-data', pkgId, 'installed')
|
this.patch.watch$('package-data', pkgId)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap(pkg => this.pkg = pkg),
|
tap(pkg => this.pkg = pkg),
|
||||||
tap(() => this.loadingText = 'Fetching config spec...'),
|
tap(() => this.loadingText = 'Fetching config spec...'),
|
||||||
@@ -156,7 +156,7 @@ export class AppConfigPage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async save (pkg: InstalledPackageDataEntry) {
|
async save (pkg: PackageDataEntry) {
|
||||||
return this.loader.of({
|
return this.loader.of({
|
||||||
message: `Saving config...`,
|
message: `Saving config...`,
|
||||||
spinner: 'lines',
|
spinner: 'lines',
|
||||||
|
|||||||
@@ -10,12 +10,12 @@
|
|||||||
<ion-content>
|
<ion-content>
|
||||||
<ion-grid *ngIf="patch.data['package-data'][pkgId] as pkg">
|
<ion-grid *ngIf="patch.data['package-data'][pkgId] as pkg">
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col *ngFor="let interface of pkg.installed.manifest.interfaces | keyvalue: asIsOrder" sizeSm="12" sizeMd="6">
|
<ion-col *ngFor="let interface of pkg.manifest.interfaces | keyvalue: asIsOrder" sizeSm="12" sizeMd="6">
|
||||||
<ion-card>
|
<ion-card>
|
||||||
<ion-card-header>
|
<ion-card-header>
|
||||||
<ion-card-title>{{ interface.value.name }}</ion-card-title>
|
<ion-card-title>{{ interface.value.name }}</ion-card-title>
|
||||||
<ion-card-subtitle>{{ interface.value.description }}</ion-card-subtitle>
|
<ion-card-subtitle>{{ interface.value.description }}</ion-card-subtitle>
|
||||||
<ion-button style="margin-top: 12px;" *ngIf="interface.value.ui" [disabled]="!(pkg | isLaunchable)" fill="outline" color="dark" expand="block" (click)="launch(pkg.installed)">
|
<ion-button style="margin-top: 12px;" *ngIf="interface.value.ui" [disabled]="!(pkg | isLaunchable)" fill="outline" color="dark" expand="block" (click)="launch(pkg)">
|
||||||
Launch
|
Launch
|
||||||
<ion-icon slot="end" name="rocket-outline"></ion-icon>
|
<ion-icon slot="end" name="rocket-outline"></ion-icon>
|
||||||
</ion-button>
|
</ion-button>
|
||||||
|
|||||||
@@ -46,8 +46,8 @@ export class AppInterfacesPage {
|
|||||||
await toast.present()
|
await toast.present()
|
||||||
}
|
}
|
||||||
|
|
||||||
launch (installed: InstalledPackageDataEntry): void {
|
launch (pkg: PackageDataEntry): void {
|
||||||
window.open(this.config.launchableURL(installed), '_blank')
|
window.open(this.config.launchableURL(pkg), '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
asIsOrder () {
|
asIsOrder () {
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col *ngFor="let pkg of pkgs | keyvalue : asIsOrder" sizeXs="4" sizeSm="3" sizeLg="3" sizeXl="2">
|
<ion-col *ngFor="let pkg of pkgs | keyvalue : asIsOrder" sizeXs="4" sizeSm="3" sizeLg="3" sizeXl="2">
|
||||||
<ion-card class="installed-card" [routerLink]="['/services', (pkg.value | manifest).id]">
|
<ion-card class="installed-card" [routerLink]="['/services', pkg.value.manifest.id]">
|
||||||
<div class="launch-container" *ngIf="pkg.value | hasUi">
|
<div class="launch-container" *ngIf="pkg.value | hasUi">
|
||||||
<div class="launch-button-triangle" (click)="launchUi(pkg.value, $event)" [class.launch-disabled]="!(pkg.value | isLaunchable)">
|
<div class="launch-button-triangle" (click)="launchUi(pkg.value, $event)" [class.launch-disabled]="!(pkg.value | isLaunchable)">
|
||||||
<ion-icon name="rocket-outline"></ion-icon>
|
<ion-icon name="rocket-outline"></ion-icon>
|
||||||
@@ -33,14 +33,11 @@
|
|||||||
|
|
||||||
<img style="position: absolute" class="main-img" [src]="pkg.value['static-files'].icon" alt="icon" />
|
<img style="position: absolute" class="main-img" [src]="pkg.value['static-files'].icon" alt="icon" />
|
||||||
<img class="main-img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
|
<img class="main-img" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII=">
|
||||||
<img class="bulb-on" *ngIf="(pkg.key | displayBulb : 'green' : connected) | async" src="assets/img/running-bulb.png"/>
|
<img [class]="serviceInfo[pkg.key].bulbInfo.class" [src]="serviceInfo[pkg.key].bulbInfo.img"/>
|
||||||
<img class="bulb-on" *ngIf="(pkg.key | displayBulb : 'red' : connected) | async" src="assets/img/issue-bulb.png"/>
|
|
||||||
<img class="bulb-on" *ngIf="(pkg.key | displayBulb : 'yellow' : connected) | async" src="assets/img/warning-bulb.png"/>
|
|
||||||
<img class="bulb-off" *ngIf="(pkg.key | displayBulb : 'off' : connected) | async" src="assets/img/off-bulb.png"/>
|
|
||||||
|
|
||||||
<ion-card-header>
|
<ion-card-header>
|
||||||
<status *ngIf="connected" [pkgId]="pkg.key" size="calc(8px + .4vw)" weight="bold"></status>
|
<status *ngIf="connected" [rendering]="serviceInfo[pkg.key].rendering" size="calc(8px + .4vw)" weight="bold"></status>
|
||||||
<ion-card-title>{{ (pkg.value | manifest).title }}</ion-card-title>
|
<ion-card-title>{{ pkg.value.manifest.title }}</ion-card-title>
|
||||||
</ion-card-header>
|
</ion-card-header>
|
||||||
</ion-card>
|
</ion-card>
|
||||||
</ion-col>
|
</ion-col>
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import { ConfigService } from 'src/app/services/config.service'
|
|||||||
import { ConnectionService } from 'src/app/services/connection.service'
|
import { ConnectionService } from 'src/app/services/connection.service'
|
||||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||||
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
import { PackageDataEntry } from 'src/app/services/patch-db/data-model'
|
||||||
import { Subscription } from 'rxjs'
|
import { combineLatest, Subscription } from 'rxjs'
|
||||||
|
import { PkgStatusRendering, renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-list',
|
selector: 'app-list',
|
||||||
@@ -13,6 +14,13 @@ import { Subscription } from 'rxjs'
|
|||||||
export class AppListPage {
|
export class AppListPage {
|
||||||
connected: boolean
|
connected: boolean
|
||||||
subs: Subscription[] = []
|
subs: Subscription[] = []
|
||||||
|
serviceInfo: { [id: string]: {
|
||||||
|
bulbInfo: {
|
||||||
|
class: string
|
||||||
|
img: string
|
||||||
|
}
|
||||||
|
rendering: PkgStatusRendering
|
||||||
|
}} = { }
|
||||||
|
|
||||||
constructor (
|
constructor (
|
||||||
private readonly config: ConfigService,
|
private readonly config: ConfigService,
|
||||||
@@ -22,7 +30,48 @@ export class AppListPage {
|
|||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.subs = [
|
this.subs = [
|
||||||
this.patch.connected$().subscribe(c => this.connected = c),
|
combineLatest([
|
||||||
|
this.patch.connected$(),
|
||||||
|
this.patch.watch$('package-data'),
|
||||||
|
])
|
||||||
|
.subscribe(([connected, pkgs]) => {
|
||||||
|
this.connected = connected
|
||||||
|
|
||||||
|
Object.keys(pkgs).forEach(pkgId => {
|
||||||
|
let bulbClass = 'bulb-on'
|
||||||
|
let img = ''
|
||||||
|
|
||||||
|
if (!this.connected) {
|
||||||
|
bulbClass = 'bulb-off',
|
||||||
|
img = 'assets/img/off-bulb.png'
|
||||||
|
}
|
||||||
|
|
||||||
|
const rendering = renderPkgStatus(pkgs[pkgId].state, pkgs[pkgId].installed.status)
|
||||||
|
switch (rendering.color) {
|
||||||
|
case 'danger':
|
||||||
|
img = 'assets/img/danger-bulb.png'
|
||||||
|
break
|
||||||
|
case 'success':
|
||||||
|
img = 'assets/img/success-bulb.png'
|
||||||
|
break
|
||||||
|
case 'warning':
|
||||||
|
img = 'assets/img/warning-bulb.png'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
bulbClass = 'bulb-off',
|
||||||
|
img = 'assets/img/off-bulb.png'
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
this.serviceInfo[pkgId] = {
|
||||||
|
bulbInfo: {
|
||||||
|
class: bulbClass,
|
||||||
|
img,
|
||||||
|
},
|
||||||
|
rendering,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +82,7 @@ export class AppListPage {
|
|||||||
launchUi (pkg: PackageDataEntry, event: Event): void {
|
launchUi (pkg: PackageDataEntry, event: Event): void {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
window.open(this.config.launchableURL(pkg.installed), '_blank')
|
window.open(this.config.launchableURL(pkg), '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
asIsOrder () {
|
asIsOrder () {
|
||||||
|
|||||||
@@ -61,7 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div *ngIf="segmentValue === 'raw'" class="raw">
|
<div *ngIf="segmentValue === 'raw'" class="raw">
|
||||||
<pre [innerHTML]="pkg | manifest | json"></pre>
|
<pre [innerHTML]="pkg.manifest | json"></pre>
|
||||||
</div>
|
</div>
|
||||||
</ion-content>
|
</ion-content>
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ export class AppRestorePage {
|
|||||||
|
|
||||||
ngOnInit () {
|
ngOnInit () {
|
||||||
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||||
this.title = this.patch.data['package-data'][this.pkgId].installed.manifest.title
|
this.title = this.patch.data['package-data'][this.pkgId].manifest.title
|
||||||
|
|
||||||
this.getExternalDisks()
|
this.getExternalDisks()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,15 +23,15 @@
|
|||||||
<img [src]="pkg['static-files'].icon" />
|
<img [src]="pkg['static-files'].icon" />
|
||||||
</ion-thumbnail>
|
</ion-thumbnail>
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<h1 style="font-family: 'Montserrat';" [class.less-large]="manifest.title.length > 20">
|
<h1 style="font-family: 'Montserrat';" [class.less-large]="pkg.manifest.title.length > 20">
|
||||||
{{ manifest.title }}
|
{{ pkg.manifest.title }}
|
||||||
</h1>
|
</h1>
|
||||||
<h5>{{ manifest.version | displayEmver }}</h5>
|
<h5>{{ pkg.manifest.version | displayEmver }}</h5>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
|
|
||||||
<div class="status-readout">
|
<div class="status-readout">
|
||||||
<status *ngIf="connected" size="large" weight="500" [pkgId]="pkgId"></status>
|
<status *ngIf="connected" size="large" weight="500" [rendering]="rendering"></status>
|
||||||
<ion-button *ngIf="(pkgId | status | async) === FeStatus.NeedsConfig" expand="block" [routerLink]="['config']">
|
<ion-button *ngIf="(pkgId | status | async) === FeStatus.NeedsConfig" expand="block" [routerLink]="['config']">
|
||||||
Configure
|
Configure
|
||||||
</ion-button>
|
</ion-button>
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
<!-- dependencies -->
|
<!-- dependencies -->
|
||||||
<ng-container *ngIf="!(pkg.installed['current-dependencies'] | empty)">
|
<ng-container *ngIf="!(pkg.installed['current-dependencies'] | empty)">
|
||||||
<ion-item-divider id="dependencies">Dependencies</ion-item-divider>
|
<ion-item-divider id="dependencies">Dependencies</ion-item-divider>
|
||||||
<!-- A current-dependency is a subset of the manifest.dependencies that is currently required as determined by the service config. -->
|
<!-- A current-dependency is a subset of the pkg.manifest.dependencies that is currently required as determined by the service config. -->
|
||||||
<ion-grid>
|
<ion-grid>
|
||||||
<ion-row>
|
<ion-row>
|
||||||
<ion-col *ngFor="let dep of pkg.installed['current-dependencies'] | keyvalue" sizeXs="12" sizeMd="6">
|
<ion-col *ngFor="let dep of pkg.installed['current-dependencies'] | keyvalue" sizeXs="12" sizeMd="6">
|
||||||
@@ -80,8 +80,8 @@
|
|||||||
<img [src]="patch.data['package-data'][dep.key] ? patch.data['package-data'][dep.key]['static-files'].icon : pkg.installed.status['dependency-errors'][dep.key]?.icon" />
|
<img [src]="patch.data['package-data'][dep.key] ? patch.data['package-data'][dep.key]['static-files'].icon : pkg.installed.status['dependency-errors'][dep.key]?.icon" />
|
||||||
</ion-thumbnail>
|
</ion-thumbnail>
|
||||||
<ion-label class="ion-text-wrap">
|
<ion-label class="ion-text-wrap">
|
||||||
<h2 style="font-family: 'Montserrat'">{{ patch.data['package-data'][dep.key] ? (patch.data['package-data'][dep.key] | manifest).title : pkg.installed.status['dependency-errors'][dep.key]?.title }}</h2>
|
<h2 style="font-family: 'Montserrat'">{{ patch.data['package-data'][dep.key] ? patch.data['package-data'][dep.key].manifest.title : pkg.installed.status['dependency-errors'][dep.key]?.title }}</h2>
|
||||||
<p>{{ manifest.dependencies[dep.key].version | displayEmver }}</p>
|
<p>{{ pkg.manifest.dependencies[dep.key].version | displayEmver }}</p>
|
||||||
<p><ion-text [color]="pkg.installed.status['dependency-errors'][dep.key] ? 'warning' : 'success'">{{ pkg.installed.status['dependency-errors'][dep.key] ? pkg.installed.status['dependency-errors'][dep.key].type : 'satisfied' }}</ion-text></p>
|
<p><ion-text [color]="pkg.installed.status['dependency-errors'][dep.key] ? 'warning' : 'success'">{{ pkg.installed.status['dependency-errors'][dep.key] ? pkg.installed.status['dependency-errors'][dep.key].type : 'satisfied' }}</ion-text></p>
|
||||||
</ion-label>
|
</ion-label>
|
||||||
|
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import { ApiService } from 'src/app/services/api/api.service'
|
|||||||
import { ActivatedRoute, NavigationExtras } from '@angular/router'
|
import { ActivatedRoute, NavigationExtras } from '@angular/router'
|
||||||
import { chill, isEmptyObject, Recommendation } from 'src/app/util/misc.util'
|
import { chill, isEmptyObject, Recommendation } from 'src/app/util/misc.util'
|
||||||
import { LoaderService } from 'src/app/services/loader.service'
|
import { LoaderService } from 'src/app/services/loader.service'
|
||||||
import { Observable, of, Subscription } from 'rxjs'
|
import { combineLatest, Observable, of, Subscription } from 'rxjs'
|
||||||
import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component'
|
import { wizardModal } from 'src/app/components/install-wizard/install-wizard.component'
|
||||||
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
import { WizardBaker } from 'src/app/components/install-wizard/prebaked-wizards'
|
||||||
import { ConfigService, getManifest } from 'src/app/services/config.service'
|
import { ConfigService, getManifest } from 'src/app/services/config.service'
|
||||||
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
import { PatchDbModel } from 'src/app/services/patch-db/patch-db.service'
|
||||||
import { DependencyErrorConfigUnsatisfied, DependencyErrorNotInstalled, DependencyErrorType, Manifest, PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
import { DependencyErrorConfigUnsatisfied, DependencyErrorNotInstalled, DependencyErrorType, Manifest, PackageDataEntry, PackageState } from 'src/app/services/patch-db/data-model'
|
||||||
import { FEStatus } from 'src/app/services/pkg-status-rendering.service'
|
import { FEStatus, PkgStatusRendering, renderPkgStatus } from 'src/app/services/pkg-status-rendering.service'
|
||||||
import { ConnectionService } from 'src/app/services/connection.service'
|
import { ConnectionService } from 'src/app/services/connection.service'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -24,11 +24,11 @@ export class AppShowPage {
|
|||||||
pkg: PackageDataEntry
|
pkg: PackageDataEntry
|
||||||
hideLAN: boolean
|
hideLAN: boolean
|
||||||
buttons: Button[] = []
|
buttons: Button[] = []
|
||||||
manifest: Manifest = { } as Manifest
|
|
||||||
connected: boolean
|
connected: boolean
|
||||||
FeStatus = FEStatus
|
FeStatus = FEStatus
|
||||||
PackageState = PackageState
|
PackageState = PackageState
|
||||||
DependencyErrorType = DependencyErrorType
|
DependencyErrorType = DependencyErrorType
|
||||||
|
rendering: PkgStatusRendering
|
||||||
|
|
||||||
@ViewChild(IonContent) content: IonContent
|
@ViewChild(IonContent) content: IonContent
|
||||||
subs: Subscription[] = []
|
subs: Subscription[] = []
|
||||||
@@ -49,10 +49,15 @@ export class AppShowPage {
|
|||||||
async ngOnInit () {
|
async ngOnInit () {
|
||||||
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
this.pkgId = this.route.snapshot.paramMap.get('pkgId')
|
||||||
this.pkg = this.patch.data['package-data'][this.pkgId]
|
this.pkg = this.patch.data['package-data'][this.pkgId]
|
||||||
// @TODO maybe re-fetch manifest if package state changes.
|
|
||||||
this.manifest = getManifest(this.pkg)
|
|
||||||
this.subs = [
|
this.subs = [
|
||||||
this.patch.connected$().subscribe(c => this.connected = c),
|
combineLatest([
|
||||||
|
this.patch.connected$(),
|
||||||
|
this.patch.watch$('package-data', this.pkgId),
|
||||||
|
])
|
||||||
|
.subscribe(([connected, pkg]) => {
|
||||||
|
this.connected = connected
|
||||||
|
this.rendering = renderPkgStatus(pkg.state, pkg.installed.status)
|
||||||
|
}),
|
||||||
]
|
]
|
||||||
this.setButtons()
|
this.setButtons()
|
||||||
}
|
}
|
||||||
@@ -66,11 +71,11 @@ export class AppShowPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
launchUiTab (): void {
|
launchUiTab (): void {
|
||||||
window.open(this.config.launchableURL(this.pkg.installed), '_blank')
|
window.open(this.config.launchableURL(this.pkg), '_blank')
|
||||||
}
|
}
|
||||||
|
|
||||||
async stop (): Promise<void> {
|
async stop (): Promise<void> {
|
||||||
const { id, title, version } = this.pkg.installed.manifest
|
const { id, title, version } = this.pkg.manifest
|
||||||
await this.loader.of({
|
await this.loader.of({
|
||||||
message: `Stopping...`,
|
message: `Stopping...`,
|
||||||
spinner: 'lines',
|
spinner: 'lines',
|
||||||
@@ -99,7 +104,7 @@ export class AppShowPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async tryStart (): Promise<void> {
|
async tryStart (): Promise<void> {
|
||||||
const message = this.pkg.installed.manifest.alerts.start
|
const message = this.pkg.manifest.alerts.start
|
||||||
if (message) {
|
if (message) {
|
||||||
this.presentAlertStart(message)
|
this.presentAlertStart(message)
|
||||||
} else {
|
} else {
|
||||||
@@ -108,13 +113,13 @@ export class AppShowPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async donate (): Promise<void> {
|
async donate (): Promise<void> {
|
||||||
const url = this.manifest['donation-url']
|
const url = this.pkg.manifest['donation-url']
|
||||||
if (url) {
|
if (url) {
|
||||||
window.open(url, '_blank')
|
window.open(url, '_blank')
|
||||||
} else {
|
} else {
|
||||||
const alert = await this.alertCtrl.create({
|
const alert = await this.alertCtrl.create({
|
||||||
header: 'Not Accepting Donations',
|
header: 'Not Accepting Donations',
|
||||||
message: `The developers of ${this.manifest.title} have not provided a donation URL. Please contact them directly if you insist on giving them money.`,
|
message: `The developers of ${this.pkg.manifest.title} have not provided a donation URL. Please contact them directly if you insist on giving them money.`,
|
||||||
buttons: ['OK'],
|
buttons: ['OK'],
|
||||||
})
|
})
|
||||||
await alert.present()
|
await alert.present()
|
||||||
@@ -143,8 +148,8 @@ export class AppShowPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async installDep (depId: string): Promise<void> {
|
private async installDep (depId: string): Promise<void> {
|
||||||
const version = this.pkg.installed.manifest.dependencies[depId].version
|
const version = this.pkg.manifest.dependencies[depId].version
|
||||||
const dependentTitle = this.pkg.installed.manifest.title
|
const dependentTitle = this.pkg.manifest.title
|
||||||
|
|
||||||
const installRec: Recommendation = {
|
const installRec: Recommendation = {
|
||||||
dependentId: this.pkgId,
|
dependentId: this.pkgId,
|
||||||
@@ -164,7 +169,7 @@ export class AppShowPage {
|
|||||||
const configErrors = (this.pkg.installed.status['dependency-errors'][depId] as DependencyErrorConfigUnsatisfied).errors
|
const configErrors = (this.pkg.installed.status['dependency-errors'][depId] as DependencyErrorConfigUnsatisfied).errors
|
||||||
|
|
||||||
const description = `<ul>${configErrors.map(d => `<li>${d}</li>`).join('\n')}</ul>`
|
const description = `<ul>${configErrors.map(d => `<li>${d}</li>`).join('\n')}</ul>`
|
||||||
const dependentTitle = this.pkg.installed.manifest.title
|
const dependentTitle = this.pkg.manifest.title
|
||||||
|
|
||||||
const configRecommendation: Recommendation = {
|
const configRecommendation: Recommendation = {
|
||||||
dependentId: this.pkgId,
|
dependentId: this.pkgId,
|
||||||
|
|||||||
@@ -58,20 +58,20 @@
|
|||||||
<ion-label>
|
<ion-label>
|
||||||
<h2 style="font-family: 'Montserrat';">{{ pkg.title }}</h2>
|
<h2 style="font-family: 'Montserrat';">{{ pkg.title }}</h2>
|
||||||
<p>{{ pkg.descriptionShort }}</p>
|
<p>{{ pkg.descriptionShort }}</p>
|
||||||
<ng-container *ngIf="patch.data['package-data'] as pkgI">
|
<ng-container *ngIf="patch.data['package-data'][pkg.id] as localPkg">
|
||||||
<p *ngIf="pkgI.state === PackageState.Installed">
|
<p *ngIf="localPkg.state === PackageState.Installed">
|
||||||
<ion-text *ngIf="(pkg.version | compareEmver : pkgI.installed.manifest.version) === 0" color="success">Installed</ion-text>
|
<ion-text *ngIf="(pkg.version | compareEmver : localPkg.manifest.version) === 0" color="success">Installed</ion-text>
|
||||||
<ion-text *ngIf="(pkg.version | compareEmver : pkgI.installed.manifest.version) === 1" color="warning">Update Available</ion-text>
|
<ion-text *ngIf="(pkg.version | compareEmver : localPkg.manifest.version) === 1" color="warning">Update Available</ion-text>
|
||||||
</p>
|
</p>
|
||||||
<p *ngIf="pkgI.state === PackageState.Installing" style="display: flex; flex-direction: row; align-items: center;">
|
<p *ngIf="localPkg.state === PackageState.Installing" style="display: flex; flex-direction: row; align-items: center;">
|
||||||
<ion-text color="primary">Installing</ion-text>
|
<ion-text color="primary">Installing</ion-text>
|
||||||
<ion-spinner name="crescent" style="height: 10px; width: 15px; margin-left: 3px; margin-right: -4px;" color="primary"></ion-spinner>
|
<ion-spinner name="crescent" style="height: 10px; width: 15px; margin-left: 3px; margin-right: -4px;" color="primary"></ion-spinner>
|
||||||
</p>
|
</p>
|
||||||
<p *ngIf="pkgI.state === PackageState.Updating" style="display: flex; flex-direction: row; align-items: center;">
|
<p *ngIf="localPkg.state === PackageState.Updating" style="display: flex; flex-direction: row; align-items: center;">
|
||||||
<ion-text color="primary">Updating</ion-text>
|
<ion-text color="primary">Updating</ion-text>
|
||||||
<ion-spinner name="crescent" style="height: 10px; width: 15px; margin-left: 3px; margin-right: -4px;" color="primary"></ion-spinner>
|
<ion-spinner name="crescent" style="height: 10px; width: 15px; margin-left: 3px; margin-right: -4px;" color="primary"></ion-spinner>
|
||||||
</p>
|
</p>
|
||||||
<p *ngIf="pkgI.state === PackageState.Removing" style="display: flex; flex-direction: row; align-items: center;">
|
<p *ngIf="localPkg.state === PackageState.Removing" style="display: flex; flex-direction: row; align-items: center;">
|
||||||
<ion-text color="danger">Removing</ion-text>
|
<ion-text color="danger">Removing</ion-text>
|
||||||
<ion-spinner name="crescent" style="height: 10px; width: 15px; margin-left: 3px; margin-right: -4px;" color="danger"></ion-spinner>
|
<ion-spinner name="crescent" style="height: 10px; width: 15px; margin-left: 3px; margin-right: -4px;" color="danger"></ion-spinner>
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
<!-- installed -->
|
<!-- installed -->
|
||||||
<ng-template #installed>
|
<ng-template #installed>
|
||||||
<p>
|
<p>
|
||||||
<ion-text color="medium">Installed at {{ installedPkg.installed.manifest.version | displayEmver }}</ion-text>
|
<ion-text color="medium">Installed at {{ installedPkg.manifest.version | displayEmver }}</ion-text>
|
||||||
</p>
|
</p>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@@ -59,10 +59,10 @@
|
|||||||
<ng-template #installedPkg2>
|
<ng-template #installedPkg2>
|
||||||
<!-- not installing, updating, or removing -->
|
<!-- not installing, updating, or removing -->
|
||||||
<ng-container *ngIf="installedPkg.state === PackageState.Installed">
|
<ng-container *ngIf="installedPkg.state === PackageState.Installed">
|
||||||
<ion-button *ngIf="(installedPkg.installed.manifest.version | compareEmver : pkg.manifest.version) === -1" class="main-action-button" expand="block" (click)="update('update')">
|
<ion-button *ngIf="(installedPkg.manifest.version | compareEmver : pkg.manifest.version) === -1" class="main-action-button" expand="block" (click)="update('update')">
|
||||||
Update
|
Update
|
||||||
</ion-button>
|
</ion-button>
|
||||||
<ion-button *ngIf="(installedPkg.installed.manifest.version | compareEmver : pkg.manifest.version) === 1" class="main-action-button" expand="block" color="warning" (click)="update('downgrade')">
|
<ion-button *ngIf="(installedPkg.manifest.version | compareEmver : pkg.manifest.version) === 1" class="main-action-button" expand="block" color="warning" (click)="update('downgrade')">
|
||||||
Downgrade
|
Downgrade
|
||||||
</ion-button>
|
</ion-button>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
import { Pipe, PipeTransform } from '@angular/core'
|
|
||||||
import { combineLatest, Observable } from 'rxjs'
|
|
||||||
import { map } from 'rxjs/operators'
|
|
||||||
import { PatchDbModel } from '../services/patch-db/patch-db.service'
|
|
||||||
import { renderPkgStatus } from '../services/pkg-status-rendering.service'
|
|
||||||
|
|
||||||
@Pipe({
|
|
||||||
name: 'displayBulb',
|
|
||||||
})
|
|
||||||
export class DisplayBulbPipe implements PipeTransform {
|
|
||||||
|
|
||||||
constructor (
|
|
||||||
private readonly patch: PatchDbModel,
|
|
||||||
) { }
|
|
||||||
|
|
||||||
transform (pkgId: string, bulb: DisplayBulb, connected: boolean): Observable<boolean> {
|
|
||||||
return combineLatest([
|
|
||||||
this.patch.watch$('package-data', pkgId, 'state'),
|
|
||||||
this.patch.watch$('package-data', pkgId, 'installed', 'status'),
|
|
||||||
])
|
|
||||||
.pipe(
|
|
||||||
map(([state, status]) => {
|
|
||||||
if (!connected) return bulb === 'off'
|
|
||||||
const { color } = renderPkgStatus(state, status)
|
|
||||||
switch (color) {
|
|
||||||
case 'danger': return bulb === 'red'
|
|
||||||
case 'success': return bulb === 'green'
|
|
||||||
case 'warning': return bulb === 'yellow'
|
|
||||||
default: return bulb === 'off'
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type DisplayBulb = 'off' | 'red' | 'green' | 'yellow'
|
|
||||||
@@ -24,13 +24,3 @@ export class LaunchablePipe implements PipeTransform {
|
|||||||
return this.configService.isLaunchable(pkg)
|
return this.configService.isLaunchable(pkg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Pipe({
|
|
||||||
name: 'manifest',
|
|
||||||
})
|
|
||||||
export class ManifestPipe implements PipeTransform {
|
|
||||||
|
|
||||||
transform (pkg: PackageDataEntry): Manifest {
|
|
||||||
return getManifest(pkg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -307,7 +307,6 @@ export class MockApiService extends ApiService {
|
|||||||
const pkg: PackageDataEntry = {
|
const pkg: PackageDataEntry = {
|
||||||
...Mock.bitcoinproxy,
|
...Mock.bitcoinproxy,
|
||||||
state: PackageState.Installing,
|
state: PackageState.Installing,
|
||||||
'temp-manifest': Mock.MockManifestBitcoinProxy,
|
|
||||||
// installed: undefined,
|
// installed: undefined,
|
||||||
'install-progress': {
|
'install-progress': {
|
||||||
size: 100,
|
size: 100,
|
||||||
|
|||||||
@@ -578,12 +578,11 @@ export module Mock {
|
|||||||
icon: 'assets/img/service-icons/bitcoind.png',
|
icon: 'assets/img/service-icons/bitcoind.png',
|
||||||
instructions: 'instructionsUrl', // /public/package-data/bitcoind/0.21.1/INSTRUCTIONS.md
|
instructions: 'instructionsUrl', // /public/package-data/bitcoind/0.21.1/INSTRUCTIONS.md
|
||||||
},
|
},
|
||||||
'temp-manifest': undefined,
|
manifest: {
|
||||||
|
...MockManifestBitcoind,
|
||||||
|
version: '0.20.0',
|
||||||
|
},
|
||||||
installed: {
|
installed: {
|
||||||
manifest: {
|
|
||||||
...MockManifestBitcoind,
|
|
||||||
version: '0.20.0',
|
|
||||||
},
|
|
||||||
status: {
|
status: {
|
||||||
configured: true,
|
configured: true,
|
||||||
main: {
|
main: {
|
||||||
@@ -629,9 +628,8 @@ export module Mock {
|
|||||||
icon: 'assets/img/service-icons/lnd.png',
|
icon: 'assets/img/service-icons/lnd.png',
|
||||||
instructions: 'instructionsUrl', // /public/package-data/lnd/0.21.1/INSTRUCTIONS.md
|
instructions: 'instructionsUrl', // /public/package-data/lnd/0.21.1/INSTRUCTIONS.md
|
||||||
},
|
},
|
||||||
'temp-manifest': undefined,
|
manifest: MockManifestLnd,
|
||||||
installed: {
|
installed: {
|
||||||
manifest: MockManifestLnd,
|
|
||||||
status: {
|
status: {
|
||||||
configured: true,
|
configured: true,
|
||||||
main: {
|
main: {
|
||||||
@@ -681,9 +679,8 @@ export module Mock {
|
|||||||
icon: 'assets/img/service-icons/bitcoin-proxy.png',
|
icon: 'assets/img/service-icons/bitcoin-proxy.png',
|
||||||
instructions: 'instructionsUrl', // /public/package-data/bitcoinproxy/0.2.2/INSTRUCTIONS.md
|
instructions: 'instructionsUrl', // /public/package-data/bitcoinproxy/0.2.2/INSTRUCTIONS.md
|
||||||
},
|
},
|
||||||
'temp-manifest': undefined,
|
manifest: MockManifestBitcoinProxy,
|
||||||
installed: {
|
installed: {
|
||||||
manifest: MockManifestBitcoinProxy,
|
|
||||||
status: {
|
status: {
|
||||||
configured: true,
|
configured: true,
|
||||||
main: {
|
main: {
|
||||||
|
|||||||
@@ -53,16 +53,14 @@ export class ConfigService {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
const installed = pkg.installed
|
return pkg.installed.status.main.status === PackageMainStatus.Running &&
|
||||||
|
|
||||||
return installed.status.main.status === PackageMainStatus.Running &&
|
|
||||||
(
|
(
|
||||||
(hasTorUi(installed.manifest.interfaces) && this.isTor()) ||
|
(hasTorUi(pkg.manifest.interfaces) && this.isTor()) ||
|
||||||
(hasLanUi(installed.manifest.interfaces) && !this.isTor())
|
(hasLanUi(pkg.manifest.interfaces) && !this.isTor())
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
launchableURL (pkg: InstalledPackageDataEntry): string {
|
launchableURL (pkg: PackageDataEntry): string {
|
||||||
return this.isTor() ? `http://${torUiAddress(pkg)}` : `https://${lanUiAddress(pkg)}`
|
return this.isTor() ? `http://${torUiAddress(pkg)}` : `https://${lanUiAddress(pkg)}`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +73,7 @@ export function hasLanUi (interfaces: { [id: string]: InterfaceDef }): boolean {
|
|||||||
return !!Object.values(interfaces).find(i => i.ui && i['lan-config'])
|
return !!Object.values(interfaces).find(i => i.ui && i['lan-config'])
|
||||||
}
|
}
|
||||||
|
|
||||||
export function torUiAddress (pkg: InstalledPackageDataEntry): string {
|
export function torUiAddress (pkg: PackageDataEntry): string {
|
||||||
const interfaces = pkg.manifest.interfaces
|
const interfaces = pkg.manifest.interfaces
|
||||||
const id = Object.keys(interfaces).find(key => {
|
const id = Object.keys(interfaces).find(key => {
|
||||||
const val = interfaces[key]
|
const val = interfaces[key]
|
||||||
@@ -84,7 +82,7 @@ export function torUiAddress (pkg: InstalledPackageDataEntry): string {
|
|||||||
return pkg['interface-info'].addresses[id]['tor-address']
|
return pkg['interface-info'].addresses[id]['tor-address']
|
||||||
}
|
}
|
||||||
|
|
||||||
export function lanUiAddress (pkg: InstalledPackageDataEntry): string {
|
export function lanUiAddress (pkg: PackageDataEntry): string {
|
||||||
const interfaces = pkg.manifest.interfaces
|
const interfaces = pkg.manifest.interfaces
|
||||||
const id = Object.keys(interfaces).find(key => {
|
const id = Object.keys(interfaces).find(key => {
|
||||||
const val = interfaces[key]
|
const val = interfaces[key]
|
||||||
@@ -99,7 +97,7 @@ export function hasUi (interfaces: { [id: string]: InterfaceDef }): boolean {
|
|||||||
|
|
||||||
export function getManifest (pkg: PackageDataEntry): Manifest {
|
export function getManifest (pkg: PackageDataEntry): Manifest {
|
||||||
if (pkg.state === PackageState.Installed) {
|
if (pkg.state === PackageState.Installed) {
|
||||||
return pkg.installed.manifest
|
return pkg.manifest
|
||||||
}
|
}
|
||||||
return pkg['temp-manifest']
|
return pkg['temp-manifest']
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export class ConnectionService {
|
|||||||
this.connectionFailure$.next(ConnectionFailure.Network)
|
this.connectionFailure$.next(ConnectionFailure.Network)
|
||||||
} else if (!this.configService.isTor()) {
|
} else if (!this.configService.isTor()) {
|
||||||
this.connectionFailure$.next(ConnectionFailure.Lan)
|
this.connectionFailure$.next(ConnectionFailure.Lan)
|
||||||
} {
|
} else {
|
||||||
// diagnosing
|
// diagnosing
|
||||||
this.connectionFailure$.next(ConnectionFailure.Diagnosing)
|
this.connectionFailure$.next(ConnectionFailure.Diagnosing)
|
||||||
const torSuccess = await this.testAddrs(addrs?.tor || [])
|
const torSuccess = await this.testAddrs(addrs?.tor || [])
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export interface PackageDataEntry {
|
|||||||
instructions: URL
|
instructions: URL
|
||||||
icon: URL
|
icon: URL
|
||||||
}
|
}
|
||||||
'temp-manifest'?: Manifest // exists when: installing, updating, removing
|
manifest: Manifest
|
||||||
installed?: InstalledPackageDataEntry, // exists when: installed, updating
|
installed?: InstalledPackageDataEntry, // exists when: installed, updating
|
||||||
'install-progress'?: InstallProgress, // exists when: installing, updating
|
'install-progress'?: InstallProgress, // exists when: installing, updating
|
||||||
}
|
}
|
||||||
@@ -62,7 +62,6 @@ export interface InstallProgress {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface InstalledPackageDataEntry {
|
export interface InstalledPackageDataEntry {
|
||||||
manifest: Manifest
|
|
||||||
status: Status
|
status: Status
|
||||||
'interface-info': InterfaceInfo
|
'interface-info': InterfaceInfo
|
||||||
'system-pointers': any[]
|
'system-pointers': any[]
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 946 B After Width: | Height: | Size: 946 B |
|
Before Width: | Height: | Size: 1016 B After Width: | Height: | Size: 1016 B |
Reference in New Issue
Block a user