File size: 4,244 Bytes
68185ce
d89db9c
68185ce
d89db9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68185ce
 
d89db9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68185ce
d89db9c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68185ce
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import type React from "react";
import { useState } from "react";

type JsonValue = string | number | boolean | null | JsonObject | JsonArray;
type JsonObject = { [key: string]: JsonValue };
type JsonArray = JsonValue[];

const isJsonString = (str: string): boolean => {
  if (typeof str !== "string") return false;
  const trimmed = str.trim();

  // Check if it looks like JSON (starts with { or [)
  if (!trimmed.startsWith("{") && !trimmed.startsWith("[")) return false;

  try {
    const parsed = JSON.parse(trimmed);
    // Ensure it's actually an object or array, not just a primitive
    console.log("JSON parse successful:", parsed);
    return typeof parsed === "object" && parsed !== null;
  } catch (error) {
    console.log("JSON parse failed:", error);
    return false;
  }
};

const JsonCollapsible: React.FC<{ data: JsonValue; isString?: boolean }> = ({
  data,
  isString = false,
}) => {
  const [isCollapsed, setIsCollapsed] = useState(true);

  let jsonData: JsonValue;
  try {
    jsonData = isString ? JSON.parse(data as string) : data;
  } catch {
    // If parsing fails, display as string
    return (
      <pre className="text-sm text-gray-300 whitespace-pre-wrap overflow-auto">
        {String(data)}
      </pre>
    );
  }

  const isObject = typeof jsonData === "object" && jsonData !== null;

  if (!isObject) {
    return <span className="text-gray-300">{JSON.stringify(jsonData)}</span>;
  }

  const keys = Object.keys(jsonData as JsonObject);
  const preview = Array.isArray(jsonData)
    ? `[${jsonData.length} items]`
    : `{${keys.length} keys}`;

  return (
    <div className="json-collapsible">
      <button
        onClick={() => setIsCollapsed(!isCollapsed)}
        className="flex items-center gap-1 text-blue-400 hover:text-blue-300 transition-colors text-sm font-mono"
      >
        <span
          className="transform transition-transform duration-200"
          style={{
            transform: isCollapsed ? "rotate(-90deg)" : "rotate(0deg)",
          }}
        >

        </span>
        {isCollapsed ? preview : Array.isArray(jsonData) ? "[" : "{"}
      </button>
      {!isCollapsed && (
        <div className="ml-4 mt-1">
          <pre className="text-sm text-gray-300 whitespace-pre-wrap overflow-auto">
            {JSON.stringify(jsonData, null, 2)}
          </pre>
          <div className="text-blue-400 font-mono text-sm">
            {Array.isArray(jsonData) ? "]" : "}"}
          </div>
        </div>
      )}
    </div>
  );
};

const ResultBlock: React.FC<{ error?: string; result?: unknown }> = ({
  error,
  result,
}) => {
  console.log("ResultBlock component rendered with:", {
    error,
    result,
    type: typeof result,
  });

  const renderContent = () => {
    console.log("ResultBlock Debug:", {
      result,
      type: typeof result,
      isString: typeof result === "string",
      isArray: Array.isArray(result),
      startsWithBracket:
        typeof result === "string" && result.trim().startsWith("["),
      isJsonString: typeof result === "string" ? isJsonString(result) : false,
    });

    // Handle objects and arrays directly
    if (typeof result === "object" && result !== null) {
      console.log("Rendering as object/array with JsonCollapsible");
      return <JsonCollapsible data={result as JsonValue} />;
    }

    // Handle string that might be JSON
    if (typeof result === "string") {
      const trimmed = result.trim();
      if (isJsonString(trimmed)) {
        console.log("Rendering string as JSON with JsonCollapsible");
        return <JsonCollapsible data={trimmed} isString={true} />;
      }
    }

    // Fallback to plain text display
    console.log("Rendering as plain text fallback");
    return (
      <pre className="text-sm text-gray-300 whitespace-pre-wrap overflow-auto">
        {String(result)}
      </pre>
    );
  };

  return (
    <div
      className={
        error
          ? "bg-red-900 border border-red-600 rounded p-3"
          : "bg-gray-700 border border-gray-600 rounded p-3"
      }
    >
      {error ? <p className="text-red-300 text-sm">Error: {error}</p> : null}
      <div className="mt-2">{renderContent()}</div>
    </div>
  );
};

export default ResultBlock;