{{plugin.manifest.name}}
{{plugin.manifest.description || '暂无描述'}}
- +{{plugin.manifest.description || '暂无描述'}}
+diff --git a/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html b/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html index c36c4ba..b8204e9 100644 --- a/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html +++ b/apps/showcase_ui/src/app/components/agent-stream/agent-stream.component.html @@ -81,6 +81,7 @@ limitations under the License. (click)="selectTask(session.session_id, $event)" >
还没有可用插件,请先安装、授权并启用。
}不勾选任何插件时,本次任务只使用手机能力。
} @else { -{{ available().length ? '默认连接用于自动调用,也可以关闭自动选择,指定本次可用的插件。' : '还没有可用插件,手机测试不受影响。' }}
+{{ available().length ? 'AI 会按需使用可用插件,无需逐次选择。关闭自动使用后,可指定本次允许使用的插件。' : '还没有可用插件,手机测试不受影响。' }}
} 管理插件 diff --git a/apps/showcase_ui/src/app/components/task-plugins/task-plugins.component.spec.ts b/apps/showcase_ui/src/app/components/task-plugins/task-plugins.component.spec.ts index 6acb54e..f4bc2c4 100644 --- a/apps/showcase_ui/src/app/components/task-plugins/task-plugins.component.spec.ts +++ b/apps/showcase_ui/src/app/components/task-plugins/task-plugins.component.spec.ts @@ -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', () => { diff --git a/apps/showcase_ui/src/app/components/task-plugins/task-plugins.component.ts b/apps/showcase_ui/src/app/components/task-plugins/task-plugins.component.ts index 7840a1d..1655e85 100644 --- a/apps/showcase_ui/src/app/components/task-plugins/task-plugins.component.ts +++ b/apps/showcase_ui/src/app/components/task-plugins/task-plugins.component.ts @@ -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(); diff --git a/apps/showcase_ui/src/app/pages/plugins/plugins.component.html b/apps/showcase_ui/src/app/pages/plugins/plugins.component.html index af354aa..3e53f68 100644 --- a/apps/showcase_ui/src/app/pages/plugins/plugins.component.html +++ b/apps/showcase_ui/src/app/pages/plugins/plugins.component.html @@ -7,7 +7,7 @@ } @if (progress(); as job) { -从市场安装经过验证的扩展,或在下方导入自己的插件。
{{plugin.manifest.description || '暂无描述'}}
- +{{plugin.manifest.description || '暂无描述'}}
+本地插件需要包含 plugin.json;导入后配置授权范围,再手动启用。
+本地插件需要包含 plugin.json;导入后点击启用,按提示完成设置。
允许 ARTEMIS 在测试需要时查看本机窗口,并操作桌面应用和浏览器。
+ } @else {允许 ARTEMIS 在测试需要时使用此插件提供的工具。
} + + @if (error()) { } + +请先核对目标设备或远程服务,确认之前的插件动作已经停止,并检查实际状态。解除后任务才可再次操作此资源。
配置连接与允许控制的范围
{{hasSettings(plugin) ? '填写插件需要的信息,高级选项通常无需修改。' : '此插件无需填写参数,高级选项通常无需修改。'}}
仅在需要切换不同设备、账号或限制操作范围时使用。
+ @if (enableAfterSave && !defaultProfile(plugin)) {请选择一套设置,并勾选「默认使用这套设置」,以便 AI 自动调用。
} + + + + +此插件及其连接配置将不再供新任务使用。
此插件及其保存的设置将不再供新任务使用。