feat: add project key support for Jira analytics
- Introduced `projectKey` and `ignoredProjects` fields in Jira configuration to enhance analytics capabilities. - Implemented project validation logic in `JiraConfigClient` and integrated it into the `JiraConfigForm` for user input. - Updated `IntegrationsSettingsPageClient` to display analytics dashboard link based on the configured project key. - Enhanced API routes to handle project key in Jira sync and user preferences. - Marked related tasks as complete in `TODO.md`.
This commit is contained in:
@@ -10,6 +10,7 @@ export interface JiraConfig {
|
||||
baseUrl: string;
|
||||
email: string;
|
||||
apiToken: string;
|
||||
projectKey?: string; // Clé du projet à surveiller pour les analytics d'équipe (ex: "MYTEAM")
|
||||
ignoredProjects?: string[]; // Liste des clés de projets à ignorer (ex: ["DEMO", "TEST"])
|
||||
}
|
||||
|
||||
@@ -39,12 +40,42 @@ export class JiraService {
|
||||
this.config = config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide l'existence d'un projet Jira
|
||||
*/
|
||||
async validateProject(projectKey: string): Promise<{ exists: boolean; name?: string; error?: string }> {
|
||||
try {
|
||||
const response = await this.makeJiraRequestPrivate(`/rest/api/3/project/${projectKey}`);
|
||||
|
||||
if (response.status === 404) {
|
||||
return { exists: false, error: `Projet "${projectKey}" introuvable` };
|
||||
}
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
return { exists: false, error: `Erreur API: ${response.status} - ${errorText}` };
|
||||
}
|
||||
|
||||
const project = await response.json();
|
||||
return {
|
||||
exists: true,
|
||||
name: project.name
|
||||
};
|
||||
} catch (error) {
|
||||
console.error('Erreur lors de la validation du projet:', error);
|
||||
return {
|
||||
exists: false,
|
||||
error: error instanceof Error ? error.message : 'Erreur de connexion'
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Teste la connexion à Jira
|
||||
*/
|
||||
async testConnection(): Promise<boolean> {
|
||||
try {
|
||||
const response = await this.makeJiraRequest('/rest/api/3/myself');
|
||||
const response = await this.makeJiraRequestPrivate('/rest/api/3/myself');
|
||||
if (!response.ok) {
|
||||
console.error(`Test connexion Jira échoué: ${response.status} ${response.statusText}`);
|
||||
const errorText = await response.text();
|
||||
@@ -80,11 +111,10 @@ export class JiraService {
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les tickets assignés à l'utilisateur connecté avec pagination
|
||||
* Récupère les tickets avec une requête JQL personnalisée avec pagination
|
||||
*/
|
||||
async getAssignedIssues(): Promise<JiraTask[]> {
|
||||
async searchIssues(jql: string): Promise<JiraTask[]> {
|
||||
try {
|
||||
const jql = 'assignee = currentUser() AND resolution = Unresolved AND issuetype != Epic ORDER BY updated DESC';
|
||||
const fields = ['id', 'key', 'summary', 'description', 'status', 'priority', 'assignee', 'project', 'issuetype', 'duedate', 'created', 'updated', 'labels'];
|
||||
|
||||
const allIssues: unknown[] = [];
|
||||
@@ -114,7 +144,7 @@ export class JiraService {
|
||||
|
||||
console.log(`🌐 POST /rest/api/3/search/jql avec ${nextPageToken ? 'nextPageToken' : 'première page'}`);
|
||||
|
||||
const response = await this.makeJiraRequest('/rest/api/3/search/jql', 'POST', requestBody);
|
||||
const response = await this.makeJiraRequestPrivate('/rest/api/3/search/jql', 'POST', requestBody);
|
||||
|
||||
console.log(`📡 Status réponse: ${response.status}`);
|
||||
|
||||
@@ -174,6 +204,14 @@ export class JiraService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les tickets assignés à l'utilisateur connecté
|
||||
*/
|
||||
async getAssignedIssues(): Promise<JiraTask[]> {
|
||||
const jql = 'assignee = currentUser() AND resolution = Unresolved AND issuetype != Epic ORDER BY updated DESC';
|
||||
return this.searchIssues(jql);
|
||||
}
|
||||
|
||||
/**
|
||||
* S'assure que le tag "🔗 From Jira" existe dans la base
|
||||
*/
|
||||
@@ -649,10 +687,17 @@ export class JiraService {
|
||||
return priorityMapping[jiraPriority] || 'medium';
|
||||
}
|
||||
|
||||
/**
|
||||
* Effectue une requête à l'API Jira avec authentification (méthode publique pour analytics)
|
||||
*/
|
||||
async makeJiraRequest(endpoint: string, method: string = 'GET', body?: unknown): Promise<Response> {
|
||||
return this.makeJiraRequestPrivate(endpoint, method, body);
|
||||
}
|
||||
|
||||
/**
|
||||
* Effectue une requête à l'API Jira avec authentification
|
||||
*/
|
||||
private async makeJiraRequest(endpoint: string, method: string = 'GET', body?: unknown): Promise<Response> {
|
||||
private async makeJiraRequestPrivate(endpoint: string, method: string = 'GET', body?: unknown): Promise<Response> {
|
||||
const url = `${this.config.baseUrl}${endpoint}`;
|
||||
const auth = Buffer.from(`${this.config.email}:${this.config.apiToken}`).toString('base64');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user