@greatapps/greatagents-ui 0.3.10 → 0.3.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@greatapps/greatagents-ui",
3
- "version": "0.3.10",
3
+ "version": "0.3.12",
4
4
  "description": "Shared agents UI components for Great platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,3 +1,4 @@
1
+ import { useState, useCallback } from "react";
1
2
  import type { Agent } from "../../types";
2
3
  import type { GagentsHookConfig } from "../../hooks/types";
3
4
  import type { IntegrationCardData } from "../../hooks/use-integrations";
@@ -6,26 +7,24 @@ import type { ConfigOption } from "../capabilities/wizard-steps/config-step";
6
7
  import { AgentObjectivesList } from "./agent-objectives-list";
7
8
  import { AgentPromptEditor } from "./agent-prompt-editor";
8
9
  import { AgentConversationsPanel } from "../conversations/agent-conversations-panel";
9
- import { AgentCapabilitiesPage } from "../../pages/agent-capabilities-page";
10
+ import { CapabilitiesTab } from "../capabilities/capabilities-tab";
11
+ import { IntegrationsTab } from "../capabilities/integrations-tab";
12
+ import { IntegrationWizard } from "../capabilities/integration-wizard";
10
13
  import {
11
14
  Tabs,
12
15
  TabsList,
13
16
  TabsTrigger,
14
17
  TabsContent,
15
18
  } from "@greatapps/greatauth-ui/ui";
16
- import { Target, FileText, MessageCircle, Blocks } from "lucide-react";
19
+ import { Target, FileText, MessageCircle, Blocks, Plug } from "lucide-react";
17
20
 
18
21
  interface AgentTabsProps {
19
22
  agent: Agent;
20
23
  config: GagentsHookConfig;
21
24
  renderChatLink?: (inboxId: number) => React.ReactNode;
22
- /** Required for the Capacidades tab — gagents API URL for OAuth flows and advanced features. Falls back to config.baseUrl. */
23
25
  gagentsApiUrl?: string;
24
- /** Resolve wizard metadata for a given integration card. */
25
26
  resolveWizardMeta?: (card: IntegrationCardData) => WizardIntegrationMeta;
26
- /** Callback to load config options after OAuth completes. */
27
27
  loadConfigOptions?: (credentialId: number) => Promise<ConfigOption[]>;
28
- /** Called after wizard completes successfully. */
29
28
  onWizardComplete?: () => void;
30
29
  }
31
30
 
@@ -40,53 +39,102 @@ export function AgentTabs({
40
39
  }: AgentTabsProps) {
41
40
  const apiUrl = gagentsApiUrl || config.baseUrl;
42
41
 
42
+ // Wizard state for Integrações tab
43
+ const [wizardOpen, setWizardOpen] = useState(false);
44
+ const [activeCard, setActiveCard] = useState<IntegrationCardData | null>(null);
45
+
46
+ const handleConnect = useCallback((card: IntegrationCardData) => {
47
+ setActiveCard(card);
48
+ setWizardOpen(true);
49
+ }, []);
50
+
51
+ const handleWizardClose = useCallback((open: boolean) => {
52
+ if (!open) {
53
+ setActiveCard(null);
54
+ }
55
+ setWizardOpen(open);
56
+ }, []);
57
+
58
+ const handleWizardComplete = useCallback(() => {
59
+ setWizardOpen(false);
60
+ setActiveCard(null);
61
+ onWizardComplete?.();
62
+ }, [onWizardComplete]);
63
+
64
+ // Resolve wizard meta with sensible defaults
65
+ const wizardMeta: WizardIntegrationMeta | null = activeCard
66
+ ? (resolveWizardMeta?.(activeCard) ?? {
67
+ capabilities: [],
68
+ requirements: [],
69
+ hasConfigStep: false,
70
+ })
71
+ : null;
72
+
43
73
  return (
44
- <Tabs defaultValue="prompt">
45
- <TabsList>
46
- <TabsTrigger value="prompt" className="flex items-center gap-1.5">
47
- <FileText aria-hidden="true" className="h-3.5 w-3.5" />
48
- Prompt
49
- </TabsTrigger>
50
- <TabsTrigger value="objetivos" className="flex items-center gap-1.5">
51
- <Target aria-hidden="true" className="h-3.5 w-3.5" />
52
- Objetivos
53
- </TabsTrigger>
54
- <TabsTrigger value="capacidades" className="flex items-center gap-1.5">
55
- <Blocks aria-hidden="true" className="h-3.5 w-3.5" />
56
- Capacidades
57
- </TabsTrigger>
58
- <TabsTrigger value="conversas" className="flex items-center gap-1.5">
59
- <MessageCircle aria-hidden="true" className="h-3.5 w-3.5" />
60
- Conversas
61
- </TabsTrigger>
62
- </TabsList>
74
+ <>
75
+ <Tabs defaultValue="prompt">
76
+ <TabsList>
77
+ <TabsTrigger value="prompt" className="flex items-center gap-1.5">
78
+ <FileText aria-hidden="true" className="h-3.5 w-3.5" />
79
+ Prompt
80
+ </TabsTrigger>
81
+ <TabsTrigger value="objetivos" className="flex items-center gap-1.5">
82
+ <Target aria-hidden="true" className="h-3.5 w-3.5" />
83
+ Objetivos
84
+ </TabsTrigger>
85
+ <TabsTrigger value="capacidades" className="flex items-center gap-1.5">
86
+ <Blocks aria-hidden="true" className="h-3.5 w-3.5" />
87
+ Capacidades
88
+ </TabsTrigger>
89
+ <TabsTrigger value="integracoes" className="flex items-center gap-1.5">
90
+ <Plug aria-hidden="true" className="h-3.5 w-3.5" />
91
+ Integrações
92
+ </TabsTrigger>
93
+ <TabsTrigger value="conversas" className="flex items-center gap-1.5">
94
+ <MessageCircle aria-hidden="true" className="h-3.5 w-3.5" />
95
+ Conversas
96
+ </TabsTrigger>
97
+ </TabsList>
63
98
 
64
- <TabsContent value="prompt" className="mt-4">
65
- <AgentPromptEditor agent={agent} config={config} />
66
- </TabsContent>
99
+ <TabsContent value="prompt" className="mt-4">
100
+ <AgentPromptEditor agent={agent} config={config} />
101
+ </TabsContent>
67
102
 
68
- <TabsContent value="objetivos" className="mt-4">
69
- <AgentObjectivesList agent={agent} config={config} />
70
- </TabsContent>
103
+ <TabsContent value="objetivos" className="mt-4">
104
+ <AgentObjectivesList agent={agent} config={config} />
105
+ </TabsContent>
71
106
 
72
- <TabsContent value="capacidades" className="mt-4">
73
- <AgentCapabilitiesPage
74
- config={config}
107
+ <TabsContent value="capacidades" className="mt-4">
108
+ <CapabilitiesTab config={config} agentId={agent.id} />
109
+ </TabsContent>
110
+
111
+ <TabsContent value="integracoes" className="mt-4">
112
+ <IntegrationsTab config={config} agentId={agent.id} onConnect={handleConnect} />
113
+ </TabsContent>
114
+
115
+ <TabsContent value="conversas" className="mt-4">
116
+ <AgentConversationsPanel
117
+ agent={agent}
118
+ config={config}
119
+ renderChatLink={renderChatLink}
120
+ />
121
+ </TabsContent>
122
+ </Tabs>
123
+
124
+ {activeCard && wizardMeta && (
125
+ <IntegrationWizard
126
+ open={wizardOpen}
127
+ onOpenChange={handleWizardClose}
128
+ integration={activeCard.definition}
129
+ meta={wizardMeta}
75
130
  agentId={agent.id}
131
+ config={config}
76
132
  gagentsApiUrl={apiUrl}
77
- resolveWizardMeta={resolveWizardMeta}
133
+ existingCredentialId={activeCard.credentialId}
134
+ onComplete={handleWizardComplete}
78
135
  loadConfigOptions={loadConfigOptions}
79
- onWizardComplete={onWizardComplete}
80
- />
81
- </TabsContent>
82
-
83
- <TabsContent value="conversas" className="mt-4">
84
- <AgentConversationsPanel
85
- agent={agent}
86
- config={config}
87
- renderChatLink={renderChatLink}
88
136
  />
89
- </TabsContent>
90
- </Tabs>
137
+ )}
138
+ </>
91
139
  );
92
140
  }
@@ -2,9 +2,7 @@
2
2
 
3
3
  import { useState } from "react";
4
4
  import type { GagentsHookConfig } from "../../hooks/types";
5
- import { useToolCredentials } from "../../hooks";
6
5
  import { ToolsTable } from "../tools/tools-table";
7
- import { ToolCredentialsForm } from "../tools/tool-credentials-form";
8
6
  import { ToolFormDialog } from "../tools/tool-form-dialog";
9
7
  import type { Tool } from "../../types";
10
8
  import { Info } from "lucide-react";
@@ -24,10 +22,6 @@ export interface AdvancedTabProps {
24
22
  // ---------------------------------------------------------------------------
25
23
 
26
24
  export function AdvancedTab({ config, agentId, gagentsApiUrl }: AdvancedTabProps) {
27
- const { data: credentialsData, isLoading: isLoadingCredentials } =
28
- useToolCredentials(config);
29
- const credentials = credentialsData?.data ?? [];
30
-
31
25
  const [editingTool, setEditingTool] = useState<Tool | null>(null);
32
26
  const [showToolForm, setShowToolForm] = useState(false);
33
27
 
@@ -49,7 +43,7 @@ export function AdvancedTab({ config, agentId, gagentsApiUrl }: AdvancedTabProps
49
43
  <p className="text-sm text-blue-800 dark:text-blue-300">
50
44
  Use as abas <strong>Capacidades</strong> e <strong>Integrações</strong> para
51
45
  configuração simplificada. Esta aba oferece controlo manual avançado sobre
52
- ferramentas e credenciais.
46
+ ferramentas. As credenciais são geridas dentro de cada ferramenta.
53
47
  </p>
54
48
  </div>
55
49
 
@@ -59,17 +53,6 @@ export function AdvancedTab({ config, agentId, gagentsApiUrl }: AdvancedTabProps
59
53
  <ToolsTable onEdit={handleEditTool} config={config} />
60
54
  </section>
61
55
 
62
- {/* Credenciais section */}
63
- <section className="space-y-3">
64
- <h3 className="text-sm font-medium">Credenciais</h3>
65
- <ToolCredentialsForm
66
- credentials={credentials}
67
- isLoading={isLoadingCredentials}
68
- config={config}
69
- gagentsApiUrl={gagentsApiUrl}
70
- />
71
- </section>
72
-
73
56
  {/* Tool edit dialog */}
74
57
  <ToolFormDialog
75
58
  open={showToolForm}
@@ -1,6 +1,6 @@
1
1
  'use client';
2
2
 
3
- import { useState, useCallback, useRef, useEffect, useMemo } from "react";
3
+ import { useState, useCallback, useEffect, useMemo } from "react";
4
4
  import type { GagentsHookConfig } from "../../hooks/types";
5
5
  import {
6
6
  useCapabilities,
@@ -31,6 +31,7 @@ import {
31
31
  HeartHandshake,
32
32
  Package,
33
33
  ChevronDown,
34
+ Loader2,
34
35
  } from "lucide-react";
35
36
  import { toast } from "sonner";
36
37
 
@@ -129,7 +130,6 @@ export function CapabilitiesTab({ config, agentId }: CapabilitiesTabProps) {
129
130
  const [localState, setLocalState] = useState<CapabilityState>(new Map());
130
131
  const [serverState, setServerState] = useState<CapabilityState>(new Map());
131
132
  const [initialized, setInitialized] = useState(false);
132
- const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
133
133
 
134
134
  // Sync server data into local state on first load / refetch
135
135
  useEffect(() => {
@@ -151,41 +151,12 @@ export function CapabilitiesTab({ config, agentId }: CapabilitiesTabProps) {
151
151
  [localState, serverState, initialized],
152
152
  );
153
153
 
154
- // ------ Debounced save ------
155
- const scheduleSave = useCallback(
156
- (nextState: CapabilityState) => {
157
- if (debounceRef.current) clearTimeout(debounceRef.current);
158
- debounceRef.current = setTimeout(() => {
159
- const payload = stateToPayload(nextState);
160
- updateMutation.mutate(
161
- { agentId, payload },
162
- {
163
- onSuccess: () => {
164
- setServerState(cloneState(nextState));
165
- toast.success("Capacidades salvas");
166
- },
167
- onError: () => {
168
- // Rollback to server state
169
- setLocalState(cloneState(serverState));
170
- toast.error("Erro ao salvar capacidades");
171
- },
172
- },
173
- );
174
- }, 500);
175
- },
176
- [agentId, updateMutation, serverState],
177
- );
178
-
179
154
  // ------ State mutation helpers ------
180
155
  const updateState = useCallback(
181
156
  (updater: (prev: CapabilityState) => CapabilityState) => {
182
- setLocalState((prev) => {
183
- const next = updater(prev);
184
- scheduleSave(next);
185
- return next;
186
- });
157
+ setLocalState((prev) => updater(prev));
187
158
  },
188
- [scheduleSave],
159
+ [],
189
160
  );
190
161
 
191
162
  const toggleModule = useCallback(
@@ -242,12 +213,10 @@ export function CapabilitiesTab({ config, agentId }: CapabilitiesTabProps) {
242
213
  }, [updateState]);
243
214
 
244
215
  const discard = useCallback(() => {
245
- if (debounceRef.current) clearTimeout(debounceRef.current);
246
216
  setLocalState(cloneState(serverState));
247
217
  }, [serverState]);
248
218
 
249
219
  const saveNow = useCallback(() => {
250
- if (debounceRef.current) clearTimeout(debounceRef.current);
251
220
  const payload = stateToPayload(localState);
252
221
  updateMutation.mutate(
253
222
  { agentId, payload },
@@ -368,20 +337,15 @@ export function CapabilitiesTab({ config, agentId }: CapabilitiesTabProps) {
368
337
 
369
338
  {/* Save bar */}
370
339
  {hasChanges && (
371
- <div className="sticky bottom-0 bg-background border-t py-3 px-4 -mx-4 flex items-center justify-between">
372
- <span className="text-sm text-muted-foreground">
373
- Você tem alterações não salvas.
374
- </span>
375
- <div className="flex items-center gap-2">
376
- <Button variant="outline" size="sm" onClick={discard}>
340
+ <div className="sticky bottom-0 z-10 flex items-center justify-between gap-2 rounded-lg border bg-background p-3 shadow-sm">
341
+ <p className="text-sm text-muted-foreground">Você tem alterações não salvas.</p>
342
+ <div className="flex gap-2">
343
+ <Button variant="ghost" size="sm" onClick={discard} disabled={updateMutation.isPending}>
377
344
  Descartar
378
345
  </Button>
379
- <Button
380
- size="sm"
381
- onClick={saveNow}
382
- disabled={updateMutation.isPending}
383
- >
384
- {updateMutation.isPending ? "Salvando..." : "Salvar"}
346
+ <Button size="sm" onClick={saveNow} disabled={updateMutation.isPending}>
347
+ {updateMutation.isPending && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
348
+ Salvar
385
349
  </Button>
386
350
  </div>
387
351
  </div>