feat(ui): simplify plugin activation and align task status badges
This commit is contained in:
1 parent
9c82a40cbf
commit
96fedc816f
11 files changed
+242
-31
No files matched your search
@@ -13,15 +13,17 @@
|
||||
@for (plugin of available(); track plugin.manifest.id) {
|
||||
<div class="choice">
|
||||
<label><input type="checkbox" [checked]="selected[plugin.manifest.id] !== undefined" (change)="choose(plugin, $event)">{{ plugin.manifest.name }}</label>
|
||||
<select [disabled]="selected[plugin.manifest.id] === undefined" [ngModel]="selected[plugin.manifest.id] || ''" (ngModelChange)="selected[plugin.manifest.id] = $event; emit()" [attr.aria-label]="plugin.manifest.name + '连接配置'">
|
||||
<option value="" disabled>选择连接配置</option>
|
||||
@for (profile of plugin.profiles; track profile.name) { @if (profile.authorized) { <option [value]="profile.name">{{ profile.label }}</option> } }
|
||||
</select>
|
||||
@if (authorizedProfiles(plugin).length > 1) {
|
||||
<select [disabled]="selected[plugin.manifest.id] === undefined" [ngModel]="selected[plugin.manifest.id] || ''" (ngModelChange)="selected[plugin.manifest.id] = $event; emit()" [attr.aria-label]="plugin.manifest.name + '使用设置'">
|
||||
<option value="" disabled>选择要使用的设置</option>
|
||||
@for (profile of authorizedProfiles(plugin); track profile.name) { <option [value]="profile.name">{{ profile.label }}</option> }
|
||||
</select>
|
||||
}
|
||||
</div>
|
||||
} @empty { <p>还没有可用插件,请先安装、授权并启用。</p> }
|
||||
<p class="hint">不勾选任何插件时,本次任务只使用手机能力。</p>
|
||||
} @else {
|
||||
<p class="hint">{{ available().length ? '默认连接用于自动调用,也可以关闭自动选择,指定本次可用的插件。' : '还没有可用插件,手机测试不受影响。' }}</p>
|
||||
<p class="hint">{{ available().length ? 'AI 会按需使用可用插件,无需逐次选择。关闭自动使用后,可指定本次允许使用的插件。' : '还没有可用插件,手机测试不受影响。' }}</p>
|
||||
}
|
||||
<a routerLink="/plugins" class="manage-link">管理插件 <span class="material-symbols-outlined" aria-hidden="true">arrow_forward</span></a>
|
||||
</section>
|
||||
|
||||
@@ -30,7 +30,7 @@ describe('TaskPluginsComponent', () => {
|
||||
expect(emitted).toHaveBeenCalledWith({});
|
||||
});
|
||||
|
||||
it('offers authorized cross-device connections and uses the default profile', async () => {
|
||||
it('uses the single authorized setting without exposing a connection selector', async () => {
|
||||
const fixture = TestBed.createComponent(TaskPluginsComponent);
|
||||
const component = fixture.componentInstance;
|
||||
component.toggle();
|
||||
@@ -45,7 +45,26 @@ describe('TaskPluginsComponent', () => {
|
||||
checkbox.click(); fixture.detectChanges(); await fixture.whenStable();
|
||||
expect(emitted).toHaveBeenCalledWith({ plugins: [{ id: 'desktop', profile: 'lab' }] });
|
||||
expect(fixture.nativeElement.querySelectorAll('.choice').length).toBe(1);
|
||||
expect(fixture.nativeElement.querySelector('select').textContent).not.toContain('旧配置');
|
||||
expect(fixture.nativeElement.querySelector('select')).toBeNull();
|
||||
expect(fixture.nativeElement.textContent).not.toContain('连接配置');
|
||||
});
|
||||
|
||||
it('allows choosing among multiple authorized settings and excludes unauthorized ones', async () => {
|
||||
const fixture = TestBed.createComponent(TaskPluginsComponent); const component = fixture.componentInstance;
|
||||
component.toggle();
|
||||
http.expectOne('/api/plugins').flush({ plugins: [{ enabled: true,
|
||||
manifest: { id: 'desktop', name: '电脑控制', targets: ['mixed'] }, profiles: [
|
||||
{ name: 'old', label: '旧配置', authorized: false },
|
||||
{ name: 'lab', label: '实验室', authorized: true, is_default: true },
|
||||
{ name: 'office', label: '办公室', authorized: true }
|
||||
] }] });
|
||||
component.automatic = false; fixture.detectChanges(); await fixture.whenStable();
|
||||
const emitted = jasmine.createSpy('changed'); component.changed.subscribe(emitted);
|
||||
fixture.nativeElement.querySelector('.choice input').click(); fixture.detectChanges(); await fixture.whenStable();
|
||||
const select: HTMLSelectElement = fixture.nativeElement.querySelector('select');
|
||||
expect(select.value).toBe('lab'); expect(select.textContent).not.toContain('旧配置');
|
||||
select.value = 'office'; select.dispatchEvent(new Event('change')); fixture.detectChanges(); await fixture.whenStable();
|
||||
expect(emitted).toHaveBeenCalledWith({ plugins: [{ id: 'desktop', profile: 'office' }] });
|
||||
});
|
||||
|
||||
it('shows a retryable error and keeps automatic mode on lookup failure', () => {
|
||||
|
||||
@@ -28,6 +28,7 @@ export class TaskPluginsComponent {
|
||||
return this.plugins().filter(p => p.enabled && p.profiles.some(profile => profile.authorized) &&
|
||||
p.manifest.targets.some(target => target === 'android' || target === 'mixed'));
|
||||
}
|
||||
authorizedProfiles(plugin: InstalledPlugin) { return plugin.profiles.filter(p => p.authorized); }
|
||||
toggle() {
|
||||
this.open.update(v => !v);
|
||||
if (this.open()) this.load();
|
||||
@@ -41,7 +42,7 @@ export class TaskPluginsComponent {
|
||||
}
|
||||
choose(plugin: InstalledPlugin, event: Event) {
|
||||
if ((event.target as HTMLInputElement).checked) {
|
||||
const profiles = plugin.profiles.filter(p => p.authorized);
|
||||
const profiles = this.authorizedProfiles(plugin);
|
||||
this.selected[plugin.manifest.id] = (profiles.find(p => p.is_default) || profiles[0]).name;
|
||||
} else delete this.selected[plugin.manifest.id];
|
||||
this.emit();
|
||||
|
||||
Reference in new issue
Block a user