mirror of
https://github.com/R0m1k3/Priceflow.git
synced 2026-10-24 15:48:11 +02:00
Merge pull request #217 from R0m1k3/antigravity
feat: Add automated item checking scheduler service and new dashboard…
This commit is contained in:
3 files changed
+24
-12
No files matched your search
@@ -135,6 +135,18 @@ async def process_item_check(item_id: int):
|
|||||||
if not screenshot_path:
|
if not screenshot_path:
|
||||||
raise Exception("Failed to capture screenshot")
|
raise Exception("Failed to capture screenshot")
|
||||||
|
|
||||||
|
# Update the main item screenshot for the UI
|
||||||
|
try:
|
||||||
|
import shutil
|
||||||
|
import os
|
||||||
|
dest_path = f"/app/screenshots/item_{item_id}.png"
|
||||||
|
# Ensure directory exists
|
||||||
|
os.makedirs(os.path.dirname(dest_path), exist_ok=True)
|
||||||
|
shutil.copy2(screenshot_path, dest_path)
|
||||||
|
logger.info(f"Updated main screenshot for item {item_id}")
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Failed to update main screenshot: {e}")
|
||||||
|
|
||||||
if not (ai_result := await AIService.analyze_image(screenshot_path, page_text=page_text)):
|
if not (ai_result := await AIService.analyze_image(screenshot_path, page_text=page_text)):
|
||||||
raise Exception("AI analysis failed")
|
raise Exception("AI analysis failed")
|
||||||
|
|
||||||
|
|||||||
@@ -245,17 +245,17 @@ export function ItemCard({ item, onEdit, onDelete, onCheck, onZoom, onCategoryUp
|
|||||||
|
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
{onViewHistory && (
|
{onViewHistory && (
|
||||||
<Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => onViewHistory(item)} title="Historique des prix">
|
<Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => onViewHistory(item)} title={t('dashboard.history') || "Historique"}>
|
||||||
<History className="h-3 w-3" />
|
<History className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
<Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => onEdit(item)}>
|
<Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => onEdit(item)} title={t('common.edit') || "Modifier"}>
|
||||||
<Edit2 className="h-3 w-3" />
|
<Edit2 className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => onCheck(item.id)} disabled={item.is_refreshing}>
|
<Button variant="ghost" size="icon" className="h-6 w-6" onClick={() => onCheck(item.id)} disabled={item.is_refreshing} title={t('dashboard.refresh') || "Forcer la mise à jour"}>
|
||||||
<RefreshCw className={cn("h-3 w-3", item.is_refreshing && "animate-spin text-primary")} />
|
<RefreshCw className={cn("h-3 w-3", item.is_refreshing && "animate-spin text-primary")} />
|
||||||
</Button>
|
</Button>
|
||||||
<Button variant="ghost" size="icon" className="h-6 w-6 text-destructive hover:text-destructive" onClick={() => onDelete(item)}>
|
<Button variant="ghost" size="icon" className="h-6 w-6 text-destructive hover:text-destructive" onClick={() => onDelete(item)} title={t('common.delete') || "Supprimer"}>
|
||||||
<Trash2 className="h-3 w-3" />
|
<Trash2 className="h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ export function ItemModal({ item, onClose, onSaved, open, categories = [] }) {
|
|||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Input
|
<Input
|
||||||
id="custom_category"
|
id="custom_category"
|
||||||
placeholder="Enter new category"
|
placeholder="Entrer une nouvelle catégorie"
|
||||||
value={formData.category}
|
value={formData.category}
|
||||||
onChange={e => setFormData({ ...formData, category: e.target.value })}
|
onChange={e => setFormData({ ...formData, category: e.target.value })}
|
||||||
autoFocus
|
autoFocus
|
||||||
@@ -151,7 +151,7 @@ export function ItemModal({ item, onClose, onSaved, open, categories = [] }) {
|
|||||||
setShowCustomInput(false);
|
setShowCustomInput(false);
|
||||||
setFormData({ ...formData, category: '' });
|
setFormData({ ...formData, category: '' });
|
||||||
}}
|
}}
|
||||||
title="Select existing category"
|
title="Sélectionner une catégorie existante"
|
||||||
>
|
>
|
||||||
<X className="h-4 w-4" />
|
<X className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
@@ -171,30 +171,30 @@ export function ItemModal({ item, onClose, onSaved, open, categories = [] }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-full">
|
<SelectTrigger className="w-full">
|
||||||
<SelectValue placeholder="Select a category" />
|
<SelectValue placeholder="Sélectionner une catégorie" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="none">None</SelectItem>
|
<SelectItem value="none">Aucune</SelectItem>
|
||||||
{categories.map(cat => (
|
{categories.map(cat => (
|
||||||
<SelectItem key={cat} value={cat}>{cat}</SelectItem>
|
<SelectItem key={cat} value={cat}>{cat}</SelectItem>
|
||||||
))}
|
))}
|
||||||
<SelectItem value="__custom__">Custom...</SelectItem>
|
<SelectItem value="__custom__">Autre...</SelectItem>
|
||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="channel">Notification Channel</Label>
|
<Label htmlFor="channel">Canal de Notification</Label>
|
||||||
<Select
|
<Select
|
||||||
value={formData.notification_channel_id}
|
value={formData.notification_channel_id}
|
||||||
onValueChange={(val) => setFormData({ ...formData, notification_channel_id: val })}
|
onValueChange={(val) => setFormData({ ...formData, notification_channel_id: val })}
|
||||||
>
|
>
|
||||||
<SelectTrigger>
|
<SelectTrigger>
|
||||||
<SelectValue placeholder="Select a channel" />
|
<SelectValue placeholder="Sélectionner un canal" />
|
||||||
</SelectTrigger>
|
</SelectTrigger>
|
||||||
<SelectContent>
|
<SelectContent>
|
||||||
<SelectItem value="none">None</SelectItem>
|
<SelectItem value="none">Aucun</SelectItem>
|
||||||
{channels.map(channel => (
|
{channels.map(channel => (
|
||||||
<SelectItem key={channel.id} value={channel.id.toString()}>
|
<SelectItem key={channel.id} value={channel.id.toString()}>
|
||||||
{channel.name} ({channel.type})
|
{channel.name} ({channel.type})
|
||||||
|
|||||||
Reference in new issue
Block a user