Commit c081b0c8 authored by Lennard Sprong's avatar Lennard Sprong
Browse files

feat: Display busy indicator on item in Pipeline tree

parent e37dd3a7
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
import vscode from 'vscode';
import { getGitLabService } from '../gitlab/get_gitlab_service';
import { job, projectInRepository } from '../test_utils/entities';
import { GitLabService } from '../gitlab/gitlab_service';
import { JobItemModel } from '../tree_view/items/job_item_model';
import { createFakePartial } from '../../common/test_utils/create_fake_partial';
import { currentBranchRefresher } from '../current_branch_refresher';
import { cancelJob, executeJob, retryJob } from './job_actions';

jest.mock('../gitlab/get_gitlab_service');
jest.mock('../current_branch_refresher');

describe('retryOrCancelJobItemModel', () => {
  const mockActions: Record<string, 'canceled' | 'pending'> = {
@@ -23,7 +24,7 @@ describe('retryOrCancelJobItemModel', () => {
  const model = new JobItemModel(projectInRepository, job);

  beforeEach(() => {
    (vscode.window.withProgress as jest.Mock).mockImplementation((_, task) => task());
    jest.mocked(currentBranchRefresher.refresh).mockResolvedValue(undefined);
    jest.mocked(getGitLabService).mockReturnValue(gitlabService);
  });

+4 −4
Original line number Diff line number Diff line
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../command_names';
import { getGitLabService } from '../gitlab/get_gitlab_service';
import { JobItemModel } from '../tree_view/items/job_item_model';
import { currentBranchDataProvider } from '../tree_view/current_branch_data_provider';
import { currentBranchRefresher } from '../current_branch_refresher';

async function retryOrCancelJobItemModel(
  action: 'retry' | 'cancel' | 'play',
@@ -9,9 +9,9 @@ async function retryOrCancelJobItemModel(
): Promise<RestJob | undefined> {
  const { job, projectInRepository } = item;
  const gitlabService = getGitLabService(projectInRepository);
  return vscode.window.withProgress({ location: { viewId: 'currentBranchInfo' } }, async () => {
  return currentBranchDataProvider.withMarkedAsBusy('job', job.id, async () => {
    const result = await gitlabService.cancelOrRetryJob(action, projectInRepository.project, job);
    if (result) await vscode.commands.executeCommand(USER_COMMANDS.REFRESH_SIDEBAR);
    if (result) await currentBranchRefresher.refresh();
    return result;
  });
}
+3 −2
Original line number Diff line number Diff line
import vscode from 'vscode';
import { createFakePartial } from '../../common/test_utils/create_fake_partial';
import { getGitLabService } from '../gitlab/get_gitlab_service';
import { GitLabService } from '../gitlab/gitlab_service';
import { job, pipeline, projectInRepository } from '../test_utils/entities';
import { PipelineItemModel } from '../tree_view/items/pipeline_item_model';
import { currentBranchRefresher } from '../current_branch_refresher';
import { cancelPipeline, retryPipeline } from './pipeline_actions';

jest.mock('../gitlab/get_gitlab_service');
jest.mock('../current_branch_refresher');

describe('retryOrCancelPipeline', () => {
  const item = new PipelineItemModel(projectInRepository, pipeline, [job]);
@@ -15,7 +16,7 @@ describe('retryOrCancelPipeline', () => {
  });

  beforeEach(() => {
    (vscode.window.withProgress as jest.Mock).mockImplementation((_, task) => task());
    jest.mocked(currentBranchRefresher.refresh).mockResolvedValue(undefined);
    jest.mocked(getGitLabService).mockReturnValue(gitLabService);
  });

+4 −4
Original line number Diff line number Diff line
import * as vscode from 'vscode';
import { USER_COMMANDS } from '../command_names';
import { getGitLabService } from '../gitlab/get_gitlab_service';
import { ProjectInRepositoryProvider } from '../gitlab/new_project';
import { PipelineProvider } from '../tree_view/items/pipeline_provider';
import { PipelineItemModel } from '../tree_view/items/pipeline_item_model';
import { currentBranchDataProvider } from '../tree_view/current_branch_data_provider';
import { currentBranchRefresher } from '../current_branch_refresher';

async function retryOrCancelPipeline(
  action: 'retry' | 'cancel',
@@ -11,13 +11,13 @@ async function retryOrCancelPipeline(
): Promise<RestPipeline | undefined> {
  const { pipeline, projectInRepository } = provider;
  const gitlabService = getGitLabService(projectInRepository);
  return vscode.window.withProgress({ location: { viewId: 'currentBranchInfo' } }, async () => {
  return currentBranchDataProvider.withMarkedAsBusy('pipeline', pipeline.id, async () => {
    const result = await gitlabService.cancelOrRetryPipeline(
      action,
      projectInRepository.project,
      pipeline,
    );
    if (result) await vscode.commands.executeCommand(USER_COMMANDS.REFRESH_SIDEBAR);
    if (result) await currentBranchRefresher.refresh();
    return result;
  });
}
+25 −6
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ export interface CiStatusMetadata {
}

type IconName =
  | 'sync~spin'
  | 'pass'
  | 'play'
  | 'debug-pause'
@@ -31,8 +32,10 @@ const errorColor = 'testing.iconErrored';
const inProgressColor = 'debugIcon.pauseForeground';
const grayColor = 'testing.iconSkipped';

const icon = (name: IconName, color: string) =>
  new vscode.ThemeIcon(name, new vscode.ThemeColor(color));
const icon = (name: IconName, color?: string) =>
  new vscode.ThemeIcon(name, color ? new vscode.ThemeColor(color) : undefined);

const syncingIcon = icon('sync~spin');

const STATUS_METADATA: Record<string, CiStatusMetadata> = {
  manual: {
@@ -125,7 +128,7 @@ const STATUS_METADATA: Record<string, CiStatusMetadata> = {
  },
  canceling: {
    name: 'Cancelling',
    icon: icon('circle-slash', grayColor),
    icon: icon('circle-slash'),
    priority: 10,
    contextAction: 'retryable',
    illustration: {
@@ -170,7 +173,7 @@ const ERASED: Partial<CiStatusMetadata> = {
  },
};

export const getJobMetadata = (job: RestJob): CiStatusMetadata => {
export const getJobMetadata = (job: RestJob, isBusy: boolean = false): CiStatusMetadata => {
  let data: CiStatusMetadata;
  if (job.status === 'failed' && job.allow_failure) {
    data = FAILED_ALLOWED;
@@ -178,11 +181,27 @@ export const getJobMetadata = (job: RestJob): CiStatusMetadata => {
    data = STATUS_METADATA[job.status] || UNKNOWN_STATUS;
  }

  if (isBusy && data.contextAction === 'cancellable') {
    data = STATUS_METADATA.canceling;
  } else if (isBusy) {
    data = { ...data, icon: syncingIcon };
  }

  if (job.erased_at) {
    data = { ...data, ...ERASED };
  }
  return { ...COMMON, ...data };
};

export const getPipelineMetadata = (pipeline: RestPipeline): CiStatusMetadata =>
  STATUS_METADATA[pipeline.status] || UNKNOWN_STATUS;
export const getPipelineMetadata = (
  pipeline: RestPipeline,
  isBusy: boolean = false,
): CiStatusMetadata => {
  let data = STATUS_METADATA[pipeline.status] || UNKNOWN_STATUS;
  if (isBusy && data.contextAction === 'cancellable') {
    data = STATUS_METADATA.canceling;
  } else if (isBusy) {
    data = { ...data, icon: syncingIcon };
  }
  return data;
};
Loading