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:
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react';
|
||||
import { Button } from '@/components/ui/Button';
|
||||
import { Badge } from '@/components/ui/Badge';
|
||||
import { useJiraConfig } from '@/hooks/useJiraConfig';
|
||||
import { jiraConfigClient } from '@/clients/jira-config-client';
|
||||
|
||||
export function JiraConfigForm() {
|
||||
const { config, isLoading: configLoading, saveConfig, deleteConfig } = useJiraConfig();
|
||||
@@ -12,9 +13,12 @@ export function JiraConfigForm() {
|
||||
baseUrl: '',
|
||||
email: '',
|
||||
apiToken: '',
|
||||
projectKey: '',
|
||||
ignoredProjects: [] as string[]
|
||||
});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
const [isValidating, setIsValidating] = useState(false);
|
||||
const [validationResult, setValidationResult] = useState<{ type: 'success' | 'error', text: string } | null>(null);
|
||||
const [message, setMessage] = useState<{ type: 'success' | 'error', text: string } | null>(null);
|
||||
|
||||
// Charger les données existantes dans le formulaire
|
||||
@@ -24,6 +28,7 @@ export function JiraConfigForm() {
|
||||
baseUrl: config.baseUrl || '',
|
||||
email: config.email || '',
|
||||
apiToken: config.apiToken || '',
|
||||
projectKey: config.projectKey || '',
|
||||
ignoredProjects: config.ignoredProjects || []
|
||||
});
|
||||
}
|
||||
@@ -74,6 +79,7 @@ export function JiraConfigForm() {
|
||||
baseUrl: '',
|
||||
email: '',
|
||||
apiToken: '',
|
||||
projectKey: '',
|
||||
ignoredProjects: []
|
||||
});
|
||||
setMessage({
|
||||
@@ -96,6 +102,42 @@ export function JiraConfigForm() {
|
||||
}
|
||||
};
|
||||
|
||||
const handleValidateProject = async () => {
|
||||
if (!formData.projectKey.trim()) {
|
||||
setValidationResult({
|
||||
type: 'error',
|
||||
text: 'Veuillez saisir une clé de projet'
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
setIsValidating(true);
|
||||
setValidationResult(null);
|
||||
|
||||
try {
|
||||
const result = await jiraConfigClient.validateProject(formData.projectKey);
|
||||
|
||||
if (result.success && result.exists) {
|
||||
setValidationResult({
|
||||
type: 'success',
|
||||
text: `✓ Projet trouvé : ${result.projectName}`
|
||||
});
|
||||
} else {
|
||||
setValidationResult({
|
||||
type: 'error',
|
||||
text: result.error || result.message
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
setValidationResult({
|
||||
type: 'error',
|
||||
text: error instanceof Error ? error.message : 'Erreur lors de la validation'
|
||||
});
|
||||
} finally {
|
||||
setIsValidating(false);
|
||||
}
|
||||
};
|
||||
|
||||
const isJiraConfigured = config?.enabled && (config?.baseUrl || config?.email);
|
||||
const isLoading = configLoading || isSubmitting;
|
||||
|
||||
@@ -139,6 +181,12 @@ export function JiraConfigForm() {
|
||||
{config?.apiToken ? '••••••••' : 'Non défini'}
|
||||
</code>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-[var(--muted-foreground)]">Projet surveillé:</span>{' '}
|
||||
<code className="bg-[var(--background)] px-2 py-1 rounded text-xs">
|
||||
{config?.projectKey || 'Non défini'}
|
||||
</code>
|
||||
</div>
|
||||
<div>
|
||||
<span className="text-[var(--muted-foreground)]">Projets ignorés:</span>{' '}
|
||||
{config?.ignoredProjects && config.ignoredProjects.length > 0 ? (
|
||||
@@ -218,6 +266,49 @@ export function JiraConfigForm() {
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">
|
||||
Projet à surveiller (optionnel)
|
||||
</label>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={formData.projectKey}
|
||||
onChange={(e) => {
|
||||
setFormData(prev => ({ ...prev, projectKey: e.target.value.trim().toUpperCase() }));
|
||||
setValidationResult(null); // Reset validation when input changes
|
||||
}}
|
||||
placeholder="MYTEAM"
|
||||
className="flex-1 px-3 py-2 border border-[var(--border)] rounded bg-[var(--background)] text-[var(--foreground)] focus:outline-none focus:ring-2 focus:ring-[var(--primary)] focus:border-transparent"
|
||||
/>
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={handleValidateProject}
|
||||
disabled={isValidating || !formData.projectKey.trim() || !isJiraConfigured}
|
||||
className="px-4 shrink-0"
|
||||
>
|
||||
{isValidating ? 'Validation...' : 'Valider'}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Résultat de la validation */}
|
||||
{validationResult && (
|
||||
<div className={`mt-2 p-2 rounded text-sm ${
|
||||
validationResult.type === 'success'
|
||||
? 'bg-green-50 border border-green-200 text-green-800 dark:bg-green-900/20 dark:border-green-800 dark:text-green-200'
|
||||
: 'bg-red-50 border border-red-200 text-red-800 dark:bg-red-900/20 dark:border-red-800 dark:text-red-200'
|
||||
}`}>
|
||||
{validationResult.text}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-xs text-[var(--muted-foreground)] mt-1">
|
||||
Clé du projet pour les analytics d'équipe (ex: MYTEAM, DEV, PROD).
|
||||
Laissez vide pour désactiver la surveillance d'équipe.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium mb-2">
|
||||
Projets à ignorer (optionnel)
|
||||
|
||||
Reference in New Issue
Block a user