feat: TFS Sync
This commit is contained in:
@@ -17,6 +17,7 @@ import {
|
||||
} from '@/lib/types';
|
||||
|
||||
export interface JiraAnalyticsConfig {
|
||||
enabled: boolean;
|
||||
baseUrl: string;
|
||||
email: string;
|
||||
apiToken: string;
|
||||
|
||||
@@ -93,6 +93,7 @@ export class JiraScheduler {
|
||||
|
||||
// Créer le service Jira
|
||||
const jiraService = new JiraService({
|
||||
enabled: jiraConfig.enabled,
|
||||
baseUrl: jiraConfig.baseUrl,
|
||||
email: jiraConfig.email,
|
||||
apiToken: jiraConfig.apiToken,
|
||||
@@ -111,7 +112,7 @@ export class JiraScheduler {
|
||||
const result = await jiraService.syncTasks();
|
||||
|
||||
if (result.success) {
|
||||
console.log(`✅ Scheduled Jira sync completed: ${result.tasksCreated} created, ${result.tasksUpdated} updated, ${result.tasksSkipped} skipped`);
|
||||
console.log(`✅ Scheduled Jira sync completed: ${result.stats.created} created, ${result.stats.updated} updated, ${result.stats.skipped} skipped`);
|
||||
} else {
|
||||
console.error(`❌ Scheduled Jira sync failed: ${result.errors.join(', ')}`);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ export class JiraSummaryService {
|
||||
title: task.title,
|
||||
status: task.status,
|
||||
type: task.jiraType || 'Unknown',
|
||||
url: `${jiraConfig.baseUrl.replace('/rest/api/3', '')}/browse/${task.jiraKey}`,
|
||||
url: `${jiraConfig.baseUrl!.replace('/rest/api/3', '')}/browse/${task.jiraKey}`,
|
||||
estimatedPoints: estimateStoryPoints(task.jiraType || '')
|
||||
}));
|
||||
|
||||
@@ -114,6 +114,7 @@ export class JiraSummaryService {
|
||||
}
|
||||
|
||||
return {
|
||||
enabled: preferences.jiraConfig.enabled,
|
||||
baseUrl: preferences.jiraConfig.baseUrl,
|
||||
email: preferences.jiraConfig.email,
|
||||
apiToken: preferences.jiraConfig.apiToken,
|
||||
|
||||
@@ -8,9 +8,10 @@ import { prisma } from './database';
|
||||
import { parseDate, formatDateForDisplay } from '@/lib/date-utils';
|
||||
|
||||
export interface JiraConfig {
|
||||
baseUrl: string;
|
||||
email: string;
|
||||
apiToken: string;
|
||||
enabled: boolean;
|
||||
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"])
|
||||
}
|
||||
@@ -23,6 +24,27 @@ export interface JiraSyncAction {
|
||||
changes?: string[]; // Liste des champs modifiés pour les updates
|
||||
}
|
||||
|
||||
// Type générique pour compatibilité avec d'autres services
|
||||
export interface SyncAction {
|
||||
type: 'created' | 'updated' | 'skipped' | 'deleted';
|
||||
itemId: string | number;
|
||||
title: string;
|
||||
message?: string;
|
||||
}
|
||||
|
||||
export interface SyncResult {
|
||||
success: boolean;
|
||||
totalItems: number;
|
||||
actions: SyncAction[];
|
||||
errors: string[];
|
||||
stats: {
|
||||
created: number;
|
||||
updated: number;
|
||||
skipped: number;
|
||||
deleted: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface JiraSyncResult {
|
||||
success: boolean;
|
||||
tasksFound: number;
|
||||
@@ -35,7 +57,7 @@ export interface JiraSyncResult {
|
||||
}
|
||||
|
||||
export class JiraService {
|
||||
private config: JiraConfig;
|
||||
readonly config: JiraConfig;
|
||||
|
||||
constructor(config: JiraConfig) {
|
||||
this.config = config;
|
||||
@@ -89,6 +111,32 @@ export class JiraService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Valide la configuration Jira
|
||||
*/
|
||||
async validateConfig(): Promise<{ valid: boolean; error?: string }> {
|
||||
if (!this.config.enabled) {
|
||||
return { valid: false, error: 'Jira désactivé' };
|
||||
}
|
||||
if (!this.config.baseUrl) {
|
||||
return { valid: false, error: 'URL de base Jira manquante' };
|
||||
}
|
||||
if (!this.config.email) {
|
||||
return { valid: false, error: 'Email Jira manquant' };
|
||||
}
|
||||
if (!this.config.apiToken) {
|
||||
return { valid: false, error: 'Token API Jira manquant' };
|
||||
}
|
||||
|
||||
// Tester la connexion pour validation complète
|
||||
const connectionOk = await this.testConnection();
|
||||
if (!connectionOk) {
|
||||
return { valid: false, error: 'Impossible de se connecter avec ces paramètres' };
|
||||
}
|
||||
|
||||
return { valid: true };
|
||||
}
|
||||
|
||||
/**
|
||||
* Filtre les tâches Jira selon les projets ignorés
|
||||
*/
|
||||
@@ -245,17 +293,18 @@ export class JiraService {
|
||||
/**
|
||||
* Synchronise les tickets Jira avec la base locale
|
||||
*/
|
||||
async syncTasks(): Promise<JiraSyncResult> {
|
||||
const result: JiraSyncResult = {
|
||||
async syncTasks(): Promise<SyncResult> {
|
||||
const result: SyncResult = {
|
||||
success: false,
|
||||
tasksFound: 0,
|
||||
tasksCreated: 0,
|
||||
tasksUpdated: 0,
|
||||
tasksSkipped: 0,
|
||||
tasksDeleted: 0,
|
||||
totalItems: 0,
|
||||
actions: [],
|
||||
errors: [],
|
||||
actions: []
|
||||
stats: { created: 0, updated: 0, skipped: 0, deleted: 0 }
|
||||
};
|
||||
|
||||
// Variables locales pour compatibilité avec l'ancien code
|
||||
let tasksDeleted = 0;
|
||||
const jiraActions: JiraSyncAction[] = [];
|
||||
|
||||
try {
|
||||
console.log('🔄 Début de la synchronisation Jira...');
|
||||
@@ -265,7 +314,7 @@ export class JiraService {
|
||||
|
||||
// Récupérer les tickets Jira actuellement assignés
|
||||
const jiraTasks = await this.getAssignedIssues();
|
||||
result.tasksFound = jiraTasks.length;
|
||||
result.totalItems = jiraTasks.length;
|
||||
|
||||
console.log(`📋 ${jiraTasks.length} tickets trouvés dans Jira`);
|
||||
|
||||
@@ -281,16 +330,25 @@ export class JiraService {
|
||||
try {
|
||||
const syncAction = await this.syncSingleTask(jiraTask);
|
||||
|
||||
// Convertir JiraSyncAction vers SyncAction
|
||||
const standardAction: SyncAction = {
|
||||
type: syncAction.type,
|
||||
itemId: syncAction.taskKey,
|
||||
title: syncAction.taskTitle,
|
||||
message: syncAction.reason || syncAction.changes?.join('; ')
|
||||
};
|
||||
|
||||
// Ajouter l'action au résultat
|
||||
result.actions.push(syncAction);
|
||||
result.actions.push(standardAction);
|
||||
jiraActions.push(syncAction);
|
||||
|
||||
// Compter les actions
|
||||
if (syncAction.type === 'created') {
|
||||
result.tasksCreated++;
|
||||
result.stats.created++;
|
||||
} else if (syncAction.type === 'updated') {
|
||||
result.tasksUpdated++;
|
||||
result.stats.updated++;
|
||||
} else {
|
||||
result.tasksSkipped++;
|
||||
result.stats.skipped++;
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`Erreur sync ticket ${jiraTask.key}:`, error);
|
||||
@@ -300,8 +358,19 @@ export class JiraService {
|
||||
|
||||
// Nettoyer les tâches Jira qui ne sont plus assignées à l'utilisateur
|
||||
const deletedActions = await this.cleanupUnassignedTasks(currentJiraIds);
|
||||
result.tasksDeleted = deletedActions.length;
|
||||
result.actions.push(...deletedActions);
|
||||
tasksDeleted = deletedActions.length;
|
||||
result.stats.deleted = tasksDeleted;
|
||||
|
||||
// Convertir les actions de suppression
|
||||
for (const action of deletedActions) {
|
||||
const standardAction: SyncAction = {
|
||||
type: 'deleted',
|
||||
itemId: action.taskKey,
|
||||
title: action.taskTitle,
|
||||
message: action.reason
|
||||
};
|
||||
result.actions.push(standardAction);
|
||||
}
|
||||
|
||||
// Déterminer le succès et enregistrer le log
|
||||
result.success = result.errors.length === 0;
|
||||
@@ -721,14 +790,14 @@ export class JiraService {
|
||||
/**
|
||||
* Enregistre un log de synchronisation
|
||||
*/
|
||||
private async logSync(result: JiraSyncResult): Promise<void> {
|
||||
private async logSync(result: SyncResult): Promise<void> {
|
||||
try {
|
||||
await prisma.syncLog.create({
|
||||
data: {
|
||||
source: 'jira',
|
||||
status: result.success ? 'success' : 'error',
|
||||
message: result.errors.length > 0 ? result.errors.join('; ') : null,
|
||||
tasksSync: result.tasksCreated + result.tasksUpdated
|
||||
tasksSync: result.stats.created + result.stats.updated
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
@@ -750,5 +819,10 @@ export function createJiraService(): JiraService | null {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new JiraService({ baseUrl, email, apiToken });
|
||||
return new JiraService({
|
||||
enabled: true,
|
||||
baseUrl,
|
||||
email,
|
||||
apiToken
|
||||
});
|
||||
}
|
||||
|
||||
@@ -365,6 +365,12 @@ export class TasksService {
|
||||
jiraProject: prismaTask.jiraProject ?? undefined,
|
||||
jiraKey: prismaTask.jiraKey ?? undefined,
|
||||
jiraType: prismaTask.jiraType ?? undefined,
|
||||
// Champs TFS
|
||||
tfsProject: prismaTask.tfsProject ?? undefined,
|
||||
tfsPullRequestId: prismaTask.tfsPullRequestId ?? undefined,
|
||||
tfsRepository: prismaTask.tfsRepository ?? undefined,
|
||||
tfsSourceBranch: prismaTask.tfsSourceBranch ?? undefined,
|
||||
tfsTargetBranch: prismaTask.tfsTargetBranch ?? undefined,
|
||||
assignee: prismaTask.assignee ?? undefined
|
||||
};
|
||||
}
|
||||
|
||||
1117
src/services/tfs.ts
Normal file
1117
src/services/tfs.ts
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,12 @@
|
||||
import { TaskStatus, KanbanFilters, ViewPreferences, ColumnVisibility, UserPreferences, JiraConfig } from '@/lib/types';
|
||||
import {
|
||||
TaskStatus,
|
||||
KanbanFilters,
|
||||
ViewPreferences,
|
||||
ColumnVisibility,
|
||||
UserPreferences,
|
||||
JiraConfig,
|
||||
} from '@/lib/types';
|
||||
import { TfsConfig } from '@/services/tfs';
|
||||
import { prisma } from './database';
|
||||
import { getConfig } from '@/lib/config';
|
||||
|
||||
@@ -32,7 +40,17 @@ const DEFAULT_PREFERENCES: UserPreferences = {
|
||||
ignoredProjects: []
|
||||
},
|
||||
jiraAutoSync: false,
|
||||
jiraSyncInterval: 'daily'
|
||||
jiraSyncInterval: 'daily',
|
||||
tfsConfig: {
|
||||
enabled: false,
|
||||
organizationUrl: '',
|
||||
projectName: '',
|
||||
personalAccessToken: '',
|
||||
repositories: [],
|
||||
ignoredRepositories: [],
|
||||
},
|
||||
tfsAutoSync: false,
|
||||
tfsSyncInterval: 'daily',
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -57,10 +75,10 @@ class UserPreferencesService {
|
||||
jiraConfig: DEFAULT_PREFERENCES.jiraConfig as any, // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// S'assurer que les nouveaux champs existent (migration douce)
|
||||
await this.ensureJiraSchedulerFields();
|
||||
|
||||
|
||||
return userPrefs;
|
||||
}
|
||||
|
||||
@@ -82,7 +100,7 @@ class UserPreferencesService {
|
||||
}
|
||||
|
||||
// === FILTRES KANBAN ===
|
||||
|
||||
|
||||
/**
|
||||
* Sauvegarde les filtres Kanban
|
||||
*/
|
||||
@@ -126,7 +144,10 @@ class UserPreferencesService {
|
||||
data: { viewPreferences: preferences }
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la sauvegarde des préférences de vue:', error);
|
||||
console.warn(
|
||||
'Erreur lors de la sauvegarde des préférences de vue:',
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -140,7 +161,10 @@ class UserPreferencesService {
|
||||
const preferences = userPrefs.viewPreferences as ViewPreferences | null;
|
||||
return { ...DEFAULT_PREFERENCES.viewPreferences, ...(preferences || {}) };
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la récupération des préférences de vue:', error);
|
||||
console.warn(
|
||||
'Erreur lors de la récupération des préférences de vue:',
|
||||
error
|
||||
);
|
||||
return DEFAULT_PREFERENCES.viewPreferences;
|
||||
}
|
||||
}
|
||||
@@ -155,10 +179,13 @@ class UserPreferencesService {
|
||||
const userPrefs = await this.getOrCreateUserPreferences();
|
||||
await prisma.userPreferences.update({
|
||||
where: { id: userPrefs.id },
|
||||
data: { columnVisibility: visibility }
|
||||
data: { columnVisibility: visibility },
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la sauvegarde de la visibilité des colonnes:', error);
|
||||
console.warn(
|
||||
'Erreur lors de la sauvegarde de la visibilité des colonnes:',
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -172,7 +199,10 @@ class UserPreferencesService {
|
||||
const visibility = userPrefs.columnVisibility as ColumnVisibility | null;
|
||||
return { ...DEFAULT_PREFERENCES.columnVisibility, ...(visibility || {}) };
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la récupération de la visibilité des colonnes:', error);
|
||||
console.warn(
|
||||
'Erreur lors de la récupération de la visibilité des colonnes:',
|
||||
error
|
||||
);
|
||||
return DEFAULT_PREFERENCES.columnVisibility;
|
||||
}
|
||||
}
|
||||
@@ -218,19 +248,22 @@ class UserPreferencesService {
|
||||
try {
|
||||
const userPrefs = await this.getOrCreateUserPreferences();
|
||||
const dbConfig = userPrefs.jiraConfig as JiraConfig | null;
|
||||
|
||||
|
||||
// Si config en DB, l'utiliser
|
||||
if (dbConfig && (dbConfig.baseUrl || dbConfig.email || dbConfig.apiToken)) {
|
||||
if (
|
||||
dbConfig &&
|
||||
(dbConfig.baseUrl || dbConfig.email || dbConfig.apiToken)
|
||||
) {
|
||||
return { ...DEFAULT_PREFERENCES.jiraConfig, ...dbConfig };
|
||||
}
|
||||
|
||||
|
||||
// Sinon fallback sur les variables d'environnement (existant)
|
||||
const config = getConfig();
|
||||
return {
|
||||
baseUrl: config.integrations.jira.baseUrl,
|
||||
email: config.integrations.jira.email,
|
||||
apiToken: '', // On ne retourne pas le token des env vars pour la sécurité
|
||||
enabled: config.integrations.jira.enabled
|
||||
enabled: config.integrations.jira.enabled,
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la récupération de la config Jira:', error);
|
||||
@@ -238,12 +271,120 @@ class UserPreferencesService {
|
||||
}
|
||||
}
|
||||
|
||||
// === CONFIGURATION TFS ===
|
||||
|
||||
/**
|
||||
* Sauvegarde la configuration TFS
|
||||
*/
|
||||
async saveTfsConfig(config: TfsConfig): Promise<void> {
|
||||
try {
|
||||
const userPrefs = await this.getOrCreateUserPreferences();
|
||||
await prisma.userPreferences.update({
|
||||
where: { id: userPrefs.id },
|
||||
data: { tfsConfig: config as any }, // eslint-disable-line @typescript-eslint/no-explicit-any
|
||||
});
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la sauvegarde de la config TFS:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère la configuration TFS depuis la base de données
|
||||
*/
|
||||
async getTfsConfig(): Promise<TfsConfig> {
|
||||
try {
|
||||
const userPrefs = await this.getOrCreateUserPreferences();
|
||||
const dbConfig = userPrefs.tfsConfig as TfsConfig | null;
|
||||
|
||||
if (
|
||||
dbConfig &&
|
||||
(dbConfig.organizationUrl ||
|
||||
dbConfig.projectName ||
|
||||
dbConfig.personalAccessToken)
|
||||
) {
|
||||
return { ...DEFAULT_PREFERENCES.tfsConfig, ...dbConfig };
|
||||
}
|
||||
|
||||
return DEFAULT_PREFERENCES.tfsConfig;
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la récupération de la config TFS:', error);
|
||||
return DEFAULT_PREFERENCES.tfsConfig;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sauvegarde les préférences du scheduler TFS
|
||||
*/
|
||||
async saveTfsSchedulerConfig(
|
||||
tfsAutoSync: boolean,
|
||||
tfsSyncInterval: 'hourly' | 'daily' | 'weekly'
|
||||
): Promise<void> {
|
||||
try {
|
||||
const userPrefs = await this.getOrCreateUserPreferences();
|
||||
await prisma.$executeRaw`
|
||||
UPDATE user_preferences
|
||||
SET tfsAutoSync = ${tfsAutoSync}, tfsSyncInterval = ${tfsSyncInterval}
|
||||
WHERE id = ${userPrefs.id}
|
||||
`;
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'Erreur lors de la sauvegarde de la config scheduler TFS:',
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les préférences du scheduler TFS
|
||||
*/
|
||||
async getTfsSchedulerConfig(): Promise<{
|
||||
tfsAutoSync: boolean;
|
||||
tfsSyncInterval: 'hourly' | 'daily' | 'weekly';
|
||||
}> {
|
||||
try {
|
||||
const userPrefs = await this.getOrCreateUserPreferences();
|
||||
const result = await prisma.$queryRaw<
|
||||
Array<{ tfsAutoSync: number; tfsSyncInterval: string }>
|
||||
>`
|
||||
SELECT tfsAutoSync, tfsSyncInterval FROM user_preferences WHERE id = ${userPrefs.id}
|
||||
`;
|
||||
|
||||
if (result.length > 0) {
|
||||
return {
|
||||
tfsAutoSync: Boolean(result[0].tfsAutoSync),
|
||||
tfsSyncInterval:
|
||||
(result[0].tfsSyncInterval as 'hourly' | 'daily' | 'weekly') ||
|
||||
DEFAULT_PREFERENCES.tfsSyncInterval,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
tfsAutoSync: DEFAULT_PREFERENCES.tfsAutoSync,
|
||||
tfsSyncInterval: DEFAULT_PREFERENCES.tfsSyncInterval,
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'Erreur lors de la récupération de la config scheduler TFS:',
|
||||
error
|
||||
);
|
||||
return {
|
||||
tfsAutoSync: DEFAULT_PREFERENCES.tfsAutoSync,
|
||||
tfsSyncInterval: DEFAULT_PREFERENCES.tfsSyncInterval,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// === CONFIGURATION SCHEDULER JIRA ===
|
||||
|
||||
/**
|
||||
* Sauvegarde les préférences du scheduler Jira
|
||||
*/
|
||||
async saveJiraSchedulerConfig(jiraAutoSync: boolean, jiraSyncInterval: 'hourly' | 'daily' | 'weekly'): Promise<void> {
|
||||
async saveJiraSchedulerConfig(
|
||||
jiraAutoSync: boolean,
|
||||
jiraSyncInterval: 'hourly' | 'daily' | 'weekly'
|
||||
): Promise<void> {
|
||||
try {
|
||||
const userPrefs = await this.getOrCreateUserPreferences();
|
||||
// Utiliser une requête SQL brute temporairement pour éviter les problèmes de types
|
||||
@@ -253,7 +394,10 @@ class UserPreferencesService {
|
||||
WHERE id = ${userPrefs.id}
|
||||
`;
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la sauvegarde de la config scheduler Jira:', error);
|
||||
console.warn(
|
||||
'Erreur lors de la sauvegarde de la config scheduler Jira:',
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -261,24 +405,31 @@ class UserPreferencesService {
|
||||
/**
|
||||
* Récupère les préférences du scheduler Jira
|
||||
*/
|
||||
async getJiraSchedulerConfig(): Promise<{ jiraAutoSync: boolean; jiraSyncInterval: 'hourly' | 'daily' | 'weekly' }> {
|
||||
async getJiraSchedulerConfig(): Promise<{
|
||||
jiraAutoSync: boolean;
|
||||
jiraSyncInterval: 'hourly' | 'daily' | 'weekly';
|
||||
}> {
|
||||
try {
|
||||
const userPrefs = await this.getOrCreateUserPreferences();
|
||||
// Utiliser une requête SQL brute pour récupérer les nouveaux champs
|
||||
const result = await prisma.$queryRaw<Array<{ jiraAutoSync: number; jiraSyncInterval: string }>>`
|
||||
const result = await prisma.$queryRaw<
|
||||
Array<{ jiraAutoSync: number; jiraSyncInterval: string }>
|
||||
>`
|
||||
SELECT jiraAutoSync, jiraSyncInterval FROM user_preferences WHERE id = ${userPrefs.id}
|
||||
`;
|
||||
|
||||
|
||||
if (result.length > 0) {
|
||||
return {
|
||||
jiraAutoSync: Boolean(result[0].jiraAutoSync),
|
||||
jiraSyncInterval: (result[0].jiraSyncInterval as 'hourly' | 'daily' | 'weekly') || DEFAULT_PREFERENCES.jiraSyncInterval
|
||||
jiraSyncInterval:
|
||||
(result[0].jiraSyncInterval as 'hourly' | 'daily' | 'weekly') ||
|
||||
DEFAULT_PREFERENCES.jiraSyncInterval,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
jiraAutoSync: DEFAULT_PREFERENCES.jiraAutoSync,
|
||||
jiraSyncInterval: DEFAULT_PREFERENCES.jiraSyncInterval
|
||||
jiraSyncInterval: DEFAULT_PREFERENCES.jiraSyncInterval,
|
||||
};
|
||||
} catch (error) {
|
||||
console.warn('Erreur lors de la récupération de la config scheduler Jira:', error);
|
||||
@@ -289,16 +440,33 @@ class UserPreferencesService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère les préférences utilisateur (alias pour getAllPreferences)
|
||||
*/
|
||||
async getUserPreferences(): Promise<UserPreferences> {
|
||||
return this.getAllPreferences();
|
||||
}
|
||||
|
||||
/**
|
||||
* Récupère toutes les préférences utilisateur
|
||||
*/
|
||||
async getAllPreferences(): Promise<UserPreferences> {
|
||||
const [kanbanFilters, viewPreferences, columnVisibility, jiraConfig, jiraSchedulerConfig] = await Promise.all([
|
||||
const [
|
||||
kanbanFilters,
|
||||
viewPreferences,
|
||||
columnVisibility,
|
||||
jiraConfig,
|
||||
jiraSchedulerConfig,
|
||||
tfsConfig,
|
||||
tfsSchedulerConfig,
|
||||
] = await Promise.all([
|
||||
this.getKanbanFilters(),
|
||||
this.getViewPreferences(),
|
||||
this.getColumnVisibility(),
|
||||
this.getJiraConfig(),
|
||||
this.getJiraSchedulerConfig()
|
||||
this.getJiraSchedulerConfig(),
|
||||
this.getTfsConfig(),
|
||||
this.getTfsSchedulerConfig(),
|
||||
]);
|
||||
|
||||
return {
|
||||
@@ -307,7 +475,10 @@ class UserPreferencesService {
|
||||
columnVisibility,
|
||||
jiraConfig,
|
||||
jiraAutoSync: jiraSchedulerConfig.jiraAutoSync,
|
||||
jiraSyncInterval: jiraSchedulerConfig.jiraSyncInterval
|
||||
jiraSyncInterval: jiraSchedulerConfig.jiraSyncInterval,
|
||||
tfsConfig,
|
||||
tfsAutoSync: tfsSchedulerConfig.tfsAutoSync,
|
||||
tfsSyncInterval: tfsSchedulerConfig.tfsSyncInterval,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -320,7 +491,15 @@ class UserPreferencesService {
|
||||
this.saveViewPreferences(preferences.viewPreferences),
|
||||
this.saveColumnVisibility(preferences.columnVisibility),
|
||||
this.saveJiraConfig(preferences.jiraConfig),
|
||||
this.saveJiraSchedulerConfig(preferences.jiraAutoSync, preferences.jiraSyncInterval)
|
||||
this.saveJiraSchedulerConfig(
|
||||
preferences.jiraAutoSync,
|
||||
preferences.jiraSyncInterval
|
||||
),
|
||||
this.saveTfsConfig(preferences.tfsConfig),
|
||||
this.saveTfsSchedulerConfig(
|
||||
preferences.tfsAutoSync,
|
||||
preferences.tfsSyncInterval
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -369,13 +548,13 @@ class UserPreferencesService {
|
||||
async toggleColumnVisibility(status: TaskStatus): Promise<void> {
|
||||
const current = await this.getColumnVisibility();
|
||||
const hiddenStatuses = new Set(current.hiddenStatuses);
|
||||
|
||||
|
||||
if (hiddenStatuses.has(status)) {
|
||||
hiddenStatuses.delete(status);
|
||||
} else {
|
||||
hiddenStatuses.add(status);
|
||||
}
|
||||
|
||||
|
||||
await this.saveColumnVisibility({
|
||||
hiddenStatuses: Array.from(hiddenStatuses)
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user