feat: add TFS filters and integration
- Introduced TFS filtering capabilities in `KanbanFilters` with options to show/hide TFS tasks and filter by TFS projects. - Integrated `TfsQuickFilter` component into `KanbanPageClient` and `MobileControls` for enhanced task management. - Updated `TasksContext` to support new TFS filter states and ensure proper task filtering based on TFS criteria. - Enhanced type definitions in `types.ts` to accommodate new TFS filter properties.
This commit is contained in:
@@ -10,6 +10,7 @@ import { CreateTaskData } from '@/clients/tasks-client';
|
|||||||
import { CreateTaskForm } from '@/components/forms/CreateTaskForm';
|
import { CreateTaskForm } from '@/components/forms/CreateTaskForm';
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { JiraQuickFilter } from '@/components/kanban/JiraQuickFilter';
|
import { JiraQuickFilter } from '@/components/kanban/JiraQuickFilter';
|
||||||
|
import { TfsQuickFilter } from '@/components/kanban/TfsQuickFilter';
|
||||||
import { FontSizeToggle } from '@/components/ui/FontSizeToggle';
|
import { FontSizeToggle } from '@/components/ui/FontSizeToggle';
|
||||||
import { MobileControls } from '@/components/kanban/MobileControls';
|
import { MobileControls } from '@/components/kanban/MobileControls';
|
||||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||||
@@ -119,6 +120,12 @@ function KanbanPageContent() {
|
|||||||
onFiltersChange={setKanbanFilters}
|
onFiltersChange={setKanbanFilters}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
{/* Raccourcis TFS */}
|
||||||
|
<TfsQuickFilter
|
||||||
|
filters={kanbanFilters}
|
||||||
|
onFiltersChange={setKanbanFilters}
|
||||||
|
/>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={handleToggleCompactView}
|
onClick={handleToggleCompactView}
|
||||||
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-mono transition-all ${
|
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-mono transition-all ${
|
||||||
|
|||||||
@@ -27,6 +27,10 @@ export interface KanbanFilters {
|
|||||||
hideJiraTasks?: boolean; // Masquer toutes les tâches Jira
|
hideJiraTasks?: boolean; // Masquer toutes les tâches Jira
|
||||||
jiraProjects?: string[]; // Filtrer par projet Jira
|
jiraProjects?: string[]; // Filtrer par projet Jira
|
||||||
jiraTypes?: string[]; // Filtrer par type Jira (Story, Task, Bug, etc.)
|
jiraTypes?: string[]; // Filtrer par type Jira (Story, Task, Bug, etc.)
|
||||||
|
// Filtres spécifiques TFS
|
||||||
|
showTfsOnly?: boolean; // Afficher seulement les tâches TFS
|
||||||
|
hideTfsTasks?: boolean; // Masquer toutes les tâches TFS
|
||||||
|
tfsProjects?: string[]; // Filtrer par projet TFS
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KanbanFiltersProps {
|
interface KanbanFiltersProps {
|
||||||
@@ -162,6 +166,27 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
|||||||
onFiltersChange({ ...filters, ...updates });
|
onFiltersChange({ ...filters, ...updates });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTfsToggle = (mode: 'show' | 'hide' | 'all') => {
|
||||||
|
const updates: Partial<KanbanFilters> = {};
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case 'show':
|
||||||
|
updates.showTfsOnly = true;
|
||||||
|
updates.hideTfsTasks = false;
|
||||||
|
break;
|
||||||
|
case 'hide':
|
||||||
|
updates.showTfsOnly = false;
|
||||||
|
updates.hideTfsTasks = true;
|
||||||
|
break;
|
||||||
|
case 'all':
|
||||||
|
updates.showTfsOnly = false;
|
||||||
|
updates.hideTfsTasks = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFiltersChange({ ...filters, ...updates });
|
||||||
|
};
|
||||||
|
|
||||||
const handleJiraProjectToggle = (project: string) => {
|
const handleJiraProjectToggle = (project: string) => {
|
||||||
const currentProjects = filters.jiraProjects || [];
|
const currentProjects = filters.jiraProjects || [];
|
||||||
const newProjects = currentProjects.includes(project)
|
const newProjects = currentProjects.includes(project)
|
||||||
@@ -186,6 +211,18 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleTfsProjectToggle = (project: string) => {
|
||||||
|
const currentProjects = filters.tfsProjects || [];
|
||||||
|
const newProjects = currentProjects.includes(project)
|
||||||
|
? currentProjects.filter(p => p !== project)
|
||||||
|
: [...currentProjects, project];
|
||||||
|
|
||||||
|
onFiltersChange({
|
||||||
|
...filters,
|
||||||
|
tfsProjects: newProjects
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleClearFilters = () => {
|
const handleClearFilters = () => {
|
||||||
onFiltersChange({});
|
onFiltersChange({});
|
||||||
};
|
};
|
||||||
@@ -215,6 +252,20 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
|||||||
// Vérifier s'il y a des tâches Jira dans le système (même masquées)
|
// Vérifier s'il y a des tâches Jira dans le système (même masquées)
|
||||||
const hasJiraTasks = regularTasks.some(task => task.source === 'jira');
|
const hasJiraTasks = regularTasks.some(task => task.source === 'jira');
|
||||||
|
|
||||||
|
// Récupérer les projets TFS disponibles dans TOUTES les tâches
|
||||||
|
const availableTfsProjects = useMemo(() => {
|
||||||
|
const projects = new Set<string>();
|
||||||
|
regularTasks.forEach(task => {
|
||||||
|
if (task.source === 'tfs' && task.tfsProject) {
|
||||||
|
projects.add(task.tfsProject);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Array.from(projects).sort();
|
||||||
|
}, [regularTasks]);
|
||||||
|
|
||||||
|
// Vérifier s'il y a des tâches TFS dans le système (même masquées)
|
||||||
|
const hasTfsTasks = regularTasks.some(task => task.source === 'tfs');
|
||||||
|
|
||||||
// Calculer les compteurs pour les priorités
|
// Calculer les compteurs pour les priorités
|
||||||
const priorityCounts = useMemo(() => {
|
const priorityCounts = useMemo(() => {
|
||||||
const counts: Record<string, number> = {};
|
const counts: Record<string, number> = {};
|
||||||
@@ -509,6 +560,69 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
{/* Filtres TFS - Ligne séparée mais intégrée */}
|
||||||
|
{hasTfsTasks && (
|
||||||
|
<div className="border-t border-[var(--border)]/30 pt-4 mt-4">
|
||||||
|
<div className="flex items-center gap-4 mb-3">
|
||||||
|
<label className="block text-xs font-mono font-medium text-[var(--muted-foreground)] uppercase tracking-wider">
|
||||||
|
📦 TFS
|
||||||
|
</label>
|
||||||
|
|
||||||
|
{/* Toggle TFS Show/Hide - inline avec le titre */}
|
||||||
|
<div className="flex gap-1">
|
||||||
|
<Button
|
||||||
|
variant={filters.showTfsOnly ? "primary" : "ghost"}
|
||||||
|
onClick={() => handleTfsToggle('show')}
|
||||||
|
size="sm"
|
||||||
|
className="text-xs px-2 py-1 h-auto"
|
||||||
|
>
|
||||||
|
🔷 Seul
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={filters.hideTfsTasks ? "danger" : "ghost"}
|
||||||
|
onClick={() => handleTfsToggle('hide')}
|
||||||
|
size="sm"
|
||||||
|
className="text-xs px-2 py-1 h-auto"
|
||||||
|
>
|
||||||
|
🚫 Mask
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
variant={(!filters.showTfsOnly && !filters.hideTfsTasks) ? "primary" : "ghost"}
|
||||||
|
onClick={() => handleTfsToggle('all')}
|
||||||
|
size="sm"
|
||||||
|
className="text-xs px-2 py-1 h-auto"
|
||||||
|
>
|
||||||
|
📋 All
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Projets TFS */}
|
||||||
|
{availableTfsProjects.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<label className="block text-xs font-medium text-[var(--muted-foreground)] mb-2">
|
||||||
|
Projets
|
||||||
|
</label>
|
||||||
|
<div className="flex flex-wrap gap-1">
|
||||||
|
{availableTfsProjects.map((project) => (
|
||||||
|
<button
|
||||||
|
key={project}
|
||||||
|
onClick={() => handleTfsProjectToggle(project)}
|
||||||
|
className={`px-2 py-1 rounded border transition-all text-xs font-medium ${
|
||||||
|
filters.tfsProjects?.includes(project)
|
||||||
|
? 'border-orange-400 bg-orange-400/10 text-orange-400'
|
||||||
|
: 'border-[var(--border)] bg-[var(--card)] text-[var(--muted-foreground)] hover:border-[var(--border)]'
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
📦 {project}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Visibilité des colonnes */}
|
{/* Visibilité des colonnes */}
|
||||||
<div className="col-span-full border-t border-[var(--border)]/50 pt-6 mt-4">
|
<div className="col-span-full border-t border-[var(--border)]/50 pt-6 mt-4">
|
||||||
<ColumnVisibilityToggle
|
<ColumnVisibilityToggle
|
||||||
@@ -561,6 +675,21 @@ export function KanbanFilters({ filters, onFiltersChange, hiddenStatuses: propsH
|
|||||||
Types Jira: <span className="text-purple-400">{filters.jiraTypes?.filter(Boolean).join(', ')}</span>
|
Types Jira: <span className="text-purple-400">{filters.jiraTypes?.filter(Boolean).join(', ')}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
{filters.showTfsOnly && (
|
||||||
|
<div className="text-[var(--muted-foreground)]">
|
||||||
|
Affichage: <span className="text-orange-400">TFS seulement</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{filters.hideTfsTasks && (
|
||||||
|
<div className="text-[var(--muted-foreground)]">
|
||||||
|
Affichage: <span className="text-red-400">Masquer TFS</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{(filters.tfsProjects?.filter(Boolean).length || 0) > 0 && (
|
||||||
|
<div className="text-[var(--muted-foreground)]">
|
||||||
|
Projets TFS: <span className="text-orange-400">{filters.tfsProjects?.filter(Boolean).join(', ')}</span>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Button } from '@/components/ui/Button';
|
import { Button } from '@/components/ui/Button';
|
||||||
import { JiraQuickFilter } from '@/components/kanban/JiraQuickFilter';
|
import { JiraQuickFilter } from '@/components/kanban/JiraQuickFilter';
|
||||||
|
import { TfsQuickFilter } from '@/components/kanban/TfsQuickFilter';
|
||||||
import { FontSizeToggle } from '@/components/ui/FontSizeToggle';
|
import { FontSizeToggle } from '@/components/ui/FontSizeToggle';
|
||||||
import { KanbanFilters } from '@/components/kanban/KanbanFilters';
|
import { KanbanFilters } from '@/components/kanban/KanbanFilters';
|
||||||
|
|
||||||
@@ -147,15 +148,21 @@ export function MobileControls({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Section Jira */}
|
{/* Section Jira & TFS */}
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-xs font-mono text-[var(--muted-foreground)] uppercase tracking-wide mb-2">
|
<h3 className="text-xs font-mono text-[var(--muted-foreground)] uppercase tracking-wide mb-2">
|
||||||
Raccourcis Jira
|
Raccourcis
|
||||||
</h3>
|
</h3>
|
||||||
<JiraQuickFilter
|
<div className="space-y-2">
|
||||||
filters={kanbanFilters}
|
<JiraQuickFilter
|
||||||
onFiltersChange={onFiltersChange}
|
filters={kanbanFilters}
|
||||||
/>
|
onFiltersChange={onFiltersChange}
|
||||||
|
/>
|
||||||
|
<TfsQuickFilter
|
||||||
|
filters={kanbanFilters}
|
||||||
|
onFiltersChange={onFiltersChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
101
src/components/kanban/TfsQuickFilter.tsx
Normal file
101
src/components/kanban/TfsQuickFilter.tsx
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
import { useTasksContext } from '@/contexts/TasksContext';
|
||||||
|
import { KanbanFilters } from './KanbanFilters';
|
||||||
|
|
||||||
|
interface TfsQuickFilterProps {
|
||||||
|
filters: KanbanFilters;
|
||||||
|
onFiltersChange: (filters: KanbanFilters) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TfsQuickFilter({ filters, onFiltersChange }: TfsQuickFilterProps) {
|
||||||
|
const { regularTasks } = useTasksContext();
|
||||||
|
|
||||||
|
// Vérifier s'il y a des tâches TFS dans le système
|
||||||
|
const hasTfsTasks = useMemo(() => {
|
||||||
|
return regularTasks.some(task => task.source === 'tfs');
|
||||||
|
}, [regularTasks]);
|
||||||
|
|
||||||
|
// Si pas de tâches TFS, on n'affiche rien
|
||||||
|
if (!hasTfsTasks) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Déterminer l'état actuel
|
||||||
|
const currentMode = filters.showTfsOnly ? 'show' : filters.hideTfsTasks ? 'hide' : 'all';
|
||||||
|
|
||||||
|
const handleTfsCycle = () => {
|
||||||
|
const updates: Partial<KanbanFilters> = {};
|
||||||
|
|
||||||
|
// Cycle : All -> TFS only -> No TFS -> All
|
||||||
|
switch (currentMode) {
|
||||||
|
case 'all':
|
||||||
|
// All -> TFS only
|
||||||
|
updates.showTfsOnly = true;
|
||||||
|
updates.hideTfsTasks = false;
|
||||||
|
break;
|
||||||
|
case 'show':
|
||||||
|
// TFS only -> No TFS
|
||||||
|
updates.showTfsOnly = false;
|
||||||
|
updates.hideTfsTasks = true;
|
||||||
|
break;
|
||||||
|
case 'hide':
|
||||||
|
// No TFS -> All
|
||||||
|
updates.showTfsOnly = false;
|
||||||
|
updates.hideTfsTasks = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
onFiltersChange({ ...filters, ...updates });
|
||||||
|
};
|
||||||
|
|
||||||
|
// Définir l'apparence selon l'état
|
||||||
|
const getButtonStyle = () => {
|
||||||
|
switch (currentMode) {
|
||||||
|
case 'show':
|
||||||
|
return 'bg-[var(--primary)]/20 text-[var(--primary)] border border-[var(--primary)]/30';
|
||||||
|
case 'hide':
|
||||||
|
return 'bg-red-500/20 text-red-400 border border-red-400/30';
|
||||||
|
default:
|
||||||
|
return 'bg-[var(--card)] text-[var(--muted-foreground)] border border-[var(--border)] hover:border-[var(--primary)]/50';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getButtonContent = () => {
|
||||||
|
switch (currentMode) {
|
||||||
|
case 'show':
|
||||||
|
return { icon: '🔷', text: 'TFS only' };
|
||||||
|
case 'hide':
|
||||||
|
return { icon: '🚫', text: 'No TFS' };
|
||||||
|
default:
|
||||||
|
return { icon: '📦', text: 'All tasks' };
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTooltip = () => {
|
||||||
|
switch (currentMode) {
|
||||||
|
case 'all':
|
||||||
|
return 'Cliquer pour afficher seulement TFS';
|
||||||
|
case 'show':
|
||||||
|
return 'Cliquer pour masquer TFS';
|
||||||
|
case 'hide':
|
||||||
|
return 'Cliquer pour afficher tout';
|
||||||
|
default:
|
||||||
|
return 'Filtrer les tâches TFS';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const content = getButtonContent();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
onClick={handleTfsCycle}
|
||||||
|
className={`flex items-center gap-2 px-3 py-1.5 rounded-md text-sm font-mono transition-all ${getButtonStyle()}`}
|
||||||
|
title={getTooltip()}
|
||||||
|
>
|
||||||
|
<span>{content.icon}</span>
|
||||||
|
{content.text}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -64,7 +64,11 @@ export function TasksProvider({ children, initialTasks, initialTags, initialStat
|
|||||||
showJiraOnly: preferences.kanbanFilters.showJiraOnly || false,
|
showJiraOnly: preferences.kanbanFilters.showJiraOnly || false,
|
||||||
hideJiraTasks: preferences.kanbanFilters.hideJiraTasks || false,
|
hideJiraTasks: preferences.kanbanFilters.hideJiraTasks || false,
|
||||||
jiraProjects: preferences.kanbanFilters.jiraProjects || [],
|
jiraProjects: preferences.kanbanFilters.jiraProjects || [],
|
||||||
jiraTypes: preferences.kanbanFilters.jiraTypes || []
|
jiraTypes: preferences.kanbanFilters.jiraTypes || [],
|
||||||
|
// Filtres TFS
|
||||||
|
showTfsOnly: preferences.kanbanFilters.showTfsOnly || false,
|
||||||
|
hideTfsTasks: preferences.kanbanFilters.hideTfsTasks || false,
|
||||||
|
tfsProjects: preferences.kanbanFilters.tfsProjects || []
|
||||||
}), [preferences]);
|
}), [preferences]);
|
||||||
|
|
||||||
// Fonction pour mettre à jour les filtres avec persistance
|
// Fonction pour mettre à jour les filtres avec persistance
|
||||||
@@ -80,7 +84,11 @@ export function TasksProvider({ children, initialTasks, initialTags, initialStat
|
|||||||
showJiraOnly: newFilters.showJiraOnly,
|
showJiraOnly: newFilters.showJiraOnly,
|
||||||
hideJiraTasks: newFilters.hideJiraTasks,
|
hideJiraTasks: newFilters.hideJiraTasks,
|
||||||
jiraProjects: newFilters.jiraProjects,
|
jiraProjects: newFilters.jiraProjects,
|
||||||
jiraTypes: newFilters.jiraTypes
|
jiraTypes: newFilters.jiraTypes,
|
||||||
|
// Filtres TFS
|
||||||
|
showTfsOnly: newFilters.showTfsOnly,
|
||||||
|
hideTfsTasks: newFilters.hideTfsTasks,
|
||||||
|
tfsProjects: newFilters.tfsProjects
|
||||||
};
|
};
|
||||||
|
|
||||||
const viewPreferenceUpdates = {
|
const viewPreferenceUpdates = {
|
||||||
@@ -133,7 +141,10 @@ export function TasksProvider({ children, initialTasks, initialTags, initialStat
|
|||||||
(kanbanFilters.jiraProjects?.filter(Boolean).length || 0) +
|
(kanbanFilters.jiraProjects?.filter(Boolean).length || 0) +
|
||||||
(kanbanFilters.jiraTypes?.filter(Boolean).length || 0) +
|
(kanbanFilters.jiraTypes?.filter(Boolean).length || 0) +
|
||||||
(kanbanFilters.showJiraOnly ? 1 : 0) +
|
(kanbanFilters.showJiraOnly ? 1 : 0) +
|
||||||
(kanbanFilters.hideJiraTasks ? 1 : 0);
|
(kanbanFilters.hideJiraTasks ? 1 : 0) +
|
||||||
|
(kanbanFilters.tfsProjects?.filter(Boolean).length || 0) +
|
||||||
|
(kanbanFilters.showTfsOnly ? 1 : 0) +
|
||||||
|
(kanbanFilters.hideTfsTasks ? 1 : 0);
|
||||||
}, [kanbanFilters]);
|
}, [kanbanFilters]);
|
||||||
|
|
||||||
// Filtrage et tri des tâches régulières (pas les épinglées)
|
// Filtrage et tri des tâches régulières (pas les épinglées)
|
||||||
@@ -187,6 +198,20 @@ export function TasksProvider({ children, initialTasks, initialTags, initialStat
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Filtres spécifiques TFS
|
||||||
|
if (kanbanFilters.showTfsOnly) {
|
||||||
|
filtered = filtered.filter(task => task.source === 'tfs');
|
||||||
|
} else if (kanbanFilters.hideTfsTasks) {
|
||||||
|
filtered = filtered.filter(task => task.source !== 'tfs');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Filtre par projets TFS
|
||||||
|
if (kanbanFilters.tfsProjects?.length) {
|
||||||
|
filtered = filtered.filter(task =>
|
||||||
|
task.source !== 'tfs' || kanbanFilters.tfsProjects!.includes(task.tfsProject || '')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// Tri des tâches
|
// Tri des tâches
|
||||||
if (kanbanFilters.sortBy) {
|
if (kanbanFilters.sortBy) {
|
||||||
const sortOption = getSortOption(kanbanFilters.sortBy);
|
const sortOption = getSortOption(kanbanFilters.sortBy);
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ export interface KanbanFilters {
|
|||||||
hideJiraTasks?: boolean;
|
hideJiraTasks?: boolean;
|
||||||
jiraProjects?: string[];
|
jiraProjects?: string[];
|
||||||
jiraTypes?: string[];
|
jiraTypes?: string[];
|
||||||
|
// Filtres spécifiques TFS
|
||||||
|
showTfsOnly?: boolean;
|
||||||
|
hideTfsTasks?: boolean;
|
||||||
|
tfsProjects?: string[];
|
||||||
[key: string]: string | string[] | TaskPriority[] | boolean | undefined;
|
[key: string]: string | string[] | TaskPriority[] | boolean | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user