mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-16 19:59:42 +02:00
feat: Add MinIO endpoint/public URL configuration via settings UI
Store endpointUrl and publicUrl in cloudinary_config DB table so MinIO connection can be fully configured from the app settings without needing environment variables. - DB migration: adds endpoint_url and public_url columns - Schema: adds endpointUrl/publicUrl to cloudinaryConfig table - MinIO service: reads endpoint from DB (falls back to MINIO_ENDPOINT env) - buildMinioUrl: accepts optional publicUrl override from DB config - All routes updated to pass config.publicUrl to buildMinioUrl - Settings UI (desktop + mobile): adds Endpoint URL and Public URL fields Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
841ffb306c
commit
ba94e7cc7d
8 files changed
+105
-21
No files matched your search
@@ -20,6 +20,8 @@ export default function SettingsMobile() {
|
||||
const [cloudName, setCloudName] = useState("");
|
||||
const [apiKey, setApiKey] = useState("");
|
||||
const [apiSecret, setApiSecret] = useState("");
|
||||
const [endpointUrl, setEndpointUrl] = useState("");
|
||||
const [publicUrl, setPublicUrl] = useState("");
|
||||
const [openrouterApiKey, setOpenrouterApiKey] = useState("");
|
||||
const [openrouterModel, setOpenrouterModel] = useState("anthropic/claude-3.5-sonnet");
|
||||
const [openrouterSystemPrompt, setOpenrouterSystemPrompt] = useState("Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
||||
@@ -50,6 +52,8 @@ export default function SettingsMobile() {
|
||||
if (cloudinaryConfig) {
|
||||
setCloudName((cloudinaryConfig as any).cloudName || "");
|
||||
setApiKey((cloudinaryConfig as any).apiKey || "");
|
||||
setEndpointUrl((cloudinaryConfig as any).endpointUrl || "");
|
||||
setPublicUrl((cloudinaryConfig as any).publicUrl || "");
|
||||
|
||||
if ((cloudinaryConfig as any).logoUrl) {
|
||||
setLogoPreview((cloudinaryConfig as any).logoUrl);
|
||||
@@ -70,6 +74,8 @@ export default function SettingsMobile() {
|
||||
mutationFn: () => {
|
||||
const payload: any = {
|
||||
cloudName,
|
||||
endpointUrl: endpointUrl || undefined,
|
||||
publicUrl: publicUrl || undefined,
|
||||
};
|
||||
|
||||
if (apiKey && apiKey.trim() !== "") {
|
||||
@@ -368,7 +374,7 @@ export default function SettingsMobile() {
|
||||
Configuration Stockage MinIO
|
||||
</CardTitle>
|
||||
<CardDescription className="text-xs">
|
||||
Configurez MinIO pour le stockage des médias (endpoint via variable MINIO_ENDPOINT)
|
||||
Configurez MinIO pour le stockage des médias
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4 p-5 pt-0">
|
||||
@@ -414,6 +420,36 @@ export default function SettingsMobile() {
|
||||
Votre Secret Key restera sécurisé et ne sera jamais exposé
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="endpointUrl" className="text-sm">URL Endpoint (interne)</Label>
|
||||
<Input
|
||||
id="endpointUrl"
|
||||
type="url"
|
||||
value={endpointUrl}
|
||||
onChange={(e) => setEndpointUrl(e.target.value)}
|
||||
placeholder="http://minio:9000"
|
||||
className="min-h-[48px]"
|
||||
data-testid="input-endpoint-url"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
URL interne de votre serveur MinIO (ex: http://192.168.1.10:9000)
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="publicUrl" className="text-sm">URL Publique</Label>
|
||||
<Input
|
||||
id="publicUrl"
|
||||
type="url"
|
||||
value={publicUrl}
|
||||
onChange={(e) => setPublicUrl(e.target.value)}
|
||||
placeholder="https://media.votre-domaine.com"
|
||||
className="min-h-[48px]"
|
||||
data-testid="input-public-url"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
URL publique pour accéder aux fichiers depuis internet
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => saveCloudinaryMutation.mutate()}
|
||||
disabled={saveCloudinaryMutation.isPending || !cloudName || !apiKey || !apiSecret}
|
||||
|
||||
@@ -20,6 +20,8 @@ export default function Settings() {
|
||||
const [cloudName, setCloudName] = useState("");
|
||||
const [apiKey, setApiKey] = useState("");
|
||||
const [apiSecret, setApiSecret] = useState("");
|
||||
const [endpointUrl, setEndpointUrl] = useState("");
|
||||
const [publicUrl, setPublicUrl] = useState("");
|
||||
const [openrouterApiKey, setOpenrouterApiKey] = useState("");
|
||||
const [openrouterModel, setOpenrouterModel] = useState("anthropic/claude-3.5-sonnet");
|
||||
const [openrouterSystemPrompt, setOpenrouterSystemPrompt] = useState("Tu es un expert en marketing des réseaux sociaux. Génère 3 variations de textes engageants pour des publications Facebook et Instagram à partir des informations produit fournies. Chaque variation doit être unique, captivante et optimisée pour l'engagement.");
|
||||
@@ -56,6 +58,8 @@ export default function Settings() {
|
||||
if (cloudinaryConfig) {
|
||||
setCloudName((cloudinaryConfig as any).cloudName || "");
|
||||
setApiKey((cloudinaryConfig as any).apiKey || "");
|
||||
setEndpointUrl((cloudinaryConfig as any).endpointUrl || "");
|
||||
setPublicUrl((cloudinaryConfig as any).publicUrl || "");
|
||||
|
||||
if ((cloudinaryConfig as any).logoUrl) {
|
||||
setLogoPreview((cloudinaryConfig as any).logoUrl);
|
||||
@@ -129,6 +133,8 @@ export default function Settings() {
|
||||
mutationFn: () => {
|
||||
const payload: any = {
|
||||
cloudName,
|
||||
endpointUrl: endpointUrl || undefined,
|
||||
publicUrl: publicUrl || undefined,
|
||||
};
|
||||
|
||||
// N'inclure apiKey et apiSecret que s'ils ne sont pas vides
|
||||
@@ -455,7 +461,7 @@ export default function Settings() {
|
||||
Configuration Stockage MinIO
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Configurez MinIO pour le stockage des médias (endpoint configuré via variable d'environnement MINIO_ENDPOINT)
|
||||
Configurez MinIO pour le stockage des médias
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
@@ -498,6 +504,34 @@ export default function Settings() {
|
||||
Votre Secret Key restera sécurisé et ne sera jamais exposé
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="endpointUrl">URL Endpoint (interne)</Label>
|
||||
<Input
|
||||
id="endpointUrl"
|
||||
type="url"
|
||||
value={endpointUrl}
|
||||
onChange={(e) => setEndpointUrl(e.target.value)}
|
||||
placeholder="http://minio:9000"
|
||||
data-testid="input-endpoint-url"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
URL interne de votre serveur MinIO (ex: http://minio:9000 ou http://192.168.1.10:9000)
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="publicUrl">URL Publique</Label>
|
||||
<Input
|
||||
id="publicUrl"
|
||||
type="url"
|
||||
value={publicUrl}
|
||||
onChange={(e) => setPublicUrl(e.target.value)}
|
||||
placeholder="https://media.votre-domaine.com"
|
||||
data-testid="input-public-url"
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
URL publique pour accéder aux fichiers depuis internet (ex: https://media.example.com)
|
||||
</p>
|
||||
</div>
|
||||
<Button
|
||||
onClick={() => saveCloudinaryMutation.mutate()}
|
||||
disabled={saveCloudinaryMutation.isPending || !cloudName || !apiKey || !apiSecret}
|
||||
|
||||
Reference in new issue
Block a user