You've already forked wizgit-vscode-extension
- Implemented exportIssues and exportPullRequests functions to export data in markdown, CSV, and JSON formats. - Created helper functions for generating markdown and CSV formats for issues and pull requests. - Added showExportDialog for user interaction to select export options. - Implemented saveToFile function to handle file saving. feat: Implement favorites and recent repositories management - Added functionality to add, remove, and check favorites for repositories. - Implemented recent repositories tracking with a limit on the number of recent entries. - Created a quick pick interface to show favorites and recent repositories. feat: Introduce notifications management - Implemented functions to fetch, mark as read, and manage notifications. - Created a NotificationProvider class to display notifications in a tree view. - Added functionality to show notifications in a modal with quick actions. feat: Implement search functionality for repositories, issues, and pull requests - Added searchRepositories, searchIssues, and searchPullRequests functions with filtering options. - Implemented getLabels and getCollaborators functions for additional filtering capabilities. - Created a showFilterQuickPick function for user interaction to select filters. feat: Enhance status bar with shortcuts and dynamic updates - Added default keyboard shortcuts for various commands. - Implemented createStatusBarItem and updateStatusBar functions to manage status bar display. - Created a showStatusMenu function for quick actions related to the extension.
266 lines
7.3 KiB
TypeScript
266 lines
7.3 KiB
TypeScript
import * as vscode from 'vscode';
|
|
import fetch from 'node-fetch';
|
|
|
|
export interface SearchOptions {
|
|
query: string;
|
|
state?: 'open' | 'closed';
|
|
labels?: string[];
|
|
assignee?: string;
|
|
sort?: 'created' | 'updated' | 'popularity';
|
|
order?: 'asc' | 'desc';
|
|
}
|
|
|
|
export interface FilterOptions {
|
|
state?: 'open' | 'closed';
|
|
labels?: string[];
|
|
assignee?: string;
|
|
}
|
|
|
|
/**
|
|
* Search repositories across WizGIT
|
|
*/
|
|
export async function searchRepositories(
|
|
apiEndpoint: string,
|
|
token: string,
|
|
query: string,
|
|
page: number = 1,
|
|
limit: number = 30
|
|
): Promise<any> {
|
|
try {
|
|
const url = new URL(`${apiEndpoint}/repos/search`);
|
|
url.searchParams.append('q', query);
|
|
url.searchParams.append('page', page.toString());
|
|
url.searchParams.append('limit', limit.toString());
|
|
|
|
const response = await fetch(url.toString(), {
|
|
headers: {
|
|
'Authorization': `token ${token}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Search failed: ${response.statusText}`);
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error('Repository search error:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Search issues in a repository with filters
|
|
*/
|
|
export async function searchIssues(
|
|
apiEndpoint: string,
|
|
token: string,
|
|
owner: string,
|
|
repo: string,
|
|
options: SearchOptions & { page?: number; limit?: number }
|
|
): Promise<any> {
|
|
try {
|
|
const url = new URL(`${apiEndpoint}/repos/${owner}/${repo}/issues`);
|
|
|
|
url.searchParams.append('page', (options.page || 1).toString());
|
|
url.searchParams.append('limit', (options.limit || 30).toString());
|
|
|
|
if (options.query) {
|
|
url.searchParams.append('q', options.query);
|
|
}
|
|
if (options.state) {
|
|
url.searchParams.append('state', options.state);
|
|
}
|
|
if (options.sort) {
|
|
url.searchParams.append('sort', options.sort);
|
|
}
|
|
if (options.order) {
|
|
url.searchParams.append('order', options.order);
|
|
}
|
|
if (options.labels && options.labels.length > 0) {
|
|
url.searchParams.append('labels', options.labels.join(','));
|
|
}
|
|
if (options.assignee) {
|
|
url.searchParams.append('assignee', options.assignee);
|
|
}
|
|
|
|
const response = await fetch(url.toString(), {
|
|
headers: {
|
|
'Authorization': `token ${token}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Search failed: ${response.statusText}`);
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error('Issue search error:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Search pull requests with filters
|
|
*/
|
|
export async function searchPullRequests(
|
|
apiEndpoint: string,
|
|
token: string,
|
|
owner: string,
|
|
repo: string,
|
|
options: SearchOptions & { page?: number; limit?: number }
|
|
): Promise<any> {
|
|
try {
|
|
const url = new URL(`${apiEndpoint}/repos/${owner}/${repo}/pulls`);
|
|
|
|
url.searchParams.append('page', (options.page || 1).toString());
|
|
url.searchParams.append('limit', (options.limit || 30).toString());
|
|
|
|
if (options.query) {
|
|
url.searchParams.append('q', options.query);
|
|
}
|
|
if (options.state) {
|
|
url.searchParams.append('state', options.state);
|
|
}
|
|
if (options.sort) {
|
|
url.searchParams.append('sort', options.sort);
|
|
}
|
|
if (options.order) {
|
|
url.searchParams.append('order', options.order);
|
|
}
|
|
if (options.assignee) {
|
|
url.searchParams.append('assignee', options.assignee);
|
|
}
|
|
|
|
const response = await fetch(url.toString(), {
|
|
headers: {
|
|
'Authorization': `token ${token}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Search failed: ${response.statusText}`);
|
|
}
|
|
|
|
return await response.json();
|
|
} catch (error) {
|
|
console.error('PR search error:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get available labels for filtering
|
|
*/
|
|
export async function getLabels(
|
|
apiEndpoint: string,
|
|
token: string,
|
|
owner: string,
|
|
repo: string
|
|
): Promise<any[]> {
|
|
try {
|
|
const response = await fetch(`${apiEndpoint}/repos/${owner}/${repo}/labels`, {
|
|
headers: {
|
|
'Authorization': `token ${token}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch labels: ${response.statusText}`);
|
|
}
|
|
|
|
return (await response.json()) as any[];
|
|
} catch (error) {
|
|
console.error('Get labels error:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get collaborators for assignee filtering
|
|
*/
|
|
export async function getCollaborators(
|
|
apiEndpoint: string,
|
|
token: string,
|
|
owner: string,
|
|
repo: string
|
|
): Promise<any[]> {
|
|
try {
|
|
const response = await fetch(`${apiEndpoint}/repos/${owner}/${repo}/collaborators`, {
|
|
headers: {
|
|
'Authorization': `token ${token}`,
|
|
'Accept': 'application/json'
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error(`Failed to fetch collaborators: ${response.statusText}`);
|
|
}
|
|
|
|
return (await response.json()) as any[];
|
|
} catch (error) {
|
|
console.error('Get collaborators error:', error);
|
|
return [];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Show a quick filter picker for issues/PRs
|
|
*/
|
|
export async function showFilterQuickPick(
|
|
apiEndpoint: string,
|
|
token: string,
|
|
owner: string,
|
|
repo: string,
|
|
type: 'issues' | 'pulls'
|
|
): Promise<FilterOptions | null> {
|
|
const filterOptions: FilterOptions = {};
|
|
|
|
// State filter
|
|
const stateSelection = await vscode.window.showQuickPick(
|
|
['All', 'Open', 'Closed'],
|
|
{ placeHolder: 'Filter by state (optional)' }
|
|
);
|
|
|
|
if (stateSelection && stateSelection !== 'All') {
|
|
filterOptions.state = stateSelection === 'Open' ? 'open' : 'closed';
|
|
}
|
|
|
|
// Assignee filter
|
|
const collaborators = await getCollaborators(apiEndpoint, token, owner, repo);
|
|
if (collaborators.length > 0) {
|
|
const assigneeItems = ['No filter', ...collaborators.map(c => c.login)];
|
|
const assigneeSelection = await vscode.window.showQuickPick(
|
|
assigneeItems,
|
|
{ placeHolder: 'Filter by assignee (optional)' }
|
|
);
|
|
|
|
if (assigneeSelection && assigneeSelection !== 'No filter') {
|
|
filterOptions.assignee = assigneeSelection;
|
|
}
|
|
}
|
|
|
|
// Labels filter (only for issues)
|
|
if (type === 'issues') {
|
|
const labels = await getLabels(apiEndpoint, token, owner, repo);
|
|
if (labels.length > 0) {
|
|
const labelItems = labels.map(l => l.name);
|
|
const labelSelection = await vscode.window.showQuickPick(
|
|
labelItems,
|
|
{ placeHolder: 'Filter by label (optional)', canPickMany: true }
|
|
);
|
|
|
|
if (labelSelection && labelSelection.length > 0) {
|
|
filterOptions.labels = labelSelection;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Object.keys(filterOptions).length > 0 ? filterOptions : null;
|
|
}
|