fix: improve plugins functionality with server management

This commit is contained in:
2026-04-29 20:33:54 +02:00
parent b8f6d58d99
commit fa2cca6fa4
82 changed files with 1708 additions and 303 deletions

View File

@@ -18,7 +18,8 @@ import {
lucideHash,
lucideMenu,
lucidePackage,
lucideRefreshCw
lucideRefreshCw,
lucideShield
} from '@ng-icons/lucide';
import { NavigationEnd, Router } from '@angular/router';
import { toSignal } from '@angular/core/rxjs-interop';
@@ -42,9 +43,15 @@ import { PlatformService } from '../../../core/platform';
import { clearStoredCurrentUserId } from '../../../core/storage/current-user-storage';
import { SettingsModalService } from '../../../core/services/settings-modal.service';
import { LeaveServerDialogComponent } from '../../../shared';
import { Room } from '../../../shared-kernel';
import { Room, type PluginRequirementSummary } from '../../../shared-kernel';
import { VoiceWorkspaceService } from '../../../domains/voice-session';
import { ThemeNodeDirective } from '../../../domains/theme';
import {
PluginRegistryService,
PluginRequirementStateService,
PluginStoreService
} from '../../../domains/plugins';
import { getPluginInstallScope } from '../../../domains/plugins/domain/logic/plugin-install-scope.logic';
@Component({
selector: 'app-title-bar',
@@ -64,7 +71,8 @@ import { ThemeNodeDirective } from '../../../domains/theme';
lucideHash,
lucideMenu,
lucidePackage,
lucideRefreshCw })
lucideRefreshCw,
lucideShield })
],
templateUrl: './title-bar.component.html'
})
@@ -80,6 +88,9 @@ export class TitleBarComponent {
private platform = inject(PlatformService);
private voiceWorkspace = inject(VoiceWorkspaceService);
private settingsModal = inject(SettingsModalService);
private pluginRegistry = inject(PluginRegistryService);
private pluginRequirements = inject(PluginRequirementStateService);
private pluginStore = inject(PluginStoreService);
private getWindowControlsApi() {
return this.electronBridge.getApi();
@@ -153,11 +164,20 @@ export class TitleBarComponent {
|| this.isReconnecting()
)
);
serverPluginCount = computed(() => this.pluginRegistry.entries()
.filter((entry) => getPluginInstallScope(entry.manifest) === 'server')
.length);
hasServerPlugins = computed(() => this.inRoom() && this.serverPluginCount() > 0);
requiredPluginRequirements = this.pluginRequirements.missingRequiredRequirements;
optionalPluginRequirement = computed(() => this.inRoom() ? this.pluginRequirements.visibleOptionalRequirements()[0] ?? null : null);
optionalPluginRequirementCount = computed(() => this.pluginRequirements.visibleOptionalRequirements().length);
private _showMenu = signal(false);
showMenu = computed(() => this._showMenu());
showLeaveConfirm = signal(false);
inviteStatus = signal<string | null>(null);
creatingInvite = signal(false);
pluginRequirementBusy = signal(false);
pluginRequirementError = signal<string | null>(null);
/** Minimize the Electron window. */
minimize() {
@@ -192,6 +212,17 @@ export class TitleBarComponent {
void this.router.navigate(['/plugin-store'], { queryParams: { returnUrl } });
}
openServerPlugins(): void {
const roomId = this.currentRoom()?.id;
if (!roomId) {
return;
}
this._showMenu.set(false);
this.settingsModal.open('serverPlugins', roomId);
}
openSettings(): void {
this._showMenu.set(false);
this.settingsModal.open('general');
@@ -267,6 +298,24 @@ export class TitleBarComponent {
this.openLeaveConfirm();
}
installRequiredServerPlugins(): void {
void this.installServerRequirements(this.requiredPluginRequirements());
}
installOptionalServerPlugin(requirement: PluginRequirementSummary): void {
void this.installServerRequirements([requirement]);
}
rejectOptionalServerPlugin(requirement: PluginRequirementSummary): void {
this.pluginRequirements.dismissOptionalRequirement(requirement);
this.pluginRequirementError.set(null);
}
hideOptionalServerPlugin(requirement: PluginRequirementSummary): void {
this.pluginRequirements.dismissOptionalRequirement(requirement, { persist: true });
this.pluginRequirementError.set(null);
}
/** Confirm the unified leave action and remove the server locally. */
confirmLeave(result: { nextOwnerKey?: string }) {
const roomId = this.currentRoom()?.id;
@@ -294,6 +343,25 @@ export class TitleBarComponent {
this._showMenu.set(false);
}
private async installServerRequirements(requirements: PluginRequirementSummary[]): Promise<void> {
const room = this.currentRoom();
if (!room || requirements.length === 0 || this.pluginRequirementBusy()) {
return;
}
this.pluginRequirementBusy.set(true);
this.pluginRequirementError.set(null);
try {
await this.pluginStore.installServerRequirementsLocally(room.id, requirements, { activate: true });
} catch (error) {
this.pluginRequirementError.set(error instanceof Error ? error.message : 'Unable to install server plugin');
} finally {
this.pluginRequirementBusy.set(false);
}
}
/** Log out the current user, disconnect from signaling, and navigate to login. */
logout() {
this._showMenu.set(false);