cli/cmd/lthn-desktop/frontend/src/frame/application.frame.ts
Snider 9ef000853e feat: add lthn-desktop as default GUI and restructure build targets
- Set lthn-desktop as the default gui build target (port 9247)
- Add core-demo GUI with Vite frontend (port 9245)
- Configure core-gui on port 9246 to avoid conflicts
- Update .gitignore for lthn-desktop and core-demo artifacts
- Include lthn-desktop Angular frontend with Monaco editor and Claude panel
- Add frontend.old directory preserving original lthn-desktop pages

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 14:40:33 +00:00

149 lines
4.8 KiB
TypeScript

import {Component, CUSTOM_ELEMENTS_SCHEMA, OnDestroy, OnInit} from '@angular/core';
import { CommonModule, TitleCasePipe } from '@angular/common';
import { NavigationEnd, Router, RouterLink, RouterLinkActive, RouterOutlet } from '@angular/router';
import { ShowEnvironmentDialog } from "@lthn/core/display/service"
import { OpenDocsWindow } from "@lthn/docs/service"
import { EnableFeature, IsFeatureEnabled } from "@lthn/core/config/service";
import { TranslationService } from '../app/services/translation.service';
import { I18nService } from '../app/services/i18n.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'application-frame',
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA],
imports: [CommonModule, RouterOutlet, RouterLink, RouterLinkActive, TitleCasePipe],
templateUrl: './application.frame.html',
})
export class ApplicationFrame implements OnInit, OnDestroy {
sidebarOpen = false;
userMenuOpen = false;
currentRole = 'Developer';
time: string = '';
private intervalId: number | undefined;
private langChangeSubscription: Subscription | undefined;
featureKey: string | null = null;
isFeatureEnabled: boolean = false;
userNavigation: any[] = [];
navigation: any[] = [];
roleNavigation: any[] = [];
constructor(
private router: Router,
public t: TranslationService,
private i18nService: I18nService
) {
}
async ngOnInit(): Promise<void> {
this.updateTime();
this.intervalId = window.setInterval(() => {
this.updateTime();
}, 1000);
await this.t.onReady();
this.initializeUserNavigation();
this.langChangeSubscription = this.i18nService.currentLanguage$.subscribe(async () => {
await this.t.onReady();
this.initializeUserNavigation();
});
this.router.events.subscribe(event => {
if (event instanceof NavigationEnd) {
this.extractFeatureKeyAndCheckStatus(event.urlAfterRedirects);
}
});
this.navigation = [
{ name: this.t._('menu.blockchain'), href: 'blockchain', icon: "fa-chart-network fa-regular fa-2xl shrink-0" },
{ name: this.t._('menu.mining'), href: 'mining', icon: "fa-pickaxe fa-regular fa-2xl shrink-0" },
{ name: this.t._('Developer'), href: 'dev/edit', icon: "fa-code fa-regular fa-2xl shrink-0" },
{ name: this.t._('Claude AI'), href: 'dev/claude', icon: "fa-robot fa-regular fa-2xl shrink-0" },
];
this.roleNavigation = [
{ name: this.t._('menu.hub-client'), href: '/config/client-hub' },
{ name: this.t._('menu.hub-server'), href: '/config/server-hub' },
{ name: this.t._('menu.hub-developer'), href: '/config/developer-hub' },
{ name: this.t._('menu.hub-gateway'), href: '/config/gateway-hub' },
{ name: this.t._('menu.hub-admin'), href: '/config/admin-hub' },
];
await this.extractFeatureKeyAndCheckStatus(this.router.url); // Initial check
}
ngOnDestroy(): void {
if (this.intervalId) {
clearInterval(this.intervalId);
}
if (this.langChangeSubscription) {
this.langChangeSubscription.unsubscribe();
}
}
initializeUserNavigation(): void {
this.userNavigation = [
{ name: this.t._('menu.your-profile'), href: '#', icon: "fa-id-card fa-regular" },
{ name: this.t._('menu.logout'), href: '#', icon: "fa-right-from-bracket fa-regular" },
];
}
updateTime(): void {
const now = new Date();
this.time = now.toLocaleTimeString();
}
async extractFeatureKeyAndCheckStatus(url: string): Promise<void> {
// Remove leading slash and split by slash
const parts = url.startsWith('/') ? url.substring(1).split('/') : url.split('/');
if (parts.length > 0 && parts[0] !== '') {
this.featureKey = parts[0];
await this.checkFeatureStatus();
} else {
this.featureKey = null;
this.isFeatureEnabled = true; // No feature key, so assume enabled
}
}
async checkFeatureStatus(): Promise<void> {
if (this.featureKey) {
try {
this.isFeatureEnabled = await IsFeatureEnabled(this.featureKey);
} catch (error) {
console.error(`Error checking feature ${this.featureKey}:`, error);
this.isFeatureEnabled = false;
}
} else {
this.isFeatureEnabled = true;
}
}
async activateFeature(): Promise<void> {
if (this.featureKey) {
try {
await EnableFeature(this.featureKey);
await this.checkFeatureStatus();
} catch (error) {
console.error(`Error activating feature ${this.featureKey}:`, error);
}
}
}
showTestDialog(): void {
alert('Test Dialog Triggered!');
}
openDocs() {
return OpenDocsWindow("getting-started/chain#using-the-cli")
}
switchRole(roleName: string) {
if (roleName.endsWith(' Hub')) {
this.currentRole = roleName.replace(' Hub', '');
}
this.userMenuOpen = false;
}
protected readonly ShowEnvironmentDialog = ShowEnvironmentDialog;
}