feat(ui): harmoniser les pages Scrapers sur le design system Mangarr
- Layout canonique px-6 py-8 + sections border-t (suppression container mx-auto) - Toolbar : label titre + bouton retour (ScrapperEdit) + boutons actions (ScrapperConfigurations) - Bouton submit déplacé dans la toolbar droite via defineExpose/ref - ContentSourceForm aplati (suppression du wrapper carte et du header) - Séparation des sections du formulaire par border-t - Suppression de tous les rounded-* sur les 4 composants - Suppression du bloc debug "aucune source" et du h1 volant
This commit is contained in:
parent
367b361eef
commit
da8a19cbcb
@@ -3,43 +3,36 @@
|
||||
<Toolbar :config="toolbarConfig" />
|
||||
|
||||
<div class="overflow-y-auto flex-1">
|
||||
<div class="container mx-auto px-4 py-6">
|
||||
<!-- Back Navigation -->
|
||||
<div class="mb-6">
|
||||
<button
|
||||
@click="goBack"
|
||||
class="flex items-center space-x-2 text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-200 transition-colors">
|
||||
<ArrowLeftIcon class="w-5 h-5" />
|
||||
<span>Retour aux configurations</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- Loading State -->
|
||||
<div v-if="loadingCurrentSource" class="flex justify-center py-12">
|
||||
<div class="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-500"></div>
|
||||
</div>
|
||||
|
||||
<!-- Error State -->
|
||||
<div v-else-if="currentSourceError" class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 rounded-lg p-4 mb-6">
|
||||
<div class="flex items-center">
|
||||
<ExclamationTriangleIcon class="w-5 h-5 text-red-400 mr-2" />
|
||||
<p class="text-red-800 dark:text-red-200">{{ currentSourceError }}</p>
|
||||
<div class="px-6 py-8">
|
||||
<section class="border-t border-gray-200 dark:border-gray-700 pt-6">
|
||||
<!-- Loading State -->
|
||||
<div v-if="loadingCurrentSource" class="flex justify-center py-12">
|
||||
<div class="animate-spin h-12 w-12 border-b-2 border-blue-500"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
<div v-else class="max-w-4xl mx-auto">
|
||||
<ContentSourceForm
|
||||
:source="currentSource"
|
||||
:saving="saving"
|
||||
:error="saveError"
|
||||
@submit="handleSubmit"
|
||||
@test="handleTest" />
|
||||
</div>
|
||||
<!-- Error State -->
|
||||
<div v-else-if="currentSourceError" class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 p-4 mb-6">
|
||||
<div class="flex items-center">
|
||||
<ExclamationTriangleIcon class="w-5 h-5 text-red-400 mr-2" />
|
||||
<p class="text-red-800 dark:text-red-200">{{ currentSourceError }}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Form -->
|
||||
<div v-else>
|
||||
<ContentSourceForm
|
||||
ref="formRef"
|
||||
:source="currentSource"
|
||||
:saving="saving"
|
||||
:error="saveError"
|
||||
@submit="handleSubmit"
|
||||
@test="handleTest" />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Test Results Modal -->
|
||||
<div v-if="showTestResults" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
|
||||
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-xl w-full max-w-4xl max-h-[80vh] overflow-hidden">
|
||||
<div class="bg-white dark:bg-gray-800 shadow-xl w-full max-w-4xl max-h-[80vh] overflow-hidden">
|
||||
<div class="p-6 border-b border-gray-200 dark:border-gray-600">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-lg font-semibold">Résultats du test</h3>
|
||||
@@ -54,7 +47,7 @@
|
||||
<div class="p-6 overflow-y-auto">
|
||||
<!-- Loading state during test -->
|
||||
<div v-if="testingConfiguration" class="flex items-center justify-center py-8">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500 mr-3"></div>
|
||||
<div class="animate-spin h-8 w-8 border-b-2 border-blue-500 mr-3"></div>
|
||||
<span class="text-gray-600">Test en cours...</span>
|
||||
</div>
|
||||
|
||||
@@ -65,7 +58,7 @@
|
||||
<span class="font-medium">Test réussi !</span>
|
||||
</div>
|
||||
|
||||
<div class="bg-green-50 dark:bg-green-900 border border-green-200 dark:border-green-700 rounded-lg p-4">
|
||||
<div class="bg-green-50 dark:bg-green-900 border border-green-200 dark:border-green-700 p-4">
|
||||
<div class="grid grid-cols-2 gap-4 text-sm">
|
||||
<div>
|
||||
<span class="font-medium text-green-800 dark:text-green-200">URL testée:</span>
|
||||
@@ -92,10 +85,10 @@
|
||||
<img
|
||||
:src="imageUrl"
|
||||
:alt="`Image ${index + 1}`"
|
||||
class="w-full h-32 object-cover rounded border border-gray-200 dark:border-gray-600"
|
||||
class="w-full h-32 object-cover border border-gray-200 dark:border-gray-600"
|
||||
@error="handleImageError"
|
||||
@load="handleImageLoad" />
|
||||
<div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-30 transition-opacity rounded flex items-center justify-center">
|
||||
<div class="absolute inset-0 bg-black bg-opacity-0 group-hover:bg-opacity-30 transition-opacity flex items-center justify-center">
|
||||
<span class="text-white opacity-0 group-hover:opacity-100 text-sm font-medium">
|
||||
Page {{ index + 1 }}
|
||||
</span>
|
||||
@@ -107,7 +100,7 @@
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div v-else class="bg-yellow-50 dark:bg-yellow-900 border border-yellow-200 dark:border-yellow-700 rounded-lg p-4">
|
||||
<div v-else class="bg-yellow-50 dark:bg-yellow-900 border border-yellow-200 dark:border-yellow-700 p-4">
|
||||
<div class="flex items-center">
|
||||
<ExclamationTriangleIcon class="w-5 h-5 text-yellow-400 mr-2" />
|
||||
<p class="text-yellow-800 dark:text-yellow-200">
|
||||
@@ -125,7 +118,7 @@
|
||||
<span class="font-medium">Test échoué</span>
|
||||
</div>
|
||||
|
||||
<div class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 rounded-lg p-4 mb-4">
|
||||
<div class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 p-4 mb-4">
|
||||
<div class="text-sm text-red-800 dark:text-red-200">
|
||||
<div><strong>URL testée:</strong> {{ testResults.testedUrl || 'N/A' }}</div>
|
||||
<div><strong>Type de scraping:</strong> {{ testResults.scrapingType || 'N/A' }}</div>
|
||||
@@ -138,14 +131,14 @@
|
||||
<div
|
||||
v-for="(error, index) in testResults.errors"
|
||||
:key="index"
|
||||
class="bg-red-100 dark:bg-red-800 border-l-4 border-red-400 p-4 rounded">
|
||||
class="bg-red-100 dark:bg-red-800 border-l-4 border-red-400 p-4">
|
||||
<div class="flex items-start">
|
||||
<div class="flex-shrink-0">
|
||||
<ExclamationTriangleIcon class="w-5 h-5 text-red-400" />
|
||||
</div>
|
||||
<div class="ml-3 flex-1">
|
||||
<div class="flex items-center mb-1">
|
||||
<span class="inline-flex items-center px-2 py-1 rounded-full text-xs font-medium bg-red-200 text-red-800 dark:bg-red-700 dark:text-red-200 mr-2">
|
||||
<span class="inline-flex items-center px-2 py-1 text-xs font-medium bg-red-200 text-red-800 dark:bg-red-700 dark:text-red-200 mr-2">
|
||||
{{ formatErrorType(error.type) }}
|
||||
</span>
|
||||
<span class="text-sm font-medium text-red-800 dark:text-red-200">
|
||||
@@ -155,7 +148,7 @@
|
||||
<p class="text-sm text-red-700 dark:text-red-300 mb-2">
|
||||
{{ error.message }}
|
||||
</p>
|
||||
<div class="bg-red-50 dark:bg-red-900 rounded p-2">
|
||||
<div class="bg-red-50 dark:bg-red-900 p-2">
|
||||
<p class="text-xs text-red-600 dark:text-red-400">
|
||||
<strong>Suggestion :</strong> {{ error.suggestion }}
|
||||
</p>
|
||||
@@ -166,7 +159,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Generic Error -->
|
||||
<div v-else-if="testResults.error" class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 rounded p-3">
|
||||
<div v-else-if="testResults.error" class="bg-red-50 dark:bg-red-900 border border-red-200 dark:border-red-700 p-3">
|
||||
<code class="text-sm text-red-800 dark:text-red-200">
|
||||
{{ testResults.error }}
|
||||
</code>
|
||||
@@ -177,7 +170,7 @@
|
||||
</div>
|
||||
|
||||
<!-- Success Message -->
|
||||
<div v-if="showSuccessMessage" class="fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 rounded-lg shadow-lg">
|
||||
<div v-if="showSuccessMessage" class="fixed bottom-4 right-4 bg-green-500 text-white px-4 py-2 shadow-lg">
|
||||
Configuration {{ isEditing ? 'mise à jour' : 'créée' }} avec succès !
|
||||
</div>
|
||||
</div>
|
||||
@@ -190,6 +183,7 @@ import {
|
||||
ArrowLeftIcon,
|
||||
CheckCircleIcon,
|
||||
ExclamationTriangleIcon,
|
||||
PencilSquareIcon,
|
||||
XCircleIcon,
|
||||
XMarkIcon
|
||||
} from '@heroicons/vue/24/outline';
|
||||
@@ -214,6 +208,9 @@ const {
|
||||
saveError
|
||||
} = storeToRefs(contentSourceStore);
|
||||
|
||||
// Form ref
|
||||
const formRef = ref(null);
|
||||
|
||||
// Local state
|
||||
const showTestResults = ref(false);
|
||||
const showSuccessMessage = ref(false);
|
||||
@@ -233,16 +230,18 @@ onMounted(async () => {
|
||||
});
|
||||
|
||||
// Toolbar configuration
|
||||
const toolbarConfig = {
|
||||
leftSection: [],
|
||||
rightSection: []
|
||||
};
|
||||
const toolbarConfig = computed(() => ({
|
||||
leftSection: [
|
||||
{ type: 'button', icon: ArrowLeftIcon, label: 'Retour', onClick: () => router.push({ name: 'scrapper-configurations' }) },
|
||||
{ type: 'divider' },
|
||||
{ type: 'label', text: isEditing.value ? 'Modifier la configuration' : 'Nouvelle configuration', class: 'text-sm font-medium' },
|
||||
],
|
||||
rightSection: [
|
||||
{ type: 'button', icon: PencilSquareIcon, label: isEditing.value ? 'Mettre à jour' : 'Créer', onClick: () => formRef.value?.submitForm(), disabled: saving.value },
|
||||
],
|
||||
}));
|
||||
|
||||
// Actions
|
||||
const goBack = () => {
|
||||
router.push({ name: 'scrapper-configurations' });
|
||||
};
|
||||
|
||||
const handleSubmit = async (formData) => {
|
||||
try {
|
||||
if (isEditing.value) {
|
||||
|
||||
Reference in New Issue
Block a user