Path: blob/main/src/vs/workbench/test/browser/componentFixtures/sessions/agentSessionsViewer.fixture.ts
13405 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { URI } from '../../../../../base/common/uri.js';6import { Codicon } from '../../../../../base/common/codicons.js';7import { MarkdownString } from '../../../../../base/common/htmlContent.js';8import { mock } from '../../../../../base/test/common/mock.js';9import { FuzzyScore } from '../../../../../base/common/filters.js';10import { ITreeNode } from '../../../../../base/browser/ui/tree/tree.js';11import { observableValue } from '../../../../../base/common/observable.js';12import { Event } from '../../../../../base/common/event.js';13import { IMarkdownRendererService, MarkdownRendererService } from '../../../../../platform/markdown/browser/markdownRenderer.js';14import { IProductService } from '../../../../../platform/product/common/productService.js';15import { IConfigurationService } from '../../../../../platform/configuration/common/configuration.js';16import { TestConfigurationService } from '../../../../../platform/configuration/test/common/testConfigurationService.js';17import { EditorMarkdownCodeBlockRenderer } from '../../../../../editor/browser/widget/markdownRenderer/browser/editorMarkdownCodeBlockRenderer.js';18import { AgentSessionRenderer, AgentSessionSectionRenderer, IAgentSessionRendererOptions } from '../../../../contrib/chat/browser/agentSessions/agentSessionsViewer.js';19import { IChatSessionsService } from '../../../../contrib/chat/common/chatSessionsService.js';20import { AgentSessionStatus, IAgentSession, AgentSessionSection, IAgentSessionSection } from '../../../../contrib/chat/browser/agentSessions/agentSessionsModel.js';21import { AgentSessionProviders } from '../../../../contrib/chat/browser/agentSessions/agentSessions.js';22import { AgentSessionApprovalModel, IAgentSessionApprovalInfo } from '../../../../contrib/chat/browser/agentSessions/agentSessionApprovalModel.js';23import { HoverPosition } from '../../../../../base/browser/ui/hover/hoverWidget.js';24import { ComponentFixtureContext, createEditorServices, defineComponentFixture, defineThemedFixtureGroup, registerWorkbenchServices } from '../fixtureUtils.js';2526import '../../../../contrib/chat/browser/agentSessions/media/agentsessionsviewer.css';2728// ============================================================================29// Mock helpers30// ============================================================================3132function createMockSession(overrides: Partial<IAgentSession> & { label: string; status: AgentSessionStatus; providerType: string }): IAgentSession {33const now = Date.now();34return new class extends mock<IAgentSession>() {35override readonly resource = overrides.resource ?? URI.parse(`vscode-chat-session://${overrides.providerType}/session-${Math.random().toString(36).slice(2)}`);36override readonly label = overrides.label;37override readonly status = overrides.status;38override readonly providerType = overrides.providerType;39override readonly providerLabel = overrides.providerLabel ?? overrides.providerType;40override readonly icon = overrides.icon ?? Codicon.vm;41override readonly badge = overrides.badge;42override readonly description = overrides.description;43override readonly tooltip = overrides.tooltip;44override readonly changes = overrides.changes;45override readonly timing = overrides.timing ?? {46created: now - 60 * 60 * 1000,47lastRequestStarted: undefined,48lastRequestEnded: undefined,49};50override isArchived(): boolean { return overrides.isArchived?.() ?? false; }51override setArchived(): void { }52override isPinned(): boolean { return overrides.isPinned?.() ?? false; }53override setPinned(): void { }54override isRead(): boolean { return overrides.isRead?.() ?? true; }55override isMarkedUnread(): boolean { return false; }56override setRead(): void { }57}();58}5960function wrapAsTreeNode<T>(element: T): ITreeNode<T, FuzzyScore> {61return {62element,63children: [],64depth: 0,65visibleChildrenCount: 0,66visibleChildIndex: 0,67collapsible: false,68collapsed: false,69visible: true,70filterData: undefined,71};72}7374const rendererOptions: IAgentSessionRendererOptions = {75disableHover: true,76getHoverPosition: () => HoverPosition.BELOW,77};7879// ============================================================================80// Render helpers81// ============================================================================8283function createMockApprovalModel(sessionResource: URI, info: IAgentSessionApprovalInfo): AgentSessionApprovalModel {84const obs = observableValue<IAgentSessionApprovalInfo | undefined>('mockApproval', info);85return new class extends mock<AgentSessionApprovalModel>() {86override getApproval(resource: URI) {87if (resource.toString() === sessionResource.toString()) {88return obs;89}90return observableValue<IAgentSessionApprovalInfo | undefined>('mockApproval.empty', undefined);91}92}();93}9495function renderSessionItem(ctx: ComponentFixtureContext, session: IAgentSession, approvalModel?: AgentSessionApprovalModel): void {96const { container, disposableStore } = ctx;9798const instantiationService = createEditorServices(disposableStore, {99colorTheme: ctx.theme,100additionalServices: (reg) => {101registerWorkbenchServices(reg);102reg.define(IMarkdownRendererService, MarkdownRendererService);103reg.defineInstance(IProductService, new class extends mock<IProductService>() {104override readonly urlProtocol = 'vscode';105}());106reg.defineInstance(IChatSessionsService, new class extends mock<IChatSessionsService>() {107override readonly onDidChangeItemsProviders = Event.None;108override readonly onDidChangeSessionItems = Event.None;109override readonly onDidChangeAvailability = Event.None;110override readonly onDidChangeInProgress = Event.None;111override async resolveChatSessionItem() { return undefined; }112}());113},114});115116const configService = instantiationService.get(IConfigurationService) as TestConfigurationService;117configService.setUserConfiguration('editor', { fontFamily: 'monospace' });118const markdownRendererService = instantiationService.get(IMarkdownRendererService);119markdownRendererService.setDefaultCodeBlockRenderer(instantiationService.createInstance(EditorMarkdownCodeBlockRenderer));120121const renderer = disposableStore.add(122instantiationService.createInstance(AgentSessionRenderer, rendererOptions, approvalModel ?? undefined, observableValue<URI | undefined>('activeSessionResource', undefined))123);124125container.style.width = '350px';126container.style.height = 'auto';127container.style.backgroundColor = 'var(--vscode-sideBar-background)';128container.classList.add('agent-sessions-viewer');129130const listRow = document.createElement('div');131listRow.classList.add('monaco-list-row');132listRow.style.position = 'relative';133container.appendChild(listRow);134135const template = renderer.renderTemplate(listRow);136renderer.renderElement(wrapAsTreeNode(session), 0, template);137}138139function renderSectionItem(ctx: ComponentFixtureContext, section: IAgentSessionSection): void {140const { container, disposableStore } = ctx;141142const instantiationService = createEditorServices(disposableStore, {143colorTheme: ctx.theme,144additionalServices: (reg) => {145registerWorkbenchServices(reg);146},147});148149const renderer = instantiationService.createInstance(AgentSessionSectionRenderer, {});150151container.style.width = '350px';152container.style.height = 'auto';153container.style.backgroundColor = 'var(--vscode-sideBar-background)';154container.classList.add('agent-sessions-viewer');155156const listRow = document.createElement('div');157listRow.classList.add('monaco-list-row');158listRow.style.position = 'relative';159container.appendChild(listRow);160161const template = renderer.renderTemplate(listRow);162renderer.renderElement(wrapAsTreeNode(section), 0, template);163}164165// ============================================================================166// Fixtures167// ============================================================================168169const now = Date.now();170171export default defineThemedFixtureGroup({172173// --- Status variants ---174175CompletedRead: defineComponentFixture({176render: (ctx) => renderSessionItem(ctx, createMockSession({177label: 'Refactor auth middleware',178status: AgentSessionStatus.Completed,179providerType: AgentSessionProviders.Local,180timing: {181created: now - 2 * 60 * 60 * 1000,182lastRequestStarted: now - 2 * 60 * 60 * 1000,183lastRequestEnded: now - 2 * 60 * 60 * 1000 + 45 * 1000,184},185})),186}),187188CompletedUnread: defineComponentFixture({189render: (ctx) => renderSessionItem(ctx, createMockSession({190label: 'Add unit tests for parser',191status: AgentSessionStatus.Completed,192providerType: AgentSessionProviders.Local,193isRead: () => false,194timing: {195created: now - 30 * 60 * 1000,196lastRequestStarted: now - 30 * 60 * 1000,197lastRequestEnded: now - 25 * 60 * 1000,198},199})),200}),201202InProgress: defineComponentFixture({203render: (ctx) => renderSessionItem(ctx, createMockSession({204label: 'Implement dark mode toggle',205status: AgentSessionStatus.InProgress,206providerType: AgentSessionProviders.Local,207timing: {208created: now - 5 * 60 * 1000,209lastRequestStarted: now - 2 * 60 * 1000,210lastRequestEnded: undefined,211},212})),213}),214215NeedsInput: defineComponentFixture({216render: (ctx) => renderSessionItem(ctx, createMockSession({217label: 'Fix CI pipeline configuration',218status: AgentSessionStatus.NeedsInput,219providerType: AgentSessionProviders.Local,220isRead: () => false,221timing: {222created: now - 10 * 60 * 1000,223lastRequestStarted: now - 8 * 60 * 1000,224lastRequestEnded: undefined,225},226})),227}),228229FailedWithDuration: defineComponentFixture({230render: (ctx) => renderSessionItem(ctx, createMockSession({231label: 'Deploy staging environment',232status: AgentSessionStatus.Failed,233providerType: AgentSessionProviders.Local,234timing: {235created: now - 60 * 60 * 1000,236lastRequestStarted: now - 60 * 60 * 1000,237lastRequestEnded: now - 60 * 60 * 1000 + 3 * 60 * 1000,238},239})),240}),241242FailedWithoutDuration: defineComponentFixture({243render: (ctx) => renderSessionItem(ctx, createMockSession({244label: 'Migrate database schema',245status: AgentSessionStatus.Failed,246providerType: AgentSessionProviders.Local,247timing: {248created: now - 3 * 60 * 60 * 1000,249lastRequestStarted: undefined,250lastRequestEnded: undefined,251},252})),253}),254255// --- Content variants ---256257WithDiffChanges: defineComponentFixture({258render: (ctx) => renderSessionItem(ctx, createMockSession({259label: 'Refactor settings page',260status: AgentSessionStatus.Completed,261providerType: AgentSessionProviders.Local,262changes: { files: 5, insertions: 142, deletions: 87 },263timing: {264created: now - 45 * 60 * 1000,265lastRequestStarted: now - 45 * 60 * 1000,266lastRequestEnded: now - 40 * 60 * 1000,267},268})),269}),270271WithFileChangesList: defineComponentFixture({272render: (ctx) => renderSessionItem(ctx, createMockSession({273label: 'Update API endpoints',274status: AgentSessionStatus.Completed,275providerType: AgentSessionProviders.Background,276icon: Codicon.worktree,277changes: [278{ modifiedUri: URI.file('/src/api/routes.ts'), insertions: 25, deletions: 10 },279{ modifiedUri: URI.file('/src/api/handlers.ts'), insertions: 50, deletions: 30 },280{ modifiedUri: URI.file('/tests/api.test.ts'), insertions: 40, deletions: 5 },281],282timing: {283created: now - 2 * 60 * 60 * 1000,284lastRequestStarted: now - 2 * 60 * 60 * 1000,285lastRequestEnded: now - 90 * 60 * 1000,286},287})),288}),289290WithBadge: defineComponentFixture({291render: (ctx) => renderSessionItem(ctx, createMockSession({292label: 'Optimize build pipeline',293status: AgentSessionStatus.Completed,294providerType: AgentSessionProviders.Local,295badge: 'PR #1234',296timing: {297created: now - 4 * 60 * 60 * 1000,298lastRequestStarted: now - 4 * 60 * 60 * 1000,299lastRequestEnded: now - 3.5 * 60 * 60 * 1000,300},301})),302}),303304WithMarkdownBadge: defineComponentFixture({305render: (ctx) => renderSessionItem(ctx, createMockSession({306label: 'Review security patches',307status: AgentSessionStatus.Completed,308providerType: AgentSessionProviders.Cloud,309icon: Codicon.cloud,310badge: new MarkdownString('$(shield) Secure'),311timing: {312created: now - 6 * 60 * 60 * 1000,313lastRequestStarted: now - 6 * 60 * 60 * 1000,314lastRequestEnded: now - 5.5 * 60 * 60 * 1000,315},316})),317}),318319WithDescription: defineComponentFixture({320render: (ctx) => renderSessionItem(ctx, createMockSession({321label: 'Upgrade dependencies',322status: AgentSessionStatus.Completed,323providerType: AgentSessionProviders.Local,324description: 'Updated 12 packages to latest versions',325timing: {326created: now - 24 * 60 * 60 * 1000,327lastRequestStarted: now - 24 * 60 * 60 * 1000,328lastRequestEnded: now - 23.5 * 60 * 60 * 1000,329},330})),331}),332333WithMarkdownDescription: defineComponentFixture({334render: (ctx) => renderSessionItem(ctx, createMockSession({335label: 'Fix accessibility issues',336status: AgentSessionStatus.Completed,337providerType: AgentSessionProviders.Local,338description: new MarkdownString('$(check) All WCAG checks passed'),339timing: {340created: now - 48 * 60 * 60 * 1000,341lastRequestStarted: now - 48 * 60 * 60 * 1000,342lastRequestEnded: now - 47 * 60 * 60 * 1000,343},344})),345}),346347WithBadgeAndDiff: defineComponentFixture({348render: (ctx) => renderSessionItem(ctx, createMockSession({349label: 'Implement search feature',350status: AgentSessionStatus.Completed,351providerType: AgentSessionProviders.Local,352badge: 'draft',353changes: { files: 8, insertions: 320, deletions: 45 },354timing: {355created: now - 3 * 60 * 60 * 1000,356lastRequestStarted: now - 3 * 60 * 60 * 1000,357lastRequestEnded: now - 2.5 * 60 * 60 * 1000,358},359})),360}),361362// --- State variants ---363364Archived: defineComponentFixture({365render: (ctx) => renderSessionItem(ctx, createMockSession({366label: 'Old migration script',367status: AgentSessionStatus.Completed,368providerType: AgentSessionProviders.Local,369isArchived: () => true,370timing: {371created: now - 7 * 24 * 60 * 60 * 1000,372lastRequestStarted: now - 7 * 24 * 60 * 60 * 1000,373lastRequestEnded: now - 7 * 24 * 60 * 60 * 1000 + 10 * 60 * 1000,374},375})),376}),377378ArchivedUnread: defineComponentFixture({379render: (ctx) => renderSessionItem(ctx, createMockSession({380label: 'Archived unread task',381status: AgentSessionStatus.Completed,382providerType: AgentSessionProviders.Local,383isArchived: () => true,384isRead: () => false,385timing: {386created: now - 5 * 24 * 60 * 60 * 1000,387lastRequestStarted: now - 5 * 24 * 60 * 60 * 1000,388lastRequestEnded: now - 5 * 24 * 60 * 60 * 1000 + 5 * 60 * 1000,389},390})),391}),392393// --- Provider-type variants ---394395CloudProvider: defineComponentFixture({396render: (ctx) => renderSessionItem(ctx, createMockSession({397label: 'Generate API documentation',398status: AgentSessionStatus.Completed,399providerType: AgentSessionProviders.Cloud,400icon: Codicon.cloud,401timing: {402created: now - 90 * 60 * 1000,403lastRequestStarted: now - 90 * 60 * 1000,404lastRequestEnded: now - 80 * 60 * 1000,405},406})),407}),408409BackgroundProvider: defineComponentFixture({410render: (ctx) => renderSessionItem(ctx, createMockSession({411label: 'Run linter across codebase',412status: AgentSessionStatus.Completed,413providerType: AgentSessionProviders.Background,414icon: Codicon.worktree,415timing: {416created: now - 120 * 60 * 1000,417lastRequestStarted: now - 120 * 60 * 1000,418lastRequestEnded: now - 110 * 60 * 1000,419},420})),421}),422423ClaudeProvider: defineComponentFixture({424render: (ctx) => renderSessionItem(ctx, createMockSession({425label: 'Analyze code complexity',426status: AgentSessionStatus.Completed,427providerType: AgentSessionProviders.Claude,428icon: Codicon.claude,429timing: {430created: now - 150 * 60 * 1000,431lastRequestStarted: now - 150 * 60 * 1000,432lastRequestEnded: now - 140 * 60 * 1000,433},434})),435}),436437CloudProviderInProgress: defineComponentFixture({438render: (ctx) => renderSessionItem(ctx, createMockSession({439label: 'Build integration tests',440status: AgentSessionStatus.InProgress,441providerType: AgentSessionProviders.Cloud,442icon: Codicon.cloud,443isRead: () => false,444timing: {445created: now - 10 * 60 * 1000,446lastRequestStarted: now - 3 * 60 * 1000,447lastRequestEnded: undefined,448},449})),450}),451452// --- In-progress with description override ---453454InProgressWithDescription: defineComponentFixture({455render: (ctx) => renderSessionItem(ctx, createMockSession({456label: 'Scaffold new microservice',457status: AgentSessionStatus.InProgress,458providerType: AgentSessionProviders.Background,459icon: Codicon.worktree,460description: 'Installing dependencies...',461timing: {462created: now - 5 * 60 * 1000,463lastRequestStarted: now - 60 * 1000,464lastRequestEnded: undefined,465},466})),467}),468469// --- Section headers ---470471SectionToday: defineComponentFixture({472render: (ctx) => renderSectionItem(ctx, {473section: AgentSessionSection.Today,474label: 'Today',475sessions: [],476}),477}),478479SectionYesterday: defineComponentFixture({480render: (ctx) => renderSectionItem(ctx, {481section: AgentSessionSection.Yesterday,482label: 'Yesterday',483sessions: [],484}),485}),486487SectionLastWeek: defineComponentFixture({488render: (ctx) => renderSectionItem(ctx, {489section: AgentSessionSection.Week,490label: 'Last 7 days',491sessions: [],492}),493}),494495SectionOlder: defineComponentFixture({496render: (ctx) => renderSectionItem(ctx, {497section: AgentSessionSection.Older,498label: 'Older',499sessions: [],500}),501}),502503SectionArchived: defineComponentFixture({504render: (ctx) => renderSectionItem(ctx, {505section: AgentSessionSection.Archived,506label: 'Archived',507sessions: [],508}),509}),510511SectionMore: defineComponentFixture({512render: (ctx) => renderSectionItem(ctx, {513section: AgentSessionSection.More,514label: 'More',515sessions: [],516}),517}),518519// --- Approval row variants ---520521ApprovalRowJson: defineComponentFixture({522render: (ctx) => {523const resource = URI.parse('vscode-chat-session://local/approval-json');524const approvalModel = createMockApprovalModel(resource, {525label: '{ "action": "deleteFile", "path": "/src/old-module.ts" }',526languageId: 'json',527since: new Date(),528confirm: () => { },529});530renderSessionItem(ctx, createMockSession({531resource,532label: 'Clean up deprecated modules',533status: AgentSessionStatus.InProgress,534providerType: AgentSessionProviders.Local,535timing: {536created: now - 5 * 60 * 1000,537lastRequestStarted: now - 2 * 60 * 1000,538lastRequestEnded: undefined,539},540}), approvalModel);541},542}),543544ApprovalRowBash: defineComponentFixture({545render: (ctx) => {546const resource = URI.parse('vscode-chat-session://local/approval-bash');547const approvalModel = createMockApprovalModel(resource, {548label: 'npm install --save express@latest',549languageId: 'sh',550since: new Date(),551confirm: () => { },552});553renderSessionItem(ctx, createMockSession({554resource,555label: 'Update server dependencies',556status: AgentSessionStatus.InProgress,557providerType: AgentSessionProviders.Local,558timing: {559created: now - 3 * 60 * 1000,560lastRequestStarted: now - 60 * 1000,561lastRequestEnded: undefined,562},563}), approvalModel);564},565}),566567ApprovalRowPowerShell: defineComponentFixture({568render: (ctx) => {569const resource = URI.parse('vscode-chat-session://local/approval-powershell');570const approvalModel = createMockApprovalModel(resource, {571label: 'Start-Job -ScriptBlock { Set-Location \'c:\\some\\path\'; npm install } | Out-Null',572languageId: 'pwsh',573since: new Date(),574confirm: () => { },575});576renderSessionItem(ctx, createMockSession({577resource,578label: 'Clean up old log files',579status: AgentSessionStatus.InProgress,580providerType: AgentSessionProviders.Local,581timing: {582created: now - 4 * 60 * 1000,583lastRequestStarted: now - 2 * 60 * 1000,584lastRequestEnded: undefined,585},586}), approvalModel);587},588}),589590ApprovalRowLongLabel: defineComponentFixture({591render: (ctx) => {592const resource = URI.parse('vscode-chat-session://local/approval-long');593const approvalModel = createMockApprovalModel(resource, {594label: 'rm -rf node_modules && npm cache clean --force && npm install --legacy-peer-deps --ignore-scripts',595languageId: 'sh',596since: new Date(),597confirm: () => { },598});599renderSessionItem(ctx, createMockSession({600resource,601label: 'Reset and reinstall all dependencies',602status: AgentSessionStatus.NeedsInput,603providerType: AgentSessionProviders.Cloud,604icon: Codicon.cloud,605isRead: () => false,606timing: {607created: now - 10 * 60 * 1000,608lastRequestStarted: now - 5 * 60 * 1000,609lastRequestEnded: undefined,610},611}), approvalModel);612},613}),614615ApprovalRow1Line: defineComponentFixture({616render: (ctx) => {617const resource = URI.parse('vscode-chat-session://local/approval-1line');618const approvalModel = createMockApprovalModel(resource, {619label: 'npm install --save express@latest',620languageId: 'sh',621since: new Date(),622confirm: () => { },623});624renderSessionItem(ctx, createMockSession({625resource,626label: 'Install express',627status: AgentSessionStatus.InProgress,628providerType: AgentSessionProviders.Local,629timing: {630created: now - 3 * 60 * 1000,631lastRequestStarted: now - 60 * 1000,632lastRequestEnded: undefined,633},634}), approvalModel);635},636}),637638ApprovalRow2Lines: defineComponentFixture({639render: (ctx) => {640const resource = URI.parse('vscode-chat-session://local/approval-2lines');641const approvalModel = createMockApprovalModel(resource, {642label: 'cd /workspace/project\nnpm install',643languageId: 'sh',644since: new Date(),645confirm: () => { },646});647renderSessionItem(ctx, createMockSession({648resource,649label: 'Setup project dependencies',650status: AgentSessionStatus.InProgress,651providerType: AgentSessionProviders.Local,652timing: {653created: now - 3 * 60 * 1000,654lastRequestStarted: now - 60 * 1000,655lastRequestEnded: undefined,656},657}), approvalModel);658},659}),660661ApprovalRow3Lines: defineComponentFixture({662render: (ctx) => {663const resource = URI.parse('vscode-chat-session://local/approval-3lines');664const approvalModel = createMockApprovalModel(resource, {665label: 'cd /workspace/project\nnpm install\nnpm run build',666languageId: 'sh',667since: new Date(),668confirm: () => { },669});670renderSessionItem(ctx, createMockSession({671resource,672label: 'Build the project',673status: AgentSessionStatus.InProgress,674providerType: AgentSessionProviders.Local,675timing: {676created: now - 2 * 60 * 1000,677lastRequestStarted: now - 60 * 1000,678lastRequestEnded: undefined,679},680}), approvalModel);681},682}),683684ApprovalRow4Lines: defineComponentFixture({685render: (ctx) => {686const resource = URI.parse('vscode-chat-session://local/approval-4lines');687const approvalModel = createMockApprovalModel(resource, {688label: 'cd /workspace/project\nnpm install\nnpm run build\nnpm run test -- --coverage',689languageId: 'sh',690since: new Date(),691confirm: () => { },692});693renderSessionItem(ctx, createMockSession({694resource,695label: 'Build and test project',696status: AgentSessionStatus.InProgress,697providerType: AgentSessionProviders.Local,698timing: {699created: now - 2 * 60 * 1000,700lastRequestStarted: now - 60 * 1000,701lastRequestEnded: undefined,702},703}), approvalModel);704},705}),706707ApprovalRow3LongLines: defineComponentFixture({708render: (ctx) => {709const resource = URI.parse('vscode-chat-session://local/approval-3longlines');710const approvalModel = createMockApprovalModel(resource, {711label: 'RUSTFLAGS="-C target-cpu=native -C opt-level=3" cargo build --release --target x86_64-unknown-linux-gnu\nfind ./target/release -name "*.so" -exec strip --strip-unneeded {} \\; && tar czf release-bundle.tar.gz -C target/release .\ncurl -X POST https://deploy.internal.example.com/api/v2/artifacts/upload --header "Authorization: Bearer $DEPLOY_TOKEN" --form "[email protected]"',712languageId: 'sh',713since: new Date(),714confirm: () => { },715});716renderSessionItem(ctx, createMockSession({717resource,718label: 'Build and deploy native release',719status: AgentSessionStatus.InProgress,720providerType: AgentSessionProviders.Local,721timing: {722created: now - 2 * 60 * 1000,723lastRequestStarted: now - 60 * 1000,724lastRequestEnded: undefined,725},726}), approvalModel);727},728}),729});730731732