updated home grid to display all custom and existing apps before "easy setup"

This commit is contained in:
1dabread 2026-08-12 14:43:29 -05:00
parent 09d5639ab9
commit 79a09717a2
4 changed files with 48 additions and 16 deletions

View File

@ -36,6 +36,8 @@ import type { HttpContext } from '@adonisjs/core/http'
import logger from '@adonisjs/core/services/logger'
import Service from '#models/service'
const CUSTOM_APP_HOME_DISPLAY_ORDER = 49
@inject()
export default class SystemController {
constructor(
@ -441,6 +443,7 @@ export default class SystemController {
is_dependency_service: false,
is_custom: true,
category: payload.category ?? 'custom',
display_order: uiLocation ? CUSTOM_APP_HOME_DISPLAY_ORDER : null,
depends_on: null,
})
@ -486,7 +489,7 @@ export default class SystemController {
is_dependency_service: false,
is_custom: true,
category: payload.category ?? 'custom',
display_order: publishedHostPort ? 49 : null,
display_order: publishedHostPort ? CUSTOM_APP_HOME_DISPLAY_ORDER : null,
depends_on: null,
})
@ -569,6 +572,19 @@ export default class SystemController {
}
service.custom_url = normalized
if (
normalized &&
(service.display_order === null || service.display_order >= 50)
) {
service.display_order = CUSTOM_APP_HOME_DISPLAY_ORDER
}
if (
!normalized &&
!service.ui_location &&
service.display_order === CUSTOM_APP_HOME_DISPLAY_ORDER
) {
service.display_order = null
}
await service.save()
return response.send({ success: true, custom_url: service.custom_url })
@ -704,6 +720,19 @@ export default class SystemController {
? `${prevScheme}:${uiLocation}`
: uiLocation
service.category = payload.category ?? service.category ?? 'custom'
if (
(service.ui_location || service.custom_url) &&
(service.display_order === null || service.display_order >= 50)
) {
service.display_order = CUSTOM_APP_HOME_DISPLAY_ORDER
}
if (
!service.ui_location &&
!service.custom_url &&
service.display_order === CUSTOM_APP_HOME_DISPLAY_ORDER
) {
service.display_order = null
}
if (payload.icon) service.icon = payload.icon
// Flag as user-modified so the seeder stops overwriting this app's config on future runs.
service.is_user_modified = true

View File

@ -24,6 +24,8 @@ import { isNewerVersion } from '../utils/version.js'
import { invalidateAssistantNameCache } from '../../config/inertia.js'
import { KiwixLibraryService } from '#services/kiwix_library_service'
const CUSTOM_APP_HOME_DISPLAY_ORDER = 49
@inject()
export class SystemService {
private static appVersion: string | null = null
@ -319,7 +321,7 @@ export class SystemService {
async getServices({ installedOnly = true }: { installedOnly?: boolean }): Promise<ServiceSlim[]> {
const statuses = await this._syncContainersWithDatabase() // Sync and reuse the fetched status list
await this._syncExistingPublishedAppLinks()
await this._syncCustomAppHomeLinks()
const query = Service.query()
.orderBy('display_order', 'asc')
@ -390,23 +392,21 @@ export class SystemService {
}
/**
* Backfill launch metadata for existing Docker containers added before published ports were
* detected. A published existing app gets a Command Center link and a pre-system sort order;
* unpublished containers stay manageable in Supply Depot without a dead dashboard tile.
* Backfill launch metadata for custom app records. Launchable apps get the same pre-system
* Command Center sort order whether they were created by NOMAD or registered from an existing
* Docker container.
*/
private async _syncExistingPublishedAppLinks(): Promise<void> {
private async _syncCustomAppHomeLinks(): Promise<void> {
try {
const existingApps = await Service.query()
const customApps = await Service.query()
.where('installed', true)
.where('is_custom', true)
.where('is_dependency_service', false)
.whereNull('container_config')
for (const service of existingApps) {
for (const service of customApps) {
const inspect = await this.dockerService.inspectContainerByName(service.service_name)
if (!inspect) continue
const publishedHostPort = inspect ? DockerService.getFirstPublishedHostPort(inspect) : null
const publishedHostPort = DockerService.getFirstPublishedHostPort(inspect)
let changed = false
if (publishedHostPort && service.ui_location !== publishedHostPort) {
@ -414,10 +414,10 @@ export class SystemService {
changed = true
}
if (
publishedHostPort &&
(publishedHostPort || service.ui_location || service.custom_url) &&
(service.display_order === null || service.display_order >= 50)
) {
service.display_order = 49
service.display_order = CUSTOM_APP_HOME_DISPLAY_ORDER
changed = true
}
if (!publishedHostPort && service.ui_location === service.service_name) {
@ -431,7 +431,7 @@ export class SystemService {
}
} catch (error) {
logger.warn(
`[SystemService] Existing app launch metadata sync failed: ${
`[SystemService] Custom app launch metadata sync failed: ${
error instanceof Error ? error.message : error
}`
)

View File

@ -24,6 +24,8 @@ import Alert from '~/components/Alert'
import WhatsNewBanner from '~/components/WhatsNewBanner'
import { SERVICE_NAMES } from '../../constants/service_names'
const APP_FALLBACK_DISPLAY_ORDER = 49
// Maps is a Core Capability (display_order: 4)
const MAPS_ITEM = {
label: 'Maps',
@ -153,7 +155,8 @@ export default function Home(props: {
<IconWifiOff size={48} />
),
installed: service.installed,
displayOrder: service.display_order ?? 100,
// Launchable apps without an explicit order still belong before system tiles.
displayOrder: service.display_order ?? APP_FALLBACK_DISPLAY_ORDER,
poweredBy: service.powered_by ?? null,
})
})

View File

@ -9,7 +9,7 @@
name: project-nomad
services:
admin:
image: nomad:1.0
image: nomad:app-button
container_name: nomad_admin
restart: unless-stopped
extra_hosts: