fix fix fi x fix
This commit is contained in:
@@ -2,6 +2,7 @@ import { useState, useEffect, useCallback } from 'react';
|
||||
import PageMeta from '../../components/common/PageMeta';
|
||||
import SiteCard from '../../components/common/SiteCard';
|
||||
import FormModal, { FormField } from '../../components/common/FormModal';
|
||||
import ConfirmDialog from '../../components/common/ConfirmDialog';
|
||||
import Button from '../../components/ui/button/Button';
|
||||
import { useToast } from '../../components/ui/toast/ToastContainer';
|
||||
import Alert from '../../components/ui/alert/Alert';
|
||||
@@ -39,6 +40,9 @@ export default function Sites() {
|
||||
const [showSiteModal, setShowSiteModal] = useState(false);
|
||||
const [showSectorsModal, setShowSectorsModal] = useState(false);
|
||||
const [showDetailsModal, setShowDetailsModal] = useState(false);
|
||||
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
|
||||
const [siteToDelete, setSiteToDelete] = useState<Site | null>(null);
|
||||
const [isDeleting, setIsDeleting] = useState(false);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [togglingSiteId, setTogglingSiteId] = useState<number | null>(null);
|
||||
const [industries, setIndustries] = useState<Industry[]>([]);
|
||||
@@ -293,13 +297,17 @@ export default function Sites() {
|
||||
};
|
||||
|
||||
|
||||
const handleDeleteSite = async (site: Site) => {
|
||||
if (!window.confirm(`Are you sure you want to delete "${site.name}"? This action cannot be undone.`)) {
|
||||
return;
|
||||
}
|
||||
const handleDeleteSite = (site: Site) => {
|
||||
setSiteToDelete(site);
|
||||
setShowDeleteConfirm(true);
|
||||
};
|
||||
|
||||
const confirmDeleteSite = async () => {
|
||||
if (!siteToDelete) return;
|
||||
|
||||
setIsDeleting(true);
|
||||
try {
|
||||
await deleteSite(site.id);
|
||||
await deleteSite(siteToDelete.id);
|
||||
toast.success('Site deleted successfully');
|
||||
await loadSites();
|
||||
if (showDetailsModal) {
|
||||
@@ -307,6 +315,10 @@ export default function Sites() {
|
||||
}
|
||||
} catch (error: any) {
|
||||
toast.error(`Failed to delete site: ${error.message}`);
|
||||
} finally {
|
||||
setIsDeleting(false);
|
||||
setShowDeleteConfirm(false);
|
||||
setSiteToDelete(null);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -604,6 +616,22 @@ export default function Sites() {
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Delete Confirmation Dialog */}
|
||||
<ConfirmDialog
|
||||
isOpen={showDeleteConfirm}
|
||||
onClose={() => {
|
||||
setShowDeleteConfirm(false);
|
||||
setSiteToDelete(null);
|
||||
}}
|
||||
onConfirm={confirmDeleteSite}
|
||||
title="Delete Site"
|
||||
message={`Are you sure you want to delete "${siteToDelete?.name}"? This action cannot be undone.`}
|
||||
confirmText="Delete"
|
||||
cancelText="Cancel"
|
||||
variant="danger"
|
||||
isLoading={isDeleting}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -49,6 +49,17 @@ interface ContentGenerationSettings {
|
||||
defaultLength: string;
|
||||
}
|
||||
|
||||
// AI Model Config from API
|
||||
interface AIModelConfig {
|
||||
model_name: string;
|
||||
display_name: string;
|
||||
model_type: string;
|
||||
provider: string;
|
||||
valid_sizes?: string[];
|
||||
quality_tier?: string;
|
||||
credits_per_image?: number;
|
||||
}
|
||||
|
||||
// Map user-friendly quality to internal service/model configuration
|
||||
const QUALITY_TO_CONFIG: Record<string, { service: 'openai' | 'runware'; model: string }> = {
|
||||
standard: { service: 'openai', model: 'dall-e-2' },
|
||||
@@ -63,8 +74,24 @@ const getQualityFromConfig = (service?: string, model?: string): 'standard' | 'p
|
||||
return 'standard';
|
||||
};
|
||||
|
||||
// Get available image sizes based on provider and model
|
||||
const getImageSizes = (provider: string, model: string) => {
|
||||
|
||||
// Get available image sizes based on provider and model (from API or fallback)
|
||||
const getImageSizes = (provider: string, model: string, imageModels: AIModelConfig[]) => {
|
||||
// First, try to find the model in the fetched models
|
||||
const modelConfig = imageModels.find(m =>
|
||||
m.model_name === model ||
|
||||
(m.provider === provider && m.model_name.includes(model))
|
||||
);
|
||||
|
||||
// If found and has valid_sizes, use them
|
||||
if (modelConfig?.valid_sizes && modelConfig.valid_sizes.length > 0) {
|
||||
return modelConfig.valid_sizes.map(size => ({
|
||||
value: size,
|
||||
label: `${size.replace('x', '×')} pixels`
|
||||
}));
|
||||
}
|
||||
|
||||
// Fallback to hardcoded sizes for backward compatibility
|
||||
if (provider === 'runware') {
|
||||
return [
|
||||
{ value: '1280x832', label: '1280×832 pixels' },
|
||||
@@ -101,6 +128,9 @@ export default function ContentSettingsPage() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [saving, setSaving] = useState(false);
|
||||
|
||||
// Image Models from API - for dynamic size options
|
||||
const [imageModels, setImageModels] = useState<AIModelConfig[]>([]);
|
||||
|
||||
// Content Generation Settings
|
||||
const [contentSettings, setContentSettings] = useState<ContentGenerationSettings>({
|
||||
appendToPrompt: '',
|
||||
@@ -141,20 +171,21 @@ export default function ContentSettingsPage() {
|
||||
};
|
||||
}, [imageQuality]);
|
||||
|
||||
// Get available sizes for current quality
|
||||
// Get available sizes for current quality (uses imageModels from API)
|
||||
const availableSizes = getImageSizes(
|
||||
getCurrentConfig().service,
|
||||
getCurrentConfig().model
|
||||
getCurrentConfig().model,
|
||||
imageModels
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
loadSettings();
|
||||
}, []);
|
||||
|
||||
// Update image sizes when quality changes
|
||||
// Update image sizes when quality changes or imageModels are loaded
|
||||
useEffect(() => {
|
||||
const config = getCurrentConfig();
|
||||
const sizes = getImageSizes(config.service, config.model);
|
||||
const sizes = getImageSizes(config.service, config.model, imageModels);
|
||||
const defaultSize = sizes.length > 0 ? sizes[0].value : '1024x1024';
|
||||
|
||||
const validSizes = sizes.map(s => s.value);
|
||||
@@ -178,12 +209,24 @@ export default function ContentSettingsPage() {
|
||||
model: config.model,
|
||||
}));
|
||||
}
|
||||
}, [imageQuality, getCurrentConfig]);
|
||||
}, [imageQuality, getCurrentConfig, imageModels]);
|
||||
|
||||
const loadSettings = async () => {
|
||||
try {
|
||||
setLoading(true);
|
||||
|
||||
// Load available image models from API (for dynamic sizes)
|
||||
try {
|
||||
const modelsResponse = await fetchAPI('/v1/billing/models/?type=image');
|
||||
if (modelsResponse?.data) {
|
||||
setImageModels(modelsResponse.data);
|
||||
} else if (Array.isArray(modelsResponse)) {
|
||||
setImageModels(modelsResponse);
|
||||
}
|
||||
} catch (err) {
|
||||
console.log('Image models not available, using hardcoded sizes');
|
||||
}
|
||||
|
||||
// Load image generation settings
|
||||
const imageData = await fetchAPI('/v1/system/settings/integrations/image_generation/');
|
||||
if (imageData) {
|
||||
|
||||
Reference in New Issue
Block a user