@greatapps/greatagents-ui 0.3.6 → 0.3.8

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.6",
3
+ "version": "0.3.8",
4
4
  "description": "Shared agents UI components for Great platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -3,7 +3,6 @@ import type { GagentsHookConfig } from "../../hooks/types";
3
3
  import type { IntegrationCardData } from "../../hooks/use-integrations";
4
4
  import type { WizardIntegrationMeta } from "../capabilities/types";
5
5
  import type { ConfigOption } from "../capabilities/wizard-steps/config-step";
6
- import { AgentToolsList } from "./agent-tools-list";
7
6
  import { AgentObjectivesList } from "./agent-objectives-list";
8
7
  import { AgentPromptEditor } from "./agent-prompt-editor";
9
8
  import { AgentConversationsPanel } from "../conversations/agent-conversations-panel";
@@ -14,7 +13,7 @@ import {
14
13
  TabsTrigger,
15
14
  TabsContent,
16
15
  } from "@greatapps/greatauth-ui/ui";
17
- import { Wrench, Target, FileText, MessageCircle, Blocks } from "lucide-react";
16
+ import { Target, FileText, MessageCircle, Blocks } from "lucide-react";
18
17
 
19
18
  interface AgentTabsProps {
20
19
  agent: Agent;
@@ -52,10 +51,6 @@ export function AgentTabs({
52
51
  <Target aria-hidden="true" className="h-3.5 w-3.5" />
53
52
  Objetivos
54
53
  </TabsTrigger>
55
- <TabsTrigger value="ferramentas" className="flex items-center gap-1.5">
56
- <Wrench aria-hidden="true" className="h-3.5 w-3.5" />
57
- Ferramentas
58
- </TabsTrigger>
59
54
  <TabsTrigger value="capacidades" className="flex items-center gap-1.5">
60
55
  <Blocks aria-hidden="true" className="h-3.5 w-3.5" />
61
56
  Capacidades
@@ -74,10 +69,6 @@ export function AgentTabs({
74
69
  <AgentObjectivesList agent={agent} config={config} />
75
70
  </TabsContent>
76
71
 
77
- <TabsContent value="ferramentas" className="mt-4">
78
- <AgentToolsList agent={agent} config={config} />
79
- </TabsContent>
80
-
81
72
  <TabsContent value="capacidades" className="mt-4">
82
73
  <AgentCapabilitiesPage
83
74
  config={config}
@@ -70,10 +70,15 @@ export function AgentToolsList({ agent, config }: AgentToolsListProps) {
70
70
  const allCredentials: ToolCredential[] = credentialsData?.data || [];
71
71
 
72
72
  const agentTools = agentToolsData?.data || [];
73
- const allTools = allToolsData?.data || [];
73
+ const allTools = (allToolsData?.data || []).filter((t: Tool) => !t.slug?.startsWith("gclinic_"));
74
74
  const assignedToolIds = new Set(agentTools.map((at) => at.id_tool));
75
- const availableTools = allTools.filter((t) => !assignedToolIds.has(t.id));
76
- const filteredAvailable = availableTools.filter((t) =>
75
+ // Filter out internal gclinic_* tools from assigned tools display
76
+ const visibleAgentTools = agentTools.filter((at) => {
77
+ const tool = allTools.find((t: Tool) => t.id === at.id_tool);
78
+ return !tool || !tool.slug?.startsWith("gclinic_");
79
+ });
80
+ const availableTools = allTools.filter((t: Tool) => !assignedToolIds.has(t.id));
81
+ const filteredAvailable = availableTools.filter((t: Tool) =>
77
82
  t.name.toLowerCase().includes(search.toLowerCase()),
78
83
  );
79
84
 
@@ -170,7 +175,7 @@ export function AgentToolsList({ agent, config }: AgentToolsListProps) {
170
175
  <div className="space-y-4 p-4">
171
176
  <div className="flex items-center justify-between">
172
177
  <h3 className="text-sm font-medium text-muted-foreground">
173
- {agentTools.length} ferramenta{agentTools.length !== 1 ? "s" : ""} associada{agentTools.length !== 1 ? "s" : ""}
178
+ {visibleAgentTools.length} ferramenta{visibleAgentTools.length !== 1 ? "s" : ""} associada{visibleAgentTools.length !== 1 ? "s" : ""}
174
179
  </h3>
175
180
  <Popover open={addOpen} onOpenChange={setAddOpen}>
176
181
  <PopoverTrigger asChild>
@@ -217,7 +222,7 @@ export function AgentToolsList({ agent, config }: AgentToolsListProps) {
217
222
  </Popover>
218
223
  </div>
219
224
 
220
- {agentTools.length === 0 ? (
225
+ {visibleAgentTools.length === 0 ? (
221
226
  <div className="flex flex-col items-center justify-center rounded-lg border border-dashed p-8 text-center">
222
227
  <Wrench className="mb-2 h-8 w-8 text-muted-foreground" />
223
228
  <p className="text-sm text-muted-foreground">
@@ -226,7 +231,7 @@ export function AgentToolsList({ agent, config }: AgentToolsListProps) {
226
231
  </div>
227
232
  ) : (
228
233
  <div className="space-y-2">
229
- {agentTools.map((agentTool) => {
234
+ {visibleAgentTools.map((agentTool) => {
230
235
  const tool = getToolInfo(agentTool.id_tool);
231
236
  return (
232
237
  <div
@@ -337,7 +337,7 @@ export function CapabilitiesTab({ config, agentId }: CapabilitiesTabProps) {
337
337
  </Badge>
338
338
  </div>
339
339
  </AccordionTrigger>
340
- <AccordionContent className="pb-3">
340
+ <AccordionContent className="pb-3 !h-auto">
341
341
  <div className="space-y-1">
342
342
  {cat.modules.map((mod) => {
343
343
  const enabledOps = localState.get(mod.slug);
@@ -218,49 +218,64 @@ export function IntegrationWizard({
218
218
  // OAuth start
219
219
  // -----------------------------------------------------------------------
220
220
 
221
- function startOAuth() {
222
- const { language = "pt-br", idWl = 1, accountId } = config;
223
-
224
- // Build OAuth authorize URL -- the backend already handles the full flow
225
- const redirectUri = `${window.location.origin}/oauth/callback`;
226
- const url = new URL(
227
- `${gagentsApiUrl}/v1/${language}/${idWl}/accounts/${accountId}/oauth/authorize/${integration.slug}`,
228
- );
229
- url.searchParams.set("redirect_uri", redirectUri);
221
+ async function startOAuth() {
222
+ const { language = "pt-br", idWl = 1, accountId, token } = config;
230
223
 
231
224
  setOauthStatus("waiting");
232
225
 
233
- // Open popup
234
- const popup = window.open(
235
- url.toString(),
236
- "oauth-popup",
237
- "width=500,height=600,scrollbars=yes,resizable=yes",
238
- );
239
- popupRef.current = popup;
240
-
241
- // Poll for popup closed without completing
242
- if (popup) {
243
- // Clear any previous poll interval
244
- if (popupPollRef.current) {
245
- clearInterval(popupPollRef.current);
226
+ try {
227
+ // 1. Get auth URL from backend
228
+ const response = await fetch(
229
+ `${gagentsApiUrl}/v1/${language}/${idWl}/accounts/${accountId}/oauth/authorize/${integration.slug}`,
230
+ { headers: { Authorization: `Bearer ${token}` } },
231
+ );
232
+ const result = await response.json();
233
+
234
+ if (result.status !== 1 || !result.data?.auth_url) {
235
+ setOauthStatus("error");
236
+ setOauthResult({
237
+ success: false,
238
+ error: result.message || "Erro ao obter URL de autorização",
239
+ });
240
+ return;
246
241
  }
247
- popupPollRef.current = setInterval(() => {
248
- if (popup.closed) {
249
- if (popupPollRef.current) {
250
- clearInterval(popupPollRef.current);
251
- popupPollRef.current = null;
252
- }
253
- // Only set error if we're still waiting (no success message received)
254
- setOauthStatus((prev) =>
255
- prev === "waiting" ? "error" : prev,
256
- );
257
- setOauthResult((prev) =>
258
- prev === null
259
- ? { success: false, error: "Janela fechada antes de concluir" }
260
- : prev,
261
- );
242
+
243
+ // 2. Open auth URL in popup
244
+ const popup = window.open(
245
+ result.data.auth_url,
246
+ "oauth-popup",
247
+ "width=500,height=600,scrollbars=yes,resizable=yes",
248
+ );
249
+ popupRef.current = popup;
250
+
251
+ // Poll for popup closed without completing
252
+ if (popup) {
253
+ if (popupPollRef.current) {
254
+ clearInterval(popupPollRef.current);
262
255
  }
263
- }, 500);
256
+ popupPollRef.current = setInterval(() => {
257
+ if (popup.closed) {
258
+ if (popupPollRef.current) {
259
+ clearInterval(popupPollRef.current);
260
+ popupPollRef.current = null;
261
+ }
262
+ setOauthStatus((prev) =>
263
+ prev === "waiting" ? "error" : prev,
264
+ );
265
+ setOauthResult((prev) =>
266
+ prev === null
267
+ ? { success: false, error: "Janela fechada antes de concluir" }
268
+ : prev,
269
+ );
270
+ }
271
+ }, 500);
272
+ }
273
+ } catch (err) {
274
+ setOauthStatus("error");
275
+ setOauthResult({
276
+ success: false,
277
+ error: "Erro de rede ao obter URL de autorização",
278
+ });
264
279
  }
265
280
  }
266
281
 
@@ -77,7 +77,11 @@ function OAuthCredentials({
77
77
  {/* OAuth status area */}
78
78
  <div className="flex flex-col items-center gap-4 rounded-lg border p-6">
79
79
  {oauthStatus === "idle" && (
80
- <Button onClick={onStartOAuth} size="lg" className="gap-2">
80
+ <Button
81
+ onClick={onStartOAuth}
82
+ size="lg"
83
+ className="gap-2"
84
+ >
81
85
  {meta.icon}
82
86
  {isReconnect
83
87
  ? `Reconectar com ${providerLabel}`
@@ -185,7 +185,7 @@ export function ToolCredentialsForm({
185
185
  const updateMutation = useUpdateToolCredential(config);
186
186
  const deleteMutation = useDeleteToolCredential(config);
187
187
  const { data: toolsData } = useTools(config);
188
- const tools: Tool[] = toolsData?.data || [];
188
+ const tools: Tool[] = (toolsData?.data || []).filter((t: Tool) => !t.slug?.startsWith("gclinic_"));
189
189
 
190
190
  const [search, setSearch] = useState("");
191
191
  const [internalCreateOpen, setInternalCreateOpen] = useState(false);
@@ -209,17 +209,31 @@ export function ToolCredentialsForm({
209
209
 
210
210
  const [removeTarget, setRemoveTarget] = useState<ToolCredential | null>(null);
211
211
 
212
+ // Build a set of internal tool IDs to exclude from credentials display
213
+ const internalToolIds = useMemo(() => {
214
+ const allRawTools: Tool[] = toolsData?.data || [];
215
+ return new Set(
216
+ allRawTools
217
+ .filter((t: Tool) => t.slug?.startsWith("gclinic_"))
218
+ .map((t: Tool) => t.id),
219
+ );
220
+ }, [toolsData]);
221
+
212
222
  const filteredCredentials = useMemo(() => {
213
- if (!search) return credentials;
223
+ // Exclude credentials linked to internal gclinic_* tools
224
+ const visible = credentials.filter(
225
+ (cred) => !cred.id_tool || !internalToolIds.has(cred.id_tool),
226
+ );
227
+ if (!search) return visible;
214
228
  const term = search.toLowerCase();
215
- return credentials.filter((cred) => {
229
+ return visible.filter((cred) => {
216
230
  const toolName = tools.find((t) => t.id === cred.id_tool)?.name || "";
217
231
  return (
218
232
  (cred.label || "").toLowerCase().includes(term) ||
219
233
  toolName.toLowerCase().includes(term)
220
234
  );
221
235
  });
222
- }, [credentials, search, tools]);
236
+ }, [credentials, search, tools, internalToolIds]);
223
237
 
224
238
  const columns = useColumns(
225
239
  tools,
@@ -145,8 +145,9 @@ export function ToolsTable({ onEdit, config }: ToolsTableProps) {
145
145
  const deleteTool = useDeleteTool(config);
146
146
  const [deleteId, setDeleteId] = useState<number | null>(null);
147
147
 
148
- const tools = data?.data || [];
149
- const total = data?.total || 0;
148
+ const rawTools = data?.data || [];
149
+ const tools = rawTools.filter((t: Tool) => !t.slug?.startsWith("gclinic_"));
150
+ const total = tools.length;
150
151
 
151
152
  const columns = useColumns(
152
153
  (tool) => onEdit(tool),