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

@@ -208,8 +208,8 @@ const App: React.FC = () => {
// Session Management
const [sessions, setSessions] = useState<ProjectHistoryItem[]>([]);
const [viewingSessions, setViewingSessions] = useState(true); // Start in session view
const [viewingSessions, setViewingSessions] = useState(false); // Start in input view
// Local state for adding new items (Human in the Loop inputs)
// Phase 1
const [newFeatureInput, setNewFeatureInput] = useState("");
@@ -237,6 +237,10 @@ const App: React.FC = () => {
const [brushColor, setBrushColor] = useState('#ef4444'); // Red for annotations
const [brushSize, setBrushSize] = useState(4);
// Specs Editing
const [isEditingSpecs, setIsEditingSpecs] = useState(false);
const [specsJsonInput, setSpecsJsonInput] = useState("");
const labels = TRANSLATIONS[language];
// Apply theme to body
@@ -918,6 +922,31 @@ const App: React.FC = () => {
}));
};
const handleSaveSpecs = async () => {
if (!state.projectId) return;
try {
const parsedSpecs = JSON.parse(specsJsonInput);
setState(s => ({ ...s, isLoading: true }));
await Gemini.updateSpecs(state.projectId, parsedSpecs);
setState(s => ({
...s,
isLoading: false,
phase1Result: s.phase1Result ? {
...s.phase1Result,
specs: parsedSpecs
} : undefined
}));
setIsEditingSpecs(false);
setError(null);
} catch (e: any) {
console.error("Failed to save specs", e);
setError("Invalid JSON or Save Failed: " + e.message);
setState(s => ({ ...s, isLoading: false }));
}
};
// --- Render Helpers ---
const renderInputPhase = () => (
@@ -1074,7 +1103,7 @@ const App: React.FC = () => {
<div>
<h3 className="text-sm font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">{labels.features}</h3>
<ul className="space-y-2">
{state.phase1Result?.features.map((f, i) => (
{(state.phase1Result?.features || []).map((f, i) => (
<li key={i} className="flex justify-between items-center group text-sm p-2 rounded border transition-colors
bg-slate-50 border-slate-200 text-slate-700
dark:bg-robo-900 dark:border-robo-700 dark:text-slate-200
@@ -1113,7 +1142,7 @@ const App: React.FC = () => {
<div>
<h3 className="text-sm font-bold uppercase tracking-wider text-slate-500 dark:text-slate-400 mb-2">{labels.constraints}</h3>
<ul className="space-y-2">
{state.phase1Result?.constraints.map((c, i) => (
{(state.phase1Result?.constraints || []).map((c, i) => (
<li key={i} className="flex justify-between items-center group text-sm p-2 rounded border transition-colors
bg-red-50 border-red-200 text-red-700
dark:bg-robo-900 dark:border-red-900/30 dark:text-red-200
@@ -1153,10 +1182,51 @@ const App: React.FC = () => {
{/* NEW: Hard Facts Specs Display */}
{state.phase1Result?.specs && 'metadata' in state.phase1Result.specs && (
<div className="p-6 rounded-xl border transition-colors bg-white border-slate-200 dark:bg-robo-800 dark:border-robo-700">
<h2 className="text-xl font-bold mb-4 flex items-center gap-2 text-slate-900 dark:text-white">
<Database className="text-blue-500" /> Technical Specifications (Hard Facts)
</h2>
<div className="flex justify-between items-center mb-4">
<h2 className="text-xl font-bold flex items-center gap-2 text-slate-900 dark:text-white">
<Database className="text-blue-500" /> Technical Specifications (Hard Facts)
</h2>
{!isEditingSpecs ? (
<button
onClick={() => {
setSpecsJsonInput(JSON.stringify(state.phase1Result?.specs, null, 2));
setIsEditingSpecs(true);
}}
className="text-xs font-bold px-3 py-1.5 rounded bg-slate-100 dark:bg-robo-700 hover:bg-slate-200 dark:hover:bg-robo-600 text-slate-600 dark:text-slate-300 transition-colors flex items-center gap-1"
>
<Pencil size={12}/> Edit Raw Data
</button>
) : (
<div className="flex gap-2">
<button
onClick={() => setIsEditingSpecs(false)}
className="text-xs font-bold px-3 py-1.5 rounded bg-slate-100 dark:bg-robo-700 hover:bg-slate-200 dark:hover:bg-robo-600 text-slate-600 dark:text-slate-300 transition-colors"
>
Cancel
</button>
<button
onClick={handleSaveSpecs}
className="text-xs font-bold px-3 py-1.5 rounded bg-blue-600 hover:bg-blue-700 text-white transition-colors flex items-center gap-1"
>
<Save size={12}/> Save Changes
</button>
</div>
)}
</div>
{isEditingSpecs ? (
<div className="animate-in fade-in">
<p className="text-xs text-slate-500 mb-2">
Edit the raw JSON data below. Be careful with the syntax. This data is used for the Strategy Report.
</p>
<textarea
value={specsJsonInput}
onChange={(e) => setSpecsJsonInput(e.target.value)}
className="w-full h-96 font-mono text-xs p-4 rounded bg-slate-50 border border-slate-300 text-slate-800 focus:ring-2 focus:ring-blue-500 outline-none
dark:bg-robo-900 dark:border-robo-600 dark:text-slate-300"
/>
</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
{/* Core Data */}
<div className="p-4 bg-slate-50 dark:bg-robo-900 rounded-lg border border-slate-200 dark:border-robo-700">
@@ -1222,9 +1292,9 @@ const App: React.FC = () => {
)}
</div>
</div>
)}
{/* Extended Features */}
{state.phase1Result.specs.extended_features.length > 0 && (
{!isEditingSpecs && state.phase1Result.specs.extended_features.length > 0 && (
<div>
<h3 className="text-xs font-bold uppercase tracking-wider text-slate-500 mb-2">Extended Features</h3>
<div className="flex flex-wrap gap-2">
@@ -1239,7 +1309,7 @@ const App: React.FC = () => {
</div>
)}
{state.phase1Result?.conflictCheck.hasConflict ? (
{state.phase1Result?.conflictCheck?.hasConflict ? (
<div className="border p-6 rounded-xl flex gap-4 transition-colors
bg-red-50 border-red-200
dark:bg-red-950/50 dark:border-red-500/50
@@ -1299,7 +1369,7 @@ const App: React.FC = () => {
<h2 className="text-2xl font-bold flex items-center gap-2 text-slate-900 dark:text-white">
<Target className="text-blue-600 dark:text-robo-accent"/> {labels.targetId}
</h2>
{state.phase2Result?.icps.map((icp, i) => (
{(state.phase2Result?.icps || []).map((icp, i) => (
<div key={i} className="relative p-6 rounded-xl border transition-colors cursor-default group
bg-white border-slate-200 hover:border-blue-400
dark:bg-robo-800 dark:border-robo-700 dark:hover:border-robo-500
@@ -1361,7 +1431,7 @@ const App: React.FC = () => {
<Database size={16}/> {labels.dataProxies}
</h3>
<div className="space-y-3">
{state.phase2Result?.dataProxies.map((proxy, i) => (
{(state.phase2Result?.dataProxies || []).map((proxy, i) => (
<div key={i} className="flex gap-4 items-center p-3 rounded-lg group relative
bg-white border border-slate-200
dark:bg-black/20 dark:border-transparent
@@ -1452,7 +1522,7 @@ const App: React.FC = () => {
</h3>
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
{state.phase3Result?.whales.map((whaleGroup, groupIdx) => (
{(state.phase3Result?.whales || []).map((whaleGroup, groupIdx) => (
<div key={groupIdx} className="p-6 rounded-xl border transition-colors flex flex-col
bg-white border-slate-200
dark:bg-robo-800 dark:border-robo-700
@@ -1518,7 +1588,7 @@ const App: React.FC = () => {
<UserCircle className="text-blue-500 dark:text-blue-400"/> {labels.roles}
</h3>
<ul className="space-y-3">
{state.phase3Result?.roles.map((role: any, i) => (
{(state.phase3Result?.roles || []).map((role: any, i) => (
<li key={i} className="flex items-center justify-between group p-3 rounded-lg border transition-colors
bg-slate-50 border-slate-200
dark:bg-robo-900 dark:border-robo-800
@@ -1613,7 +1683,7 @@ const App: React.FC = () => {
</tr>
</thead>
<tbody className="divide-y divide-slate-200 dark:divide-robo-700 bg-white dark:bg-robo-800">
{state.phase4Result?.strategyMatrix.map((row, i) => (
{(state.phase4Result?.strategyMatrix || []).map((row, i) => (
<tr key={i} className="hover:bg-slate-50 dark:hover:bg-robo-700/50 transition-colors">
<td className="p-4 font-bold text-slate-800 dark:text-white">{row.segment}</td>
<td className="p-4 text-sm text-red-600 dark:text-red-300">{row.painPoint}</td>
@@ -1657,6 +1727,14 @@ const App: React.FC = () => {
<Terminal className="text-pink-600 dark:text-pink-400"/> {labels.genAssets}
</h2>
<div className="flex items-center gap-4">
<button
onClick={handlePhase5Submit}
disabled={state.isLoading}
className="text-xs flex items-center gap-1 bg-blue-100 dark:bg-robo-700 text-blue-700 dark:text-blue-300 px-3 py-1.5 rounded hover:bg-blue-200 dark:hover:bg-robo-600 transition-colors font-bold"
title="Regenerate Report with latest data"
>
<RefreshCw size={14}/> Refresh
</button>
<div className="text-xs font-mono text-slate-500">format: markdown</div>
</div>
</div>