mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-31 04:23:40 +00:00
feat: enable strictNullChecks
feat: enable `noImplicitAny` chore: remove sync data access fix loading package data for affected dependencies chore: properly get alt marketplace data update patchdb client to allow for emit on undefined values
This commit is contained in:
@@ -1,12 +1,10 @@
|
||||
<div [hidden]="!control.dirty && !control.touched" class="validation-error">
|
||||
<!-- primitive -->
|
||||
<p *ngIf="control.hasError('required')">
|
||||
{{ spec.name }} is required
|
||||
</p>
|
||||
<p *ngIf="control.hasError('required')">{{ spec.name }} is required</p>
|
||||
|
||||
<!-- string -->
|
||||
<p *ngIf="control.hasError('pattern')">
|
||||
{{ spec['pattern-description'] }}
|
||||
{{ $any(spec)['pattern-description'] }}
|
||||
</p>
|
||||
|
||||
<!-- number -->
|
||||
@@ -15,7 +13,7 @@
|
||||
{{ spec.name }} must be an integer
|
||||
</p>
|
||||
<p *ngIf="control.hasError('numberNotInRange')">
|
||||
{{ control.errors['numberNotInRange'].value }}
|
||||
{{ control.errors?.['numberNotInRange']?.value }}
|
||||
</p>
|
||||
<p *ngIf="control.hasError('notNumber')">
|
||||
{{ spec.name }} must be a number
|
||||
@@ -25,13 +23,13 @@
|
||||
<!-- list -->
|
||||
<ng-container *ngIf="spec.type === 'list'">
|
||||
<p *ngIf="control.hasError('listNotInRange')">
|
||||
{{ control.errors['listNotInRange'].value }}
|
||||
{{ control.errors?.['listNotInRange']?.value }}
|
||||
</p>
|
||||
<p *ngIf="control.hasError('listNotUnique')">
|
||||
{{ control.errors['listNotUnique'].value }}
|
||||
{{ control.errors?.['listNotUnique']?.value }}
|
||||
</p>
|
||||
<p *ngIf="control.hasError('listItemIssue')">
|
||||
{{ control.errors['listItemIssue'].value }}
|
||||
{{ control.errors?.['listItemIssue']?.value }}
|
||||
</p>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<form-label
|
||||
[data]="{
|
||||
spec: spec,
|
||||
new: current && current[entry.key] === undefined,
|
||||
new: !!current && current[entry.key] === undefined,
|
||||
edited: entry.value.dirty
|
||||
}"
|
||||
></form-label>
|
||||
@@ -129,7 +129,7 @@
|
||||
<!-- enum -->
|
||||
<!-- class enter-click disables the enter click on the modal behind the select -->
|
||||
<ion-select
|
||||
*ngIf="spec.type === 'enum'"
|
||||
*ngIf="spec.type === 'enum' && formGroup.get(entry.key) as control"
|
||||
[interfaceOptions]="{
|
||||
message: getWarningText(spec.warning),
|
||||
cssClass: 'enter-click'
|
||||
@@ -137,7 +137,7 @@
|
||||
slot="end"
|
||||
placeholder="Select"
|
||||
[formControlName]="entry.key"
|
||||
[selectedText]="spec['value-names'][formGroup.get(entry.key).value]"
|
||||
[selectedText]="spec['value-names'][control.value]"
|
||||
>
|
||||
<ion-select-option
|
||||
*ngFor="let option of spec.values"
|
||||
@@ -157,7 +157,7 @@
|
||||
<form-label
|
||||
[data]="{
|
||||
spec: spec,
|
||||
new: current && current[entry.key] === undefined,
|
||||
new: !!current && current[entry.key] === undefined,
|
||||
edited: entry.value.dirty
|
||||
}"
|
||||
></form-label>
|
||||
@@ -208,7 +208,7 @@
|
||||
<form-label
|
||||
[data]="{
|
||||
spec: spec,
|
||||
new: current && current[entry.key] === undefined,
|
||||
new: !!current && current[entry.key] === undefined,
|
||||
edited: entry.value.dirty
|
||||
}"
|
||||
></form-label>
|
||||
@@ -281,16 +281,12 @@
|
||||
: $any(spec.spec).spec
|
||||
"
|
||||
[formGroup]="abstractControl"
|
||||
[current]="
|
||||
current && current[entry.key]
|
||||
? current[entry.key][i]
|
||||
: undefined
|
||||
"
|
||||
[current]="current?.[entry.key]?.[i]"
|
||||
[unionSpec]="
|
||||
spec.subtype === 'union' ? $any(spec.spec) : undefined
|
||||
"
|
||||
(onInputChange)="
|
||||
updateLabel(entry.key, i, spec.spec['display-as'])
|
||||
updateLabel(entry.key, i, $any(spec.spec)['display-as'])
|
||||
"
|
||||
(onExpand)="resize(entry.key, i)"
|
||||
></form-object>
|
||||
@@ -350,7 +346,7 @@
|
||||
<form-label
|
||||
[data]="{
|
||||
spec: spec,
|
||||
new: current && current[entry.key] === undefined,
|
||||
new: !!current && current[entry.key] === undefined,
|
||||
edited: entry.value.dirty
|
||||
}"
|
||||
></form-label>
|
||||
@@ -372,7 +368,7 @@
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
<form-error
|
||||
*ngIf="formGroup.get(entry.key).errors"
|
||||
*ngIf="formGroup.get(entry.key)?.errors"
|
||||
[control]="$any(formGroup.get(entry.key))"
|
||||
[spec]="spec"
|
||||
>
|
||||
|
||||
@@ -34,8 +34,8 @@ const Mustache = require('mustache')
|
||||
export class FormObjectComponent {
|
||||
@Input() objectSpec: ConfigSpec
|
||||
@Input() formGroup: FormGroup
|
||||
@Input() unionSpec: ValueSpecUnion
|
||||
@Input() current: { [key: string]: any }
|
||||
@Input() unionSpec?: ValueSpecUnion
|
||||
@Input() current?: { [key: string]: any }
|
||||
@Input() showEdited: boolean = false
|
||||
@Output() onInputChange = new EventEmitter<void>()
|
||||
@Output() onExpand = new EventEmitter<void>()
|
||||
@@ -61,7 +61,7 @@ export class FormObjectComponent {
|
||||
|
||||
if (spec.type === 'list' && ['object', 'union'].includes(spec.subtype)) {
|
||||
this.objectListDisplay[key] = []
|
||||
this.formGroup.get(key).value.forEach((obj, index) => {
|
||||
this.formGroup.get(key)?.value.forEach((obj: any, index: number) => {
|
||||
const displayAs = (spec.spec as ListValueSpecOf<'object'>)[
|
||||
'display-as'
|
||||
]
|
||||
@@ -87,7 +87,7 @@ export class FormObjectComponent {
|
||||
}
|
||||
|
||||
updateUnion(e: any): void {
|
||||
const primary = this.unionSpec.tag.id
|
||||
const primary = this.unionSpec?.tag.id
|
||||
|
||||
Object.keys(this.formGroup.controls).forEach(control => {
|
||||
if (control === primary) return
|
||||
@@ -104,7 +104,7 @@ export class FormObjectComponent {
|
||||
this.formGroup.addControl(control, unionGroup.controls[control])
|
||||
})
|
||||
|
||||
Object.entries(this.unionSpec.variants[e.detail.value]).forEach(
|
||||
Object.entries(this.unionSpec?.variants[e.detail.value] || {}).forEach(
|
||||
([key, value]) => {
|
||||
if (['object', 'union'].includes(value.type)) {
|
||||
this.objectDisplay[key] = {
|
||||
@@ -138,6 +138,9 @@ export class FormObjectComponent {
|
||||
if (markDirty) arr.markAsDirty()
|
||||
const listSpec = this.objectSpec[key] as ValueSpecList
|
||||
const newItem = this.formService.getListItem(listSpec, val)
|
||||
|
||||
if (!newItem) return
|
||||
|
||||
newItem.markAllAsTouched()
|
||||
arr.insert(0, newItem)
|
||||
if (['object', 'union'].includes(listSpec.subtype)) {
|
||||
@@ -177,13 +180,14 @@ export class FormObjectComponent {
|
||||
|
||||
updateLabel(key: string, i: number, displayAs: string) {
|
||||
this.objectListDisplay[key][i].displayAs = displayAs
|
||||
? Mustache.render(displayAs, this.formGroup.get(key).value[i])
|
||||
? Mustache.render(displayAs, this.formGroup.get(key)?.value[i])
|
||||
: ''
|
||||
}
|
||||
|
||||
getWarningText(text: string): IonicSafeString {
|
||||
if (text)
|
||||
return new IonicSafeString(`<ion-text color="warning">${text}</ion-text>`)
|
||||
getWarningText(text: string = ''): IonicSafeString | string {
|
||||
return text
|
||||
? new IonicSafeString(`<ion-text color="warning">${text}</ion-text>`)
|
||||
: ''
|
||||
}
|
||||
|
||||
handleInputChange() {
|
||||
@@ -192,8 +196,8 @@ export class FormObjectComponent {
|
||||
|
||||
handleBooleanChange(key: string, spec: ValueSpecBoolean) {
|
||||
if (spec.warning) {
|
||||
const current = this.formGroup.get(key).value
|
||||
const cancelFn = () => this.formGroup.get(key).setValue(!current)
|
||||
const current = this.formGroup.get(key)?.value
|
||||
const cancelFn = () => this.formGroup.get(key)?.setValue(!current)
|
||||
this.presentAlertChangeWarning(key, spec, undefined, cancelFn)
|
||||
}
|
||||
}
|
||||
@@ -307,7 +311,7 @@ export class FormObjectComponent {
|
||||
}
|
||||
|
||||
private updateEnumList(key: string, current: string[], updated: string[]) {
|
||||
this.formGroup.get(key).markAsDirty()
|
||||
this.formGroup.get(key)?.markAsDirty()
|
||||
|
||||
for (let i = current.length - 1; i >= 0; i--) {
|
||||
if (!updated.includes(current[i])) {
|
||||
@@ -322,9 +326,9 @@ export class FormObjectComponent {
|
||||
})
|
||||
}
|
||||
|
||||
private getDocSize(key: string, index = 0) {
|
||||
private getDocSize(key: string, index = 0): string {
|
||||
const element = document.getElementById(this.getElementId(key, index))
|
||||
return `${element.scrollHeight}px`
|
||||
return `${element?.scrollHeight}px`
|
||||
}
|
||||
|
||||
getElementId(key: string, index = 0): string {
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
{{ dependentViolation }}
|
||||
</div>
|
||||
|
||||
<div *ngIf="patch.data['package-data']" class="items">
|
||||
<div *ngIf="pkgs$ | async as pkgs" class="items">
|
||||
<div class="affected">
|
||||
<ion-text color="warning">Affected Services</ion-text>
|
||||
</div>
|
||||
@@ -26,13 +26,10 @@
|
||||
*ngFor="let dep of dependentBreakages | keyvalue"
|
||||
>
|
||||
<ion-thumbnail class="thumbnail" slot="start">
|
||||
<img
|
||||
alt=""
|
||||
[src]="patch.data['package-data'][dep.key]['static-files'].icon"
|
||||
/>
|
||||
<img alt="" [src]="pkgs[dep.key]['static-files'].icon" />
|
||||
</ion-thumbnail>
|
||||
<ion-label>
|
||||
<h5>{{ patch.data['package-data'][dep.key].manifest.title }}</h5>
|
||||
<h5>{{ pkgs[dep.key].manifest.title }}</h5>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</div>
|
||||
|
||||
@@ -35,6 +35,8 @@ export class DependentsComponent {
|
||||
loading$ = new BehaviorSubject(false)
|
||||
cancel$ = new Subject<void>()
|
||||
|
||||
readonly pkgs$ = this.patch.watch$('package-data')
|
||||
|
||||
constructor(public readonly patch: PatchDbService) {}
|
||||
|
||||
load() {
|
||||
@@ -45,6 +47,7 @@ export class DependentsComponent {
|
||||
)
|
||||
.subscribe({
|
||||
complete: () => {
|
||||
console.log('DEP BREAKS, ', this.dependentBreakages)
|
||||
if (
|
||||
this.dependentBreakages &&
|
||||
!isEmptyObject(this.dependentBreakages)
|
||||
|
||||
@@ -33,7 +33,7 @@ export class WizardBaker {
|
||||
const action = 'update'
|
||||
const toolbar: TopbarParams = { action, title, version }
|
||||
|
||||
const slideDefinitions: SlideDefinition[] = [
|
||||
const slideDefinitions: Array<SlideDefinition | undefined> = [
|
||||
installAlert
|
||||
? {
|
||||
slide: {
|
||||
@@ -170,7 +170,7 @@ export class WizardBaker {
|
||||
const action = 'downgrade'
|
||||
const toolbar: TopbarParams = { action, title, version }
|
||||
|
||||
const slideDefinitions: SlideDefinition[] = [
|
||||
const slideDefinitions: Array<SlideDefinition | undefined> = [
|
||||
installAlert
|
||||
? {
|
||||
slide: {
|
||||
|
||||
@@ -66,19 +66,20 @@ export class LogsPage {
|
||||
try {
|
||||
// get logs
|
||||
const logs = await this.fetch()
|
||||
if (!logs.length) return
|
||||
if (!logs?.length) return
|
||||
|
||||
const container = document.getElementById('container')
|
||||
const beforeContainerHeight = container.scrollHeight
|
||||
const newLogs = document
|
||||
.getElementById('template')
|
||||
.cloneNode(true) as HTMLElement
|
||||
const beforeContainerHeight = container?.scrollHeight || 0
|
||||
const newLogs = document.getElementById('template')?.cloneNode(true)
|
||||
|
||||
if (!(newLogs instanceof HTMLElement)) return
|
||||
|
||||
newLogs.innerHTML =
|
||||
logs
|
||||
.map(l => `${l.timestamp} ${convert.toHtml(l.message)}`)
|
||||
.join('\n') + (logs.length ? '\n' : '')
|
||||
container.prepend(newLogs)
|
||||
const afterContainerHeight = container.scrollHeight
|
||||
container?.prepend(newLogs)
|
||||
const afterContainerHeight = container?.scrollHeight || 0
|
||||
|
||||
// scroll down
|
||||
scrollBy(0, afterContainerHeight - beforeContainerHeight)
|
||||
@@ -97,17 +98,18 @@ export class LogsPage {
|
||||
try {
|
||||
this.loadingMore = true
|
||||
const logs = await this.fetch(false)
|
||||
if (!logs.length) return (this.loadingMore = false)
|
||||
if (!logs?.length) return (this.loadingMore = false)
|
||||
|
||||
const container = document.getElementById('container')
|
||||
const newLogs = document
|
||||
.getElementById('template')
|
||||
.cloneNode(true) as HTMLElement
|
||||
const newLogs = document.getElementById('template')?.cloneNode(true)
|
||||
|
||||
if (!(newLogs instanceof HTMLElement)) return
|
||||
|
||||
newLogs.innerHTML =
|
||||
logs
|
||||
.map(l => `${l.timestamp} ${convert.toHtml(l.message)}`)
|
||||
.join('\n') + (logs.length ? '\n' : '')
|
||||
container.append(newLogs)
|
||||
container?.append(newLogs)
|
||||
this.loadingMore = false
|
||||
this.scrollEvent()
|
||||
} catch (e) {}
|
||||
@@ -116,7 +118,7 @@ export class LogsPage {
|
||||
scrollEvent() {
|
||||
const buttonDiv = document.getElementById('button-div')
|
||||
this.isOnBottom =
|
||||
buttonDiv && buttonDiv.getBoundingClientRect().top < window.innerHeight
|
||||
!!buttonDiv && buttonDiv.getBoundingClientRect().top < window.innerHeight
|
||||
}
|
||||
|
||||
scrollToBottom() {
|
||||
|
||||
@@ -20,5 +20,5 @@ export class StatusComponent {
|
||||
@Input() weight?: string = 'normal'
|
||||
@Input() disconnected?: boolean = false
|
||||
@Input() installProgress?: number
|
||||
@Input() sigtermTimeout?: string
|
||||
@Input() sigtermTimeout?: string | null = null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user