frontend changes
This commit is contained in:
parent
952f260b5c
commit
fd3c81a560
@ -56,6 +56,8 @@ function AdminDashboardContent() {
|
|||||||
|
|
||||||
const { unreadCount, removeByReference } = useAdminNotifications()
|
const { unreadCount, removeByReference } = useAdminNotifications()
|
||||||
|
|
||||||
|
console.log("pendingFeatures__", pendingFeatures)
|
||||||
|
|
||||||
// Load dashboard data
|
// Load dashboard data
|
||||||
const loadDashboardData = async () => {
|
const loadDashboardData = async () => {
|
||||||
try {
|
try {
|
||||||
@ -184,18 +186,9 @@ function AdminDashboardContent() {
|
|||||||
// Get the feature details first
|
// Get the feature details first
|
||||||
const feature = pendingFeatures.find(f => f.id === item.id)
|
const feature = pendingFeatures.find(f => f.id === item.id)
|
||||||
if (feature) {
|
if (feature) {
|
||||||
// Create new approved feature in main template_features table
|
// Only update the custom feature status to approved
|
||||||
await adminApi.createApprovedFeature({
|
// The backend reviewFeature method will handle mirroring to template_features if needed
|
||||||
template_id: feature.template_id,
|
await adminApi.reviewCustomFeature(item.id, { status: 'approved', admin_notes: 'Approved by admin' })
|
||||||
name: feature.name,
|
|
||||||
description: feature.description,
|
|
||||||
complexity: feature.complexity,
|
|
||||||
business_rules: feature.business_rules,
|
|
||||||
technical_requirements: feature.technical_requirements
|
|
||||||
})
|
|
||||||
|
|
||||||
// Update the custom feature status to approved
|
|
||||||
await adminApi.reviewCustomFeature(item.id, { status: 'approved', admin_notes: 'Approved and created in main templates' })
|
|
||||||
|
|
||||||
// already optimistically removed
|
// already optimistically removed
|
||||||
// Remove related notifications for this feature
|
// Remove related notifications for this feature
|
||||||
@ -532,7 +525,7 @@ function AdminDashboardContent() {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="flex items-center space-x-4 text-sm text-gray-500">
|
<div className="flex items-center space-x-4 text-sm text-gray-500">
|
||||||
<span>Template: {feature.template_title || 'Unknown'}</span>
|
<span>Template Type: {feature.template_type || 'Unknown'}</span>
|
||||||
<span>Submitted: {formatDate(feature.created_at)}</span>
|
<span>Submitted: {formatDate(feature.created_at)}</span>
|
||||||
{feature.similarity_score && (
|
{feature.similarity_score && (
|
||||||
<span>Similarity: {(feature.similarity_score * 100).toFixed(1)}%</span>
|
<span>Similarity: {(feature.similarity_score * 100).toFixed(1)}%</span>
|
||||||
|
|||||||
@ -904,9 +904,21 @@ function FeatureSelectionStep({
|
|||||||
const load = async () => {
|
const load = async () => {
|
||||||
try {
|
try {
|
||||||
setLoading(true)
|
setLoading(true)
|
||||||
|
console.log('[FeatureSelectionStep] Loading features for template:', template.id)
|
||||||
|
console.log('[FeatureSelectionStep] Template object:', template)
|
||||||
const data = await fetchFeatures(template.id)
|
const data = await fetchFeatures(template.id)
|
||||||
|
console.log('[FeatureSelectionStep] Raw features received:', data)
|
||||||
|
console.log('[FeatureSelectionStep] API endpoint called:', `/api/templates/${template.id}/features`)
|
||||||
|
console.log('[FeatureSelectionStep] Features by type:', {
|
||||||
|
essential: data.filter(f => f.feature_type === 'essential').length,
|
||||||
|
suggested: data.filter(f => f.feature_type === 'suggested').length,
|
||||||
|
custom: data.filter(f => f.feature_type === 'custom').length,
|
||||||
|
total: data.length
|
||||||
|
})
|
||||||
|
console.log('[FeatureSelectionStep] All features with types:', data.map(f => ({ name: f.name, type: f.feature_type })))
|
||||||
setFeatures(data)
|
setFeatures(data)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.error('[FeatureSelectionStep] Error loading features:', e)
|
||||||
setError(e instanceof Error ? e.message : 'Failed to load features')
|
setError(e instanceof Error ? e.message : 'Failed to load features')
|
||||||
} finally {
|
} finally {
|
||||||
setLoading(false)
|
setLoading(false)
|
||||||
@ -1076,8 +1088,7 @@ function FeatureSelectionStep({
|
|||||||
<p className="text-xl text-white/60 max-w-3xl mx-auto">Choose defaults or add your own custom features.</p>
|
<p className="text-xl text-white/60 max-w-3xl mx-auto">Choose defaults or add your own custom features.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{section('Essential Features', essentials)}
|
{features.length > 0 && section('Template Features', features)}
|
||||||
{/* {section('Suggested Features', suggested)} */}
|
|
||||||
|
|
||||||
{/* Add custom feature with AI */}
|
{/* Add custom feature with AI */}
|
||||||
<div className="bg-white/5 border border-white/10 rounded-xl p-6 space-y-4">
|
<div className="bg-white/5 border border-white/10 rounded-xl p-6 space-y-4">
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Main backend URL - change this to update all API calls
|
// Main backend URL - change this to update all API calls
|
||||||
export const BACKEND_URL = 'http://192.168.1.25:8000';
|
export const BACKEND_URL = 'http://192.168.1.20:8000';
|
||||||
// export const BACKEND_URL = 'https://backend.codenuk.com';
|
// export const BACKEND_URL = 'https://backend.codenuk.com';
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -54,7 +54,6 @@ export interface TemplatesByCategory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class TemplateService {
|
class TemplateService {
|
||||||
private async makeRequest<T>(endpoint: string, requireAuth: boolean = false): Promise<T> {
|
private async makeRequest<T>(endpoint: string, requireAuth: boolean = false): Promise<T> {
|
||||||
try {
|
try {
|
||||||
@ -391,9 +390,9 @@ class TemplateService {
|
|||||||
|
|
||||||
const toKey = (f: TemplateFeature) => {
|
const toKey = (f: TemplateFeature) => {
|
||||||
const normName = (f.name || '').trim().toLowerCase()
|
const normName = (f.name || '').trim().toLowerCase()
|
||||||
// For custom features, dedupe by normalized name; for others, prefer feature_id
|
// Use normalized name for all features to enable proper deduplication
|
||||||
if (f.feature_type === 'custom') return `custom:${normName}`
|
// between template_features and custom_features tables
|
||||||
return `std:${f.feature_id || normName}`
|
return normName
|
||||||
}
|
}
|
||||||
|
|
||||||
const prefer = (a: TemplateFeature, b: TemplateFeature): TemplateFeature => {
|
const prefer = (a: TemplateFeature, b: TemplateFeature): TemplateFeature => {
|
||||||
@ -419,6 +418,12 @@ class TemplateService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
console.log('[getFeaturesForTemplate] Deduplication results:', {
|
||||||
|
originalCount: items.length,
|
||||||
|
deduplicatedCount: byKey.size,
|
||||||
|
duplicatesRemoved: items.length - byKey.size
|
||||||
|
})
|
||||||
|
|
||||||
return Array.from(byKey.values())
|
return Array.from(byKey.values())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -468,13 +473,28 @@ class TemplateService {
|
|||||||
// Only include normalized fields if valid
|
// Only include normalized fields if valid
|
||||||
business_rules: normalizeJsonField(featureData.business_rules) as CreateFeaturePayload['business_rules'],
|
business_rules: normalizeJsonField(featureData.business_rules) as CreateFeaturePayload['business_rules'],
|
||||||
logic_rules: normalizeJsonField(featureData.logic_rules) as CreateFeaturePayload['logic_rules'],
|
logic_rules: normalizeJsonField(featureData.logic_rules) as CreateFeaturePayload['logic_rules'],
|
||||||
// @ts-expect-error: allow passthrough of optional technical_requirements if present in callers
|
|
||||||
technical_requirements: normalizeJsonField((featureData as any).technical_requirements),
|
technical_requirements: normalizeJsonField((featureData as any).technical_requirements),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if this is for a custom template by checking if template exists in custom_templates
|
||||||
|
let isCustomTemplate = false
|
||||||
|
if (cleanedFeatureData.template_id) {
|
||||||
|
try {
|
||||||
|
// Check if template exists in custom_templates table
|
||||||
|
const templateCheckResponse = await fetch(`${BACKEND_URL}/api/templates/${cleanedFeatureData.template_id}`)
|
||||||
|
if (templateCheckResponse.ok) {
|
||||||
|
const templateData = await templateCheckResponse.json()
|
||||||
|
// If template has is_custom flag or comes from custom_templates, route to custom endpoint
|
||||||
|
isCustomTemplate = templateData.data?.is_custom === true || templateData.data?.template_type === 'custom'
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.warn('Could not check template type, defaulting to regular endpoint:', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
cleanedFeatureData &&
|
cleanedFeatureData &&
|
||||||
(cleanedFeatureData.feature_type === 'custom')
|
(cleanedFeatureData.feature_type === 'custom' || isCustomTemplate)
|
||||||
) {
|
) {
|
||||||
const customHeaders: Record<string, string> = { 'Content-Type': 'application/json' }
|
const customHeaders: Record<string, string> = { 'Content-Type': 'application/json' }
|
||||||
const customToken = getAccessToken()
|
const customToken = getAccessToken()
|
||||||
|
|||||||
@ -22,6 +22,7 @@ export interface AdminFeature {
|
|||||||
similarity_score?: number;
|
similarity_score?: number;
|
||||||
// Additional fields from joins
|
// Additional fields from joins
|
||||||
template_title?: string;
|
template_title?: string;
|
||||||
|
template_type?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AdminNotification {
|
export interface AdminNotification {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user