Update: GTM Architect v2.6.2 (Edit Specs, Report Fix) & Company Explorer v0.4 (Export, Timestamps)

This commit is contained in:
2026-01-09 09:15:16 +00:00
parent d07fbcb2cd
commit c4fcc990b0
10 changed files with 617 additions and 111 deletions

View File

@@ -1,6 +1,6 @@
import { useEffect, useState } from 'react'
import axios from 'axios'
import { X, ExternalLink, Bot, Briefcase, Calendar, Globe, Users, DollarSign, MapPin, Tag, RefreshCw as RefreshCwIcon, Search as SearchIcon, Pencil, Check } from 'lucide-react'
import { X, ExternalLink, Bot, Briefcase, Calendar, Globe, Users, DollarSign, MapPin, Tag, RefreshCw as RefreshCwIcon, Search as SearchIcon, Pencil, Check, Download, Clock } from 'lucide-react'
import clsx from 'clsx'
interface InspectorProps {
@@ -20,6 +20,7 @@ type EnrichmentData = {
source_type: string
content: any
is_locked?: boolean
created_at?: string
}
type CompanyDetail = {
@@ -110,6 +111,38 @@ export function Inspector({ companyId, onClose, apiBase }: InspectorProps) {
}
}
const handleExport = () => {
if (!data) return;
// Prepare full export object
const exportData = {
metadata: {
id: data.id,
exported_at: new Date().toISOString(),
source: "Company Explorer (Robotics Edition)"
},
company: {
name: data.name,
website: data.website,
status: data.status,
industry_ai: data.industry_ai,
created_at: data.created_at
},
enrichment: data.enrichment_data,
signals: data.signals
};
const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `company-export-${data.id}-${data.name.replace(/[^a-z0-9]/gi, '_').toLowerCase()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};
const handleWikiOverride = async () => {
if (!companyId) return
setIsProcessing(true)
@@ -145,11 +178,16 @@ export function Inspector({ companyId, onClose, apiBase }: InspectorProps) {
const wikiEntry = data?.enrichment_data?.find(e => e.source_type === 'wikipedia')
const wiki = wikiEntry?.content
const isLocked = wikiEntry?.is_locked
const wikiDate = wikiEntry?.created_at
const aiAnalysis = data?.enrichment_data?.find(e => e.source_type === 'ai_analysis')?.content
const aiAnalysisEntry = data?.enrichment_data?.find(e => e.source_type === 'ai_analysis')
const aiAnalysis = aiAnalysisEntry?.content
const aiDate = aiAnalysisEntry?.created_at
const scrapeData = data?.enrichment_data?.find(e => e.source_type === 'website_scrape')?.content
const scrapeEntry = data?.enrichment_data?.find(e => e.source_type === 'website_scrape')
const scrapeData = scrapeEntry?.content
const impressum = scrapeData?.impressum
const scrapeDate = scrapeEntry?.created_at
return (
<div className="fixed inset-y-0 right-0 w-[550px] bg-slate-900 border-l border-slate-800 shadow-2xl transform transition-transform duration-300 ease-in-out z-40 overflow-y-auto">
@@ -164,6 +202,13 @@ export function Inspector({ companyId, onClose, apiBase }: InspectorProps) {
<div className="flex justify-between items-start mb-4">
<h2 className="text-xl font-bold text-white leading-tight">{data.name}</h2>
<div className="flex items-center gap-2">
<button
onClick={handleExport}
className="p-1.5 text-slate-500 hover:text-blue-400 transition-colors"
title="Export JSON"
>
<Download className="h-4 w-4" />
</button>
<button
onClick={() => fetchData(true)}
className="p-1.5 text-slate-500 hover:text-white transition-colors"
@@ -261,11 +306,18 @@ export function Inspector({ companyId, onClose, apiBase }: InspectorProps) {
{/* Impressum / Legal Data (NEW) */}
{impressum && (
<div className="bg-slate-950 rounded-lg p-4 border border-slate-800 flex flex-col gap-2">
<div className="flex items-center gap-2 mb-1">
<div className="p-1 bg-slate-800 rounded text-slate-400">
<Briefcase className="h-3 w-3" />
<div className="flex items-center justify-between mb-1">
<div className="flex items-center gap-2">
<div className="p-1 bg-slate-800 rounded text-slate-400">
<Briefcase className="h-3 w-3" />
</div>
<span className="text-[10px] uppercase font-bold text-slate-500 tracking-wider">Official Legal Data</span>
</div>
<span className="text-[10px] uppercase font-bold text-slate-500 tracking-wider">Official Legal Data</span>
{scrapeDate && (
<div className="text-[10px] text-slate-600 flex items-center gap-1">
<Clock className="h-3 w-3" /> {new Date(scrapeDate).toLocaleDateString()}
</div>
)}
</div>
<div className="text-sm font-medium text-white">
@@ -293,9 +345,16 @@ export function Inspector({ companyId, onClose, apiBase }: InspectorProps) {
{/* AI Analysis Dossier (NEW) */}
{aiAnalysis && (
<div className="space-y-4">
<h3 className="text-sm font-semibold text-slate-400 uppercase tracking-wider flex items-center gap-2">
<Bot className="h-4 w-4" /> AI Strategic Dossier
</h3>
<div className="flex items-center justify-between">
<h3 className="text-sm font-semibold text-slate-400 uppercase tracking-wider flex items-center gap-2">
<Bot className="h-4 w-4" /> AI Strategic Dossier
</h3>
{aiDate && (
<div className="text-[10px] text-slate-600 flex items-center gap-1">
<Clock className="h-3 w-3" /> {new Date(aiDate).toLocaleDateString()}
</div>
)}
</div>
<div className="bg-slate-800/30 rounded-xl p-5 border border-slate-800/50 space-y-4">
<div>
<div className="text-[10px] text-blue-400 uppercase font-bold tracking-tight mb-1">Business Model</div>
@@ -317,32 +376,40 @@ export function Inspector({ companyId, onClose, apiBase }: InspectorProps) {
<h3 className="text-sm font-semibold text-slate-400 uppercase tracking-wider flex items-center gap-2">
<Globe className="h-4 w-4" /> Company Profile (Wikipedia)
</h3>
{!isEditingWiki ? (
<button
onClick={() => { setWikiUrlInput(wiki?.url || ""); setIsEditingWiki(true); }}
className="p-1 text-slate-500 hover:text-blue-400 transition-colors"
title="Edit / Override URL"
>
<Pencil className="h-3.5 w-3.5" />
</button>
) : (
<div className="flex items-center gap-1">
<div className="flex items-center gap-2">
{wikiDate && (
<div className="text-[10px] text-slate-600 flex items-center gap-1 mr-2">
<Clock className="h-3 w-3" /> {new Date(wikiDate).toLocaleDateString()}
</div>
)}
{!isEditingWiki ? (
<button
onClick={handleWikiOverride}
className="p-1 bg-green-900/50 text-green-400 rounded hover:bg-green-900 transition-colors"
title="Save & Rescan"
onClick={() => { setWikiUrlInput(wiki?.url || ""); setIsEditingWiki(true); }}
className="p-1 text-slate-500 hover:text-blue-400 transition-colors"
title="Edit / Override URL"
>
<Check className="h-3.5 w-3.5" />
<Pencil className="h-3.5 w-3.5" />
</button>
<button
onClick={() => setIsEditingWiki(false)}
className="p-1 text-slate-500 hover:text-red-400 transition-colors"
title="Cancel"
>
<X className="h-3.5 w-3.5" />
</button>
</div>
)}
) : (
<div className="flex items-center gap-1">
<button
onClick={handleWikiOverride}
className="p-1 bg-green-900/50 text-green-400 rounded hover:bg-green-900 transition-colors"
title="Save & Rescan"
>
<Check className="h-3.5 w-3.5" />
</button>
<button
onClick={() => setIsEditingWiki(false)}
className="p-1 text-slate-500 hover:text-red-400 transition-colors"
title="Cancel"
>
<X className="h-3.5 w-3.5" />
</button>
</div>
)}
</div>
</div>
{isEditingWiki && (