@flowtomic/logic 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/hooks/useAnimatedIndicator/useAnimatedIndicator.d.ts +5 -0
- package/dist/hooks/useAnimatedIndicator/useAnimatedIndicator.d.ts.map +1 -1
- package/dist/hooks/useAnimatedIndicator/useAnimatedIndicator.js +16 -2
- package/dist/hooks/useAutocomplete/index.d.ts +3 -0
- package/dist/hooks/useAutocomplete/index.d.ts.map +1 -0
- package/dist/hooks/useAutocomplete/index.js +1 -0
- package/dist/hooks/useAutocomplete/useAutocomplete.d.ts +197 -0
- package/dist/hooks/useAutocomplete/useAutocomplete.d.ts.map +1 -0
- package/dist/hooks/useAutocomplete/useAutocomplete.js +379 -0
- package/dist/hooks/useGenealogy/useGenealogy.d.ts.map +1 -1
- package/dist/hooks/useGenealogy/useGenealogy.js +11 -5
- package/dist/hooks/useScriptEditor/index.d.ts +3 -0
- package/dist/hooks/useScriptEditor/index.d.ts.map +1 -0
- package/dist/hooks/useScriptEditor/index.js +1 -0
- package/dist/hooks/useScriptEditor/useScriptEditor.d.ts +147 -0
- package/dist/hooks/useScriptEditor/useScriptEditor.d.ts.map +1 -0
- package/dist/hooks/useScriptEditor/useScriptEditor.js +247 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -16
- package/package.json +2 -2
|
@@ -16,8 +16,9 @@ function calculateLevels(hierarchy) {
|
|
|
16
16
|
const visited = new Set();
|
|
17
17
|
// Função recursiva para calcular nível
|
|
18
18
|
const calculateLevel = (entityId) => {
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const cachedLevel = levels.get(entityId);
|
|
20
|
+
if (cachedLevel !== undefined) {
|
|
21
|
+
return cachedLevel;
|
|
21
22
|
}
|
|
22
23
|
if (visited.has(entityId)) {
|
|
23
24
|
// Ciclo detectado, retornar 0 como fallback
|
|
@@ -46,7 +47,7 @@ function calculateLevels(hierarchy) {
|
|
|
46
47
|
/**
|
|
47
48
|
* Organiza entidades por nível (geração) e calcula posições hierárquicas
|
|
48
49
|
*/
|
|
49
|
-
function calculateHierarchicalPositions(
|
|
50
|
+
function calculateHierarchicalPositions(_data, hierarchy, nodeWidth, nodeHeight, horizontalSpacing, verticalSpacing) {
|
|
50
51
|
const positions = new Map();
|
|
51
52
|
const levels = calculateLevels(hierarchy);
|
|
52
53
|
// Agrupar entidades por nível
|
|
@@ -55,12 +56,14 @@ function calculateHierarchicalPositions(data, hierarchy, nodeWidth, nodeHeight,
|
|
|
55
56
|
if (!entitiesByLevel.has(level)) {
|
|
56
57
|
entitiesByLevel.set(level, []);
|
|
57
58
|
}
|
|
58
|
-
entitiesByLevel.get(level)
|
|
59
|
+
entitiesByLevel.get(level)?.push(entityId);
|
|
59
60
|
});
|
|
60
61
|
// Calcular posições para cada nível, começando do nível 0 (raiz)
|
|
61
62
|
const sortedLevels = Array.from(entitiesByLevel.keys()).sort((a, b) => a - b);
|
|
62
63
|
sortedLevels.forEach((level) => {
|
|
63
64
|
const entityIds = entitiesByLevel.get(level);
|
|
65
|
+
if (!entityIds)
|
|
66
|
+
return;
|
|
64
67
|
// Ordenar entidades do mesmo nível (por ID para consistência)
|
|
65
68
|
entityIds.sort();
|
|
66
69
|
// Calcular posição Y baseada no nível (pais acima, filhos abaixo)
|
|
@@ -91,10 +94,13 @@ function calculateHierarchicalPositions(data, hierarchy, nodeWidth, nodeHeight,
|
|
|
91
94
|
// Ajustar posições para evitar sobreposição
|
|
92
95
|
entityIds.forEach((entityId, index) => {
|
|
93
96
|
const currentPos = positions.get(entityId);
|
|
94
|
-
|
|
97
|
+
if (!currentPos)
|
|
98
|
+
return;
|
|
95
99
|
// Verificar se há sobreposição com outros nós do mesmo nível
|
|
96
100
|
entityIds.slice(0, index).forEach((otherId) => {
|
|
97
101
|
const otherPos = positions.get(otherId);
|
|
102
|
+
if (!otherPos)
|
|
103
|
+
return;
|
|
98
104
|
if (Math.abs(currentPos.x - otherPos.x) < nodeWidth + horizontalSpacing) {
|
|
99
105
|
// Ajustar para evitar sobreposição
|
|
100
106
|
currentPos.x = otherPos.x + nodeWidth + horizontalSpacing;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/hooks/useScriptEditor/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,qBAAqB,EACrB,YAAY,EACZ,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { useScriptEditor } from "./useScriptEditor";
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useScriptEditor - Headless UI Hook
|
|
3
|
+
*
|
|
4
|
+
* Fornece apenas: lógica, estado, processamento e API
|
|
5
|
+
* NÃO fornece: markup, styles ou implementações pré-construídas
|
|
6
|
+
*
|
|
7
|
+
* Padrão Headless UI: você controla o markup e styles
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* function MyScriptEditor() {
|
|
12
|
+
* const {
|
|
13
|
+
* script,
|
|
14
|
+
* setScript,
|
|
15
|
+
* terminalLines,
|
|
16
|
+
* preview,
|
|
17
|
+
* isRunning,
|
|
18
|
+
* isConnected,
|
|
19
|
+
* executeScript,
|
|
20
|
+
* stopExecution,
|
|
21
|
+
* clearTerminal,
|
|
22
|
+
* } = useScriptEditor({
|
|
23
|
+
* wsUrl: "ws://localhost:8080/ws/terminal",
|
|
24
|
+
* executeScript: async (script) => {
|
|
25
|
+
* const response = await fetch("/api/scripts/execute", {
|
|
26
|
+
* method: "POST",
|
|
27
|
+
* body: JSON.stringify({ script }),
|
|
28
|
+
* });
|
|
29
|
+
* return response.json();
|
|
30
|
+
* },
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* return (
|
|
34
|
+
* <div>
|
|
35
|
+
* <textarea value={script} onChange={(e) => setScript(e.target.value)} />
|
|
36
|
+
* <button onClick={executeScript}>Executar</button>
|
|
37
|
+
* <div>
|
|
38
|
+
* {terminalLines.map((line) => (
|
|
39
|
+
* <div key={line.id}>{line.content}</div>
|
|
40
|
+
* ))}
|
|
41
|
+
* </div>
|
|
42
|
+
* </div>
|
|
43
|
+
* );
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export interface TerminalLine {
|
|
48
|
+
id: string;
|
|
49
|
+
type: "input" | "output" | "error" | "system";
|
|
50
|
+
content: string;
|
|
51
|
+
timestamp: Date;
|
|
52
|
+
}
|
|
53
|
+
export interface ExecuteScriptResponse {
|
|
54
|
+
output?: string;
|
|
55
|
+
error?: string;
|
|
56
|
+
result?: unknown;
|
|
57
|
+
}
|
|
58
|
+
export interface UseScriptEditorOptions {
|
|
59
|
+
/**
|
|
60
|
+
* URL do WebSocket para conexão em tempo real
|
|
61
|
+
* @default undefined
|
|
62
|
+
*/
|
|
63
|
+
wsUrl?: string;
|
|
64
|
+
/**
|
|
65
|
+
* Função para executar script via HTTP (fallback quando WebSocket não está disponível)
|
|
66
|
+
* @default undefined
|
|
67
|
+
*/
|
|
68
|
+
executeScript?: (script: string) => Promise<ExecuteScriptResponse>;
|
|
69
|
+
/**
|
|
70
|
+
* Callback quando uma linha é adicionada ao terminal
|
|
71
|
+
*/
|
|
72
|
+
onOutput?: (line: TerminalLine) => void;
|
|
73
|
+
/**
|
|
74
|
+
* Callback quando ocorre um erro
|
|
75
|
+
*/
|
|
76
|
+
onError?: (error: Error) => void;
|
|
77
|
+
/**
|
|
78
|
+
* Se deve conectar automaticamente ao WebSocket
|
|
79
|
+
* @default true
|
|
80
|
+
*/
|
|
81
|
+
autoConnect?: boolean;
|
|
82
|
+
/**
|
|
83
|
+
* Número máximo de tentativas de reconexão
|
|
84
|
+
* @default 3
|
|
85
|
+
*/
|
|
86
|
+
maxReconnectAttempts?: number;
|
|
87
|
+
/**
|
|
88
|
+
* Script inicial
|
|
89
|
+
* @default ""
|
|
90
|
+
*/
|
|
91
|
+
defaultScript?: string;
|
|
92
|
+
}
|
|
93
|
+
export interface UseScriptEditorReturn {
|
|
94
|
+
/**
|
|
95
|
+
* Script atual
|
|
96
|
+
*/
|
|
97
|
+
script: string;
|
|
98
|
+
/**
|
|
99
|
+
* Atualizar script
|
|
100
|
+
*/
|
|
101
|
+
setScript: (script: string) => void;
|
|
102
|
+
/**
|
|
103
|
+
* Linhas do terminal
|
|
104
|
+
*/
|
|
105
|
+
terminalLines: TerminalLine[];
|
|
106
|
+
/**
|
|
107
|
+
* Preview formatado (JSON)
|
|
108
|
+
*/
|
|
109
|
+
preview: string;
|
|
110
|
+
/**
|
|
111
|
+
* Aba ativa (terminal ou preview)
|
|
112
|
+
*/
|
|
113
|
+
activeTab: "terminal" | "preview";
|
|
114
|
+
/**
|
|
115
|
+
* Mudar aba ativa
|
|
116
|
+
*/
|
|
117
|
+
setActiveTab: (tab: "terminal" | "preview") => void;
|
|
118
|
+
/**
|
|
119
|
+
* Se o script está sendo executado
|
|
120
|
+
*/
|
|
121
|
+
isRunning: boolean;
|
|
122
|
+
/**
|
|
123
|
+
* Se o WebSocket está conectado
|
|
124
|
+
*/
|
|
125
|
+
isConnected: boolean;
|
|
126
|
+
/**
|
|
127
|
+
* Executar script
|
|
128
|
+
*/
|
|
129
|
+
executeScript: () => Promise<void>;
|
|
130
|
+
/**
|
|
131
|
+
* Parar execução
|
|
132
|
+
*/
|
|
133
|
+
stopExecution: () => void;
|
|
134
|
+
/**
|
|
135
|
+
* Limpar terminal e preview
|
|
136
|
+
*/
|
|
137
|
+
clearTerminal: () => void;
|
|
138
|
+
/**
|
|
139
|
+
* Adicionar linha ao terminal manualmente
|
|
140
|
+
*/
|
|
141
|
+
addTerminalLine: (type: TerminalLine["type"], content: string) => void;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Hook headless para gerenciar editor de scripts com terminal interativo
|
|
145
|
+
*/
|
|
146
|
+
export declare function useScriptEditor(options?: UseScriptEditorOptions): UseScriptEditorReturn;
|
|
147
|
+
//# sourceMappingURL=useScriptEditor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useScriptEditor.d.ts","sourceRoot":"","sources":["../../../src/hooks/useScriptEditor/useScriptEditor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AAIH,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,QAAQ,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IAEf;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,qBAAqB,CAAC,CAAC;IAEnE;;OAEG;IACH,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IAExC;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAEjC;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;;OAGG;IACH,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAE9B;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC;;OAEG;IACH,MAAM,EAAE,MAAM,CAAC;IAEf;;OAEG;IACH,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAEpC;;OAEG;IACH,aAAa,EAAE,YAAY,EAAE,CAAC;IAE9B;;OAEG;IACH,OAAO,EAAE,MAAM,CAAC;IAEhB;;OAEG;IACH,SAAS,EAAE,UAAU,GAAG,SAAS,CAAC;IAElC;;OAEG;IACH,YAAY,EAAE,CAAC,GAAG,EAAE,UAAU,GAAG,SAAS,KAAK,IAAI,CAAC;IAEpD;;OAEG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,WAAW,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,aAAa,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;OAEG;IACH,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B;;OAEG;IACH,aAAa,EAAE,MAAM,IAAI,CAAC;IAE1B;;OAEG;IACH,eAAe,EAAE,CAAC,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACxE;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,qBAAqB,CAoO3F"}
|
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useScriptEditor - Headless UI Hook
|
|
3
|
+
*
|
|
4
|
+
* Fornece apenas: lógica, estado, processamento e API
|
|
5
|
+
* NÃO fornece: markup, styles ou implementações pré-construídas
|
|
6
|
+
*
|
|
7
|
+
* Padrão Headless UI: você controla o markup e styles
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```tsx
|
|
11
|
+
* function MyScriptEditor() {
|
|
12
|
+
* const {
|
|
13
|
+
* script,
|
|
14
|
+
* setScript,
|
|
15
|
+
* terminalLines,
|
|
16
|
+
* preview,
|
|
17
|
+
* isRunning,
|
|
18
|
+
* isConnected,
|
|
19
|
+
* executeScript,
|
|
20
|
+
* stopExecution,
|
|
21
|
+
* clearTerminal,
|
|
22
|
+
* } = useScriptEditor({
|
|
23
|
+
* wsUrl: "ws://localhost:8080/ws/terminal",
|
|
24
|
+
* executeScript: async (script) => {
|
|
25
|
+
* const response = await fetch("/api/scripts/execute", {
|
|
26
|
+
* method: "POST",
|
|
27
|
+
* body: JSON.stringify({ script }),
|
|
28
|
+
* });
|
|
29
|
+
* return response.json();
|
|
30
|
+
* },
|
|
31
|
+
* });
|
|
32
|
+
*
|
|
33
|
+
* return (
|
|
34
|
+
* <div>
|
|
35
|
+
* <textarea value={script} onChange={(e) => setScript(e.target.value)} />
|
|
36
|
+
* <button onClick={executeScript}>Executar</button>
|
|
37
|
+
* <div>
|
|
38
|
+
* {terminalLines.map((line) => (
|
|
39
|
+
* <div key={line.id}>{line.content}</div>
|
|
40
|
+
* ))}
|
|
41
|
+
* </div>
|
|
42
|
+
* </div>
|
|
43
|
+
* );
|
|
44
|
+
* }
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
48
|
+
/**
|
|
49
|
+
* Hook headless para gerenciar editor de scripts com terminal interativo
|
|
50
|
+
*/
|
|
51
|
+
export function useScriptEditor(options = {}) {
|
|
52
|
+
const { wsUrl, executeScript: executeScriptFn, onOutput, onError, autoConnect = true, maxReconnectAttempts = 3, defaultScript = "", } = options;
|
|
53
|
+
const [script, setScript] = useState(defaultScript);
|
|
54
|
+
const [terminalLines, setTerminalLines] = useState([]);
|
|
55
|
+
const [preview, setPreview] = useState("");
|
|
56
|
+
const [activeTab, setActiveTab] = useState("terminal");
|
|
57
|
+
const [isRunning, setIsRunning] = useState(false);
|
|
58
|
+
const [isConnected, setIsConnected] = useState(false);
|
|
59
|
+
const wsRef = useRef(null);
|
|
60
|
+
const reconnectAttemptsRef = useRef(0);
|
|
61
|
+
const shouldReconnectRef = useRef(true);
|
|
62
|
+
// Adicionar linha ao terminal
|
|
63
|
+
const addTerminalLine = useCallback((type, content) => {
|
|
64
|
+
const line = {
|
|
65
|
+
id: `${Date.now()}-${Math.random()}`,
|
|
66
|
+
type,
|
|
67
|
+
content,
|
|
68
|
+
timestamp: new Date(),
|
|
69
|
+
};
|
|
70
|
+
setTerminalLines((prev) => [...prev, line]);
|
|
71
|
+
onOutput?.(line);
|
|
72
|
+
}, [onOutput]);
|
|
73
|
+
// Conectar WebSocket
|
|
74
|
+
const connectWebSocket = useCallback(() => {
|
|
75
|
+
if (!wsUrl)
|
|
76
|
+
return;
|
|
77
|
+
// Verificar se já existe uma conexão ativa
|
|
78
|
+
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
// Fechar conexão anterior se existir
|
|
82
|
+
if (wsRef.current) {
|
|
83
|
+
try {
|
|
84
|
+
wsRef.current.close();
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Ignorar erros ao fechar
|
|
88
|
+
}
|
|
89
|
+
wsRef.current = null;
|
|
90
|
+
}
|
|
91
|
+
if (!shouldReconnectRef.current)
|
|
92
|
+
return;
|
|
93
|
+
try {
|
|
94
|
+
const ws = new WebSocket(wsUrl);
|
|
95
|
+
wsRef.current = ws;
|
|
96
|
+
ws.onopen = () => {
|
|
97
|
+
setIsConnected(true);
|
|
98
|
+
reconnectAttemptsRef.current = 0;
|
|
99
|
+
};
|
|
100
|
+
ws.onmessage = (event) => {
|
|
101
|
+
try {
|
|
102
|
+
const data = JSON.parse(event.data);
|
|
103
|
+
if (data.type === "output") {
|
|
104
|
+
addTerminalLine("output", data.content);
|
|
105
|
+
}
|
|
106
|
+
else if (data.type === "error") {
|
|
107
|
+
addTerminalLine("error", data.content);
|
|
108
|
+
}
|
|
109
|
+
else if (data.type === "result") {
|
|
110
|
+
setPreview(JSON.stringify(data.content, null, 2));
|
|
111
|
+
setActiveTab("preview");
|
|
112
|
+
}
|
|
113
|
+
else if (data.type === "system") {
|
|
114
|
+
// Mensagens de sistema não são exibidas no terminal
|
|
115
|
+
console.log("[useScriptEditor] Mensagem de sistema:", data.content);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
addTerminalLine("output", event.data);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
ws.onerror = (error) => {
|
|
123
|
+
console.error("[useScriptEditor] WebSocket error:", error);
|
|
124
|
+
setIsConnected(false);
|
|
125
|
+
onError?.(new Error("Erro na conexão WebSocket"));
|
|
126
|
+
};
|
|
127
|
+
ws.onclose = (event) => {
|
|
128
|
+
setIsConnected(false);
|
|
129
|
+
wsRef.current = null;
|
|
130
|
+
// Tentar reconectar apenas se não excedeu tentativas e ainda deve reconectar
|
|
131
|
+
if (event.code !== 1000 &&
|
|
132
|
+
shouldReconnectRef.current &&
|
|
133
|
+
reconnectAttemptsRef.current < maxReconnectAttempts) {
|
|
134
|
+
reconnectAttemptsRef.current += 1;
|
|
135
|
+
setTimeout(() => {
|
|
136
|
+
if (shouldReconnectRef.current) {
|
|
137
|
+
connectWebSocket();
|
|
138
|
+
}
|
|
139
|
+
}, 3000);
|
|
140
|
+
}
|
|
141
|
+
else if (reconnectAttemptsRef.current >= maxReconnectAttempts) {
|
|
142
|
+
console.warn("[useScriptEditor] Máximo de tentativas de reconexão atingido");
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
console.error("[useScriptEditor] Erro ao conectar WebSocket:", error);
|
|
148
|
+
setIsConnected(false);
|
|
149
|
+
onError?.(error instanceof Error ? error : new Error("Erro desconhecido ao conectar"));
|
|
150
|
+
}
|
|
151
|
+
}, [wsUrl, maxReconnectAttempts, addTerminalLine, onError]);
|
|
152
|
+
// Conectar WebSocket quando montar (se autoConnect)
|
|
153
|
+
useEffect(() => {
|
|
154
|
+
if (autoConnect && wsUrl) {
|
|
155
|
+
const connectTimeout = setTimeout(() => {
|
|
156
|
+
connectWebSocket();
|
|
157
|
+
}, 100);
|
|
158
|
+
return () => {
|
|
159
|
+
clearTimeout(connectTimeout);
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
}, [autoConnect, wsUrl, connectWebSocket]);
|
|
163
|
+
// Limpar conexão ao desmontar
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
return () => {
|
|
166
|
+
shouldReconnectRef.current = false;
|
|
167
|
+
if (wsRef.current) {
|
|
168
|
+
try {
|
|
169
|
+
wsRef.current.close(1000, "Component unmounting");
|
|
170
|
+
}
|
|
171
|
+
catch {
|
|
172
|
+
// Ignorar erros ao fechar
|
|
173
|
+
}
|
|
174
|
+
wsRef.current = null;
|
|
175
|
+
}
|
|
176
|
+
};
|
|
177
|
+
}, []);
|
|
178
|
+
// Executar script
|
|
179
|
+
const executeScript = useCallback(async () => {
|
|
180
|
+
if (!script.trim()) {
|
|
181
|
+
addTerminalLine("error", "❌ Script vazio");
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
setIsRunning(true);
|
|
185
|
+
addTerminalLine("input", script);
|
|
186
|
+
try {
|
|
187
|
+
// Enviar script via WebSocket se conectado
|
|
188
|
+
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
|
|
189
|
+
wsRef.current.send(JSON.stringify({ type: "execute", script }));
|
|
190
|
+
}
|
|
191
|
+
else if (executeScriptFn) {
|
|
192
|
+
// Fallback para HTTP se WebSocket não estiver disponível
|
|
193
|
+
try {
|
|
194
|
+
const result = await executeScriptFn(script);
|
|
195
|
+
if (result.output) {
|
|
196
|
+
addTerminalLine("output", result.output);
|
|
197
|
+
}
|
|
198
|
+
if (result.error) {
|
|
199
|
+
addTerminalLine("error", result.error);
|
|
200
|
+
}
|
|
201
|
+
if (result.result) {
|
|
202
|
+
setPreview(JSON.stringify(result.result, null, 2));
|
|
203
|
+
setActiveTab("preview");
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
catch (error) {
|
|
207
|
+
addTerminalLine("error", `❌ Erro na requisição: ${error instanceof Error ? error.message : "Erro desconhecido"}`);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
else {
|
|
211
|
+
addTerminalLine("error", "❌ Nenhuma forma de execução disponível (WebSocket ou HTTP)");
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
addTerminalLine("error", `❌ Erro ao executar: ${error instanceof Error ? error.message : "Erro desconhecido"}`);
|
|
216
|
+
}
|
|
217
|
+
finally {
|
|
218
|
+
setIsRunning(false);
|
|
219
|
+
}
|
|
220
|
+
}, [script, executeScriptFn, addTerminalLine]);
|
|
221
|
+
// Parar execução
|
|
222
|
+
const stopExecution = useCallback(() => {
|
|
223
|
+
if (wsRef.current && wsRef.current.readyState === WebSocket.OPEN) {
|
|
224
|
+
wsRef.current.send(JSON.stringify({ type: "stop" }));
|
|
225
|
+
}
|
|
226
|
+
setIsRunning(false);
|
|
227
|
+
}, []);
|
|
228
|
+
// Limpar terminal
|
|
229
|
+
const clearTerminal = useCallback(() => {
|
|
230
|
+
setTerminalLines([]);
|
|
231
|
+
setPreview("");
|
|
232
|
+
}, []);
|
|
233
|
+
return {
|
|
234
|
+
script,
|
|
235
|
+
setScript,
|
|
236
|
+
terminalLines,
|
|
237
|
+
preview,
|
|
238
|
+
activeTab,
|
|
239
|
+
setActiveTab,
|
|
240
|
+
isRunning,
|
|
241
|
+
isConnected,
|
|
242
|
+
executeScript,
|
|
243
|
+
stopExecution,
|
|
244
|
+
clearTerminal,
|
|
245
|
+
addTerminalLine,
|
|
246
|
+
};
|
|
247
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export * from "./hooks/useProjectStats";
|
|
|
12
12
|
export * from "./hooks/useReactTableBack";
|
|
13
13
|
export * from "./hooks/useReactTableFront";
|
|
14
14
|
export * from "./hooks/useResizable";
|
|
15
|
+
export * from "./hooks/useScriptEditor";
|
|
15
16
|
export * from "./hooks/useStatCard";
|
|
16
17
|
export * from "./hooks/useTimeTracker";
|
|
18
|
+
export * from "./hooks/useAutocomplete";
|
|
17
19
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AAErC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,cAAc,8BAA8B,CAAC;AAC7C,cAAc,sBAAsB,CAAC;AACrC,cAAc,oBAAoB,CAAC;AACnC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,yBAAyB,CAAC;AACxC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,sBAAsB,CAAC;AAErC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,wBAAwB,CAAC;AACvC,cAAc,yBAAyB,CAAC"}
|