mirror of
https://github.com/R0m1k3/Priceflow.git
synced 2026-10-23 23:28:12 +02:00
fix: SearXNG printf command + edit site modal
SearXNG: - Use proper command list format instead of shell string - Use printf with \n for proper newlines in limiter.toml - Use exec to properly start the entrypoint Edit Site Modal: - Add Dialog component import - Add siteModalOpen and editSiteData state - Create proper modal with form for editing sites - Modal opens when clicking edit button - All site fields editable in modal
This commit is contained in:
2 files changed
+110
-12
No files matched your search
+7
-10
@@ -62,16 +62,13 @@ services:
|
|||||||
- SEARXNG_SECRET=priceflow-searxng-secret
|
- SEARXNG_SECRET=priceflow-searxng-secret
|
||||||
volumes:
|
volumes:
|
||||||
- ./searxng/settings.yml:/etc/searxng/settings.yml:ro
|
- ./searxng/settings.yml:/etc/searxng/settings.yml:ro
|
||||||
command: >
|
command:
|
||||||
sh -c "
|
- sh
|
||||||
rm -rf /etc/searxng/limiter.toml &&
|
- -c
|
||||||
echo '[botdetection.ip_limit]
|
- |
|
||||||
link_token = false
|
rm -rf /etc/searxng/limiter.toml
|
||||||
[botdetection.ip_lists]
|
printf '[botdetection.ip_limit]\nlink_token = false\n\n[botdetection.ip_lists]\npass_ip = ["0.0.0.0/0", "127.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "10.0.0.0/8", "::/0"]\nblock_ip = []\n' > /etc/searxng/limiter.toml
|
||||||
pass_ip = [\"0.0.0.0/0\", \"127.0.0.0/8\", \"172.16.0.0/12\", \"192.168.0.0/16\", \"10.0.0.0/8\", \"::/0\"]
|
exec /usr/local/searxng/dockerfiles/docker-entrypoint.sh
|
||||||
block_ip = []' > /etc/searxng/limiter.toml &&
|
|
||||||
/usr/local/searxng/dockerfiles/docker-entrypoint.sh
|
|
||||||
"
|
|
||||||
networks:
|
networks:
|
||||||
- nginx_default
|
- nginx_default
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import { Switch } from '@/components/ui/switch';
|
|||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||||
import { Slider } from '@/components/ui/slider';
|
import { Slider } from '@/components/ui/slider';
|
||||||
|
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog';
|
||||||
import { cn } from '@/lib/utils';
|
import { cn } from '@/lib/utils';
|
||||||
|
|
||||||
const API_URL = '/api';
|
const API_URL = '/api';
|
||||||
@@ -58,6 +59,8 @@ export default function Settings() {
|
|||||||
const [searchSites, setSearchSites] = useState([]);
|
const [searchSites, setSearchSites] = useState([]);
|
||||||
const [newSite, setNewSite] = useState({ name: '', domain: '', category: '', is_active: true, priority: 0, requires_js: false, price_selector: '' });
|
const [newSite, setNewSite] = useState({ name: '', domain: '', category: '', is_active: true, priority: 0, requires_js: false, price_selector: '' });
|
||||||
const [editingSiteId, setEditingSiteId] = useState(null);
|
const [editingSiteId, setEditingSiteId] = useState(null);
|
||||||
|
const [siteModalOpen, setSiteModalOpen] = useState(false);
|
||||||
|
const [editSiteData, setEditSiteData] = useState(null);
|
||||||
|
|
||||||
// OpenRouter state
|
// OpenRouter state
|
||||||
const [openrouterModels, setOpenrouterModels] = useState([]);
|
const [openrouterModels, setOpenrouterModels] = useState([]);
|
||||||
@@ -260,7 +263,8 @@ export default function Settings() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const editSite = (site) => {
|
const editSite = (site) => {
|
||||||
setNewSite({
|
setEditSiteData({
|
||||||
|
id: site.id,
|
||||||
name: site.name,
|
name: site.name,
|
||||||
domain: site.domain,
|
domain: site.domain,
|
||||||
category: site.category || '',
|
category: site.category || '',
|
||||||
@@ -269,7 +273,21 @@ export default function Settings() {
|
|||||||
requires_js: site.requires_js,
|
requires_js: site.requires_js,
|
||||||
price_selector: site.price_selector || ''
|
price_selector: site.price_selector || ''
|
||||||
});
|
});
|
||||||
setEditingSiteId(site.id);
|
setSiteModalOpen(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleEditSiteSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
if (!editSiteData) return;
|
||||||
|
try {
|
||||||
|
await axios.put(`${API_URL}/search-sites/${editSiteData.id}`, editSiteData);
|
||||||
|
toast.success('Site mis à jour');
|
||||||
|
setSiteModalOpen(false);
|
||||||
|
setEditSiteData(null);
|
||||||
|
fetchAll();
|
||||||
|
} catch (error) {
|
||||||
|
toast.error('Erreur lors de la mise à jour');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const cancelSiteEdit = () => {
|
const cancelSiteEdit = () => {
|
||||||
@@ -836,6 +854,89 @@ export default function Settings() {
|
|||||||
</div>
|
</div>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|
||||||
|
{/* Modal d'édition de site */}
|
||||||
|
<Dialog open={siteModalOpen} onOpenChange={setSiteModalOpen}>
|
||||||
|
<DialogContent className="sm:max-w-[500px]">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Modifier le site</DialogTitle>
|
||||||
|
</DialogHeader>
|
||||||
|
{editSiteData && (
|
||||||
|
<form onSubmit={handleEditSiteSubmit} className="space-y-4">
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Nom du site</Label>
|
||||||
|
<Input
|
||||||
|
required
|
||||||
|
value={editSiteData.name}
|
||||||
|
onChange={(e) => setEditSiteData({ ...editSiteData, name: e.target.value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Domaine</Label>
|
||||||
|
<Input
|
||||||
|
required
|
||||||
|
value={editSiteData.domain}
|
||||||
|
onChange={(e) => setEditSiteData({ ...editSiteData, domain: e.target.value })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="grid grid-cols-2 gap-4">
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Catégorie</Label>
|
||||||
|
<Input
|
||||||
|
value={editSiteData.category}
|
||||||
|
onChange={(e) => setEditSiteData({ ...editSiteData, category: e.target.value })}
|
||||||
|
placeholder="ex: Électronique"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Priorité</Label>
|
||||||
|
<Input
|
||||||
|
type="number"
|
||||||
|
min="0"
|
||||||
|
value={editSiteData.priority}
|
||||||
|
onChange={(e) => setEditSiteData({ ...editSiteData, priority: parseInt(e.target.value) || 0 })}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<Label>Sélecteur CSS (prix)</Label>
|
||||||
|
<Input
|
||||||
|
value={editSiteData.price_selector}
|
||||||
|
onChange={(e) => setEditSiteData({ ...editSiteData, price_selector: e.target.value })}
|
||||||
|
placeholder="ex: .price, #product-price"
|
||||||
|
/>
|
||||||
|
<p className="text-xs text-muted-foreground">Sélecteur CSS pour extraire le prix</p>
|
||||||
|
</div>
|
||||||
|
<div className="flex gap-4">
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Switch
|
||||||
|
checked={editSiteData.is_active}
|
||||||
|
onCheckedChange={(checked) => setEditSiteData({ ...editSiteData, is_active: checked })}
|
||||||
|
/>
|
||||||
|
<Label>Actif</Label>
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center space-x-2">
|
||||||
|
<Switch
|
||||||
|
checked={editSiteData.requires_js}
|
||||||
|
onCheckedChange={(checked) => setEditSiteData({ ...editSiteData, requires_js: checked })}
|
||||||
|
/>
|
||||||
|
<Label>Nécessite JavaScript</Label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<DialogFooter>
|
||||||
|
<Button type="button" variant="outline" onClick={() => setSiteModalOpen(false)}>
|
||||||
|
Annuler
|
||||||
|
</Button>
|
||||||
|
<Button type="submit">
|
||||||
|
Enregistrer
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</form>
|
||||||
|
)}
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user