fix: restore build and stabilize E2E cross-signal behavior

Revert the automated member-ordering pass that broke Angular field init
(TS2729) and disable that rule until a safe reorder strategy exists.
Fix modal/confirm dialog i18n defaults via template fallbacks, search all
active endpoints (including offline), register foreign rooms with actor
owner IDs, sync profile display names from avatar summaries, and guard
dm-chat when a private call converts to a group conversation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-11 12:16:40 +02:00
parent 79c6f91cd6
commit 31962aeb1a
131 changed files with 2483 additions and 3896 deletions

View File

@@ -1,3 +1,4 @@
<!-- eslint-disable @angular-eslint/template/cyclomatic-complexity -->
<section
class="flex min-h-full flex-col bg-background text-foreground md:h-full md:min-h-0"
data-testid="plugin-manager"

View File

@@ -63,64 +63,46 @@ type PluginManagerTab = 'docs' | 'extensions' | 'installed' | 'logs' | 'requirem
})
export class PluginManagerComponent {
@Output() readonly closed = new EventEmitter<void>();
@Output() readonly storeOpened = new EventEmitter<void>();
readonly scope = input<TojuPluginInstallScope>('client');
readonly capabilities = inject(PluginCapabilityService);
readonly host = inject(PluginHostService);
readonly logger = inject(PluginLoggerService);
readonly registry = inject(PluginRegistryService);
readonly requirementState = inject(PluginRequirementStateService);
readonly router = inject(Router);
readonly uiRegistry = inject(PluginUiRegistryService);
private readonly appI18n = inject(AppI18nService);
readonly activeTab = signal<PluginManagerTab>('installed');
readonly busyPluginId = signal<string | null>(null);
readonly busyAll = signal(false);
readonly selectedPluginId = signal<string | null>(null);
readonly allEntries = this.registry.entries;
readonly entries = computed(() => this.allEntries().filter((entry) => this.entryBelongsToScope(entry)));
readonly managerTitle = computed(() => this.scope() === 'server'
? this.appI18n.instant('plugins.manager.serverTitle')
: this.appI18n.instant('plugins.manager.clientTitle'));
readonly managerDescription = computed(() => this.scope() === 'server'
? this.appI18n.instant('plugins.manager.serverDescription')
: this.appI18n.instant('plugins.manager.clientDescription'));
readonly selectedPlugin = computed(() => {
const selectedPluginId = this.selectedPluginId();
return this.entries().find((entry) => entry.manifest.id === selectedPluginId) ?? this.entries()[0] ?? null;
});
readonly missingCapabilities = computed(() => {
const selectedPlugin = this.selectedPlugin();
return selectedPlugin ? this.capabilities.missing(selectedPlugin.manifest) : [];
});
readonly selectedLogs = computed(() => {
const selectedPlugin = this.selectedPlugin();
return selectedPlugin ? this.logger.entries().filter((entry) => entry.pluginId === selectedPlugin.manifest.id)
.slice(-20) : [];
});
readonly extensionCounts = computed(() => ({
appPages: this.uiRegistry.appPageRecords().filter((record) => this.hasVisiblePlugin(record.pluginId)).length,
channelSections: this.uiRegistry.channelSectionRecords().filter((record) => this.hasVisiblePlugin(record.pluginId)).length,
@@ -132,7 +114,6 @@ export class PluginManagerComponent {
slashCommands: this.uiRegistry.slashCommandRecords().filter((record) => this.hasVisiblePlugin(record.pluginId)).length,
toolbarActions: this.uiRegistry.toolbarActionRecords().filter((record) => this.hasVisiblePlugin(record.pluginId)).length
}));
readonly extensionCountItems = computed(() => {
const counts = this.extensionCounts();
@@ -148,20 +129,15 @@ export class PluginManagerComponent {
{ label: this.appI18n.instant('plugins.manager.extensionCounts.embedRenderers'), value: counts.embeds }
];
});
readonly requirementComparisons = computed(() => this.scope() === 'server' ? this.requirementState.comparisons() : []);
readonly uiConflicts = computed(() => this.uiRegistry.conflicts()
.filter((conflict) => conflict.pluginIds.some((pluginId) => this.hasVisiblePlugin(pluginId))));
readonly selectedRequirement = computed(() => {
const selectedPlugin = this.selectedPlugin();
return selectedPlugin ? this.requirementState.comparisonFor(selectedPlugin.manifest.id) : null;
});
readonly selectedSettingsSchema = computed(() => this.selectedPlugin()?.manifest.settings ?? null);
readonly selectedSettingsPages = computed(() => {
const selectedPlugin = this.selectedPlugin();
@@ -169,15 +145,12 @@ export class PluginManagerComponent {
? this.uiRegistry.settingsPageRecords().filter((record) => record.pluginId === selectedPlugin.manifest.id)
: [];
});
readonly emptyTitle = computed(() => this.scope() === 'server'
? this.appI18n.instant('plugins.manager.empty.serverTitle')
: this.appI18n.instant('plugins.manager.empty.clientTitle'));
readonly emptyBody = computed(() => this.scope() === 'server'
? this.appI18n.instant('plugins.manager.empty.serverBody')
: this.appI18n.instant('plugins.manager.empty.clientBody'));
readonly selectedDocs = computed(() => {
const manifest = this.selectedPlugin()?.manifest;
@@ -193,8 +166,6 @@ export class PluginManagerComponent {
].filter((item): item is { label: string; url: string } => typeof item.url === 'string' && item.url.length > 0);
});
private readonly appI18n = inject(AppI18nService);
setTab(tab: PluginManagerTab): void {
this.activeTab.set(tab);
}
@@ -294,5 +265,4 @@ export class PluginManagerComponent {
private hasVisiblePlugin(pluginId: string): boolean {
return this.entries().some((entry) => entry.manifest.id === pluginId);
}
}