mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-04-04 22:39:46 +00:00
Frontend fixes/improvements (#2950)
* fix Tor logs actually fetching od logs * chore: switch from `mime-types` to `mime` for browser environment support (#2951) * change V2 s9pk title to Legacy * show warning for domains when not public, disable launch too --------- Co-authored-by: Alex Inkin <alexander@inkin.ru> Co-authored-by: Mariusz Kogen <k0gen@pm.me>
This commit is contained in:
@@ -190,7 +190,7 @@ impl TryFrom<ManifestV1> for Manifest {
|
|||||||
let default_url = value.upstream_repo.clone();
|
let default_url = value.upstream_repo.clone();
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
id: value.id,
|
id: value.id,
|
||||||
title: format!("{} (Compatibility Mode)", value.title).into(),
|
title: format!("{} (Legacy)", value.title).into(),
|
||||||
version: ExtendedVersion::from(
|
version: ExtendedVersion::from(
|
||||||
exver::emver::Version::from_str(&value.version)
|
exver::emver::Version::from_str(&value.version)
|
||||||
.with_kind(ErrorKind::Deserialization)?,
|
.with_kind(ErrorKind::Deserialization)?,
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
PackageId,
|
PackageId,
|
||||||
} from "../osBindings"
|
} from "../osBindings"
|
||||||
import { ArrayBufferReader, MerkleArchive } from "./merkleArchive"
|
import { ArrayBufferReader, MerkleArchive } from "./merkleArchive"
|
||||||
import mime from "mime-types"
|
import mime from "mime"
|
||||||
import { DirectoryContents } from "./merkleArchive/directoryContents"
|
import { DirectoryContents } from "./merkleArchive/directoryContents"
|
||||||
import { FileContents } from "./merkleArchive/fileContents"
|
import { FileContents } from "./merkleArchive/fileContents"
|
||||||
|
|
||||||
@@ -60,14 +60,13 @@ export class S9pk {
|
|||||||
async icon(): Promise<DataUrl> {
|
async icon(): Promise<DataUrl> {
|
||||||
const iconName = Object.keys(this.archive.contents.contents).find(
|
const iconName = Object.keys(this.archive.contents.contents).find(
|
||||||
(name) =>
|
(name) =>
|
||||||
name.startsWith("icon.") &&
|
name.startsWith("icon.") && mime.getType(name)?.startsWith("image/"),
|
||||||
(mime.contentType(name) || null)?.startsWith("image/"),
|
|
||||||
)
|
)
|
||||||
if (!iconName) {
|
if (!iconName) {
|
||||||
throw new Error("no icon found in archive")
|
throw new Error("no icon found in archive")
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
`data:${mime.contentType(iconName)};base64,` +
|
`data:${mime.getType(iconName)};base64,` +
|
||||||
Buffer.from(
|
Buffer.from(
|
||||||
await this.archive.contents.getPath([iconName])!.verifiedFileContents(),
|
await this.archive.contents.getPath([iconName])!.verifiedFileContents(),
|
||||||
).toString("base64")
|
).toString("base64")
|
||||||
@@ -91,12 +90,11 @@ export class S9pk {
|
|||||||
if (!dir || !(dir.contents instanceof DirectoryContents)) return null
|
if (!dir || !(dir.contents instanceof DirectoryContents)) return null
|
||||||
const iconName = Object.keys(dir.contents.contents).find(
|
const iconName = Object.keys(dir.contents.contents).find(
|
||||||
(name) =>
|
(name) =>
|
||||||
name.startsWith("icon.") &&
|
name.startsWith("icon.") && mime.getType(name)?.startsWith("image/"),
|
||||||
(mime.contentType(name) || null)?.startsWith("image/"),
|
|
||||||
)
|
)
|
||||||
if (!iconName) return null
|
if (!iconName) return null
|
||||||
return (
|
return (
|
||||||
`data:${mime.contentType(iconName)};base64,` +
|
`data:${mime.getType(iconName)};base64,` +
|
||||||
Buffer.from(
|
Buffer.from(
|
||||||
await dir.contents.getPath([iconName])!.verifiedFileContents(),
|
await dir.contents.getPath([iconName])!.verifiedFileContents(),
|
||||||
).toString("base64")
|
).toString("base64")
|
||||||
|
|||||||
36
sdk/base/package-lock.json
generated
36
sdk/base/package-lock.json
generated
@@ -12,14 +12,13 @@
|
|||||||
"@noble/hashes": "^1.7.2",
|
"@noble/hashes": "^1.7.2",
|
||||||
"deep-equality-data-structures": "^1.5.0",
|
"deep-equality-data-structures": "^1.5.0",
|
||||||
"isomorphic-fetch": "^3.0.0",
|
"isomorphic-fetch": "^3.0.0",
|
||||||
"mime-types": "^3.0.1",
|
"mime": "^4.0.7",
|
||||||
"ts-matches": "^6.3.2",
|
"ts-matches": "^6.3.2",
|
||||||
"yaml": "^2.7.1"
|
"yaml": "^2.7.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.4.0",
|
"@types/jest": "^29.4.0",
|
||||||
"@types/lodash.merge": "^4.6.2",
|
"@types/lodash.merge": "^4.6.2",
|
||||||
"@types/mime-types": "^2.1.4",
|
|
||||||
"jest": "^29.4.3",
|
"jest": "^29.4.3",
|
||||||
"peggy": "^3.0.2",
|
"peggy": "^3.0.2",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
@@ -1609,13 +1608,6 @@
|
|||||||
"@types/lodash": "*"
|
"@types/lodash": "*"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/mime-types": {
|
|
||||||
"version": "2.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@types/mime-types/-/mime-types-2.1.4.tgz",
|
|
||||||
"integrity": "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w==",
|
|
||||||
"dev": true,
|
|
||||||
"license": "MIT"
|
|
||||||
},
|
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.10.0",
|
"version": "22.10.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.0.tgz",
|
||||||
@@ -3770,25 +3762,19 @@
|
|||||||
"node": ">=8.6"
|
"node": ">=8.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mime-db": {
|
"node_modules/mime": {
|
||||||
"version": "1.54.0",
|
"version": "4.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.7.tgz",
|
||||||
"integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==",
|
"integrity": "sha512-2OfDPL+e03E0LrXaGYOtTFIYhiuzep94NSsuhrNULq+stylcJedcHdzHtz0atMUuGwJfFYs0YL5xeC/Ca2x0eQ==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/sponsors/broofa"
|
||||||
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"bin": {
|
||||||
"node": ">= 0.6"
|
"mime": "bin/cli.js"
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime-types": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz",
|
|
||||||
"integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==",
|
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
|
||||||
"mime-db": "^1.54.0"
|
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 0.6"
|
"node": ">=16"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mimic-fn": {
|
"node_modules/mimic-fn": {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
"@noble/curves": "^1.8.2",
|
"@noble/curves": "^1.8.2",
|
||||||
"@noble/hashes": "^1.7.2",
|
"@noble/hashes": "^1.7.2",
|
||||||
"isomorphic-fetch": "^3.0.0",
|
"isomorphic-fetch": "^3.0.0",
|
||||||
"mime-types": "^3.0.1",
|
"mime": "^4.0.7",
|
||||||
"ts-matches": "^6.3.2",
|
"ts-matches": "^6.3.2",
|
||||||
"yaml": "^2.7.1",
|
"yaml": "^2.7.1",
|
||||||
"deep-equality-data-structures": "^1.5.0"
|
"deep-equality-data-structures": "^1.5.0"
|
||||||
@@ -39,7 +39,6 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/jest": "^29.4.0",
|
"@types/jest": "^29.4.0",
|
||||||
"@types/lodash.merge": "^4.6.2",
|
"@types/lodash.merge": "^4.6.2",
|
||||||
"@types/mime-types": "^2.1.4",
|
|
||||||
"jest": "^29.4.3",
|
"jest": "^29.4.3",
|
||||||
"peggy": "^3.0.2",
|
"peggy": "^3.0.2",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
import { ChangeDetectionStrategy, Component, inject } from '@angular/core'
|
||||||
import { toSignal } from '@angular/core/rxjs-interop'
|
import { toSignal } from '@angular/core/rxjs-interop'
|
||||||
import { ActivatedRoute, Data } from '@angular/router'
|
import { ActivatedRoute } from '@angular/router'
|
||||||
import { TuiDialogContext, TuiLoader, TuiNotification } from '@taiga-ui/core'
|
import { TuiDialogContext, TuiLoader, TuiNotification } from '@taiga-ui/core'
|
||||||
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
import { injectContext, PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||||
import { NgDompurifyModule } from '@tinkoff/ng-dompurify'
|
import { NgDompurifyModule } from '@tinkoff/ng-dompurify'
|
||||||
|
|||||||
@@ -518,4 +518,5 @@ export default {
|
|||||||
516: 'Empfohlen',
|
516: 'Empfohlen',
|
||||||
517: 'Möchten Sie diese Aufgabe wirklich verwerfen?',
|
517: 'Möchten Sie diese Aufgabe wirklich verwerfen?',
|
||||||
518: 'Verwerfen',
|
518: 'Verwerfen',
|
||||||
|
519: 'Um Clearnet-Domains zu veröffentlichen, musst du oben auf „Öffentlich machen“ klicken.',
|
||||||
} satisfies i18n
|
} satisfies i18n
|
||||||
|
|||||||
@@ -517,4 +517,5 @@ export const ENGLISH = {
|
|||||||
'Recommended': 516, // as in, we recommend this
|
'Recommended': 516, // as in, we recommend this
|
||||||
'Are you sure you want to dismiss this task?': 517,
|
'Are you sure you want to dismiss this task?': 517,
|
||||||
'Dismiss': 518, // as in, dismiss or delete a task
|
'Dismiss': 518, // as in, dismiss or delete a task
|
||||||
|
'To publish clearnet domains, you must click "Make Public", above.': 519,
|
||||||
} as const
|
} as const
|
||||||
|
|||||||
@@ -518,4 +518,5 @@ export default {
|
|||||||
516: 'Recomendado',
|
516: 'Recomendado',
|
||||||
517: '¿Estás seguro de que deseas descartar esta tarea?',
|
517: '¿Estás seguro de que deseas descartar esta tarea?',
|
||||||
518: 'Descartar',
|
518: 'Descartar',
|
||||||
|
519: 'Para publicar dominios en clearnet, debes hacer clic en "Hacer público" arriba.',
|
||||||
} satisfies i18n
|
} satisfies i18n
|
||||||
|
|||||||
@@ -518,4 +518,5 @@ export default {
|
|||||||
516: 'Recommandé',
|
516: 'Recommandé',
|
||||||
517: 'Êtes-vous sûr de vouloir ignorer cette tâche ?',
|
517: 'Êtes-vous sûr de vouloir ignorer cette tâche ?',
|
||||||
518: 'Ignorer',
|
518: 'Ignorer',
|
||||||
|
519: 'Pour publier des domaines clearnet, vous devez cliquer sur « Rendre public » ci-dessus.',
|
||||||
} satisfies i18n
|
} satisfies i18n
|
||||||
|
|||||||
@@ -518,4 +518,5 @@ export default {
|
|||||||
516: 'Zalecane',
|
516: 'Zalecane',
|
||||||
517: 'Czy na pewno chcesz odrzucić to zadanie?',
|
517: 'Czy na pewno chcesz odrzucić to zadanie?',
|
||||||
518: 'Odrzuć',
|
518: 'Odrzuć',
|
||||||
|
519: 'Aby opublikować domeny w clearnet, kliknij „Upublicznij” powyżej.',
|
||||||
} satisfies i18n
|
} satisfies i18n
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import {
|
|||||||
TuiDataList,
|
TuiDataList,
|
||||||
TuiIcon,
|
TuiIcon,
|
||||||
TuiLink,
|
TuiLink,
|
||||||
|
TuiNotification,
|
||||||
} from '@taiga-ui/core'
|
} from '@taiga-ui/core'
|
||||||
import { TuiTooltip } from '@taiga-ui/kit'
|
import { TuiTooltip } from '@taiga-ui/kit'
|
||||||
import { PatchDB } from 'patch-db-client'
|
import { PatchDB } from 'patch-db-client'
|
||||||
@@ -66,12 +67,25 @@ type ClearnetForm = {
|
|||||||
</a>
|
</a>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
@if (clearnet().length) {
|
@if (clearnet().length) {
|
||||||
<button tuiButton iconStart="@tui.plus" (click)="add()">
|
<button
|
||||||
|
tuiButton
|
||||||
|
iconStart="@tui.plus"
|
||||||
|
[style.margin-inline-start]="'auto'"
|
||||||
|
(click)="add()"
|
||||||
|
>
|
||||||
{{ 'Add' | i18n }}
|
{{ 'Add' | i18n }}
|
||||||
</button>
|
</button>
|
||||||
}
|
}
|
||||||
</header>
|
</header>
|
||||||
@if (clearnet().length) {
|
@if (clearnet().length) {
|
||||||
|
@if (!isPublic()) {
|
||||||
|
<tui-notification appearance="negative" [style.margin-bottom]="'1rem'">
|
||||||
|
{{
|
||||||
|
'To publish clearnet domains, you must click "Make Public", above.'
|
||||||
|
| i18n
|
||||||
|
}}
|
||||||
|
</tui-notification>
|
||||||
|
}
|
||||||
<table [appTable]="['ACME', 'URL', null]">
|
<table [appTable]="['ACME', 'URL', null]">
|
||||||
@for (address of clearnet(); track $index) {
|
@for (address of clearnet(); track $index) {
|
||||||
<tr>
|
<tr>
|
||||||
@@ -79,7 +93,11 @@ type ClearnetForm = {
|
|||||||
{{ interface.value().addSsl ? (address.acme | acme) : '-' }}
|
{{ interface.value().addSsl ? (address.acme | acme) : '-' }}
|
||||||
</td>
|
</td>
|
||||||
<td>{{ address.url | mask }}</td>
|
<td>{{ address.url | mask }}</td>
|
||||||
<td actions [href]="address.url" [disabled]="!isRunning()">
|
<td
|
||||||
|
actions
|
||||||
|
[href]="address.url"
|
||||||
|
[disabled]="!isRunning() || !isPublic()"
|
||||||
|
>
|
||||||
@if (address.isDomain) {
|
@if (address.isDomain) {
|
||||||
<button
|
<button
|
||||||
tuiIconButton
|
tuiIconButton
|
||||||
@@ -129,6 +147,7 @@ type ClearnetForm = {
|
|||||||
InterfaceActionsComponent,
|
InterfaceActionsComponent,
|
||||||
i18nPipe,
|
i18nPipe,
|
||||||
DocsLinkDirective,
|
DocsLinkDirective,
|
||||||
|
TuiNotification,
|
||||||
],
|
],
|
||||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
@@ -143,6 +162,7 @@ export class InterfaceClearnetComponent {
|
|||||||
|
|
||||||
readonly clearnet = input.required<readonly ClearnetAddress[]>()
|
readonly clearnet = input.required<readonly ClearnetAddress[]>()
|
||||||
readonly isRunning = input.required<boolean>()
|
readonly isRunning = input.required<boolean>()
|
||||||
|
readonly isPublic = input.required<boolean>()
|
||||||
|
|
||||||
readonly acme = toSignal(
|
readonly acme = toSignal(
|
||||||
inject<PatchDB<DataModel>>(PatchDB)
|
inject<PatchDB<DataModel>>(PatchDB)
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import { MappedServiceInterface } from './interface.utils'
|
|||||||
</button>
|
</button>
|
||||||
<section
|
<section
|
||||||
[clearnet]="value().addresses.clearnet"
|
[clearnet]="value().addresses.clearnet"
|
||||||
|
[isPublic]="value().public"
|
||||||
[isRunning]="isRunning()"
|
[isRunning]="isRunning()"
|
||||||
></section>
|
></section>
|
||||||
<section [tor]="value().addresses.tor" [isRunning]="isRunning()"></section>
|
<section [tor]="value().addresses.tor" [isRunning]="isRunning()"></section>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import { i18nPipe } from '@start9labs/shared'
|
|||||||
import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component'
|
import { LogsComponent } from 'src/app/routes/portal/components/logs/logs.component'
|
||||||
import { RR } from 'src/app/services/api/api.types'
|
import { RR } from 'src/app/services/api/api.types'
|
||||||
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
import { ApiService } from 'src/app/services/api/embassy-api.service'
|
||||||
|
|
||||||
import { LogsHeaderComponent } from '../components/header.component'
|
import { LogsHeaderComponent } from '../components/header.component'
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@@ -31,10 +30,4 @@ export default class SystemKernelComponent {
|
|||||||
|
|
||||||
protected readonly fetch = (params: RR.GetServerLogsReq) =>
|
protected readonly fetch = (params: RR.GetServerLogsReq) =>
|
||||||
this.api.getKernelLogs(params)
|
this.api.getKernelLogs(params)
|
||||||
|
|
||||||
log = {
|
|
||||||
title: 'Kernel Logs',
|
|
||||||
subtitle: 'Diagnostics for drivers and other kernel processes',
|
|
||||||
icon: '@tui.square-chevron-right',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,10 +30,4 @@ export default class SystemOSComponent {
|
|||||||
|
|
||||||
protected readonly fetch = (params: RR.GetServerLogsReq) =>
|
protected readonly fetch = (params: RR.GetServerLogsReq) =>
|
||||||
this.api.getServerLogs(params)
|
this.api.getServerLogs(params)
|
||||||
|
|
||||||
log = {
|
|
||||||
title: 'Kernel Logs',
|
|
||||||
subtitle: 'Diagnostics for drivers and other kernel processes',
|
|
||||||
icon: '@tui.square-chevron-right',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,14 +26,8 @@ export default class SystemOSComponent {
|
|||||||
private readonly api = inject(ApiService)
|
private readonly api = inject(ApiService)
|
||||||
|
|
||||||
protected readonly follow = (params: RR.FollowServerLogsReq) =>
|
protected readonly follow = (params: RR.FollowServerLogsReq) =>
|
||||||
this.api.followServerLogs(params)
|
this.api.followTorLogs(params)
|
||||||
|
|
||||||
protected readonly fetch = (params: RR.GetServerLogsReq) =>
|
protected readonly fetch = (params: RR.GetServerLogsReq) =>
|
||||||
this.api.getServerLogs(params)
|
this.api.getTorLogs(params)
|
||||||
|
|
||||||
log = {
|
|
||||||
title: 'Kernel Logs',
|
|
||||||
subtitle: 'Diagnostics for drivers and other kernel processes',
|
|
||||||
icon: '@tui.square-chevron-right',
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user