@greatapps/greatagents-ui 0.3.14 → 0.3.15

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.
@@ -1,22 +1,15 @@
1
1
  'use client';
2
2
 
3
3
  import { useMemo, useCallback, useState } from "react";
4
+ import { useQueryClient } from "@tanstack/react-query";
4
5
  import { useToolCredentials, useAgents, useTools } from "../hooks";
5
- import { ToolCredentialsForm } from "../components/tools/tool-credentials-form";
6
6
  import { IntegrationCard } from "../components/capabilities/integration-card";
7
7
  import { IntegrationWizard } from "../components/capabilities/integration-wizard";
8
8
  import { useIntegrationState, type IntegrationCardData } from "../hooks/use-integrations";
9
+ import { useDeleteToolCredential, useUpdateToolCredential } from "../hooks/use-settings";
9
10
  import type { WizardIntegrationMeta } from "../components/capabilities/types";
10
11
  import type { ConfigOption } from "../components/capabilities/wizard-steps/config-step";
11
- import {
12
- Badge,
13
- Button,
14
- Tabs,
15
- TabsContent,
16
- TabsList,
17
- TabsTrigger,
18
- } from "@greatapps/greatauth-ui/ui";
19
- import { Plug, KeyRound, Info, Loader2 } from "lucide-react";
12
+ import { Plug, Loader2 } from "lucide-react";
20
13
  import type { GagentsHookConfig } from "../hooks/types";
21
14
  import type { Agent, Tool, ToolCredential } from "../types";
22
15
 
@@ -33,45 +26,17 @@ export interface IntegrationsManagementPageProps {
33
26
  subtitle?: string;
34
27
  }
35
28
 
36
- /**
37
- * Build a map of credential id -> list of agent names that use it.
38
- */
39
- function useCredentialAgentSummary(
40
- credentials: ToolCredential[],
41
- tools: Tool[],
42
- agents: Agent[],
43
- ) {
44
- return useMemo(() => {
45
- const toolIdsWithCredentials = new Set(
46
- credentials.map((c) => c.id_tool).filter(Boolean),
47
- );
48
-
49
- const linkedCount = credentials.filter(
50
- (c) => c.id_tool && toolIdsWithCredentials.has(c.id_tool),
51
- ).length;
52
-
53
- return {
54
- totalCredentials: credentials.length,
55
- linkedToTools: linkedCount,
56
- totalAgents: agents.length,
57
- totalTools: tools.length,
58
- };
59
- }, [credentials, tools, agents]);
60
- }
61
-
62
29
  export function IntegrationsManagementPage({
63
30
  config,
64
31
  gagentsApiUrl,
65
32
  resolveWizardMeta,
66
33
  loadConfigOptions,
67
34
  onWizardComplete,
68
- title = "Integrações e Credenciais",
69
- subtitle = "Gerencie todas as integrações e credenciais da conta.",
35
+ title = "Integrações",
36
+ subtitle = "Gerencie as integrações da conta.",
70
37
  }: IntegrationsManagementPageProps) {
71
- const { data: credentialsData, isLoading: credentialsLoading } =
72
- useToolCredentials(config);
73
- const { data: agentsData } = useAgents(config);
74
- const { data: toolsData } = useTools(config);
38
+ const queryClient = useQueryClient();
39
+
75
40
  // Integration cards state (account-level, agentId=null)
76
41
  const { cards, isLoading: cardsLoading } = useIntegrationState(config, null);
77
42
 
@@ -79,17 +44,33 @@ export function IntegrationsManagementPage({
79
44
  const [wizardOpen, setWizardOpen] = useState(false);
80
45
  const [activeCard, setActiveCard] = useState<IntegrationCardData | null>(null);
81
46
 
82
- const credentials = credentialsData?.data || [];
83
- const agents: Agent[] = agentsData?.data || [];
84
- const tools: Tool[] = toolsData?.data || [];
85
-
86
- const summary = useCredentialAgentSummary(credentials, tools, agents);
47
+ // Mutations for card actions
48
+ const deleteCredential = useDeleteToolCredential(config);
49
+ const updateCredential = useUpdateToolCredential(config);
87
50
 
88
51
  const handleConnect = useCallback((card: IntegrationCardData) => {
89
52
  setActiveCard(card);
90
53
  setWizardOpen(true);
91
54
  }, []);
92
55
 
56
+ const handleReconnect = useCallback((card: IntegrationCardData) => {
57
+ setActiveCard(card);
58
+ setWizardOpen(true);
59
+ }, []);
60
+
61
+ const handleDisconnect = useCallback((card: IntegrationCardData) => {
62
+ if (!card.credentialId) return;
63
+ updateCredential.mutate({
64
+ id: card.credentialId,
65
+ body: { status: "inactive" },
66
+ });
67
+ }, [updateCredential]);
68
+
69
+ const handleDelete = useCallback((card: IntegrationCardData) => {
70
+ if (!card.credentialId) return;
71
+ deleteCredential.mutate(card.credentialId);
72
+ }, [deleteCredential]);
73
+
93
74
  const handleWizardClose = useCallback((open: boolean) => {
94
75
  if (!open) {
95
76
  setActiveCard(null);
@@ -98,10 +79,15 @@ export function IntegrationsManagementPage({
98
79
  }, []);
99
80
 
100
81
  const handleWizardComplete = useCallback(() => {
82
+ // Invalidate queries BEFORE closing so data refreshes
83
+ queryClient.invalidateQueries({ queryKey: ["greatagents", "tool-credentials"] });
84
+ queryClient.invalidateQueries({ queryKey: ["greatagents", "tools"] });
85
+ queryClient.invalidateQueries({ queryKey: ["greatagents", "agent-tools"] });
86
+
101
87
  setWizardOpen(false);
102
88
  setActiveCard(null);
103
89
  onWizardComplete?.();
104
- }, [onWizardComplete]);
90
+ }, [onWizardComplete, queryClient]);
105
91
 
106
92
  // Resolve wizard meta with sensible defaults
107
93
  const wizardMeta: WizardIntegrationMeta | null = activeCard
@@ -129,120 +115,64 @@ export function IntegrationsManagementPage({
129
115
  </div>
130
116
  </div>
131
117
 
132
- <Tabs defaultValue="integrations" className="w-full">
133
- <TabsList>
134
- <TabsTrigger value="integrations" className="gap-2">
135
- <Plug className="h-4 w-4" />
136
- Integrações
137
- </TabsTrigger>
138
- <TabsTrigger value="credentials" className="gap-2">
139
- <KeyRound className="h-4 w-4" />
140
- Credenciais
141
- </TabsTrigger>
142
- </TabsList>
143
-
144
- <TabsContent value="integrations" className="mt-4">
145
- {cardsLoading ? (
146
- <div className="flex items-center justify-center py-16">
147
- <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
148
- </div>
149
- ) : cards.length === 0 ? (
150
- <div className="flex flex-col items-center justify-center gap-3 py-16 text-muted-foreground">
151
- <Plug className="h-10 w-10" />
152
- <p className="text-sm">Nenhuma integração disponível</p>
153
- </div>
154
- ) : (
155
- <div className="space-y-6">
156
- {/* Connected accounts */}
157
- {connectedCards.length > 0 && (
158
- <div>
159
- <h3 className="mb-3 text-xs font-medium uppercase tracking-wider text-muted-foreground">
160
- Contas conectadas
161
- </h3>
162
- <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
163
- {connectedCards.map((card) => (
164
- <IntegrationCard
165
- key={`${card.definition.slug}-cred-${card.credentialId}`}
166
- card={card}
167
- onConnect={handleConnect}
168
- />
169
- ))}
170
- </div>
171
- </div>
172
- )}
173
-
174
- {/* Add new / coming soon */}
175
- {otherCards.length > 0 && (
176
- <div>
177
- {connectedCards.length > 0 && (
178
- <h3 className="mb-3 text-xs font-medium uppercase tracking-wider text-muted-foreground">
179
- Adicionar integração
180
- </h3>
181
- )}
182
- <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
183
- {otherCards.map((card) => {
184
- const key = card.isAddNew
185
- ? `${card.definition.slug}-add-new`
186
- : card.definition.slug;
187
- return (
188
- <IntegrationCard
189
- key={key}
190
- card={card}
191
- onConnect={handleConnect}
192
- />
193
- );
194
- })}
195
- </div>
196
- </div>
197
- )}
118
+ {cardsLoading ? (
119
+ <div className="flex items-center justify-center py-16">
120
+ <Loader2 className="h-6 w-6 animate-spin text-muted-foreground" />
121
+ </div>
122
+ ) : cards.length === 0 ? (
123
+ <div className="flex flex-col items-center justify-center gap-3 py-16 text-muted-foreground">
124
+ <Plug className="h-10 w-10" />
125
+ <p className="text-sm">Nenhuma integração disponível</p>
126
+ </div>
127
+ ) : (
128
+ <div className="space-y-6">
129
+ {/* Connected accounts */}
130
+ {connectedCards.length > 0 && (
131
+ <div>
132
+ <h3 className="mb-3 text-xs font-medium uppercase tracking-wider text-muted-foreground">
133
+ Contas conectadas
134
+ </h3>
135
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
136
+ {connectedCards.map((card) => (
137
+ <IntegrationCard
138
+ key={`${card.definition.slug}-cred-${card.credentialId}`}
139
+ card={card}
140
+ onConnect={handleConnect}
141
+ onReconnect={handleReconnect}
142
+ onDisconnect={handleDisconnect}
143
+ onDelete={handleDelete}
144
+ />
145
+ ))}
146
+ </div>
198
147
  </div>
199
148
  )}
200
- </TabsContent>
201
149
 
202
- <TabsContent value="credentials" className="mt-4">
203
- {/* Summary bar */}
204
- {!credentialsLoading && (
205
- <div className="flex items-center gap-4 rounded-lg border bg-muted/50 px-4 py-3 mb-4">
206
- <Info className="h-4 w-4 text-muted-foreground shrink-0" />
207
- <div className="flex flex-wrap items-center gap-3 text-sm">
208
- <span>
209
- <Badge variant="secondary" className="mr-1">
210
- {summary.totalCredentials}
211
- </Badge>
212
- {summary.totalCredentials === 1
213
- ? "credencial configurada"
214
- : "credenciais configuradas"}
215
- </span>
216
- <span className="text-muted-foreground">|</span>
217
- <span>
218
- <Badge variant="secondary" className="mr-1">
219
- {summary.linkedToTools}
220
- </Badge>
221
- {summary.linkedToTools === 1
222
- ? "vinculada a ferramentas"
223
- : "vinculadas a ferramentas"}
224
- </span>
225
- <span className="text-muted-foreground">|</span>
226
- <span>
227
- <Badge variant="secondary" className="mr-1">
228
- {summary.totalAgents}
229
- </Badge>
230
- {summary.totalAgents === 1
231
- ? "agente na conta"
232
- : "agentes na conta"}
233
- </span>
150
+ {/* Add new / coming soon */}
151
+ {otherCards.length > 0 && (
152
+ <div>
153
+ {connectedCards.length > 0 && (
154
+ <h3 className="mb-3 text-xs font-medium uppercase tracking-wider text-muted-foreground">
155
+ Adicionar integração
156
+ </h3>
157
+ )}
158
+ <div className="grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3">
159
+ {otherCards.map((card) => {
160
+ const key = card.isAddNew
161
+ ? `${card.definition.slug}-add-new`
162
+ : card.definition.slug;
163
+ return (
164
+ <IntegrationCard
165
+ key={key}
166
+ card={card}
167
+ onConnect={handleConnect}
168
+ />
169
+ );
170
+ })}
234
171
  </div>
235
172
  </div>
236
173
  )}
237
-
238
- <ToolCredentialsForm
239
- config={config}
240
- gagentsApiUrl={gagentsApiUrl}
241
- credentials={credentials}
242
- isLoading={credentialsLoading}
243
- />
244
- </TabsContent>
245
- </Tabs>
174
+ </div>
175
+ )}
246
176
 
247
177
  {/* Integration Wizard */}
248
178
  {activeCard && wizardMeta && (
@@ -105,7 +105,7 @@ export interface ToolCredential {
105
105
  label: string;
106
106
  credentials_encrypted: string;
107
107
  expires_at: string | null;
108
- status: "active" | "expired";
108
+ status: "active" | "expired" | "inactive";
109
109
  authorized_by_contact: number | null;
110
110
  deleted: number;
111
111
  datetime_add: string;