@greatapps/greatagents-ui 0.3.13 → 0.3.14
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 +1 -3
- package/dist/index.js +71 -433
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/capabilities/capabilities-tab.tsx +2 -2
- package/src/components/capabilities/integration-card.tsx +3 -21
- package/src/components/capabilities/integrations-tab.tsx +8 -19
- package/src/components/tools/tool-credentials-form.tsx +1 -374
- package/src/pages/credentials-page.tsx +0 -10
- package/src/pages/integrations-management-page.tsx +2 -13
package/package.json
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
Skeleton,
|
|
26
26
|
} from "@greatapps/greatauth-ui/ui";
|
|
27
27
|
import {
|
|
28
|
-
|
|
28
|
+
CalendarCheck,
|
|
29
29
|
Users,
|
|
30
30
|
Settings,
|
|
31
31
|
HeartHandshake,
|
|
@@ -55,7 +55,7 @@ function getOperationLabel(slug: string): string {
|
|
|
55
55
|
// ---------------------------------------------------------------------------
|
|
56
56
|
|
|
57
57
|
const CATEGORY_ICONS: Record<string, React.ElementType> = {
|
|
58
|
-
agenda:
|
|
58
|
+
agenda: CalendarCheck,
|
|
59
59
|
cadastros: Users,
|
|
60
60
|
infraestrutura: Settings,
|
|
61
61
|
relacionamentos: HeartHandshake,
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
|
|
3
3
|
import type { IntegrationCardData, IntegrationCardState } from "../../hooks/use-integrations";
|
|
4
|
-
import { Badge, Button
|
|
4
|
+
import { Badge, Button } from "@greatapps/greatauth-ui/ui";
|
|
5
5
|
import {
|
|
6
6
|
CalendarSync,
|
|
7
7
|
Plug,
|
|
8
8
|
Settings,
|
|
9
9
|
RefreshCw,
|
|
10
|
-
Users,
|
|
11
10
|
Clock,
|
|
12
11
|
Plus,
|
|
13
12
|
} from "lucide-react";
|
|
@@ -23,7 +22,6 @@ const ICON_MAP: Record<string, LucideIcon> = {
|
|
|
23
22
|
Plug,
|
|
24
23
|
Settings,
|
|
25
24
|
RefreshCw,
|
|
26
|
-
Users,
|
|
27
25
|
Clock,
|
|
28
26
|
Plus,
|
|
29
27
|
};
|
|
@@ -84,7 +82,7 @@ export interface IntegrationCardProps {
|
|
|
84
82
|
}
|
|
85
83
|
|
|
86
84
|
export function IntegrationCard({ card, onConnect }: IntegrationCardProps) {
|
|
87
|
-
const { definition, state,
|
|
85
|
+
const { definition, state, isAddNew, accountLabel } = card;
|
|
88
86
|
const Icon = resolveIcon(definition.icon);
|
|
89
87
|
const isComingSoon = state === "coming_soon";
|
|
90
88
|
const actionLabel = getActionLabel(card);
|
|
@@ -195,23 +193,7 @@ export function IntegrationCard({ card, onConnect }: IntegrationCardProps) {
|
|
|
195
193
|
</div>
|
|
196
194
|
|
|
197
195
|
{/* Footer */}
|
|
198
|
-
<div className="mt-auto flex items-center justify-
|
|
199
|
-
{sharedByAgentsCount > 0 ? (
|
|
200
|
-
<Tooltip>
|
|
201
|
-
<TooltipTrigger asChild>
|
|
202
|
-
<span className="inline-flex items-center gap-1 text-xs text-blue-600 dark:text-blue-400">
|
|
203
|
-
<Users className="h-3.5 w-3.5" />
|
|
204
|
-
Compartilhada
|
|
205
|
-
</span>
|
|
206
|
-
</TooltipTrigger>
|
|
207
|
-
<TooltipContent>
|
|
208
|
-
Esta credencial está disponível para todos os agentes da conta
|
|
209
|
-
</TooltipContent>
|
|
210
|
-
</Tooltip>
|
|
211
|
-
) : (
|
|
212
|
-
<span />
|
|
213
|
-
)}
|
|
214
|
-
|
|
196
|
+
<div className="mt-auto flex items-center justify-end gap-2 pt-1">
|
|
215
197
|
{!isComingSoon && (
|
|
216
198
|
<Button
|
|
217
199
|
variant={state === "expired" ? "destructive" : "outline"}
|
|
@@ -4,7 +4,6 @@ import { useCallback } from "react";
|
|
|
4
4
|
import type { GagentsHookConfig } from "../../hooks/types";
|
|
5
5
|
import { useIntegrationState } from "../../hooks/use-integrations";
|
|
6
6
|
import { useAgentTools, useAddAgentTool, useRemoveAgentTool } from "../../hooks/use-agent-tools";
|
|
7
|
-
import { useTools } from "../../hooks/use-tools";
|
|
8
7
|
import { Switch, Tooltip, TooltipContent, TooltipTrigger } from "@greatapps/greatauth-ui/ui";
|
|
9
8
|
import { Plug, Loader2 } from "lucide-react";
|
|
10
9
|
import type { LucideIcon } from "lucide-react";
|
|
@@ -41,13 +40,11 @@ export function IntegrationsTab({
|
|
|
41
40
|
config,
|
|
42
41
|
agentId,
|
|
43
42
|
}: IntegrationsTabProps) {
|
|
44
|
-
const { cards, isLoading } = useIntegrationState(config,
|
|
45
|
-
const { data: toolsData } = useTools(config);
|
|
43
|
+
const { cards, isLoading } = useIntegrationState(config, agentId);
|
|
46
44
|
const { data: agentToolsData, isLoading: agentToolsLoading } = useAgentTools(config, agentId);
|
|
47
45
|
const addAgentTool = useAddAgentTool(config);
|
|
48
46
|
const removeAgentTool = useRemoveAgentTool(config);
|
|
49
47
|
|
|
50
|
-
const tools = toolsData?.data ?? [];
|
|
51
48
|
const agentTools = agentToolsData?.data ?? [];
|
|
52
49
|
|
|
53
50
|
// Only show connected credentials (account-level)
|
|
@@ -56,26 +53,22 @@ export function IntegrationsTab({
|
|
|
56
53
|
);
|
|
57
54
|
|
|
58
55
|
const handleToggle = useCallback(
|
|
59
|
-
(
|
|
60
|
-
// Find the tool record matching this integration slug
|
|
61
|
-
const tool = tools.find((t) => t.slug === toolSlug);
|
|
62
|
-
if (!tool) return;
|
|
63
|
-
|
|
56
|
+
(toolId: number, checked: boolean) => {
|
|
64
57
|
if (checked) {
|
|
65
58
|
// Add agent_tool linking this agent to this tool
|
|
66
59
|
addAgentTool.mutate({
|
|
67
60
|
idAgent: agentId,
|
|
68
|
-
body: { id_tool:
|
|
61
|
+
body: { id_tool: toolId, enabled: true },
|
|
69
62
|
});
|
|
70
63
|
} else {
|
|
71
64
|
// Find the agent_tool to remove
|
|
72
|
-
const agentTool = agentTools.find((at) => at.id_tool ===
|
|
65
|
+
const agentTool = agentTools.find((at) => at.id_tool === toolId);
|
|
73
66
|
if (agentTool) {
|
|
74
67
|
removeAgentTool.mutate({ idAgent: agentId, id: agentTool.id });
|
|
75
68
|
}
|
|
76
69
|
}
|
|
77
70
|
},
|
|
78
|
-
[
|
|
71
|
+
[agentTools, agentId, addAgentTool, removeAgentTool],
|
|
79
72
|
);
|
|
80
73
|
|
|
81
74
|
// Loading state
|
|
@@ -110,10 +103,7 @@ export function IntegrationsTab({
|
|
|
110
103
|
<div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3">
|
|
111
104
|
{connectedCards.map((card) => {
|
|
112
105
|
const Icon = resolveIcon(card.definition.icon);
|
|
113
|
-
const
|
|
114
|
-
const isLinked = tool
|
|
115
|
-
? agentTools.some((at) => at.id_tool === tool.id)
|
|
116
|
-
: false;
|
|
106
|
+
const isLinked = card.linkedToAgent;
|
|
117
107
|
const isMutating = addAgentTool.isPending || removeAgentTool.isPending;
|
|
118
108
|
|
|
119
109
|
return (
|
|
@@ -152,10 +142,9 @@ export function IntegrationsTab({
|
|
|
152
142
|
{/* Toggle */}
|
|
153
143
|
<Switch
|
|
154
144
|
checked={isLinked}
|
|
155
|
-
disabled={isMutating}
|
|
145
|
+
disabled={isMutating || !card.tool}
|
|
156
146
|
onCheckedChange={(checked) =>
|
|
157
|
-
card.
|
|
158
|
-
handleToggle(card.credentialId, card.definition.slug, checked)
|
|
147
|
+
card.tool && handleToggle(card.tool.id, checked)
|
|
159
148
|
}
|
|
160
149
|
aria-label={`${isLinked ? "Desativar" : "Ativar"} ${card.definition.name} para este agente`}
|
|
161
150
|
/>
|
|
@@ -3,8 +3,6 @@ import type { ColumnDef } from "@tanstack/react-table";
|
|
|
3
3
|
import type { Tool, ToolCredential } from "../../types";
|
|
4
4
|
import type { GagentsHookConfig } from "../../hooks/types";
|
|
5
5
|
import {
|
|
6
|
-
useCreateToolCredential,
|
|
7
|
-
useUpdateToolCredential,
|
|
8
6
|
useDeleteToolCredential,
|
|
9
7
|
} from "../../hooks";
|
|
10
8
|
import { useTools } from "../../hooks";
|
|
@@ -16,11 +14,6 @@ import {
|
|
|
16
14
|
Tooltip,
|
|
17
15
|
TooltipTrigger,
|
|
18
16
|
TooltipContent,
|
|
19
|
-
Dialog,
|
|
20
|
-
DialogContent,
|
|
21
|
-
DialogHeader,
|
|
22
|
-
DialogTitle,
|
|
23
|
-
DialogFooter,
|
|
24
17
|
AlertDialog,
|
|
25
18
|
AlertDialogAction,
|
|
26
19
|
AlertDialogCancel,
|
|
@@ -29,13 +22,8 @@ import {
|
|
|
29
22
|
AlertDialogFooter,
|
|
30
23
|
AlertDialogHeader,
|
|
31
24
|
AlertDialogTitle,
|
|
32
|
-
Select,
|
|
33
|
-
SelectContent,
|
|
34
|
-
SelectItem,
|
|
35
|
-
SelectTrigger,
|
|
36
|
-
SelectValue,
|
|
37
25
|
} from "@greatapps/greatauth-ui/ui";
|
|
38
|
-
import { Trash2,
|
|
26
|
+
import { Trash2, Search } from "lucide-react";
|
|
39
27
|
import { format } from "date-fns";
|
|
40
28
|
import { ptBR } from "date-fns/locale";
|
|
41
29
|
import { toast } from "sonner";
|
|
@@ -45,8 +33,6 @@ interface ToolCredentialsFormProps {
|
|
|
45
33
|
isLoading: boolean;
|
|
46
34
|
config: GagentsHookConfig;
|
|
47
35
|
gagentsApiUrl: string;
|
|
48
|
-
createOpen?: boolean;
|
|
49
|
-
onCreateOpenChange?: (open: boolean) => void;
|
|
50
36
|
}
|
|
51
37
|
|
|
52
38
|
function formatDate(dateStr: string | null): string {
|
|
@@ -56,8 +42,6 @@ function formatDate(dateStr: string | null): string {
|
|
|
56
42
|
|
|
57
43
|
function useColumns(
|
|
58
44
|
tools: Tool[],
|
|
59
|
-
onEdit: (cred: ToolCredential) => void,
|
|
60
|
-
onConnect: (cred: ToolCredential) => void,
|
|
61
45
|
onRemove: (cred: ToolCredential) => void,
|
|
62
46
|
): ColumnDef<ToolCredential>[] {
|
|
63
47
|
function getToolName(idTool: number | null): string {
|
|
@@ -66,12 +50,6 @@ function useColumns(
|
|
|
66
50
|
return tool?.name || `Ferramenta #${idTool}`;
|
|
67
51
|
}
|
|
68
52
|
|
|
69
|
-
function getToolType(idTool: number | null): string | null {
|
|
70
|
-
if (!idTool) return null;
|
|
71
|
-
const tool = tools.find((t) => t.id === idTool);
|
|
72
|
-
return tool?.type || null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
53
|
return [
|
|
76
54
|
{
|
|
77
55
|
accessorKey: "label",
|
|
@@ -123,36 +101,6 @@ function useColumns(
|
|
|
123
101
|
enableSorting: false,
|
|
124
102
|
cell: ({ row }) => (
|
|
125
103
|
<div className="flex items-center gap-1">
|
|
126
|
-
{getToolType(row.original.id_tool) === "oauth2" && (
|
|
127
|
-
<Tooltip>
|
|
128
|
-
<TooltipTrigger asChild>
|
|
129
|
-
<Button
|
|
130
|
-
variant="ghost"
|
|
131
|
-
size="icon"
|
|
132
|
-
className="h-8 w-8"
|
|
133
|
-
aria-label="Vincular"
|
|
134
|
-
disabled
|
|
135
|
-
>
|
|
136
|
-
<Link className="h-4 w-4" />
|
|
137
|
-
</Button>
|
|
138
|
-
</TooltipTrigger>
|
|
139
|
-
<TooltipContent>Em breve</TooltipContent>
|
|
140
|
-
</Tooltip>
|
|
141
|
-
)}
|
|
142
|
-
<Tooltip>
|
|
143
|
-
<TooltipTrigger asChild>
|
|
144
|
-
<Button
|
|
145
|
-
variant="ghost"
|
|
146
|
-
size="icon"
|
|
147
|
-
className="h-8 w-8"
|
|
148
|
-
aria-label="Editar"
|
|
149
|
-
onClick={() => onEdit(row.original)}
|
|
150
|
-
>
|
|
151
|
-
<Pencil className="h-4 w-4" />
|
|
152
|
-
</Button>
|
|
153
|
-
</TooltipTrigger>
|
|
154
|
-
<TooltipContent>Editar</TooltipContent>
|
|
155
|
-
</Tooltip>
|
|
156
104
|
<Tooltip>
|
|
157
105
|
<TooltipTrigger asChild>
|
|
158
106
|
<Button
|
|
@@ -178,35 +126,12 @@ export function ToolCredentialsForm({
|
|
|
178
126
|
isLoading,
|
|
179
127
|
config,
|
|
180
128
|
gagentsApiUrl,
|
|
181
|
-
createOpen: externalCreateOpen,
|
|
182
|
-
onCreateOpenChange,
|
|
183
129
|
}: ToolCredentialsFormProps) {
|
|
184
|
-
const createMutation = useCreateToolCredential(config);
|
|
185
|
-
const updateMutation = useUpdateToolCredential(config);
|
|
186
130
|
const deleteMutation = useDeleteToolCredential(config);
|
|
187
131
|
const { data: toolsData } = useTools(config);
|
|
188
132
|
const tools: Tool[] = (toolsData?.data || []).filter((t: Tool) => !t.slug?.startsWith("gclinic_"));
|
|
189
133
|
|
|
190
134
|
const [search, setSearch] = useState("");
|
|
191
|
-
const [internalCreateOpen, setInternalCreateOpen] = useState(false);
|
|
192
|
-
const showCreateDialog = externalCreateOpen ?? internalCreateOpen;
|
|
193
|
-
const setShowCreateDialog = onCreateOpenChange ?? setInternalCreateOpen;
|
|
194
|
-
const [createForm, setCreateForm] = useState({
|
|
195
|
-
id_tool: "",
|
|
196
|
-
label: "",
|
|
197
|
-
credentials_encrypted: "",
|
|
198
|
-
expires_at: "",
|
|
199
|
-
});
|
|
200
|
-
|
|
201
|
-
const [editTarget, setEditTarget] = useState<ToolCredential | null>(null);
|
|
202
|
-
const [editForm, setEditForm] = useState({
|
|
203
|
-
id_tool: "",
|
|
204
|
-
label: "",
|
|
205
|
-
credentials_encrypted: "",
|
|
206
|
-
expires_at: "",
|
|
207
|
-
status: "" as "active" | "expired" | "",
|
|
208
|
-
});
|
|
209
|
-
|
|
210
135
|
const [removeTarget, setRemoveTarget] = useState<ToolCredential | null>(null);
|
|
211
136
|
|
|
212
137
|
// Build a set of internal tool IDs to exclude from credentials display
|
|
@@ -237,86 +162,9 @@ export function ToolCredentialsForm({
|
|
|
237
162
|
|
|
238
163
|
const columns = useColumns(
|
|
239
164
|
tools,
|
|
240
|
-
(cred) => startEdit(cred),
|
|
241
|
-
(cred) => handleConnect(cred),
|
|
242
165
|
(cred) => setRemoveTarget(cred),
|
|
243
166
|
);
|
|
244
167
|
|
|
245
|
-
async function handleCreate() {
|
|
246
|
-
const idTool = parseInt(createForm.id_tool, 10);
|
|
247
|
-
if (!idTool || !createForm.label.trim() || !createForm.credentials_encrypted.trim()) return;
|
|
248
|
-
|
|
249
|
-
try {
|
|
250
|
-
const result = await createMutation.mutateAsync({
|
|
251
|
-
id_tool: idTool,
|
|
252
|
-
label: createForm.label.trim(),
|
|
253
|
-
credentials_encrypted: createForm.credentials_encrypted.trim(),
|
|
254
|
-
...(createForm.expires_at ? { expires_at: createForm.expires_at } : {}),
|
|
255
|
-
});
|
|
256
|
-
if (result.status === 1) {
|
|
257
|
-
toast.success("Credencial criada");
|
|
258
|
-
setShowCreateDialog(false);
|
|
259
|
-
setCreateForm({ id_tool: "", label: "", credentials_encrypted: "", expires_at: "" });
|
|
260
|
-
} else {
|
|
261
|
-
toast.error(result.message || "Erro ao criar credencial");
|
|
262
|
-
}
|
|
263
|
-
} catch {
|
|
264
|
-
toast.error("Erro ao criar credencial");
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
function startEdit(cred: ToolCredential) {
|
|
269
|
-
setEditTarget(cred);
|
|
270
|
-
setEditForm({
|
|
271
|
-
id_tool: cred.id_tool ? String(cred.id_tool) : "",
|
|
272
|
-
label: cred.label || "",
|
|
273
|
-
credentials_encrypted: "",
|
|
274
|
-
expires_at: cred.expires_at || "",
|
|
275
|
-
status: cred.status,
|
|
276
|
-
});
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
async function handleSaveEdit() {
|
|
280
|
-
if (!editTarget) return;
|
|
281
|
-
const body: Record<string, unknown> = {};
|
|
282
|
-
const newIdTool = editForm.id_tool ? parseInt(editForm.id_tool, 10) : null;
|
|
283
|
-
if (newIdTool && newIdTool !== editTarget.id_tool) {
|
|
284
|
-
body.id_tool = newIdTool;
|
|
285
|
-
}
|
|
286
|
-
if (editForm.label.trim() && editForm.label.trim() !== (editTarget.label || "")) {
|
|
287
|
-
body.label = editForm.label.trim();
|
|
288
|
-
}
|
|
289
|
-
if (editForm.credentials_encrypted.trim()) {
|
|
290
|
-
body.credentials_encrypted = editForm.credentials_encrypted.trim();
|
|
291
|
-
}
|
|
292
|
-
if (editForm.expires_at !== (editTarget.expires_at || "")) {
|
|
293
|
-
body.expires_at = editForm.expires_at || null;
|
|
294
|
-
}
|
|
295
|
-
if (editForm.status && editForm.status !== editTarget.status) {
|
|
296
|
-
body.status = editForm.status;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
if (Object.keys(body).length === 0) {
|
|
300
|
-
setEditTarget(null);
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
try {
|
|
305
|
-
const result = await updateMutation.mutateAsync({
|
|
306
|
-
id: editTarget.id,
|
|
307
|
-
body: body as Parameters<typeof updateMutation.mutateAsync>[0]["body"],
|
|
308
|
-
});
|
|
309
|
-
if (result.status === 1) {
|
|
310
|
-
toast.success("Credencial atualizada");
|
|
311
|
-
setEditTarget(null);
|
|
312
|
-
} else {
|
|
313
|
-
toast.error(result.message || "Erro ao atualizar credencial");
|
|
314
|
-
}
|
|
315
|
-
} catch {
|
|
316
|
-
toast.error("Erro ao atualizar credencial");
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
|
|
320
168
|
async function handleRemove() {
|
|
321
169
|
if (!removeTarget) return;
|
|
322
170
|
try {
|
|
@@ -333,14 +181,6 @@ export function ToolCredentialsForm({
|
|
|
333
181
|
}
|
|
334
182
|
}
|
|
335
183
|
|
|
336
|
-
function handleConnect(cred: ToolCredential) {
|
|
337
|
-
if (!config.accountId || !config.token) return;
|
|
338
|
-
const language = config.language ?? "pt-br";
|
|
339
|
-
const idWl = config.idWl ?? 1;
|
|
340
|
-
const url = `${gagentsApiUrl}/v1/${language}/${idWl}/accounts/${config.accountId}/oauth/connect?id_tool=${cred.id_tool}`;
|
|
341
|
-
window.open(url, "_blank");
|
|
342
|
-
}
|
|
343
|
-
|
|
344
184
|
return (
|
|
345
185
|
<div className="space-y-4">
|
|
346
186
|
<div className="flex items-center gap-3">
|
|
@@ -365,219 +205,6 @@ export function ToolCredentialsForm({
|
|
|
365
205
|
emptyMessage="Nenhuma credencial encontrada"
|
|
366
206
|
/>
|
|
367
207
|
|
|
368
|
-
{/* Create Dialog */}
|
|
369
|
-
<Dialog open={showCreateDialog} onOpenChange={setShowCreateDialog}>
|
|
370
|
-
<DialogContent>
|
|
371
|
-
<DialogHeader>
|
|
372
|
-
<DialogTitle>Nova Credencial</DialogTitle>
|
|
373
|
-
</DialogHeader>
|
|
374
|
-
<div className="space-y-4">
|
|
375
|
-
<div>
|
|
376
|
-
<label htmlFor="cred-tool" className="mb-1 block text-sm font-medium">
|
|
377
|
-
Ferramenta *
|
|
378
|
-
</label>
|
|
379
|
-
<Select
|
|
380
|
-
value={createForm.id_tool}
|
|
381
|
-
onValueChange={(val) =>
|
|
382
|
-
setCreateForm((f) => ({ ...f, id_tool: val }))
|
|
383
|
-
}
|
|
384
|
-
>
|
|
385
|
-
<SelectTrigger id="cred-tool">
|
|
386
|
-
<SelectValue placeholder="Selecione a ferramenta" />
|
|
387
|
-
</SelectTrigger>
|
|
388
|
-
<SelectContent>
|
|
389
|
-
{tools.map((tool) => (
|
|
390
|
-
<SelectItem key={tool.id} value={String(tool.id)}>
|
|
391
|
-
{tool.name}
|
|
392
|
-
</SelectItem>
|
|
393
|
-
))}
|
|
394
|
-
</SelectContent>
|
|
395
|
-
</Select>
|
|
396
|
-
</div>
|
|
397
|
-
<div>
|
|
398
|
-
<label htmlFor="cred-label" className="mb-1 block text-sm font-medium">
|
|
399
|
-
Label *
|
|
400
|
-
</label>
|
|
401
|
-
<Input
|
|
402
|
-
id="cred-label"
|
|
403
|
-
name="label"
|
|
404
|
-
value={createForm.label}
|
|
405
|
-
onChange={(e) =>
|
|
406
|
-
setCreateForm((f) => ({ ...f, label: e.target.value }))
|
|
407
|
-
}
|
|
408
|
-
placeholder="Ex: Google Calendar - Clínica São Paulo"
|
|
409
|
-
/>
|
|
410
|
-
</div>
|
|
411
|
-
<div>
|
|
412
|
-
<label htmlFor="cred-credential" className="mb-1 block text-sm font-medium">
|
|
413
|
-
Credencial *
|
|
414
|
-
</label>
|
|
415
|
-
<Input
|
|
416
|
-
id="cred-credential"
|
|
417
|
-
name="credential"
|
|
418
|
-
autoComplete="off"
|
|
419
|
-
type="password"
|
|
420
|
-
value={createForm.credentials_encrypted}
|
|
421
|
-
onChange={(e) =>
|
|
422
|
-
setCreateForm((f) => ({
|
|
423
|
-
...f,
|
|
424
|
-
credentials_encrypted: e.target.value,
|
|
425
|
-
}))
|
|
426
|
-
}
|
|
427
|
-
placeholder="Credencial encriptada"
|
|
428
|
-
/>
|
|
429
|
-
</div>
|
|
430
|
-
<div>
|
|
431
|
-
<label htmlFor="cred-expires" className="mb-1 block text-sm font-medium">
|
|
432
|
-
Data de Expiração (opcional)
|
|
433
|
-
</label>
|
|
434
|
-
<Input
|
|
435
|
-
id="cred-expires"
|
|
436
|
-
name="expires"
|
|
437
|
-
type="date"
|
|
438
|
-
value={createForm.expires_at}
|
|
439
|
-
onChange={(e) =>
|
|
440
|
-
setCreateForm((f) => ({ ...f, expires_at: e.target.value }))
|
|
441
|
-
}
|
|
442
|
-
/>
|
|
443
|
-
</div>
|
|
444
|
-
</div>
|
|
445
|
-
<DialogFooter>
|
|
446
|
-
<Button
|
|
447
|
-
variant="outline"
|
|
448
|
-
onClick={() => setShowCreateDialog(false)}
|
|
449
|
-
>
|
|
450
|
-
Cancelar
|
|
451
|
-
</Button>
|
|
452
|
-
<Button
|
|
453
|
-
onClick={handleCreate}
|
|
454
|
-
disabled={
|
|
455
|
-
!createForm.id_tool ||
|
|
456
|
-
!createForm.label.trim() ||
|
|
457
|
-
!createForm.credentials_encrypted.trim() ||
|
|
458
|
-
createMutation.isPending
|
|
459
|
-
}
|
|
460
|
-
>
|
|
461
|
-
Criar
|
|
462
|
-
</Button>
|
|
463
|
-
</DialogFooter>
|
|
464
|
-
</DialogContent>
|
|
465
|
-
</Dialog>
|
|
466
|
-
|
|
467
|
-
{/* Edit Dialog */}
|
|
468
|
-
<Dialog
|
|
469
|
-
open={!!editTarget}
|
|
470
|
-
onOpenChange={(open) => !open && setEditTarget(null)}
|
|
471
|
-
>
|
|
472
|
-
<DialogContent>
|
|
473
|
-
<DialogHeader>
|
|
474
|
-
<DialogTitle>Editar Credencial</DialogTitle>
|
|
475
|
-
</DialogHeader>
|
|
476
|
-
<div className="space-y-4">
|
|
477
|
-
<div>
|
|
478
|
-
<label htmlFor="edit-cred-tool" className="mb-1 block text-sm font-medium">
|
|
479
|
-
Ferramenta *
|
|
480
|
-
</label>
|
|
481
|
-
<Select
|
|
482
|
-
value={editForm.id_tool}
|
|
483
|
-
onValueChange={(val) =>
|
|
484
|
-
setEditForm((f) => ({ ...f, id_tool: val }))
|
|
485
|
-
}
|
|
486
|
-
>
|
|
487
|
-
<SelectTrigger id="edit-cred-tool">
|
|
488
|
-
<SelectValue placeholder="Selecione a ferramenta" />
|
|
489
|
-
</SelectTrigger>
|
|
490
|
-
<SelectContent>
|
|
491
|
-
{tools.map((tool) => (
|
|
492
|
-
<SelectItem key={tool.id} value={String(tool.id)}>
|
|
493
|
-
{tool.name}
|
|
494
|
-
</SelectItem>
|
|
495
|
-
))}
|
|
496
|
-
</SelectContent>
|
|
497
|
-
</Select>
|
|
498
|
-
</div>
|
|
499
|
-
<div>
|
|
500
|
-
<label htmlFor="edit-cred-label" className="mb-1 block text-sm font-medium">
|
|
501
|
-
Label
|
|
502
|
-
</label>
|
|
503
|
-
<Input
|
|
504
|
-
id="edit-cred-label"
|
|
505
|
-
name="label"
|
|
506
|
-
value={editForm.label}
|
|
507
|
-
onChange={(e) =>
|
|
508
|
-
setEditForm((f) => ({ ...f, label: e.target.value }))
|
|
509
|
-
}
|
|
510
|
-
placeholder="Label da credencial"
|
|
511
|
-
/>
|
|
512
|
-
</div>
|
|
513
|
-
<div>
|
|
514
|
-
<label htmlFor="edit-cred-credential" className="mb-1 block text-sm font-medium">
|
|
515
|
-
Nova Credencial (vazio = manter atual)
|
|
516
|
-
</label>
|
|
517
|
-
<Input
|
|
518
|
-
id="edit-cred-credential"
|
|
519
|
-
name="credential"
|
|
520
|
-
autoComplete="off"
|
|
521
|
-
type="password"
|
|
522
|
-
value={editForm.credentials_encrypted}
|
|
523
|
-
onChange={(e) =>
|
|
524
|
-
setEditForm((f) => ({
|
|
525
|
-
...f,
|
|
526
|
-
credentials_encrypted: e.target.value,
|
|
527
|
-
}))
|
|
528
|
-
}
|
|
529
|
-
placeholder="Nova credencial"
|
|
530
|
-
/>
|
|
531
|
-
</div>
|
|
532
|
-
<div>
|
|
533
|
-
<label htmlFor="edit-cred-expires" className="mb-1 block text-sm font-medium">
|
|
534
|
-
Data de Expiração
|
|
535
|
-
</label>
|
|
536
|
-
<Input
|
|
537
|
-
id="edit-cred-expires"
|
|
538
|
-
name="expires"
|
|
539
|
-
type="date"
|
|
540
|
-
value={editForm.expires_at}
|
|
541
|
-
onChange={(e) =>
|
|
542
|
-
setEditForm((f) => ({ ...f, expires_at: e.target.value }))
|
|
543
|
-
}
|
|
544
|
-
/>
|
|
545
|
-
</div>
|
|
546
|
-
<div>
|
|
547
|
-
<label htmlFor="edit-cred-status" className="mb-1 block text-sm font-medium">Status</label>
|
|
548
|
-
<Select
|
|
549
|
-
value={editForm.status || undefined}
|
|
550
|
-
onValueChange={(val) =>
|
|
551
|
-
setEditForm((f) => ({
|
|
552
|
-
...f,
|
|
553
|
-
status: val as "active" | "expired",
|
|
554
|
-
}))
|
|
555
|
-
}
|
|
556
|
-
>
|
|
557
|
-
<SelectTrigger id="edit-cred-status">
|
|
558
|
-
<SelectValue />
|
|
559
|
-
</SelectTrigger>
|
|
560
|
-
<SelectContent>
|
|
561
|
-
<SelectItem value="active">Ativo</SelectItem>
|
|
562
|
-
<SelectItem value="expired">Expirado</SelectItem>
|
|
563
|
-
</SelectContent>
|
|
564
|
-
</Select>
|
|
565
|
-
</div>
|
|
566
|
-
</div>
|
|
567
|
-
<DialogFooter>
|
|
568
|
-
<Button variant="outline" onClick={() => setEditTarget(null)}>
|
|
569
|
-
Cancelar
|
|
570
|
-
</Button>
|
|
571
|
-
<Button
|
|
572
|
-
onClick={handleSaveEdit}
|
|
573
|
-
disabled={updateMutation.isPending}
|
|
574
|
-
>
|
|
575
|
-
Salvar
|
|
576
|
-
</Button>
|
|
577
|
-
</DialogFooter>
|
|
578
|
-
</DialogContent>
|
|
579
|
-
</Dialog>
|
|
580
|
-
|
|
581
208
|
{/* Delete confirmation */}
|
|
582
209
|
<AlertDialog
|
|
583
210
|
open={!!removeTarget}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { useState } from "react";
|
|
2
1
|
import { useToolCredentials } from "../hooks";
|
|
3
2
|
import { ToolCredentialsForm } from "../components/tools/tool-credentials-form";
|
|
4
|
-
import { Button } from "@greatapps/greatauth-ui/ui";
|
|
5
|
-
import { Plus } from "lucide-react";
|
|
6
3
|
import type { GagentsHookConfig } from "../hooks/types";
|
|
7
4
|
|
|
8
5
|
export interface CredentialsPageProps {
|
|
@@ -20,7 +17,6 @@ export function CredentialsPage({
|
|
|
20
17
|
}: CredentialsPageProps) {
|
|
21
18
|
const { data: credentialsData, isLoading: credentialsLoading } =
|
|
22
19
|
useToolCredentials(config);
|
|
23
|
-
const [createOpen, setCreateOpen] = useState(false);
|
|
24
20
|
|
|
25
21
|
const credentials = credentialsData?.data || [];
|
|
26
22
|
|
|
@@ -31,10 +27,6 @@ export function CredentialsPage({
|
|
|
31
27
|
<h1 className="text-xl font-semibold">{title}</h1>
|
|
32
28
|
<p className="text-sm text-muted-foreground">{subtitle}</p>
|
|
33
29
|
</div>
|
|
34
|
-
<Button onClick={() => setCreateOpen(true)} size="sm">
|
|
35
|
-
<Plus className="mr-2 h-4 w-4" />
|
|
36
|
-
Nova Credencial
|
|
37
|
-
</Button>
|
|
38
30
|
</div>
|
|
39
31
|
|
|
40
32
|
<ToolCredentialsForm
|
|
@@ -42,8 +34,6 @@ export function CredentialsPage({
|
|
|
42
34
|
gagentsApiUrl={gagentsApiUrl}
|
|
43
35
|
credentials={credentials}
|
|
44
36
|
isLoading={credentialsLoading}
|
|
45
|
-
createOpen={createOpen}
|
|
46
|
-
onCreateOpenChange={setCreateOpen}
|
|
47
37
|
/>
|
|
48
38
|
</div>
|
|
49
39
|
);
|