feat: Replace all admin placeholders with real Directus-connected components (Geo, Spintax, Cartesian, Logs)
This commit is contained in:
79
frontend/src/components/admin/content/CartesianManager.tsx
Normal file
79
frontend/src/components/admin/content/CartesianManager.tsx
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { getDirectusClient } from '@/lib/directus/client';
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
|
||||||
|
export default function CartesianManager() {
|
||||||
|
const [patterns, setPatterns] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
|
try {
|
||||||
|
const directus = await getDirectusClient();
|
||||||
|
const response = await directus.request({
|
||||||
|
method: 'GET',
|
||||||
|
path: '/items/cartesian_patterns'
|
||||||
|
});
|
||||||
|
setPatterns(response.data || []);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading cartesian patterns:', error);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <div className="text-white">Loading Cartesian Patterns...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 gap-6">
|
||||||
|
{patterns.map((group) => (
|
||||||
|
<Card key={group.id} className="bg-slate-800 border-slate-700">
|
||||||
|
<CardHeader className="pb-2">
|
||||||
|
<CardTitle className="text-white flex justify-between items-center">
|
||||||
|
<span>{group.pattern_key.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase())}</span>
|
||||||
|
<Badge variant="outline" className="text-purple-400 border-purple-400">
|
||||||
|
{group.pattern_type}
|
||||||
|
</Badge>
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
{(group.data || []).map((pattern, i) => (
|
||||||
|
<div key={i} className="bg-slate-900 p-4 rounded border border-slate-800">
|
||||||
|
<div className="flex items-center justify-between mb-2">
|
||||||
|
<span className="text-xs text-slate-500 uppercase tracking-wider font-mono">
|
||||||
|
{pattern.id}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
<div>
|
||||||
|
<div className="text-xs text-slate-500 mb-1">Formula</div>
|
||||||
|
<code className="block bg-slate-950 p-2 rounded text-green-400 text-sm font-mono break-all">
|
||||||
|
{pattern.formula}
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div className="text-xs text-slate-500 mb-1">Example Output</div>
|
||||||
|
<div className="text-slate-300 text-sm italic">
|
||||||
|
"{pattern.example_output}"
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
78
frontend/src/components/admin/content/GeoManager.tsx
Normal file
78
frontend/src/components/admin/content/GeoManager.tsx
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { getDirectusClient } from '@/lib/directus/client';
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
|
||||||
|
export default function GeoManager() {
|
||||||
|
const [clusters, setClusters] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
|
try {
|
||||||
|
const directus = await getDirectusClient();
|
||||||
|
const response = await directus.request({
|
||||||
|
method: 'GET',
|
||||||
|
path: '/items/geo_intelligence'
|
||||||
|
});
|
||||||
|
setClusters(response.data || []);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading geo clusters:', error);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <div className="text-white">Loading Geo Intelligence...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{clusters.map((cluster) => (
|
||||||
|
<Card key={cluster.id} className="bg-slate-800 border-slate-700">
|
||||||
|
<CardHeader className="pb-2">
|
||||||
|
<CardTitle className="text-white flex justify-between items-start">
|
||||||
|
<span>{cluster.data?.cluster_name || cluster.cluster_key}</span>
|
||||||
|
</CardTitle>
|
||||||
|
<code className="text-xs text-green-400 bg-slate-900 px-2 py-1 rounded inline-block">
|
||||||
|
{cluster.cluster_key}
|
||||||
|
</code>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="space-y-4">
|
||||||
|
<div>
|
||||||
|
<div className="text-xs text-slate-500 mb-2">Target Cities</div>
|
||||||
|
<div className="space-y-2">
|
||||||
|
{(cluster.data?.cities || []).map((city, i) => (
|
||||||
|
<div key={i} className="flex items-center justify-between text-sm bg-slate-900 p-2 rounded border border-slate-800">
|
||||||
|
<span className="text-slate-200">
|
||||||
|
{city.city}, {city.state}
|
||||||
|
</span>
|
||||||
|
{city.neighborhood && (
|
||||||
|
<Badge variant="outline" className="text-xs text-blue-400 border-blue-900 bg-blue-900/20">
|
||||||
|
{city.neighborhood}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
{city.zip_focus && (
|
||||||
|
<Badge variant="outline" className="text-xs text-purple-400 border-purple-900 bg-purple-900/20">
|
||||||
|
{city.zip_focus}
|
||||||
|
</Badge>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
92
frontend/src/components/admin/content/LogViewer.tsx
Normal file
92
frontend/src/components/admin/content/LogViewer.tsx
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { getDirectusClient } from '@/lib/directus/client';
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
|
||||||
|
|
||||||
|
export default function LogViewer() {
|
||||||
|
const [logs, setLogs] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadLogs();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loadLogs = async () => {
|
||||||
|
try {
|
||||||
|
const directus = await getDirectusClient();
|
||||||
|
const response = await directus.request({
|
||||||
|
method: 'GET',
|
||||||
|
path: '/activity',
|
||||||
|
params: {
|
||||||
|
limit: 50,
|
||||||
|
sort: '-timestamp'
|
||||||
|
}
|
||||||
|
});
|
||||||
|
setLogs(response.data || []);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading logs:', error);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <div className="text-white">Loading System Logs...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card className="bg-slate-800 border-slate-700">
|
||||||
|
<CardHeader>
|
||||||
|
<CardTitle className="text-white flex justify-between items-center">
|
||||||
|
<span>Recent Activity</span>
|
||||||
|
<Badge variant="outline" className="text-slate-400">
|
||||||
|
Last 50 Events
|
||||||
|
</Badge>
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="rounded-md border border-slate-700">
|
||||||
|
<Table>
|
||||||
|
<TableHeader className="bg-slate-900">
|
||||||
|
<TableRow className="border-slate-700 hover:bg-slate-900">
|
||||||
|
<TableHead className="text-slate-400">Action</TableHead>
|
||||||
|
<TableHead className="text-slate-400">Collection</TableHead>
|
||||||
|
<TableHead className="text-slate-400">Timestamp</TableHead>
|
||||||
|
<TableHead className="text-slate-400">User/IP</TableHead>
|
||||||
|
</TableRow>
|
||||||
|
</TableHeader>
|
||||||
|
<TableBody>
|
||||||
|
{logs.map((log) => (
|
||||||
|
<TableRow key={log.id} className="border-slate-700 hover:bg-slate-700/50">
|
||||||
|
<TableCell>
|
||||||
|
<Badge
|
||||||
|
className={
|
||||||
|
log.action === 'create' ? 'bg-green-600' :
|
||||||
|
log.action === 'update' ? 'bg-blue-600' :
|
||||||
|
log.action === 'delete' ? 'bg-red-600' :
|
||||||
|
'bg-slate-600'
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{log.action}
|
||||||
|
</Badge>
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="font-mono text-xs text-slate-300">
|
||||||
|
{log.collection}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-slate-400 text-xs">
|
||||||
|
{new Date(log.timestamp).toLocaleString()}
|
||||||
|
</TableCell>
|
||||||
|
<TableCell className="text-slate-500 text-xs font-mono">
|
||||||
|
<div>{log.ip}</div>
|
||||||
|
</TableCell>
|
||||||
|
</TableRow>
|
||||||
|
))}
|
||||||
|
</TableBody>
|
||||||
|
</Table>
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
61
frontend/src/components/admin/content/SpintaxManager.tsx
Normal file
61
frontend/src/components/admin/content/SpintaxManager.tsx
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
// @ts-nocheck
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import { getDirectusClient } from '@/lib/directus/client';
|
||||||
|
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||||||
|
import { Badge } from '@/components/ui/badge';
|
||||||
|
|
||||||
|
export default function SpintaxManager() {
|
||||||
|
const [dictionaries, setDictionaries] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
loadData();
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const loadData = async () => {
|
||||||
|
try {
|
||||||
|
const directus = await getDirectusClient();
|
||||||
|
const response = await directus.request({
|
||||||
|
method: 'GET',
|
||||||
|
path: '/items/spintax_dictionaries'
|
||||||
|
});
|
||||||
|
setDictionaries(response.data || []);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error loading spintax dictionaries:', error);
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) {
|
||||||
|
return <div className="text-white">Loading Spintax Dictionaries...</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="space-y-6">
|
||||||
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||||
|
{dictionaries.map((dict) => (
|
||||||
|
<Card key={dict.id} className="bg-slate-800 border-slate-700">
|
||||||
|
<CardHeader className="pb-2">
|
||||||
|
<CardTitle className="text-white flex justify-between items-center">
|
||||||
|
<span>{dict.category}</span>
|
||||||
|
<Badge className="bg-blue-600">
|
||||||
|
{(dict.data || []).length} Terms
|
||||||
|
</Badge>
|
||||||
|
</CardTitle>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent>
|
||||||
|
<div className="flex flex-wrap gap-2 max-h-48 overflow-y-auto">
|
||||||
|
{(dict.data || []).map((term, i) => (
|
||||||
|
<Badge key={i} variant="outline" className="text-slate-300 border-slate-600 bg-slate-900/50">
|
||||||
|
{term}
|
||||||
|
</Badge>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
import Layout from '@/layouts/AdminLayout.astro';
|
import Layout from '@/layouts/AdminLayout.astro';
|
||||||
|
import CartesianManager from '@/components/admin/content/CartesianManager';
|
||||||
---
|
---
|
||||||
<Layout title="Cartesian Patterns">
|
<Layout title="Cartesian Patterns">
|
||||||
<div class="p-8">
|
<div class="p-8">
|
||||||
<h1 class="text-3xl font-bold text-white mb-4">Cartesian Patterns</h1>
|
<div class="mb-6">
|
||||||
<p class="text-gray-400">Headline and Hook Formulas.</p>
|
<h1 class="text-3xl font-bold text-white mb-2">Cartesian Patterns</h1>
|
||||||
<div class="mt-8 p-6 bg-gray-800 rounded-xl border border-gray-700">
|
<p class="text-gray-400">Headline and Hook Formulas for the Multiplication Engine.</p>
|
||||||
<p class="text-yellow-400">🚧 Intelligence Station Under Construction</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<CartesianManager client:load />
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
import Layout from '@/layouts/AdminLayout.astro';
|
import Layout from '@/layouts/AdminLayout.astro';
|
||||||
|
import GeoManager from '@/components/admin/content/GeoManager';
|
||||||
---
|
---
|
||||||
<Layout title="Geo Intelligence">
|
<Layout title="Geo Intelligence">
|
||||||
<div class="p-8">
|
<div class="p-8">
|
||||||
<h1 class="text-3xl font-bold text-white mb-4">Geo Clusters</h1>
|
<div class="mb-6">
|
||||||
<p class="text-gray-400">Manage Geographic Intelligence (Silicon Valleys, Growth Havens).</p>
|
<h1 class="text-3xl font-bold text-white mb-2">Geo Clusters</h1>
|
||||||
<div class="mt-8 p-6 bg-gray-800 rounded-xl border border-gray-700">
|
<p class="text-gray-400">Manage Geographic Intelligence (Silicon Valleys, Growth Havens) for localized content.</p>
|
||||||
<p class="text-yellow-400">🚧 Intelligence Station Under Construction</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<GeoManager client:load />
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
import Layout from '@/layouts/AdminLayout.astro';
|
import Layout from '@/layouts/AdminLayout.astro';
|
||||||
|
import SpintaxManager from '@/components/admin/content/SpintaxManager';
|
||||||
---
|
---
|
||||||
<Layout title="Spintax Dictionary">
|
<Layout title="Spintax Dictionary">
|
||||||
<div class="p-8">
|
<div class="p-8">
|
||||||
<h1 class="text-3xl font-bold text-white mb-4">Spintax Dictionaries</h1>
|
<div class="mb-6">
|
||||||
<p class="text-gray-400">Global Search & Replace Dictionaries.</p>
|
<h1 class="text-3xl font-bold text-white mb-2">Spintax Dictionaries</h1>
|
||||||
<div class="mt-8 p-6 bg-gray-800 rounded-xl border border-gray-700">
|
<p class="text-gray-400">Global Search & Replace Dictionaries for content randomization.</p>
|
||||||
<p class="text-yellow-400">🚧 Intelligence Station Under Construction</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<SpintaxManager client:load />
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
|
|
||||||
---
|
---
|
||||||
import Layout from '@/layouts/AdminLayout.astro';
|
import Layout from '@/layouts/AdminLayout.astro';
|
||||||
|
import LogViewer from '@/components/admin/content/LogViewer';
|
||||||
---
|
---
|
||||||
<Layout title="System Logs">
|
<Layout title="System Logs">
|
||||||
<div class="p-8">
|
<div class="p-8">
|
||||||
<h1 class="text-3xl font-bold text-white mb-4">System Work Log</h1>
|
<div class="mb-6">
|
||||||
<p class="text-gray-400">Backend Execution Logs.</p>
|
<h1 class="text-3xl font-bold text-white mb-2">System Work Log</h1>
|
||||||
<div class="mt-8 p-6 bg-gray-800 rounded-xl border border-gray-700">
|
<p class="text-gray-400">Real-time backend execution and activity logs.</p>
|
||||||
<p class="text-yellow-400">🚧 Log Viewer Under Construction</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
<LogViewer client:load />
|
||||||
</div>
|
</div>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|||||||
Reference in New Issue
Block a user