diff --git a/web/projects/shared/styles/shared.scss b/web/projects/shared/styles/shared.scss index 845f56c24..6dc2edbb5 100644 --- a/web/projects/shared/styles/shared.scss +++ b/web/projects/shared/styles/shared.scss @@ -110,6 +110,7 @@ body { animation-fill-mode: forwards; text-align: left; width: 1em; + margin-left: -.3rem; } @keyframes ellipsis-dot { diff --git a/web/projects/shared/styles/taiga.scss b/web/projects/shared/styles/taiga.scss index cb6044a06..a89eeb2e6 100644 --- a/web/projects/shared/styles/taiga.scss +++ b/web/projects/shared/styles/taiga.scss @@ -57,7 +57,7 @@ var(--tui-status-warning) 24%, transparent ); - --tui-status-info: rgba(128, 89, 229, 1); + --tui-status-info: rgba(53, 96, 240, 1); --tui-status-info-pale: color-mix( in hsl, var(--tui-status-info) 12%, diff --git a/web/projects/ui/src/app/routes/portal/components/interfaces/interface.service.ts b/web/projects/ui/src/app/routes/portal/components/interfaces/interface.service.ts index d9b19a5bc..6d66a77a6 100644 --- a/web/projects/ui/src/app/routes/portal/components/interfaces/interface.service.ts +++ b/web/projects/ui/src/app/routes/portal/components/interfaces/interface.service.ts @@ -166,12 +166,10 @@ export class InterfaceService { }, [] as AddressWithInfo[]) return { - common: bestAddrs.map(a => - this.toDisplayAddress(a, gateways, host.publicDomains), - ), + common: bestAddrs.map(a => this.toDisplayAddress(a, host.publicDomains)), uncommon: allAddressesWithInfo .filter(a => !bestAddrs.includes(a)) - .map(a => this.toDisplayAddress(a, gateways, host.publicDomains)), + .map(a => this.toDisplayAddress(a, host.publicDomains)), } } @@ -314,7 +312,6 @@ export class InterfaceService { private toDisplayAddress( { info, url, gateway }: AddressWithInfo, - gateways: GatewayPlus[], publicDomains: Record, ): DisplayAddress { let access: DisplayAddress['access'] @@ -360,11 +357,11 @@ export class InterfaceService { // ** Not Tor ** } else { const port = info.hostname.sslPort || info.hostname.port - const gateway = gateways.find(g => g.id === info.gateway.id)! - gatewayName = gateway.name + const g = gateway! + gatewayName = g.name - const gatewayLanIpv4 = gateway.lanIpv4[0] - const isWireguard = gateway.ipInfo.deviceType === 'wireguard' + const gatewayLanIpv4 = g.lanIpv4[0] + const isWireguard = g.ipInfo.deviceType === 'wireguard' const localIdeal = this.i18n.transform('Ideal for local access') const lanRequired = this.i18n.transform( @@ -405,9 +402,9 @@ export class InterfaceService { ), rootCaRequired, ] - if (!gateway.public) { + if (!g.public) { bullets.push( - `${portForwarding} "${gatewayName}": ${port} -> ${gateway.subnets.find(s => s.isIpv4())?.address}:${port}`, + `${portForwarding} "${gatewayName}": ${port} -> ${g.subnets.find(s => s.isIpv4())?.address}:${port}`, ) } } else { @@ -439,12 +436,12 @@ export class InterfaceService { if (info.public) { access = 'public' bullets = [ - `${dnsFor} ${info.hostname.value} ${resolvesTo} ${gateway.ipInfo.wanIp}`, + `${dnsFor} ${info.hostname.value} ${resolvesTo} ${g.ipInfo.wanIp}`, ] - if (!gateway.public) { + if (!g.public) { bullets.push( - `${portForwarding} "${gatewayName}": ${port} -> ${gateway.subnets.find(s => s.isIpv4())?.address}:${port === 443 ? 5443 : port}`, + `${portForwarding} "${gatewayName}": ${port} -> ${g.subnets.find(s => s.isIpv4())?.address}:${port === 443 ? 5443 : port}`, ) } diff --git a/web/projects/ui/src/app/routes/portal/routes/services/components/health-check.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/components/health-check.component.ts index f3c5db0f6..598e55026 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/components/health-check.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/components/health-check.component.ts @@ -97,10 +97,8 @@ export class ServiceHealthCheckComponent { return `${this.i18n.transform('Success')}: ${this.healthCheck.message || 'health check passing'}` case 'loading': case 'failure': - return this.healthCheck.message - // disabled - default: - return this.healthCheck.result + case 'disabled': + return this.healthCheck.message || this.healthCheck.result } } } diff --git a/web/projects/ui/src/app/routes/portal/routes/services/dashboard/status.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/dashboard/status.component.ts index d97e4736e..f66d25a21 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/dashboard/status.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/dashboard/status.component.ts @@ -6,22 +6,26 @@ import { } from '@angular/core' import { i18nKey, i18nPipe } from '@start9labs/shared' import { tuiPure } from '@taiga-ui/cdk' -import { TuiIcon, TuiLoader } from '@taiga-ui/core' +import { TuiIcon } from '@taiga-ui/core' import { getProgressText } from 'src/app/routes/portal/routes/services/pipes/install-progress.pipe' import { PackageDataEntry } from 'src/app/services/patch-db/data-model' -import { renderPkgStatus } from 'src/app/services/pkg-status-rendering.service' +import { + PrimaryRendering, + renderPkgStatus, +} from 'src/app/services/pkg-status-rendering.service' @Component({ selector: 'td[appStatus]', template: ` - @if (loading) { - - } @else { - @if (!healthy) { - - } + @if (!healthy) { + + } + + {{ status | i18n }} + + @if (showDots) { + } - {{ status | i18n }}{{ dots }} `, styles: ` :host { @@ -37,7 +41,7 @@ import { renderPkgStatus } from 'src/app/services/pkg-status-rendering.service' } `, changeDetection: ChangeDetectionStrategy.OnPush, - imports: [TuiIcon, TuiLoader, i18nPipe], + imports: [TuiIcon, i18nPipe], }) export class StatusComponent { @Input() @@ -58,10 +62,6 @@ export class StatusComponent { ) } - get loading(): boolean { - return this.color === 'var(--tui-status-info)' - } - @tuiPure getStatus(pkg: PackageDataEntry) { return renderPkgStatus(pkg) @@ -72,35 +72,10 @@ export class StatusComponent { return `${this.i18n.transform('Installing')}... ${this.i18n.transform(getProgressText(this.pkg.stateInfo.installingInfo.progress.overall))}` as i18nKey } - switch (this.getStatus(this.pkg).primary) { - case 'running': - return 'Running' - case 'stopped': - return 'Stopped' - case 'taskRequired': - return 'Task Required' - case 'updating': - return 'Updating' - case 'stopping': - return 'Stopping' - case 'starting': - return 'Starting' - case 'backingUp': - return 'Backing Up' - case 'restarting': - return 'Restarting' - case 'removing': - return 'Removing' - case 'restoring': - return 'Restoring' - case 'error': - return 'Error' - default: - return 'Unknown' - } + return PrimaryRendering[this.getStatus(this.pkg).primary].display } - get dots(): '...' | '' { + get showDots() { switch (this.getStatus(this.pkg).primary) { case 'updating': case 'stopping': @@ -108,9 +83,9 @@ export class StatusComponent { case 'backingUp': case 'restarting': case 'removing': - return '...' + return true default: - return '' + return false } } diff --git a/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/action-success-member.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/action-success-member.component.ts index 6f923eb88..46c9105db 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/action-success-member.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/action-success-member.component.ts @@ -27,7 +27,6 @@ import { QrCodeComponent } from 'ng-qrcode' tuiTextfield [readOnly]="true" [ngModel]="member.value" - [style.border-inline-end-width.rem]="border" [type]="member.masked && masked ? 'password' : 'text'" /> @if (member.masked) { @@ -129,16 +128,6 @@ export class ActionSuccessMemberComponent { masked = true - get border(): number { - let border = 0 - - if (this.member.masked) border += 2 - if (this.member.copyable) border += 2 - if (this.member.qr) border += 2 - - return border - } - show(template: TemplateRef) { const masked = this.masked diff --git a/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/action-success-single.component.ts b/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/action-success-single.component.ts index 24e1f7a32..a3c24a356 100644 --- a/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/action-success-single.component.ts +++ b/web/projects/ui/src/app/routes/portal/routes/services/modals/action-success/action-success-single.component.ts @@ -23,7 +23,6 @@ import { SingleResult } from './types' tuiTextfield [readOnly]="true" [ngModel]="single.value" - [style.border-inline-end-width.rem]="border" [type]="single.masked && masked ? 'password' : 'text'" /> @if (single.masked) { @@ -105,15 +104,6 @@ export class ActionSuccessSingleComponent { masked = true - get border(): number { - let border = 0 - - if (this.single.masked) border += 2 - if (this.single.copyable) border += 2 - - return border - } - copy() { const el = this.input.nativeElement diff --git a/web/projects/ui/src/app/services/dep-error.service.ts b/web/projects/ui/src/app/services/dep-error.service.ts index b92712435..899cc8a06 100644 --- a/web/projects/ui/src/app/services/dep-error.service.ts +++ b/web/projects/ui/src/app/services/dep-error.service.ts @@ -126,13 +126,14 @@ export class DepErrorService { const expected = currentDep?.versionRange || '' // incorrect version - if (!this.exver.satisfies(depManifest.version, expected)) { - if (depManifest.satisfies.some(v => !this.exver.satisfies(v, expected))) { - return { - expected, - type: 'incorrectVersion', - received: depManifest.version, - } + if ( + !this.exver.satisfies(depManifest.version, expected) && + !depManifest.satisfies.some(v => this.exver.satisfies(v, expected)) + ) { + return { + expected, + type: 'incorrectVersion', + received: depManifest.version, } } diff --git a/web/projects/ui/src/app/services/pkg-status-rendering.service.ts b/web/projects/ui/src/app/services/pkg-status-rendering.service.ts index 8fdd7ae85..9f1b7f2cf 100644 --- a/web/projects/ui/src/app/services/pkg-status-rendering.service.ts +++ b/web/projects/ui/src/app/services/pkg-status-rendering.service.ts @@ -25,11 +25,21 @@ export function getInstalledPrimaryStatus({ tasks, status, }: T.PackageDataEntry): PrimaryStatus { - return Object.values(tasks).some( - t => t.active && t.task.severity === 'critical', - ) - ? 'taskRequired' - : status.main + if ( + Object.values(tasks).some(t => t.active && t.task.severity === 'critical') + ) { + return 'taskRequired' + } + + if ( + Object.values(status.main === 'running' && status.health) + .filter(h => !!h) + .some(h => h.result === 'starting') + ) { + return 'starting' + } + + return status.main } function getHealthStatus(status: T.MainStatus): T.HealthStatus | null { @@ -43,14 +53,14 @@ function getHealthStatus(status: T.MainStatus): T.HealthStatus | null { return 'failure' } - if (values.some(h => h.result === 'loading')) { - return 'loading' - } - if (values.some(h => h.result === 'starting')) { return 'starting' } + if (values.some(h => h.result === 'loading')) { + return 'loading' + } + return 'success' }