chore: fix issues from dev channel (#2968)

This commit is contained in:
Alex Inkin
2025-06-25 20:30:28 +07:00
committed by GitHub
parent dbf08a6cf8
commit 2983b9950f
12 changed files with 77 additions and 44 deletions

View File

@@ -521,4 +521,5 @@ export default {
520: 'Update verfügbar',
521: 'Um das Problem zu beheben, siehe',
522: 'SDK Version',
523: 'Sicherungsbericht',
} satisfies i18n

View File

@@ -520,4 +520,5 @@ export const ENGLISH = {
'Update available': 520,
'To resolve the issue, refer to': 521,
'SDK Version': 522,
'Backup Report': 523,
} as const

View File

@@ -521,4 +521,5 @@ export default {
520: 'Actualización disponible',
521: 'Para resolver el problema, consulta',
522: 'Versión de SDK',
523: 'Informe de respaldo',
} satisfies i18n

View File

@@ -521,4 +521,5 @@ export default {
520: 'Mise à jour disponible',
521: 'Pour résoudre le problème, consultez',
522: 'Version de SDK',
523: 'Rapport de sauvegarde',
} satisfies i18n

View File

@@ -521,4 +521,5 @@ export default {
520: 'Aktualizacja dostępna',
521: 'Aby rozwiązać problem, zapoznaj się z',
522: 'Wersja SDK',
523: 'Raport kopii zapasowej',
} satisfies i18n

View File

@@ -1,10 +1,13 @@
import { inject, Injectable, TemplateRef } from '@angular/core'
import { inject, Injectable } from '@angular/core'
import {
TuiResponsiveDialogOptions,
TuiResponsiveDialogService,
} from '@taiga-ui/addon-mobile'
import { TUI_CONFIRM, TuiConfirmData } from '@taiga-ui/kit'
import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
import {
PolymorpheusComponent,
PolymorpheusContent,
} from '@taiga-ui/polymorpheus'
import { PROMPT, PromptOptions } from '../components/prompt.component'
import { i18nPipe } from '../i18n/i18n.pipe'
import { i18nKey } from '../i18n/i18n.providers'
@@ -73,7 +76,7 @@ export class DialogService {
}
openComponent<T = void>(
component: PolymorpheusComponent<any> | TemplateRef<any>,
component: PolymorpheusContent,
options: Partial<TuiResponsiveDialogOptions<any>> & {
label?: i18nKey
} = {},

View File

@@ -18,8 +18,16 @@ export abstract class Control<
}
get readOnly(): boolean {
const def =
'default' in this.spec &&
this.spec.default != null &&
this.spec.default !== this.value
return (
!!this.value && !!this.control.control?.pristine && this.control.immutable
!!this.value &&
!def &&
!!this.control.control?.pristine &&
this.control.immutable
)
}

View File

@@ -1,4 +1,3 @@
import { TuiButton } from '@taiga-ui/core'
import { CommonModule, TitleCasePipe } from '@angular/common'
import {
ChangeDetectionStrategy,
@@ -6,37 +5,41 @@ import {
inject,
Input,
} from '@angular/core'
import { toSignal } from '@angular/core/rxjs-interop'
import { Router } from '@angular/router'
import { MarketplacePkgBase } from '@start9labs/marketplace'
import {
Exver,
ErrorService,
Exver,
ExverPipesModule,
i18nPipe,
isEmptyObject,
LoadingService,
sameUrl,
ExverPipesModule,
i18nPipe,
} from '@start9labs/shared'
import { TuiButton } from '@taiga-ui/core'
import { PatchDB } from 'patch-db-client'
import { firstValueFrom } from 'rxjs'
import { ToManifestPipe } from 'src/app/routes/portal/pipes/to-manifest'
import { ApiService } from 'src/app/services/api/embassy-api.service'
import { MarketplaceService } from 'src/app/services/marketplace.service'
import {
DataModel,
PackageDataEntry,
} from 'src/app/services/patch-db/data-model'
import { MarketplaceService } from 'src/app/services/marketplace.service'
import { hasCurrentDeps } from 'src/app/utils/has-deps'
import { getAllPackages, getManifest } from 'src/app/utils/get-package-data'
import { dryUpdate } from 'src/app/utils/dry-update'
import { getAllPackages, getManifest } from 'src/app/utils/get-package-data'
import { hasCurrentDeps } from 'src/app/utils/has-deps'
import { MarketplacePreviewComponent } from '../modals/preview.component'
import { MarketplaceAlertsService } from '../services/alerts.service'
import { ToManifestPipe } from 'src/app/routes/portal/pipes/to-manifest'
import { ApiService } from 'src/app/services/api/embassy-api.service'
@Component({
selector: 'marketplace-controls',
template: `
@if (localPkg) {
@if (localPkg | toManifest; as localManifest) {
@switch (localManifest.version | compareExver: pkg.version) {
@switch (localManifest.version | compareExver: version() || '') {
@case (1) {
<button
tuiButton
@@ -111,6 +114,9 @@ export class MarketplaceControlsComponent {
private readonly router = inject(Router)
private readonly marketplaceService = inject(MarketplaceService)
private readonly api = inject(ApiService)
private readonly preview = inject(MarketplacePreviewComponent)
protected readonly version = toSignal(this.preview.version$)
@Input({ required: true })
pkg!: MarketplacePkgBase
@@ -147,10 +153,11 @@ export class MarketplaceControlsComponent {
}
const localManifest = getManifest(this.localPkg)
const version = this.version() || ''
if (
hasCurrentDeps(localManifest.id, await getAllPackages(this.patch)) &&
this.exver.compareExver(localManifest.version, this.pkg.version) !== 0
this.exver.compareExver(localManifest.version, version) !== 0
) {
this.dryInstall(currentUrl)
} else {
@@ -159,12 +166,14 @@ export class MarketplaceControlsComponent {
}
async showService() {
this.router.navigate(['/portal/services', this.pkg.id])
this.router.navigate(['/portal/services', this.preview.pkgId])
}
private async dryInstall(url: string | null) {
const id = this.preview.pkgId
const version = this.version() || ''
const breakages = dryUpdate(
this.pkg,
{ id, version },
await getAllPackages(this.patch),
this.exver,
)
@@ -188,7 +197,8 @@ export class MarketplaceControlsComponent {
private async install(url: string) {
const loader = this.loader.open('Beginning install').subscribe()
const { id, version } = this.pkg
const version = this.version() || ''
const id = this.preview.pkgId
try {
await this.marketplaceService.installPackage(id, version, url)

View File

@@ -167,11 +167,11 @@ export class MarketplacePreviewComponent {
private readonly exver = inject(Exver)
private readonly router = inject(Router)
private readonly marketplaceService = inject(MarketplaceService)
private readonly version$ = new BehaviorSubject<string | null>(null)
private readonly flavor$ = this.router.routerState.root.queryParamMap.pipe(
map(paramMap => paramMap.get('flavor')),
)
readonly version$ = new BehaviorSubject<string | null>(null)
readonly pkg$ = combineLatest([this.version$, this.flavor$]).pipe(
switchMap(([version, flavor]) =>
this.marketplaceService

View File

@@ -112,7 +112,7 @@ import { SystemWipeComponent } from './wipe.component'
<tui-icon icon="@tui.languages" />
<span tuiTitle>
<strong>{{ 'Language' | i18n }}</strong>
<span tuiSubtitle>
<span tuiSubtitle [style.text-transform]="'capitalize'">
@if (language; as lang) {
{{ lang | i18n }}
} @else {
@@ -197,7 +197,7 @@ import { SystemWipeComponent } from './wipe.component'
</div>
}
<img
[snek]="score()"
[snek]="score() || 0"
class="snek"
alt="Play Snake"
src="assets/img/icons/snek.png"
@@ -271,15 +271,17 @@ export default class SystemGeneralComponent {
readonly server = toSignal(this.patch.watch$('serverInfo'))
readonly name = toSignal(this.patch.watch$('ui', 'name'))
readonly score = toSignal(this.patch.watch$('ui', 'snakeHighScore'))
readonly os = inject(OSService)
readonly i18nService = inject(i18nService)
readonly languages = languages
readonly translation: TuiStringHandler<TuiContext<Languages>> = ({
$implicit,
}) => this.i18n.transform($implicit)!
readonly score = toSignal(this.patch.watch$('ui', 'snakeHighScore'), {
initialValue: 0,
})
}) => {
const [head = '', ...result] = this.i18n.transform($implicit) || ''
return [head.toUpperCase(), ...result].join('')
}
get language(): Languages | undefined {
return this.languages.find(lang => lang === this.i18nService.language)

View File

@@ -9,18 +9,6 @@ export class FormDialogService {
private readonly dialog = inject(DialogService)
private readonly i18n = inject(i18nPipe)
private readonly formService = new TuiConfirmService()
private readonly PROMPT: Partial<TuiDialogOptions<TuiConfirmData>> = {
label: this.i18n.transform('Unsaved changes'),
data: {
content: this.i18n.transform(
'You have unsaved changes. Are you sure you want to leave?',
),
yes: this.i18n.transform('Leave'),
no: this.i18n.transform('Cancel'),
},
}
private readonly prompt = this.formService.withConfirm(this.PROMPT)
private readonly injector = Injector.create({
parent: inject(Injector),
providers: [
@@ -37,10 +25,23 @@ export class FormDialogService {
label?: i18nKey
} = {},
) {
const PROMPT: Partial<TuiDialogOptions<TuiConfirmData>> = {
label: this.i18n.transform('Unsaved changes'),
data: {
content: this.i18n.transform(
'You have unsaved changes. Are you sure you want to leave?',
),
yes: this.i18n.transform('Leave'),
no: this.i18n.transform('Cancel'),
},
}
const closeable = this.formService.withConfirm(PROMPT)
this.dialog
.openComponent(new PolymorpheusComponent(component, this.injector), {
closeable: this.prompt,
dismissible: this.prompt,
dismissible: closeable,
closeable,
...options,
})
.subscribe({

View File

@@ -1,6 +1,10 @@
import { inject, Injectable } from '@angular/core'
import { ErrorService, MARKDOWN } from '@start9labs/shared'
import { TuiResponsiveDialogService } from '@taiga-ui/addon-mobile'
import {
DialogService,
ErrorService,
i18nKey,
MARKDOWN,
} from '@start9labs/shared'
import { PatchDB } from 'patch-db-client'
import { firstValueFrom, merge, of, shareReplay, Subject } from 'rxjs'
import { REPORT } from 'src/app/components/backup-report.component'
@@ -16,7 +20,7 @@ export class NotificationService {
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
private readonly errorService = inject(ErrorService)
private readonly api = inject(ApiService)
private readonly dialogs = inject(TuiResponsiveDialogService)
private readonly dialogs = inject(DialogService)
private readonly localUnreadCount$ = new Subject<number>()
readonly unreadCount$ = merge(
@@ -93,12 +97,12 @@ export class NotificationService {
{ data, createdAt, code, title, message }: ServerNotification<number>,
full = false,
) {
const label = code === 1 ? 'Backup Report' : title
const label = code === 1 ? 'Backup Report' : (title as i18nKey)
const component = code === 1 ? REPORT : MARKDOWN
const content = code === 1 ? data : of(data)
this.dialogs
.open(full ? message : component, {
.openComponent(full ? message : component, {
label,
data: {
content,