This commit is contained in:
Matt Hill
2024-03-25 13:31:30 -06:00
parent 4ab7300376
commit d202cb731d
15 changed files with 80 additions and 109 deletions

View File

@@ -25,6 +25,7 @@ import {
ServerNotifications,
} from 'src/app/services/api/api.types'
import { NotificationService } from '../../services/notification.service'
import { ToManifestPipe } from '../../pipes/to-manifest'
@Component({
selector: 'header-notifications',
@@ -47,7 +48,11 @@ import { NotificationService } from '../../services/notification.service'
[notification]="not"
>
<ng-container *ngIf="not.packageId as pkgId">
{{ $any(packageData[pkgId])?.manifest.title || pkgId }}
{{
packageData[pkgId]
? (packageData[pkgId] | toManifest).title
: pkgId
}}
</ng-container>
<button
style="align-self: flex-start; flex-shrink: 0;"
@@ -98,6 +103,7 @@ import { NotificationService } from '../../services/notification.service'
TuiCellModule,
TuiAvatarStackModule,
TuiTitleModule,
ToManifestPipe,
],
})
export class HeaderNotificationsComponent {

View File

@@ -9,6 +9,7 @@ import { WINDOW } from '@ng-web-apis/common'
import { CopyService } from '@start9labs/shared'
import { TuiDialogService } from '@taiga-ui/core'
import {
TuiBadgeModule,
TuiButtonModule,
TuiCellModule,
TuiTitleModule,
@@ -22,12 +23,12 @@ import { mask } from 'src/app/util/mask'
selector: 'app-interface-address',
template: `
<div tuiCell>
<h3 tuiTitle>
<span tuiSubtitle>{{ isMasked ? mask : address }}</span>
</h3>
<tui-badge appearance="success">
{{ label }}
</tui-badge>
<h3 tuiTitle>
<span tuiSubtitle>{{ isMasked ? mask : address }}</span>
</h3>
<button
*ngIf="isUi"
tuiIconButton
@@ -51,11 +52,25 @@ import { mask } from 'src/app/util/mask'
appearance="icon"
(click)="copyService.copy(address)"
>
Copy QR code
Copy URL
</button>
<button
tuiIconButton
iconLeft="tuiIconTrash"
appearance="icon"
(click)="destroy()"
>
Destroy
</button>
</div>
`,
imports: [NgIf, TuiCellModule, TuiTitleModule, TuiButtonModule],
imports: [
NgIf,
TuiCellModule,
TuiTitleModule,
TuiButtonModule,
TuiBadgeModule,
],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InterfaceAddressComponent {
@@ -84,4 +99,6 @@ export class InterfaceAddressComponent {
})
.subscribe()
}
destroy() {}
}

View File

@@ -43,26 +43,17 @@ type ClearnetForm = {
<strong>View instructions</strong>
</a>
</em>
<ng-container
*ngIf="
interface.serviceInterface.addresses.clearnet as addresses;
else empty
"
>
@for (
address of interface.serviceInterface.addresses.clearnet;
track $index
) {
<app-interface-address
*ngFor="let address of addresses"
[label]="address.label"
[address]="address.url"
[isMasked]="interface.serviceInterface.masked"
[isUi]="interface.serviceInterface.type === 'ui'"
/>
<div [style.display]="'flex'" [style.gap.rem]="1">
<button tuiButton size="s" appearance="danger-solid" (click)="remove()">
Remove
</button>
</div>
</ng-container>
<ng-template #empty>
} @empty {
<button
tuiButton
iconLeft="tuiIconPlus"
@@ -71,7 +62,7 @@ type ClearnetForm = {
>
Add Address
</button>
</ng-template>
}
`,
imports: [NgForOf, InterfaceAddressComponent, NgIf, TuiButtonModule],
changeDetection: ChangeDetectionStrategy.OnPush,

View File

@@ -20,26 +20,14 @@ import { InterfaceAddressComponent } from './interface-addresses.component'
</a>
</em>
<ng-container
*ngIf="
interface.serviceInterface.addresses.local as addresses;
else empty
"
>
@for (address of interface.serviceInterface.addresses.local; track $index) {
<app-interface-address
*ngFor="let address of addresses"
[label]="address.label"
[address]="address.url"
[isMasked]="interface.serviceInterface.masked"
[isUi]="interface.serviceInterface.type === 'ui'"
/>
<div [style.display]="'flex'" [style.gap.rem]="1">
<button tuiButton size="s" appearance="danger-solid" (click)="remove()">
Remove
</button>
</div>
</ng-container>
<ng-template #empty>
} @empty {
<button
tuiButton
iconLeft="tuiIconPlus"
@@ -48,7 +36,7 @@ import { InterfaceAddressComponent } from './interface-addresses.component'
>
Add Address
</button>
</ng-template>
}
`,
imports: [NgForOf, NgIf, InterfaceAddressComponent, TuiButtonModule],
changeDetection: ChangeDetectionStrategy.OnPush,

View File

@@ -2,6 +2,7 @@ import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
import { InterfaceAddressComponent } from './interface-addresses.component'
import { InterfaceComponent } from './interface.component'
import { NgForOf, NgIf } from '@angular/common'
import { TuiButtonModule } from '@taiga-ui/experimental'
@Component({
standalone: true,
@@ -19,23 +20,14 @@ import { NgForOf, NgIf } from '@angular/common'
</a>
</em>
<ng-container
*ngIf="interface.serviceInterface.addresses.tor as addresses; else empty"
>
@for (address of interface.serviceInterface.addresses.tor; track $index) {
<app-interface-address
*ngFor="let address of addresses"
[label]="address.label"
[address]="address.url"
[isMasked]="interface.serviceInterface.masked"
[isUi]="interface.serviceInterface.type === 'ui'"
/>
<div [style.display]="'flex'" [style.gap.rem]="1">
<button tuiButton size="s" appearance="danger-solid" (click)="remove()">
Remove
</button>
</div>
</ng-container>
<ng-template #empty>
} @empty {
<button
tuiButton
iconLeft="tuiIconPlus"
@@ -44,17 +36,9 @@ import { NgForOf, NgIf } from '@angular/common'
>
Add Address
</button>
</ng-template>
<app-interface-address
*ngFor="let address of interface.serviceInterface.addresses.tor"
[label]="address.label"
[address]="address.url"
[isMasked]="interface.serviceInterface.masked"
[isUi]="interface.serviceInterface.type === 'ui'"
/>
}
`,
imports: [NgForOf, NgIf, InterfaceAddressComponent],
imports: [NgForOf, NgIf, InterfaceAddressComponent, TuiButtonModule],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class InterfaceTorComponent {

View File

@@ -40,10 +40,10 @@ import { Manifest } from '@start9labs/marketplace'
</button>
} @else {
<button
*tuiLet="hasUnmet(pkg) | async as hasUnmet"
*tuiLet="hasUnmet() | async as hasUnmet"
tuiIconButton
iconLeft="tuiIconPlay"
[disabled]="!this.pkg.status.configured"
[disabled]="!pkg.status.configured"
(click)="actions.start(manifest, !!hasUnmet)"
>
Start
@@ -77,11 +77,11 @@ export class ControlsComponent {
readonly actions = inject(ActionsService)
@tuiPure
hasUnmet(pkg: PackageDataEntry): Observable<boolean> {
const id = getManifest(pkg).id
hasUnmet(): Observable<boolean> {
const id = this.manifest.id
return this.errors.getPkgDepErrors$(id).pipe(
map(errors =>
Object.keys(pkg.currentDependencies)
Object.keys(this.pkg.currentDependencies)
.map(id => !!(errors[id] as any)?.[id]) // @TODO fix
.some(Boolean),
),

View File

@@ -28,7 +28,7 @@ import { getManifest } from 'src/app/util/get-package-data'
<fieldset
appControls
[disabled]="
this.pkg.stateInfo.state !== 'installed' || !(connected$ | async)
pkg.stateInfo.state !== 'installed' || !(connected$ | async)
"
[pkg]="pkg"
></fieldset>

View File

@@ -54,7 +54,7 @@ export class StatusComponent {
}
get loading(): boolean {
return !!this.pkg.stateInfo || this.color === 'var(--tui-info-fill)'
return this.color === 'var(--tui-info-fill)'
}
@tuiPure
@@ -94,10 +94,6 @@ export class StatusComponent {
}
get color(): string {
if (this.pkg.stateInfo.installingInfo) {
return 'var(--tui-info-fill)'
}
switch (this.getStatus(this.pkg).primary) {
case PrimaryStatus.Running:
return 'var(--tui-success-fill)'

View File

@@ -84,7 +84,6 @@ import { InstallingProgressPipe } from 'src/app/apps/portal/routes/service/pipes
<service-interface-list
[pkg]="service.pkg"
[status]="service.status"
]
/>
@if (

View File

@@ -27,7 +27,7 @@ import { Domain } from 'src/app/services/patch-db/data-model'
<tbody>
<tr *ngFor="let domain of domains">
<td>{{ domain.value }}</td>
<td>{{ domain.createdAt | date : 'short' }}</td>
<td>{{ domain.createdAt | date: 'short' }}</td>
<td>{{ domain.provider }}</td>
<td>{{ getStrategy(domain) }}</td>
<td>
@@ -69,11 +69,7 @@ export class DomainsTableComponent {
readonly delete = new EventEmitter<Domain>()
getStrategy(domain: any) {
return (
domain.networkStrategy.ipStrategy ||
domain.networkStrategy.proxyId ||
'Primary Proxy'
)
return domain.networkStrategy.ipStrategy || domain.networkStrategy.proxy
}
onUsedBy({ value, usedBy }: Domain) {

View File

@@ -45,12 +45,6 @@ export class SettingsService {
icon: 'tuiIconKey',
action: () => this.promptNewPassword(),
},
{
title: 'Experimental Features',
description: 'Try out new and potentially unstable new features',
icon: 'tuiIconThermometer',
routerLink: 'experimental',
},
],
Network: [
{
@@ -134,7 +128,7 @@ export class SettingsService {
.open(TUI_PROMPT, {
label: this.isTor ? 'Warning' : 'Confirm',
data: {
content: '',
content: '@TODO how to display a checkbox in here?',
yes: 'Reset',
no: 'Cancel',
},

View File

@@ -6,7 +6,6 @@ import {
PackageDataEntry,
UpdatingState,
} from 'src/app/services/patch-db/data-model'
import { hasCurrentDeps } from 'src/app/util/has-deps'
@Pipe({
name: 'filterUpdates',

View File

@@ -6,7 +6,7 @@ import {
} from '@start9labs/marketplace'
import { TuiAvatarModule, TuiCellModule } from '@taiga-ui/experimental'
import { PatchDB } from 'patch-db-client'
import { combineLatest, map } from 'rxjs'
import { combineLatest, map, scan } from 'rxjs'
import { MarketplaceService } from 'src/app/services/marketplace.service'
import {
DataModel,
@@ -79,9 +79,10 @@ export default class UpdatesComponent {
.watch$('packageData')
.pipe(
map(pkgs =>
Object.values(pkgs).reduce(
(acc, curr) => {
if (isInstalled(curr) || isUpdating(curr)) return { ...acc, curr }
Object.entries(pkgs).reduce(
(acc, [id, val]) => {
if (isInstalled(val) || isUpdating(val))
return { ...acc, [id]: val }
return acc
},
{} as Record<

View File

@@ -63,8 +63,9 @@ export class BadgeService {
(list, [_, store]) =>
store?.packages.reduce(
(result, { manifest: { id, version } }) =>
this.emver.compare(version, getManifest(local[id])?.version) ===
1
local[id] &&
this.emver.compare(version, getManifest(local[id]).version) ===
1
? result.add(id)
: result,
list,
@@ -72,6 +73,7 @@ export class BadgeService {
new Set<string>(),
).size,
),
// @TODO shareReplay is preventing the badge from decrementing
shareReplay(1),
)

View File

@@ -340,7 +340,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/ui/domainInfo',
path: '/serverInfo/ui/domainInfo',
value: params.domainInfo,
},
]
@@ -430,7 +430,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/outboundProxy',
path: '/serverInfo/network/outboundProxy',
value: params.proxy,
},
]
@@ -526,7 +526,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/proxies',
path: '/serverInfo/network/proxies',
value: [
{
id: 'abcd-efgh-ijkl-mnop',
@@ -553,7 +553,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: `/server-info/network/proxies/0/name`,
path: `/serverInfo/network/proxies/0/name`,
value: params.name,
},
]
@@ -567,7 +567,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/proxies',
path: '/serverInfo/network/proxies',
value: [],
},
]
@@ -586,7 +586,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/start9ToSubdomain',
path: '/serverInfo/network/start9ToSubdomain',
value: {
value: 'xyz',
createdAt: new Date(),
@@ -607,7 +607,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/start9ToSubdomain',
path: '/serverInfo/network/start9ToSubdomain',
value: null,
},
]
@@ -622,7 +622,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/domains',
path: '/serverInfo/network/domains',
value: [
{
value: params.hostname,
@@ -644,7 +644,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/domains',
path: '/serverInfo/network/domains',
value: [],
},
]
@@ -663,7 +663,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/wanConfig/forwards/0/override',
path: '/serverInfo/network/wanConfig/forwards/0/override',
value: params.port,
},
]
@@ -679,7 +679,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/network/wifi/enabled',
path: '/serverInfo/network/wifi/enabled',
value: params.enable,
},
]
@@ -722,7 +722,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: '/server-info/smtp',
path: '/serverInfo/smtp',
value: params,
},
]
@@ -969,8 +969,6 @@ export class MockApiService extends ApiService {
this.updateProgress(params.id)
}, 1000)
const manifest = Mock.LocalPkgs[params.id].stateInfo.manifest
const patch: Operation<
PackageDataEntry<InstallingState | UpdatingState>
>[] = [
@@ -981,15 +979,15 @@ export class MockApiService extends ApiService {
...Mock.LocalPkgs[params.id],
stateInfo: {
// if installing
state: PackageState.Installing,
// state: PackageState.Installing,
// if updating
// state: PackageState.Updating,
// manifest,
state: PackageState.Updating,
manifest: mockPatchData.packageData[params.id].stateInfo.manifest!,
// both
installingInfo: {
newManifest: manifest,
newManifest: Mock.LocalPkgs[params.id].stateInfo.manifest,
progress: PROGRESS,
},
},
@@ -1285,7 +1283,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: `/package-data/${params.packageId}/installed/interfaceInfo/${params.interfaceId}/addressInfo/domainInfo`,
path: `/packageData/${params.packageId}/installed/interfaceInfo/${params.interfaceId}/addressInfo/domainInfo`,
value: params.domainInfo,
},
]
@@ -1301,7 +1299,7 @@ export class MockApiService extends ApiService {
const patch = [
{
op: PatchOp.REPLACE,
path: `/package-data/${params.packageId}/installed/outboundProxy`,
path: `/packageData/${params.packageId}/installed/outboundProxy`,
value: params.proxy,
},
]