@greatapps/greatagents-ui 0.3.9 → 0.3.10

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/index.d.ts CHANGED
@@ -128,6 +128,8 @@ interface ToolCredential {
128
128
  id: number;
129
129
  id_account: number;
130
130
  id_tool: number;
131
+ id_platform_integration: number | null;
132
+ external_reference: string | null;
131
133
  label: string;
132
134
  credentials_encrypted: string;
133
135
  expires_at: string | null;
@@ -472,11 +474,22 @@ interface IntegrationCardData {
472
474
  sharedByAgentsCount: number;
473
475
  /** Whether this agent has a linked agent_tool for this integration */
474
476
  linkedToAgent: boolean;
477
+ /** Credential ID — set for connected/expired cards, undefined for "add new" */
478
+ credentialId?: number;
479
+ /** Account label (email or label from credential) */
480
+ accountLabel?: string;
481
+ /** Whether this is the "add new account" card */
482
+ isAddNew?: boolean;
475
483
  }
476
484
  /**
477
485
  * Cross-references the static integrations registry with live data
478
486
  * (tools, tool_credentials, agent_tools) to produce card state for each
479
487
  * integration entry.
488
+ *
489
+ * Returns:
490
+ * - One card per existing credential (connected/expired)
491
+ * - One "add new" card per integration type
492
+ * - Coming soon cards as before
480
493
  */
481
494
  declare function useIntegrationState(config: GagentsHookConfig, agentId: number | null): {
482
495
  cards: IntegrationCardData[];
package/dist/index.js CHANGED
@@ -518,34 +518,55 @@ function useIntegrationState(config, agentId) {
518
518
  const credentials = credentialsData?.data ?? [];
519
519
  const tools = toolsData?.data ?? [];
520
520
  const agentTools = agentToolsData?.data ?? [];
521
- return INTEGRATIONS_REGISTRY.map((def) => {
521
+ const result = [];
522
+ for (const def of INTEGRATIONS_REGISTRY) {
522
523
  if (def.status === "coming_soon") {
523
- return {
524
+ result.push({
524
525
  definition: def,
525
526
  state: "coming_soon",
526
527
  credential: null,
527
528
  tool: null,
528
529
  sharedByAgentsCount: 0,
529
530
  linkedToAgent: false
530
- };
531
+ });
532
+ continue;
531
533
  }
532
534
  const matchedTool = tools.find((t) => t.slug === def.slug) ?? null;
533
- const matchedCredential = matchedTool ? credentials.find((c) => c.id_tool === matchedTool.id) ?? null : null;
535
+ const matchedCredentials = matchedTool ? credentials.filter((c) => c.id_tool === matchedTool.id) : [];
536
+ const piCredentials = credentials.filter(
537
+ (c) => c.id_platform_integration != null && !c.id_tool && // We can't directly match slug here since we don't have
538
+ // platform_integrations data, but credentials with
539
+ // id_platform_integration are for calendar integrations
540
+ // which match by the registry slug
541
+ matchedTool == null
542
+ );
543
+ const allCredentials = matchedCredentials.length > 0 ? matchedCredentials : piCredentials;
534
544
  const linkedToAgent = matchedTool ? agentTools.some((at) => at.id_tool === matchedTool.id) : false;
535
- const sharedByAgentsCount = matchedCredential ? 1 : 0;
536
- let state = "available";
537
- if (matchedCredential) {
538
- state = matchedCredential.status === "expired" ? "expired" : "connected";
545
+ for (const cred of allCredentials) {
546
+ const state = cred.status === "expired" ? "expired" : "connected";
547
+ const accountLabel = cred.external_reference || cred.label || void 0;
548
+ result.push({
549
+ definition: def,
550
+ state,
551
+ credential: cred,
552
+ tool: matchedTool,
553
+ sharedByAgentsCount: 1,
554
+ linkedToAgent,
555
+ credentialId: cred.id,
556
+ accountLabel
557
+ });
539
558
  }
540
- return {
559
+ result.push({
541
560
  definition: def,
542
- state,
543
- credential: matchedCredential,
561
+ state: "available",
562
+ credential: null,
544
563
  tool: matchedTool,
545
- sharedByAgentsCount,
546
- linkedToAgent
547
- };
548
- });
564
+ sharedByAgentsCount: 0,
565
+ linkedToAgent: false,
566
+ isAddNew: true
567
+ });
568
+ }
569
+ return result;
549
570
  }, [credentialsData, toolsData, agentToolsData]);
550
571
  return { cards, isLoading };
551
572
  }
@@ -2846,7 +2867,8 @@ import {
2846
2867
  Settings as Settings2,
2847
2868
  RefreshCw,
2848
2869
  Users as Users2,
2849
- Clock
2870
+ Clock,
2871
+ Plus as Plus2
2850
2872
  } from "lucide-react";
2851
2873
  import { jsx as jsx11, jsxs as jsxs9 } from "react/jsx-runtime";
2852
2874
  var ICON_MAP = {
@@ -2855,7 +2877,8 @@ var ICON_MAP = {
2855
2877
  Settings: Settings2,
2856
2878
  RefreshCw,
2857
2879
  Users: Users2,
2858
- Clock
2880
+ Clock,
2881
+ Plus: Plus2
2859
2882
  };
2860
2883
  function resolveIcon(name) {
2861
2884
  return ICON_MAP[name] ?? Plug;
@@ -2878,8 +2901,9 @@ var STATE_BADGES = {
2878
2901
  className: "bg-muted text-muted-foreground"
2879
2902
  }
2880
2903
  };
2881
- function getActionLabel(state) {
2882
- switch (state) {
2904
+ function getActionLabel(card) {
2905
+ if (card.isAddNew) return "Conectar";
2906
+ switch (card.state) {
2883
2907
  case "available":
2884
2908
  return "Conectar";
2885
2909
  case "connected":
@@ -2891,11 +2915,58 @@ function getActionLabel(state) {
2891
2915
  }
2892
2916
  }
2893
2917
  function IntegrationCard({ card, onConnect }) {
2894
- const { definition, state, sharedByAgentsCount } = card;
2918
+ const { definition, state, sharedByAgentsCount, isAddNew, accountLabel } = card;
2895
2919
  const Icon = resolveIcon(definition.icon);
2896
- const badge = STATE_BADGES[state];
2897
- const actionLabel = getActionLabel(state);
2898
2920
  const isComingSoon = state === "coming_soon";
2921
+ const actionLabel = getActionLabel(card);
2922
+ if (isAddNew) {
2923
+ return /* @__PURE__ */ jsxs9(
2924
+ "div",
2925
+ {
2926
+ className: cn(
2927
+ "group relative flex flex-col gap-3 rounded-xl border border-dashed bg-card/50 p-5 transition-shadow",
2928
+ "hover:shadow-md hover:border-solid hover:bg-card cursor-pointer"
2929
+ ),
2930
+ role: "button",
2931
+ tabIndex: 0,
2932
+ "aria-label": `Adicionar conta ${definition.name}`,
2933
+ onClick: () => onConnect(card),
2934
+ onKeyDown: (e) => {
2935
+ if (e.key === "Enter" || e.key === " ") {
2936
+ e.preventDefault();
2937
+ onConnect(card);
2938
+ }
2939
+ },
2940
+ children: [
2941
+ /* @__PURE__ */ jsxs9("div", { className: "flex items-start justify-between gap-2", children: [
2942
+ /* @__PURE__ */ jsx11("div", { className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-primary/5 text-primary/60", children: /* @__PURE__ */ jsx11(Icon, { className: "h-5 w-5" }) }),
2943
+ /* @__PURE__ */ jsx11(Badge6, { variant: "outline", className: "text-xs bg-muted text-muted-foreground", children: "Adicionar" })
2944
+ ] }),
2945
+ /* @__PURE__ */ jsxs9("div", { className: "space-y-1", children: [
2946
+ /* @__PURE__ */ jsx11("h3", { className: "text-sm font-semibold leading-tight text-muted-foreground", children: definition.name }),
2947
+ /* @__PURE__ */ jsxs9("p", { className: "text-xs text-muted-foreground/70 leading-relaxed flex items-center gap-1", children: [
2948
+ /* @__PURE__ */ jsx11(Plus2, { className: "h-3 w-3" }),
2949
+ "Adicionar conta"
2950
+ ] })
2951
+ ] }),
2952
+ /* @__PURE__ */ jsx11("div", { className: "mt-auto flex items-center justify-end pt-1", children: /* @__PURE__ */ jsx11(
2953
+ Button8,
2954
+ {
2955
+ variant: "outline",
2956
+ size: "sm",
2957
+ className: "text-xs",
2958
+ onClick: (e) => {
2959
+ e.stopPropagation();
2960
+ onConnect(card);
2961
+ },
2962
+ children: actionLabel
2963
+ }
2964
+ ) })
2965
+ ]
2966
+ }
2967
+ );
2968
+ }
2969
+ const badge = STATE_BADGES[state];
2899
2970
  return /* @__PURE__ */ jsxs9(
2900
2971
  "div",
2901
2972
  {
@@ -2905,7 +2976,7 @@ function IntegrationCard({ card, onConnect }) {
2905
2976
  ),
2906
2977
  role: "button",
2907
2978
  tabIndex: isComingSoon ? -1 : 0,
2908
- "aria-label": `${definition.name} \u2014 ${badge.label}`,
2979
+ "aria-label": `${definition.name}${accountLabel ? ` \u2014 ${accountLabel}` : ""} \u2014 ${badge.label}`,
2909
2980
  "aria-disabled": isComingSoon,
2910
2981
  onClick: () => !isComingSoon && onConnect(card),
2911
2982
  onKeyDown: (e) => {
@@ -2921,7 +2992,7 @@ function IntegrationCard({ card, onConnect }) {
2921
2992
  ] }),
2922
2993
  /* @__PURE__ */ jsxs9("div", { className: "space-y-1", children: [
2923
2994
  /* @__PURE__ */ jsx11("h3", { className: "text-sm font-semibold leading-tight", children: definition.name }),
2924
- /* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground leading-relaxed", children: definition.description })
2995
+ accountLabel ? /* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground leading-relaxed truncate", title: accountLabel, children: accountLabel }) : /* @__PURE__ */ jsx11("p", { className: "text-xs text-muted-foreground leading-relaxed", children: definition.description })
2925
2996
  ] }),
2926
2997
  /* @__PURE__ */ jsxs9("div", { className: "mt-auto flex items-center justify-between gap-2 pt-1", children: [
2927
2998
  sharedByAgentsCount > 0 ? /* @__PURE__ */ jsxs9(Tooltip2, { children: [
@@ -2953,6 +3024,15 @@ function IntegrationCard({ card, onConnect }) {
2953
3024
  // src/components/capabilities/integrations-tab.tsx
2954
3025
  import { Plug as Plug2, Loader2 as Loader24 } from "lucide-react";
2955
3026
  import { jsx as jsx12, jsxs as jsxs10 } from "react/jsx-runtime";
3027
+ function getCardKey(card) {
3028
+ if (card.credentialId) {
3029
+ return `${card.definition.slug}-cred-${card.credentialId}`;
3030
+ }
3031
+ if (card.isAddNew) {
3032
+ return `${card.definition.slug}-add-new`;
3033
+ }
3034
+ return card.definition.slug;
3035
+ }
2956
3036
  function IntegrationsTab({
2957
3037
  config,
2958
3038
  agentId,
@@ -2968,14 +3048,36 @@ function IntegrationsTab({
2968
3048
  /* @__PURE__ */ jsx12("p", { className: "text-sm", children: "Nenhuma integra\xE7\xE3o dispon\xEDvel" })
2969
3049
  ] });
2970
3050
  }
2971
- return /* @__PURE__ */ jsx12("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: cards.map((card) => /* @__PURE__ */ jsx12(
2972
- IntegrationCard,
2973
- {
2974
- card,
2975
- onConnect
2976
- },
2977
- card.definition.slug
2978
- )) });
3051
+ const connectedCards = cards.filter(
3052
+ (c) => !c.isAddNew && (c.state === "connected" || c.state === "expired")
3053
+ );
3054
+ const otherCards = cards.filter(
3055
+ (c) => c.isAddNew || c.state === "coming_soon"
3056
+ );
3057
+ return /* @__PURE__ */ jsxs10("div", { className: "space-y-6", children: [
3058
+ connectedCards.length > 0 && /* @__PURE__ */ jsxs10("div", { children: [
3059
+ /* @__PURE__ */ jsx12("h3", { className: "mb-3 text-xs font-medium uppercase tracking-wider text-muted-foreground", children: "Contas conectadas" }),
3060
+ /* @__PURE__ */ jsx12("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: connectedCards.map((card) => /* @__PURE__ */ jsx12(
3061
+ IntegrationCard,
3062
+ {
3063
+ card,
3064
+ onConnect
3065
+ },
3066
+ getCardKey(card)
3067
+ )) })
3068
+ ] }),
3069
+ otherCards.length > 0 && /* @__PURE__ */ jsxs10("div", { children: [
3070
+ connectedCards.length > 0 && /* @__PURE__ */ jsx12("h3", { className: "mb-3 text-xs font-medium uppercase tracking-wider text-muted-foreground", children: "Adicionar integra\xE7\xE3o" }),
3071
+ /* @__PURE__ */ jsx12("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3", children: otherCards.map((card) => /* @__PURE__ */ jsx12(
3072
+ IntegrationCard,
3073
+ {
3074
+ card,
3075
+ onConnect
3076
+ },
3077
+ getCardKey(card)
3078
+ )) })
3079
+ ] })
3080
+ ] });
2979
3081
  }
2980
3082
 
2981
3083
  // src/components/capabilities/integration-wizard.tsx
@@ -3470,10 +3572,13 @@ function IntegrationWizard({
3470
3572
  const { language = "pt-br", idWl = 1, accountId, token } = config;
3471
3573
  setOauthStatus("waiting");
3472
3574
  try {
3473
- const response = await fetch(
3474
- `${gagentsApiUrl}/v1/${language}/${idWl}/accounts/${accountId}/oauth/authorize/${integration.slug}`,
3475
- { headers: { Authorization: `Bearer ${token}` } }
3476
- );
3575
+ let authorizeUrl = `${gagentsApiUrl}/v1/${language}/${idWl}/accounts/${accountId}/oauth/authorize/${integration.slug}`;
3576
+ if (existingCredentialId) {
3577
+ authorizeUrl += `?credential_id=${existingCredentialId}`;
3578
+ }
3579
+ const response = await fetch(authorizeUrl, {
3580
+ headers: { Authorization: `Bearer ${token}` }
3581
+ });
3477
3582
  const result = await response.json();
3478
3583
  if (result.status !== 1 || !result.data?.auth_url) {
3479
3584
  setOauthStatus("error");
@@ -4950,7 +5055,7 @@ import {
4950
5055
  } from "@greatapps/greatauth-ui/ui";
4951
5056
  import {
4952
5057
  Trash2 as Trash25,
4953
- Plus as Plus2,
5058
+ Plus as Plus3,
4954
5059
  Wrench,
4955
5060
  Settings2 as Settings22
4956
5061
  } from "lucide-react";
@@ -5068,7 +5173,7 @@ function AgentToolsList({ agent, config }) {
5068
5173
  ] }),
5069
5174
  /* @__PURE__ */ jsxs22(Popover, { open: addOpen, onOpenChange: setAddOpen, children: [
5070
5175
  /* @__PURE__ */ jsx24(PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxs22(Button14, { size: "sm", disabled: availableTools.length === 0, children: [
5071
- /* @__PURE__ */ jsx24(Plus2, { className: "mr-2 h-4 w-4" }),
5176
+ /* @__PURE__ */ jsx24(Plus3, { className: "mr-2 h-4 w-4" }),
5072
5177
  "Adicionar Ferramenta"
5073
5178
  ] }) }),
5074
5179
  /* @__PURE__ */ jsxs22(PopoverContent, { className: "w-72 p-0", align: "end", children: [
@@ -5248,7 +5353,7 @@ function AgentToolsList({ agent, config }) {
5248
5353
  // src/pages/agents-page.tsx
5249
5354
  import { useState as useState16 } from "react";
5250
5355
  import { Button as Button15 } from "@greatapps/greatauth-ui/ui";
5251
- import { Plus as Plus3 } from "lucide-react";
5356
+ import { Plus as Plus4 } from "lucide-react";
5252
5357
  import { jsx as jsx25, jsxs as jsxs23 } from "react/jsx-runtime";
5253
5358
  function AgentsPage({
5254
5359
  config,
@@ -5264,7 +5369,7 @@ function AgentsPage({
5264
5369
  /* @__PURE__ */ jsx25("p", { className: "text-sm text-muted-foreground", children: subtitle })
5265
5370
  ] }),
5266
5371
  /* @__PURE__ */ jsxs23(Button15, { onClick: () => setCreateOpen(true), size: "sm", children: [
5267
- /* @__PURE__ */ jsx25(Plus3, { className: "mr-2 h-4 w-4" }),
5372
+ /* @__PURE__ */ jsx25(Plus4, { className: "mr-2 h-4 w-4" }),
5268
5373
  "Novo Agente"
5269
5374
  ] })
5270
5375
  ] }),
@@ -5376,7 +5481,7 @@ function AgentDetailPage({
5376
5481
  // src/pages/tools-page.tsx
5377
5482
  import { useState as useState18 } from "react";
5378
5483
  import { Button as Button17 } from "@greatapps/greatauth-ui/ui";
5379
- import { Plus as Plus4 } from "lucide-react";
5484
+ import { Plus as Plus5 } from "lucide-react";
5380
5485
  import { jsx as jsx27, jsxs as jsxs25 } from "react/jsx-runtime";
5381
5486
  function ToolsPage({
5382
5487
  config,
@@ -5392,7 +5497,7 @@ function ToolsPage({
5392
5497
  /* @__PURE__ */ jsx27("p", { className: "text-sm text-muted-foreground", children: subtitle })
5393
5498
  ] }),
5394
5499
  /* @__PURE__ */ jsxs25(Button17, { onClick: () => setCreateOpen(true), size: "sm", children: [
5395
- /* @__PURE__ */ jsx27(Plus4, { className: "mr-2 h-4 w-4" }),
5500
+ /* @__PURE__ */ jsx27(Plus5, { className: "mr-2 h-4 w-4" }),
5396
5501
  "Nova Ferramenta"
5397
5502
  ] })
5398
5503
  ] }),
@@ -5420,7 +5525,7 @@ function ToolsPage({
5420
5525
  // src/pages/credentials-page.tsx
5421
5526
  import { useState as useState19 } from "react";
5422
5527
  import { Button as Button18 } from "@greatapps/greatauth-ui/ui";
5423
- import { Plus as Plus5 } from "lucide-react";
5528
+ import { Plus as Plus6 } from "lucide-react";
5424
5529
  import { jsx as jsx28, jsxs as jsxs26 } from "react/jsx-runtime";
5425
5530
  function CredentialsPage({
5426
5531
  config,
@@ -5438,7 +5543,7 @@ function CredentialsPage({
5438
5543
  /* @__PURE__ */ jsx28("p", { className: "text-sm text-muted-foreground", children: subtitle })
5439
5544
  ] }),
5440
5545
  /* @__PURE__ */ jsxs26(Button18, { onClick: () => setCreateOpen(true), size: "sm", children: [
5441
- /* @__PURE__ */ jsx28(Plus5, { className: "mr-2 h-4 w-4" }),
5546
+ /* @__PURE__ */ jsx28(Plus6, { className: "mr-2 h-4 w-4" }),
5442
5547
  "Nova Credencial"
5443
5548
  ] })
5444
5549
  ] }),
@@ -5466,7 +5571,7 @@ import {
5466
5571
  TabsList as TabsList3,
5467
5572
  TabsTrigger as TabsTrigger3
5468
5573
  } from "@greatapps/greatauth-ui/ui";
5469
- import { Plus as Plus6, Plug as Plug4, KeyRound, Info as Info3 } from "lucide-react";
5574
+ import { Plus as Plus7, Plug as Plug4, KeyRound, Info as Info3 } from "lucide-react";
5470
5575
  import { jsx as jsx29, jsxs as jsxs27 } from "react/jsx-runtime";
5471
5576
  function useCredentialAgentSummary(credentials, tools, agents) {
5472
5577
  return useMemo8(() => {
@@ -5545,7 +5650,7 @@ function IntegrationsManagementPage({
5545
5650
  ] })
5546
5651
  ] }),
5547
5652
  /* @__PURE__ */ jsx29("div", { className: "flex items-center justify-end mb-4", children: /* @__PURE__ */ jsxs27(Button19, { onClick: () => setCreateOpen(true), size: "sm", children: [
5548
- /* @__PURE__ */ jsx29(Plus6, { className: "mr-2 h-4 w-4" }),
5653
+ /* @__PURE__ */ jsx29(Plus7, { className: "mr-2 h-4 w-4" }),
5549
5654
  "Nova Credencial"
5550
5655
  ] }) }),
5551
5656
  /* @__PURE__ */ jsx29(