Files
Mangarr/assets/vue/app/domain/setting/presentation/components/ContentSourceCard.vue
ext.jeremy.guillot@maxicoffee.domains 795cbeccc3 feat(setting): étendre ContentSource avec champs de test et domain model
- Ajouter testSlug, testChapterNumber, baseUrl sur ContentSource (entité, domain model, migration)
- Exposer ces champs dans les Resources, Processors, Providers et Mapper
- Mettre à jour store Pinia, repository API et composants Vue (form, card, liste)
2026-03-16 00:11:17 +01:00

121 lines
4.2 KiB
Vue

<template>
<div
@click="$emit('edit', source)"
class="bg-white dark:bg-gray-800 shadow-md border border-gray-200 dark:border-gray-700 p-6 hover:shadow-lg transition-shadow duration-200 cursor-pointer">
<!-- Header avec URL et icône externe -->
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-white truncate" :title="source.cleanBaseUrl">
{{ truncateUrl(source.cleanBaseUrl) }}
</h3>
<button
@click.stop="$emit('openLink', source.baseUrl)"
class="p-1.5 text-gray-400 hover:text-gray-600 transition-colors"
title="Ouvrir le site">
<ArrowTopRightOnSquareIcon class="w-4 h-4" />
</button>
</div>
<!-- Badges -->
<div class="flex flex-wrap gap-2 mb-4">
<!-- Badge type de scraping -->
<span
:class="getScrapingTypeBadgeClass(source.scrapingType)"
class="px-2 py-1 text-xs font-medium">
{{ source.scrapingType?.toLowerCase() || 'N/A' }}
</span>
<!-- Badge orientation basé sur les sélecteurs -->
<span
:class="getOrientationBadgeClass(source)"
class="px-2 py-1 text-xs font-medium">
{{ getOrientation(source) }}
</span>
<!-- Badge health status -->
<span
:class="getHealthBadgeClass(source.healthStatus)"
class="px-2 py-1 text-xs font-medium"
:title="source.healthLastError || ''">
{{ getHealthLabel(source.healthStatus) }}
</span>
</div>
</div>
</template>
<script setup>
import { ArrowTopRightOnSquareIcon } from '@heroicons/vue/24/outline';
import { ScraperHealthStatus } from '../../domain/model/ScraperHealthStatus';
defineProps({
source: {
type: Object,
required: true
}
});
defineEmits(['edit', 'openLink']);
// Fonction pour tronquer l'URL si elle est trop longue
const truncateUrl = (url) => {
if (!url) return '';
const maxLength = 25; // Ajustez selon vos besoins
return url.length > maxLength ? url.substring(0, maxLength) + '...' : url;
};
const getScrapingTypeBadgeClass = (type) => {
switch (type?.toLowerCase()) {
case 'html':
return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300';
case 'javascript':
return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300';
default:
return 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300';
}
};
const getOrientation = (source) => {
// Logic pour déterminer l'orientation basée sur les sélecteurs ou autre logique métier
if (source.nextPageSelector) {
return 'vertical';
}
return 'horizontal';
};
const getOrientationBadgeClass = (source) => {
const orientation = getOrientation(source);
switch (orientation) {
case 'vertical':
return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300';
case 'horizontal':
return 'bg-purple-100 text-purple-800 dark:bg-purple-900 dark:text-purple-300';
default:
return 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300';
}
};
const getHealthLabel = (status) => {
switch (status) {
case ScraperHealthStatus.OK: return '✓ ok';
case ScraperHealthStatus.KO: return '✗ ko';
case ScraperHealthStatus.TESTING: return '⟳ test';
default: return '? unknown';
}
};
const getHealthBadgeClass = (status) => {
switch (status) {
case ScraperHealthStatus.OK:
return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300';
case ScraperHealthStatus.KO:
return 'bg-red-100 text-red-800 dark:bg-red-900 dark:text-red-300';
case ScraperHealthStatus.TESTING:
return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300';
default:
return 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-400';
}
};
</script>