mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-30 20:14:49 +00:00
feat: implement URL plugins with table/row actions and prefill support
- Add URL plugin effects (register, export_url, clear_urls) in core - Add PluginHostnameInfo, HostnameMetadata::Plugin, and plugin registration types - Implement plugin URL table in web UI with tableAction button and rowAction overflow menus - Thread urlPluginMetadata (packageId, hostId, interfaceId, internalPort) as prefill to actions - Add prefill support to PackageActionData so metadata passes through form dialogs - Add i18n translations for plugin error messages - Clean up plugin URLs on package uninstall
This commit is contained in:
@@ -257,7 +257,7 @@ export class AddressActionsComponent {
|
||||
|
||||
showDnsValidation() {
|
||||
this.domainHealth.showPublicDomainSetup(
|
||||
this.address().hostnameInfo.host,
|
||||
this.address().hostnameInfo.hostname,
|
||||
this.gatewayId(),
|
||||
)
|
||||
}
|
||||
@@ -286,7 +286,7 @@ export class AddressActionsComponent {
|
||||
const loader = this.loader.open('Removing').subscribe()
|
||||
|
||||
try {
|
||||
const host = addr.hostnameInfo.host
|
||||
const host = addr.hostnameInfo.hostname
|
||||
|
||||
if (addr.hostnameInfo.metadata.kind === 'public-domain') {
|
||||
if (this.packageId()) {
|
||||
|
||||
@@ -209,7 +209,7 @@ export class InterfaceAddressItemComponent {
|
||||
const kind = addr.hostnameInfo.metadata.kind
|
||||
if (kind === 'public-domain') {
|
||||
await this.domainHealth.checkPublicDomain(
|
||||
addr.hostnameInfo.host,
|
||||
addr.hostnameInfo.hostname,
|
||||
this.gatewayId(),
|
||||
)
|
||||
} else if (kind === 'private-domain') {
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
DialogService,
|
||||
i18nPipe,
|
||||
} from '@start9labs/shared'
|
||||
import { T } from '@start9labs/start-sdk'
|
||||
import { TUI_IS_MOBILE } from '@taiga-ui/cdk'
|
||||
import {
|
||||
TuiButton,
|
||||
@@ -22,13 +23,28 @@ import { PolymorpheusComponent } from '@taiga-ui/polymorpheus'
|
||||
import { PlaceholderComponent } from 'src/app/routes/portal/components/placeholder.component'
|
||||
import { TableComponent } from 'src/app/routes/portal/components/table.component'
|
||||
import { QRModal } from 'src/app/routes/portal/modals/qr.component'
|
||||
import { PluginAddressGroup } from '../interface.service'
|
||||
import { ActionService } from 'src/app/services/action.service'
|
||||
import {
|
||||
MappedServiceInterface,
|
||||
PluginAddress,
|
||||
PluginAddressGroup,
|
||||
} from '../interface.service'
|
||||
|
||||
@Component({
|
||||
selector: 'section[pluginGroup]',
|
||||
template: `
|
||||
<header>
|
||||
{{ pluginGroup().pluginName }}
|
||||
@if (pluginGroup().tableAction; as action) {
|
||||
<button
|
||||
tuiButton
|
||||
iconStart="@tui.plus"
|
||||
[style.margin-inline-start]="'auto'"
|
||||
(click)="runTableAction()"
|
||||
>
|
||||
{{ action.metadata.name }}
|
||||
</button>
|
||||
}
|
||||
</header>
|
||||
<table [appTable]="['Protocol', 'URL', null]">
|
||||
@for (address of pluginGroup().addresses; track $index) {
|
||||
@@ -55,6 +71,23 @@ import { PluginAddressGroup } from '../interface.service'
|
||||
>
|
||||
{{ 'Copy URL' | i18n }}
|
||||
</button>
|
||||
@if (address.hostnameInfo.metadata.kind === 'plugin') {
|
||||
@for (
|
||||
actionId of address.hostnameInfo.metadata.rowActions;
|
||||
track actionId
|
||||
) {
|
||||
@if (pluginGroup().pluginActions[actionId]; as meta) {
|
||||
<button
|
||||
tuiIconButton
|
||||
appearance="flat-grayscale"
|
||||
iconStart="@tui.play"
|
||||
(click)="runRowAction(actionId, meta, address)"
|
||||
>
|
||||
{{ meta.name }}
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
</div>
|
||||
<div class="mobile">
|
||||
<button
|
||||
@@ -83,6 +116,23 @@ import { PluginAddressGroup } from '../interface.service'
|
||||
>
|
||||
{{ 'Copy URL' | i18n }}
|
||||
</button>
|
||||
@if (address.hostnameInfo.metadata.kind === 'plugin') {
|
||||
@for (
|
||||
actionId of address.hostnameInfo.metadata.rowActions;
|
||||
track actionId
|
||||
) {
|
||||
@if (pluginGroup().pluginActions[actionId]; as meta) {
|
||||
<button
|
||||
tuiOption
|
||||
new
|
||||
iconStart="@tui.play"
|
||||
(click)="runRowAction(actionId, meta, address)"
|
||||
>
|
||||
{{ meta.name }}
|
||||
</button>
|
||||
}
|
||||
}
|
||||
}
|
||||
</tui-data-list>
|
||||
</button>
|
||||
</div>
|
||||
@@ -159,10 +209,13 @@ import { PluginAddressGroup } from '../interface.service'
|
||||
export class PluginAddressesComponent {
|
||||
private readonly isMobile = inject(TUI_IS_MOBILE)
|
||||
private readonly dialog = inject(DialogService)
|
||||
private readonly actionService = inject(ActionService)
|
||||
readonly copyService = inject(CopyService)
|
||||
readonly open = signal(false)
|
||||
|
||||
readonly pluginGroup = input.required<PluginAddressGroup>()
|
||||
readonly packageId = input('')
|
||||
readonly value = input<MappedServiceInterface | undefined>()
|
||||
|
||||
showQR(url: string) {
|
||||
this.dialog
|
||||
@@ -173,4 +226,59 @@ export class PluginAddressesComponent {
|
||||
})
|
||||
.subscribe()
|
||||
}
|
||||
|
||||
runTableAction() {
|
||||
const group = this.pluginGroup()
|
||||
if (!group.tableAction || !group.pluginPkgInfo) return
|
||||
|
||||
const iface = this.value()
|
||||
const prefill: Record<string, unknown> = {}
|
||||
|
||||
if (iface) {
|
||||
prefill['urlPluginMetadata'] = {
|
||||
packageId: this.packageId() || null,
|
||||
hostId: iface.addressInfo.hostId,
|
||||
interfaceId: iface.id,
|
||||
internalPort: iface.addressInfo.internalPort,
|
||||
}
|
||||
}
|
||||
|
||||
this.actionService.present({
|
||||
pkgInfo: group.pluginPkgInfo,
|
||||
actionInfo: group.tableAction,
|
||||
prefill,
|
||||
})
|
||||
}
|
||||
|
||||
runRowAction(
|
||||
actionId: string,
|
||||
metadata: T.ActionMetadata,
|
||||
address: PluginAddress,
|
||||
) {
|
||||
const group = this.pluginGroup()
|
||||
if (!group.pluginPkgInfo) return
|
||||
|
||||
const iface = this.value()
|
||||
const prefill: Record<string, unknown> = {}
|
||||
|
||||
if (iface && address.hostnameInfo.metadata.kind === 'plugin') {
|
||||
prefill['urlPluginMetadata'] = {
|
||||
packageId: this.packageId() || null,
|
||||
hostId: iface.addressInfo.hostId,
|
||||
interfaceId: iface.id,
|
||||
internalPort: iface.addressInfo.internalPort,
|
||||
hostname: address.hostnameInfo.hostname,
|
||||
port: address.hostnameInfo.port,
|
||||
ssl: address.hostnameInfo.ssl,
|
||||
public: address.hostnameInfo.public,
|
||||
info: address.hostnameInfo.metadata.info,
|
||||
}
|
||||
}
|
||||
|
||||
this.actionService.present({
|
||||
pkgInfo: group.pluginPkgInfo,
|
||||
actionInfo: { id: actionId, metadata },
|
||||
prefill,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,11 @@ import { PluginAddressesComponent } from './addresses/plugin.component'
|
||||
></section>
|
||||
}
|
||||
@for (group of value()?.pluginGroups; track group.pluginId) {
|
||||
<section [pluginGroup]="group"></section>
|
||||
<section
|
||||
[pluginGroup]="group"
|
||||
[packageId]="packageId()"
|
||||
[value]="value()"
|
||||
></section>
|
||||
}
|
||||
`,
|
||||
styles: `
|
||||
|
||||
@@ -2,7 +2,12 @@ import { inject, Injectable } from '@angular/core'
|
||||
import { T, utils } from '@start9labs/start-sdk'
|
||||
import { ConfigService } from 'src/app/services/config.service'
|
||||
import { GatewayPlus } from 'src/app/services/gateway.service'
|
||||
import {
|
||||
PrimaryStatus,
|
||||
renderPkgStatus,
|
||||
} from 'src/app/services/pkg-status-rendering.service'
|
||||
import { toAuthorityName } from 'src/app/utils/acme'
|
||||
import { getManifest } from 'src/app/utils/get-package-data'
|
||||
|
||||
function isPublicIp(h: T.HostnameInfo): boolean {
|
||||
return h.public && (h.metadata.kind === 'ipv4' || h.metadata.kind === 'ipv6')
|
||||
@@ -13,12 +18,12 @@ function isEnabled(addr: T.DerivedAddressInfo, h: T.HostnameInfo): boolean {
|
||||
if (h.port === null) return true
|
||||
const sa =
|
||||
h.metadata.kind === 'ipv6'
|
||||
? `[${h.host}]:${h.port}`
|
||||
: `${h.host}:${h.port}`
|
||||
? `[${h.hostname}]:${h.port}`
|
||||
: `${h.hostname}:${h.port}`
|
||||
return addr.enabled.includes(sa)
|
||||
} else {
|
||||
return !addr.disabled.some(
|
||||
([host, port]) => host === h.host && port === (h.port ?? 0),
|
||||
([hostname, port]) => hostname === h.hostname && port === (h.port ?? 0),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -46,7 +51,7 @@ function getCertificate(
|
||||
if (!h.ssl) return '-'
|
||||
|
||||
if (h.metadata.kind === 'public-domain') {
|
||||
const config = host.publicDomains[h.host]
|
||||
const config = host.publicDomains[h.hostname]
|
||||
return config ? toAuthorityName(config.acme) : toAuthorityName(null)
|
||||
}
|
||||
|
||||
@@ -60,7 +65,7 @@ function sortDomainsFirst(a: GatewayAddress, b: GatewayAddress): number {
|
||||
const isDomain = (addr: GatewayAddress) =>
|
||||
addr.hostnameInfo.metadata.kind === 'public-domain' ||
|
||||
(addr.hostnameInfo.metadata.kind === 'private-domain' &&
|
||||
!addr.hostnameInfo.host.endsWith('.local'))
|
||||
!addr.hostnameInfo.hostname.endsWith('.local'))
|
||||
return Number(isDomain(b)) - Number(isDomain(a))
|
||||
}
|
||||
|
||||
@@ -72,7 +77,7 @@ function getAddressType(h: T.HostnameInfo): string {
|
||||
return 'IPv6'
|
||||
case 'public-domain':
|
||||
case 'private-domain':
|
||||
return h.host
|
||||
return h.hostname
|
||||
case 'mdns':
|
||||
return 'mDNS'
|
||||
case 'plugin':
|
||||
@@ -140,6 +145,7 @@ export class InterfaceService {
|
||||
getPluginGroups(
|
||||
serviceInterface: T.ServiceInterface,
|
||||
host: T.Host,
|
||||
allPackageData?: Record<string, T.PackageDataEntry>,
|
||||
): PluginAddressGroup[] {
|
||||
const binding = host.bindings[serviceInterface.addressInfo.internalPort]
|
||||
if (!binding) return []
|
||||
@@ -152,7 +158,7 @@ export class InterfaceService {
|
||||
if (h.metadata.kind !== 'plugin') continue
|
||||
|
||||
const url = utils.addressHostToUrl(serviceInterface.addressInfo, h)
|
||||
const pluginId = h.metadata.package
|
||||
const pluginId = h.metadata.packageId
|
||||
|
||||
if (!groupMap.has(pluginId)) {
|
||||
groupMap.set(pluginId, [])
|
||||
@@ -165,11 +171,35 @@ export class InterfaceService {
|
||||
})
|
||||
}
|
||||
|
||||
return Array.from(groupMap.entries()).map(([pluginId, addresses]) => ({
|
||||
pluginId,
|
||||
pluginName: pluginId.charAt(0).toUpperCase() + pluginId.slice(1),
|
||||
addresses,
|
||||
}))
|
||||
return Array.from(groupMap.entries()).map(([pluginId, addresses]) => {
|
||||
const pluginPkg = allPackageData?.[pluginId]
|
||||
const pluginActions = pluginPkg?.actions ?? {}
|
||||
const tableActionId = pluginPkg?.plugin?.url?.tableAction ?? null
|
||||
const tableActionMeta = tableActionId ? pluginActions[tableActionId] : undefined
|
||||
const tableAction = tableActionId && tableActionMeta
|
||||
? { id: tableActionId, metadata: tableActionMeta }
|
||||
: null
|
||||
|
||||
let pluginPkgInfo: PluginPkgInfo | null = null
|
||||
if (pluginPkg) {
|
||||
const manifest = getManifest(pluginPkg)
|
||||
pluginPkgInfo = {
|
||||
id: manifest.id,
|
||||
title: manifest.title,
|
||||
icon: pluginPkg.icon,
|
||||
status: renderPkgStatus(pluginPkg).primary,
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pluginId,
|
||||
pluginName: pluginPkgInfo?.title ?? pluginId.charAt(0).toUpperCase() + pluginId.slice(1),
|
||||
addresses,
|
||||
tableAction,
|
||||
pluginPkgInfo,
|
||||
pluginActions,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
launchableAddress(ui: T.ServiceInterface, host: T.Host): string {
|
||||
@@ -201,7 +231,7 @@ export class InterfaceService {
|
||||
matching = addresses.nonLocal
|
||||
.filter({
|
||||
kind: 'ipv4',
|
||||
predicate: h => h.host === this.config.hostname,
|
||||
predicate: h => h.hostname === this.config.hostname,
|
||||
})
|
||||
.format('urlstring')[0]
|
||||
onLan = true
|
||||
@@ -210,7 +240,7 @@ export class InterfaceService {
|
||||
matching = addresses.nonLocal
|
||||
.filter({
|
||||
kind: 'ipv6',
|
||||
predicate: h => h.host === this.config.hostname,
|
||||
predicate: h => h.hostname === this.config.hostname,
|
||||
})
|
||||
.format('urlstring')[0]
|
||||
break
|
||||
@@ -257,10 +287,20 @@ export type PluginAddress = {
|
||||
masked: boolean
|
||||
}
|
||||
|
||||
export type PluginPkgInfo = {
|
||||
id: string
|
||||
title: string
|
||||
icon: string
|
||||
status: PrimaryStatus
|
||||
}
|
||||
|
||||
export type PluginAddressGroup = {
|
||||
pluginId: string
|
||||
pluginName: string
|
||||
addresses: PluginAddress[]
|
||||
tableAction: { id: string; metadata: T.ActionMetadata } | null
|
||||
pluginPkgInfo: PluginPkgInfo | null
|
||||
pluginActions: Record<string, T.ActionMetadata>
|
||||
}
|
||||
|
||||
export type MappedServiceInterface = T.ServiceInterface & {
|
||||
|
||||
@@ -42,6 +42,7 @@ export type PackageActionData = {
|
||||
metadata: T.ActionMetadata
|
||||
}
|
||||
requestInfo?: T.Task
|
||||
prefill?: Record<string, unknown>
|
||||
}
|
||||
|
||||
@Component({
|
||||
@@ -178,11 +179,14 @@ export class ActionInputModal {
|
||||
|
||||
async execute(input: object) {
|
||||
if (await this.checkConflicts(input)) {
|
||||
const merged = this.context.data.prefill
|
||||
? { ...input, ...this.context.data.prefill }
|
||||
: input
|
||||
await this.actionService.execute(
|
||||
this.pkgInfo.id,
|
||||
this.eventId,
|
||||
this.actionId,
|
||||
input,
|
||||
merged,
|
||||
)
|
||||
this.context.$implicit.complete()
|
||||
}
|
||||
|
||||
@@ -97,6 +97,7 @@ export default class ServiceInterfaceRoute {
|
||||
readonly interfaceId = input('')
|
||||
|
||||
readonly pkg = toSignal(this.patch.watch$('packageData', this.pkgId))
|
||||
readonly allPackageData = toSignal(this.patch.watch$('packageData'))
|
||||
|
||||
readonly isRunning = computed(() => {
|
||||
const pkg = this.pkg()
|
||||
@@ -131,7 +132,7 @@ export default class ServiceInterfaceRoute {
|
||||
host,
|
||||
gateways,
|
||||
),
|
||||
pluginGroups: this.interfaceService.getPluginGroups(iFace, host),
|
||||
pluginGroups: this.interfaceService.getPluginGroups(iFace, host, this.allPackageData()),
|
||||
addSsl: !!binding?.options.addSsl,
|
||||
}
|
||||
})
|
||||
|
||||
@@ -71,10 +71,14 @@ export default class StartOsUiComponent {
|
||||
},
|
||||
}
|
||||
|
||||
private readonly patch = inject<PatchDB<DataModel>>(PatchDB)
|
||||
|
||||
readonly network = toSignal(
|
||||
inject<PatchDB<DataModel>>(PatchDB).watch$('serverInfo', 'network'),
|
||||
this.patch.watch$('serverInfo', 'network'),
|
||||
)
|
||||
|
||||
readonly allPackageData = toSignal(this.patch.watch$('packageData'))
|
||||
|
||||
readonly ui = computed(() => {
|
||||
const network = this.network()
|
||||
const gateways = this.gatewayService.gateways()
|
||||
@@ -91,6 +95,7 @@ export default class StartOsUiComponent {
|
||||
pluginGroups: this.interfaceService.getPluginGroups(
|
||||
this.iface,
|
||||
network.host,
|
||||
this.allPackageData(),
|
||||
),
|
||||
addSsl: true,
|
||||
}
|
||||
|
||||
@@ -46,9 +46,9 @@ export class ActionService {
|
||||
},
|
||||
})
|
||||
.pipe(filter(Boolean))
|
||||
.subscribe(() => this.execute(pkgInfo.id, null, actionInfo.id))
|
||||
.subscribe(() => this.execute(pkgInfo.id, null, actionInfo.id, data.prefill))
|
||||
} else {
|
||||
this.execute(pkgInfo.id, null, actionInfo.id)
|
||||
this.execute(pkgInfo.id, null, actionInfo.id, data.prefill)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +262,7 @@ export namespace Mock {
|
||||
ram: null,
|
||||
},
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
export const MockManifestLnd: T.Manifest = {
|
||||
@@ -321,6 +322,7 @@ export namespace Mock {
|
||||
ram: null,
|
||||
},
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
export const MockManifestBitcoinProxy: T.Manifest = {
|
||||
@@ -373,6 +375,7 @@ export namespace Mock {
|
||||
ram: null,
|
||||
},
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
}
|
||||
|
||||
export const BitcoinDep: T.DependencyMetadata = {
|
||||
@@ -432,6 +435,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
'#knots:26.1.20240325:0': {
|
||||
title: 'Bitcoin Knots',
|
||||
@@ -473,6 +477,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
},
|
||||
categories: ['bitcoin', 'featured'],
|
||||
@@ -524,6 +529,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
'#knots:26.1.20240325:0': {
|
||||
title: 'Bitcoin Knots',
|
||||
@@ -565,6 +571,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
},
|
||||
categories: ['bitcoin', 'featured'],
|
||||
@@ -621,6 +628,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
},
|
||||
categories: ['lightning'],
|
||||
@@ -675,6 +683,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
},
|
||||
categories: ['lightning'],
|
||||
@@ -730,6 +739,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
'#knots:27.1.0:0': {
|
||||
title: 'Bitcoin Knots',
|
||||
@@ -771,6 +781,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
},
|
||||
categories: ['bitcoin', 'featured'],
|
||||
@@ -825,6 +836,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
},
|
||||
categories: ['lightning'],
|
||||
@@ -878,6 +890,7 @@ export namespace Mock {
|
||||
],
|
||||
],
|
||||
hardwareAcceleration: false,
|
||||
plugins: [],
|
||||
},
|
||||
},
|
||||
categories: ['bitcoin'],
|
||||
@@ -2121,7 +2134,7 @@ export namespace Mock {
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'adjective-noun.local',
|
||||
hostname: 'adjective-noun.local',
|
||||
port: 1234,
|
||||
metadata: {
|
||||
kind: 'mdns',
|
||||
@@ -2131,28 +2144,28 @@ export namespace Mock {
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: '192.168.10.11',
|
||||
hostname: '192.168.10.11',
|
||||
port: 1234,
|
||||
metadata: { kind: 'ipv4', gateway: 'wlan0' },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: '10.0.0.2',
|
||||
hostname: '10.0.0.2',
|
||||
port: 1234,
|
||||
metadata: { kind: 'ipv4', gateway: 'wlan0' },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'fe80:cd00:0000:0cde:1257:0000:211e:72cd',
|
||||
hostname: 'fe80:cd00:0000:0cde:1257:0000:211e:72cd',
|
||||
port: 1234,
|
||||
metadata: { kind: 'ipv6', gateway: 'eth0', scopeId: 2 },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'fe80:cd00:0000:0cde:1257:0000:211e:1234',
|
||||
hostname: 'fe80:cd00:0000:0cde:1257:0000:211e:1234',
|
||||
port: 1234,
|
||||
metadata: { kind: 'ipv6', gateway: 'wlan0', scopeId: 3 },
|
||||
},
|
||||
@@ -2222,6 +2235,7 @@ export namespace Mock {
|
||||
outboundGateway: null,
|
||||
registry: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
plugin: { url: null },
|
||||
tasks: {
|
||||
'bitcoind-config': {
|
||||
task: {
|
||||
@@ -2291,6 +2305,7 @@ export namespace Mock {
|
||||
outboundGateway: null,
|
||||
registry: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
plugin: { url: null },
|
||||
tasks: {},
|
||||
}
|
||||
|
||||
@@ -2398,6 +2413,7 @@ export namespace Mock {
|
||||
outboundGateway: null,
|
||||
registry: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
plugin: { url: null },
|
||||
tasks: {
|
||||
config: {
|
||||
active: true,
|
||||
|
||||
@@ -1822,8 +1822,8 @@ export class MockApiService extends ApiService {
|
||||
if (h.port === null) return
|
||||
const sa =
|
||||
h.metadata.kind === 'ipv6'
|
||||
? `[${h.host}]:${h.port}`
|
||||
: `${h.host}:${h.port}`
|
||||
? `[${h.hostname}]:${h.port}`
|
||||
: `${h.hostname}:${h.port}`
|
||||
|
||||
const arr = [...current.enabled]
|
||||
|
||||
@@ -1841,11 +1841,11 @@ export class MockApiService extends ApiService {
|
||||
} else {
|
||||
const port = h.port ?? 0
|
||||
const arr = current.disabled.filter(
|
||||
([dHost, dPort]) => !(dHost === h.host && dPort === port),
|
||||
([dHost, dPort]) => !(dHost === h.hostname && dPort === port),
|
||||
)
|
||||
|
||||
if (!enabled) {
|
||||
arr.push([h.host, port])
|
||||
arr.push([h.hostname, port])
|
||||
}
|
||||
|
||||
current.disabled = arr
|
||||
|
||||
@@ -46,7 +46,7 @@ export const mockPatchData: DataModel = {
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'adjective-noun.local',
|
||||
hostname: 'adjective-noun.local',
|
||||
port: 443,
|
||||
metadata: {
|
||||
kind: 'mdns',
|
||||
@@ -56,35 +56,35 @@ export const mockPatchData: DataModel = {
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: '10.0.0.1',
|
||||
hostname: '10.0.0.1',
|
||||
port: 80,
|
||||
metadata: { kind: 'ipv4', gateway: 'eth0' },
|
||||
},
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: '10.0.0.2',
|
||||
hostname: '10.0.0.2',
|
||||
port: 80,
|
||||
metadata: { kind: 'ipv4', gateway: 'wlan0' },
|
||||
},
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: 'fe80::cd00:0000:0cde:1257:0000:211e:72cd',
|
||||
hostname: 'fe80::cd00:0000:0cde:1257:0000:211e:72cd',
|
||||
port: 80,
|
||||
metadata: { kind: 'ipv6', gateway: 'eth0', scopeId: 2 },
|
||||
},
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: 'fe80::cd00:0000:0cde:1257:0000:211e:1234',
|
||||
hostname: 'fe80::cd00:0000:0cde:1257:0000:211e:1234',
|
||||
port: 80,
|
||||
metadata: { kind: 'ipv6', gateway: 'wlan0', scopeId: 3 },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'my-server.home',
|
||||
hostname: 'my-server.home',
|
||||
port: 443,
|
||||
metadata: {
|
||||
kind: 'private-domain',
|
||||
@@ -94,16 +94,16 @@ export const mockPatchData: DataModel = {
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: 'abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567abc.onion',
|
||||
hostname: 'abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567abc.onion',
|
||||
port: 80,
|
||||
metadata: { kind: 'plugin', package: 'tor' },
|
||||
metadata: { kind: 'plugin', packageId: 'tor', rowActions: [], info: null },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567abc.onion',
|
||||
hostname: 'abc123def456ghi789jkl012mno345pqr678stu901vwx234yz567abc.onion',
|
||||
port: 443,
|
||||
metadata: { kind: 'plugin', package: 'tor' },
|
||||
metadata: { kind: 'plugin', packageId: 'tor', rowActions: [], info: null },
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -349,6 +349,7 @@ export const mockPatchData: DataModel = {
|
||||
outboundGateway: null,
|
||||
registry: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
plugin: { url: null },
|
||||
tasks: {
|
||||
config: {
|
||||
active: true,
|
||||
@@ -532,7 +533,7 @@ export const mockPatchData: DataModel = {
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'adjective-noun.local',
|
||||
hostname: 'adjective-noun.local',
|
||||
port: 42443,
|
||||
metadata: {
|
||||
kind: 'mdns',
|
||||
@@ -542,49 +543,49 @@ export const mockPatchData: DataModel = {
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: '10.0.0.1',
|
||||
hostname: '10.0.0.1',
|
||||
port: 42080,
|
||||
metadata: { kind: 'ipv4', gateway: 'eth0' },
|
||||
},
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: 'fe80::cd00:0cde:1257:211e:72cd',
|
||||
hostname: 'fe80::cd00:0cde:1257:211e:72cd',
|
||||
port: 42080,
|
||||
metadata: { kind: 'ipv6', gateway: 'eth0', scopeId: 2 },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: true,
|
||||
host: '203.0.113.45',
|
||||
hostname: '203.0.113.45',
|
||||
port: 42443,
|
||||
metadata: { kind: 'ipv4', gateway: 'eth0' },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: true,
|
||||
host: 'bitcoin.example.com',
|
||||
hostname: 'bitcoin.example.com',
|
||||
port: 42443,
|
||||
metadata: { kind: 'public-domain', gateway: 'eth0' },
|
||||
},
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: '192.168.10.11',
|
||||
hostname: '192.168.10.11',
|
||||
port: 42080,
|
||||
metadata: { kind: 'ipv4', gateway: 'wlan0' },
|
||||
},
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: 'fe80::cd00:0cde:1257:211e:1234',
|
||||
hostname: 'fe80::cd00:0cde:1257:211e:1234',
|
||||
port: 42080,
|
||||
metadata: { kind: 'ipv6', gateway: 'wlan0', scopeId: 3 },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'my-bitcoin.home',
|
||||
hostname: 'my-bitcoin.home',
|
||||
port: 42443,
|
||||
metadata: {
|
||||
kind: 'private-domain',
|
||||
@@ -594,16 +595,16 @@ export const mockPatchData: DataModel = {
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: 'xyz789abc123def456ghi789jkl012mno345pqr678stu901vwx234.onion',
|
||||
hostname: 'xyz789abc123def456ghi789jkl012mno345pqr678stu901vwx234.onion',
|
||||
port: 42080,
|
||||
metadata: { kind: 'plugin', package: 'tor' },
|
||||
metadata: { kind: 'plugin', packageId: 'tor', rowActions: [], info: null },
|
||||
},
|
||||
{
|
||||
ssl: true,
|
||||
public: false,
|
||||
host: 'xyz789abc123def456ghi789jkl012mno345pqr678stu901vwx234.onion',
|
||||
hostname: 'xyz789abc123def456ghi789jkl012mno345pqr678stu901vwx234.onion',
|
||||
port: 42443,
|
||||
metadata: { kind: 'plugin', package: 'tor' },
|
||||
metadata: { kind: 'plugin', packageId: 'tor', rowActions: [], info: null },
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -655,7 +656,7 @@ export const mockPatchData: DataModel = {
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: 'adjective-noun.local',
|
||||
hostname: 'adjective-noun.local',
|
||||
port: 48332,
|
||||
metadata: {
|
||||
kind: 'mdns',
|
||||
@@ -665,7 +666,7 @@ export const mockPatchData: DataModel = {
|
||||
{
|
||||
ssl: false,
|
||||
public: false,
|
||||
host: '10.0.0.1',
|
||||
hostname: '10.0.0.1',
|
||||
port: 48332,
|
||||
metadata: { kind: 'ipv4', gateway: 'eth0' },
|
||||
},
|
||||
@@ -711,6 +712,7 @@ export const mockPatchData: DataModel = {
|
||||
outboundGateway: null,
|
||||
registry: 'https://registry.start9.com/',
|
||||
developerKey: 'developer-key',
|
||||
plugin: { url: null },
|
||||
tasks: {
|
||||
// 'bitcoind-config': {
|
||||
// task: {
|
||||
|
||||
Reference in New Issue
Block a user