feat: integrate Jira ticket linking in TaskCard
- Added functionality to generate Jira ticket URLs based on user preferences, enhancing task interactivity. - Updated UserPreferences to include Jira configuration, ensuring seamless integration with Jira settings. - Refactored TaskCard to conditionally render Jira links, improving user experience when interacting with Jira tasks.
This commit is contained in:
@@ -6,6 +6,7 @@ import { Card } from '@/components/ui/Card';
|
|||||||
import { Badge } from '@/components/ui/Badge';
|
import { Badge } from '@/components/ui/Badge';
|
||||||
import { TagDisplay } from '@/components/ui/TagDisplay';
|
import { TagDisplay } from '@/components/ui/TagDisplay';
|
||||||
import { useTasksContext } from '@/contexts/TasksContext';
|
import { useTasksContext } from '@/contexts/TasksContext';
|
||||||
|
import { useUserPreferences } from '@/contexts/UserPreferencesContext';
|
||||||
import { useDraggable } from '@dnd-kit/core';
|
import { useDraggable } from '@dnd-kit/core';
|
||||||
import { getPriorityConfig, getPriorityColorHex } from '@/lib/status-config';
|
import { getPriorityConfig, getPriorityColorHex } from '@/lib/status-config';
|
||||||
|
|
||||||
@@ -23,6 +24,14 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
|||||||
const [showTooltip, setShowTooltip] = useState(false);
|
const [showTooltip, setShowTooltip] = useState(false);
|
||||||
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
const timeoutRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
const { tags: availableTags } = useTasksContext();
|
const { tags: availableTags } = useTasksContext();
|
||||||
|
const { preferences } = useUserPreferences();
|
||||||
|
|
||||||
|
// Helper pour construire l'URL Jira
|
||||||
|
const getJiraTicketUrl = (jiraKey: string): string => {
|
||||||
|
const baseUrl = preferences.jiraConfig.baseUrl;
|
||||||
|
if (!baseUrl || !jiraKey) return '';
|
||||||
|
return `${baseUrl}/browse/${jiraKey}`;
|
||||||
|
};
|
||||||
|
|
||||||
// Configuration du draggable
|
// Configuration du draggable
|
||||||
const {
|
const {
|
||||||
@@ -374,9 +383,29 @@ export function TaskCard({ task, onDelete, onEdit, onUpdateTitle, compactView =
|
|||||||
|
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
{task.source !== 'manual' && task.source && (
|
{task.source !== 'manual' && task.source && (
|
||||||
<Badge variant="outline" size="sm">
|
task.source === 'jira' && task.jiraKey ? (
|
||||||
{task.source === 'jira' && task.jiraKey ? task.jiraKey : task.source}
|
preferences.jiraConfig.baseUrl ? (
|
||||||
|
<a
|
||||||
|
href={getJiraTicketUrl(task.jiraKey)}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
|
className="hover:scale-105 transition-transform"
|
||||||
|
>
|
||||||
|
<Badge variant="outline" size="sm" className="hover:bg-blue-500/10 hover:border-blue-400/50 cursor-pointer">
|
||||||
|
{task.jiraKey}
|
||||||
</Badge>
|
</Badge>
|
||||||
|
</a>
|
||||||
|
) : (
|
||||||
|
<Badge variant="outline" size="sm">
|
||||||
|
{task.jiraKey}
|
||||||
|
</Badge>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<Badge variant="outline" size="sm">
|
||||||
|
{task.source}
|
||||||
|
</Badge>
|
||||||
|
)
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{task.jiraProject && (
|
{task.jiraProject && (
|
||||||
|
|||||||
@@ -78,10 +78,17 @@ export interface ColumnVisibility {
|
|||||||
[key: string]: TaskStatus[] | undefined;
|
[key: string]: TaskStatus[] | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface JiraConfig {
|
||||||
|
baseUrl?: string;
|
||||||
|
email?: string;
|
||||||
|
enabled: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface UserPreferences {
|
export interface UserPreferences {
|
||||||
kanbanFilters: KanbanFilters;
|
kanbanFilters: KanbanFilters;
|
||||||
viewPreferences: ViewPreferences;
|
viewPreferences: ViewPreferences;
|
||||||
columnVisibility: ColumnVisibility;
|
columnVisibility: ColumnVisibility;
|
||||||
|
jiraConfig: JiraConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interface pour les logs de synchronisation
|
// Interface pour les logs de synchronisation
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { TaskStatus, KanbanFilters, ViewPreferences, ColumnVisibility, UserPreferences } from '@/lib/types';
|
import { TaskStatus, KanbanFilters, ViewPreferences, ColumnVisibility, UserPreferences, JiraConfig } from '@/lib/types';
|
||||||
import { prisma } from './database';
|
import { prisma } from './database';
|
||||||
|
import { getConfig } from '@/lib/config';
|
||||||
|
|
||||||
// Valeurs par défaut
|
// Valeurs par défaut
|
||||||
const DEFAULT_PREFERENCES: UserPreferences = {
|
const DEFAULT_PREFERENCES: UserPreferences = {
|
||||||
@@ -21,6 +22,9 @@ const DEFAULT_PREFERENCES: UserPreferences = {
|
|||||||
},
|
},
|
||||||
columnVisibility: {
|
columnVisibility: {
|
||||||
hiddenStatuses: []
|
hiddenStatuses: []
|
||||||
|
},
|
||||||
|
jiraConfig: {
|
||||||
|
enabled: false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -161,31 +165,51 @@ class UserPreferencesService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Récupère la configuration Jira depuis les variables d'environnement
|
||||||
|
*/
|
||||||
|
async getJiraConfig(): Promise<JiraConfig> {
|
||||||
|
try {
|
||||||
|
const config = getConfig();
|
||||||
|
return {
|
||||||
|
baseUrl: config.integrations.jira.baseUrl,
|
||||||
|
email: config.integrations.jira.email,
|
||||||
|
enabled: config.integrations.jira.enabled
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Erreur lors de la récupération de la config Jira:', error);
|
||||||
|
return DEFAULT_PREFERENCES.jiraConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Récupère toutes les préférences utilisateur
|
* Récupère toutes les préférences utilisateur
|
||||||
*/
|
*/
|
||||||
async getAllPreferences(): Promise<UserPreferences> {
|
async getAllPreferences(): Promise<UserPreferences> {
|
||||||
const [kanbanFilters, viewPreferences, columnVisibility] = await Promise.all([
|
const [kanbanFilters, viewPreferences, columnVisibility, jiraConfig] = await Promise.all([
|
||||||
this.getKanbanFilters(),
|
this.getKanbanFilters(),
|
||||||
this.getViewPreferences(),
|
this.getViewPreferences(),
|
||||||
this.getColumnVisibility()
|
this.getColumnVisibility(),
|
||||||
|
this.getJiraConfig()
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
kanbanFilters,
|
kanbanFilters,
|
||||||
viewPreferences,
|
viewPreferences,
|
||||||
columnVisibility
|
columnVisibility,
|
||||||
|
jiraConfig
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sauvegarde toutes les préférences utilisateur
|
* Sauvegarde toutes les préférences utilisateur (jiraConfig ignorée car elle vient des env vars)
|
||||||
*/
|
*/
|
||||||
async saveAllPreferences(preferences: UserPreferences): Promise<void> {
|
async saveAllPreferences(preferences: UserPreferences): Promise<void> {
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
this.saveKanbanFilters(preferences.kanbanFilters),
|
this.saveKanbanFilters(preferences.kanbanFilters),
|
||||||
this.saveViewPreferences(preferences.viewPreferences),
|
this.saveViewPreferences(preferences.viewPreferences),
|
||||||
this.saveColumnVisibility(preferences.columnVisibility)
|
this.saveColumnVisibility(preferences.columnVisibility)
|
||||||
|
// jiraConfig n'est pas sauvegardée car elle vient des variables d'environnement
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user