@greatapps/greatagents-ui 0.3.25 → 0.3.27

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.25",
3
+ "version": "0.3.27",
4
4
  "description": "Shared agents UI components for Great platform",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -250,6 +250,26 @@ export function createGagentsClient(config: GagentsClientConfig) {
250
250
  { provider },
251
251
  ),
252
252
 
253
+ // --- Publish ---
254
+ publishAgent: async (
255
+ idAccount: number,
256
+ agentId: number,
257
+ changeNotes?: string,
258
+ ): Promise<ApiResponse<{ version: number }>> => {
259
+ const url = buildUrl(idAccount, `agents/${agentId}/publish`);
260
+ const res = await fetch(url, {
261
+ method: "POST",
262
+ headers: {
263
+ Authorization: `Bearer ${token}`,
264
+ "Content-Type": "application/json",
265
+ },
266
+ body: JSON.stringify({ change_notes: changeNotes || "" }),
267
+ });
268
+ const json = (await res.json()) as ApiResponse<{ version: number }>;
269
+ if (json.status === 0 && !res.ok) throw new Error(json.message || "Erro ao publicar");
270
+ return json;
271
+ },
272
+
253
273
  // --- Capabilities ---
254
274
  getCapabilities: (idAccount: number) =>
255
275
  request<CapabilitiesResponse>("GET", idAccount, "capabilities"),
@@ -6,12 +6,8 @@ import {
6
6
  Button,
7
7
  Badge,
8
8
  Skeleton,
9
- Dialog,
10
- DialogContent,
11
- DialogHeader,
12
- DialogTitle,
13
9
  } from "@greatapps/greatauth-ui/ui";
14
- import { FileText, RotateCcw, X, AlertTriangle } from "lucide-react";
10
+ import { FileText, RotateCcw, X } from "lucide-react";
15
11
  import { toast } from "sonner";
16
12
 
17
13
  interface AgentRevisionTabProps {
@@ -19,7 +15,6 @@ interface AgentRevisionTabProps {
19
15
  config: GagentsHookConfig;
20
16
  }
21
17
 
22
- const STRUCTURED_MARKERS = ["[IDENTIDADE]", "[MISSÃO]", "[TOM, ESTILO & FORMATO]"];
23
18
 
24
19
  function formatDate(dateStr: string): string {
25
20
  const date = new Date(dateStr);
@@ -107,16 +102,10 @@ function buildAssembledPrompt(agent: Agent): string {
107
102
  return sections.join("\n\n");
108
103
  }
109
104
 
110
- function isLegacyVersion(version: PromptVersion): boolean {
111
- const content = version.prompt_content ?? "";
112
- return !STRUCTURED_MARKERS.some((marker) => content.includes(marker));
113
- }
114
-
115
105
  export function AgentRevisionTab({ agent, config }: AgentRevisionTabProps) {
116
106
  const { data: versionsData, isLoading } = usePromptVersions(config, agent.id);
117
107
 
118
108
  const [compareVersionId, setCompareVersionId] = useState<number | null>(null);
119
- const [legacyModalVersion, setLegacyModalVersion] = useState<PromptVersion | null>(null);
120
109
 
121
110
  const versions = (versionsData?.data || []) as PromptVersion[];
122
111
  const sortedVersions = [...versions].sort(
@@ -143,12 +132,8 @@ export function AgentRevisionTab({ agent, config }: AgentRevisionTabProps) {
143
132
  ? computeDiff(compareVersion.prompt_content ?? "", currentVersion.prompt_content ?? "")
144
133
  : null;
145
134
 
146
- function handleRestore(version: PromptVersion) {
147
- if (isLegacyVersion(version)) {
148
- setLegacyModalVersion(version);
149
- } else {
150
- toast.info("Restaurar versão estruturada — funcionalidade em desenvolvimento");
151
- }
135
+ function handleRestore(_version: PromptVersion) {
136
+ toast.info("Restaurar versão — funcionalidade em desenvolvimento");
152
137
  }
153
138
 
154
139
  if (isLoading) {
@@ -319,50 +304,6 @@ export function AgentRevisionTab({ agent, config }: AgentRevisionTabProps) {
319
304
  )}
320
305
  </div>
321
306
 
322
- {/* Legacy version modal */}
323
- <Dialog
324
- open={!!legacyModalVersion}
325
- onOpenChange={(open) => {
326
- if (!open) setLegacyModalVersion(null);
327
- }}
328
- >
329
- <DialogContent className="max-w-2xl">
330
- <DialogHeader>
331
- <DialogTitle className="flex items-center gap-2">
332
- <AlertTriangle className="h-5 w-5 text-amber-500" />
333
- Versão Legada — v{legacyModalVersion?.version_number}
334
- </DialogTitle>
335
- </DialogHeader>
336
- <div className="space-y-3">
337
- <div className="rounded-lg border border-amber-500/30 bg-amber-500/5 p-3">
338
- <p className="text-sm text-amber-700 dark:text-amber-400">
339
- Esta versão foi criada antes da reestruturação e não pode ser restaurada nos campos estruturados.
340
- </p>
341
- </div>
342
- <div className="max-h-96 overflow-auto rounded-lg border p-4">
343
- <pre className="whitespace-pre-wrap font-mono text-sm leading-relaxed">
344
- {legacyModalVersion?.prompt_content ?? ""}
345
- </pre>
346
- </div>
347
- <div className="flex items-center gap-3 text-xs text-muted-foreground">
348
- <span>
349
- {(legacyModalVersion?.prompt_content ?? "").length.toLocaleString("pt-BR")} caracteres
350
- </span>
351
- {legacyModalVersion?.change_notes && (
352
- <>
353
- <span>·</span>
354
- <span className="italic">{legacyModalVersion.change_notes}</span>
355
- </>
356
- )}
357
- </div>
358
- </div>
359
- <div className="flex justify-end pt-2">
360
- <Button variant="outline" onClick={() => setLegacyModalVersion(null)}>
361
- Fechar
362
- </Button>
363
- </div>
364
- </DialogContent>
365
- </Dialog>
366
307
  </div>
367
308
  );
368
309
  }
@@ -2,7 +2,7 @@
2
2
  export { type GagentsHookConfig, useGagentsClient } from "./types";
3
3
 
4
4
  // Agents
5
- export { useAgents, useAgent, useCreateAgent, useUpdateAgent, useDeleteAgent } from "./use-agents";
5
+ export { useAgents, useAgent, useCreateAgent, useUpdateAgent, usePublishAgent, useDeleteAgent } from "./use-agents";
6
6
 
7
7
  // Tools
8
8
  export { useTools, useTool, useCreateTool, useUpdateTool, useDeleteTool } from "./use-tools";
@@ -81,6 +81,26 @@ export function useUpdateAgent(config: GagentsHookConfig) {
81
81
  });
82
82
  }
83
83
 
84
+ export function usePublishAgent(config: GagentsHookConfig) {
85
+ const queryClient = useQueryClient();
86
+ const client = useGagentsClient(config);
87
+
88
+ return useMutation({
89
+ mutationFn: async (variables: { id: number; changeNotes?: string }) => {
90
+ return client.publishAgent(Number(config.accountId), variables.id, variables.changeNotes);
91
+ },
92
+ onSuccess: (_data, variables) => {
93
+ queryClient.invalidateQueries({ queryKey: ["greatagents", "agents"] });
94
+ queryClient.invalidateQueries({
95
+ queryKey: ["greatagents", "agent", config.accountId, variables.id],
96
+ });
97
+ queryClient.invalidateQueries({
98
+ queryKey: ["greatagents", "prompt-versions", config.accountId, variables.id],
99
+ });
100
+ },
101
+ });
102
+ }
103
+
84
104
  export function useDeleteAgent(config: GagentsHookConfig) {
85
105
  const client = useGagentsClient(config);
86
106
  const queryClient = useQueryClient();
@@ -1,10 +1,24 @@
1
1
  import { useState } from "react";
2
- import { useAgent } from "../hooks";
2
+ import { useAgent, usePublishAgent } from "../hooks";
3
3
  import { AgentTabs } from "../components/agents/agent-tabs";
4
4
  import { AgentEditForm } from "../components/agents/agent-edit-form";
5
- import { Badge, Button, Skeleton } from "@greatapps/greatauth-ui/ui";
5
+ import {
6
+ AlertDialog,
7
+ AlertDialogAction,
8
+ AlertDialogCancel,
9
+ AlertDialogContent,
10
+ AlertDialogDescription,
11
+ AlertDialogFooter,
12
+ AlertDialogHeader,
13
+ AlertDialogTitle,
14
+ Badge,
15
+ Button,
16
+ Input,
17
+ Skeleton,
18
+ } from "@greatapps/greatauth-ui/ui";
6
19
  import { EntityAvatar } from "@greatapps/greatauth-ui";
7
- import { ArrowLeft, Pencil } from "lucide-react";
20
+ import { ArrowLeft, Loader2, Pencil, Upload } from "lucide-react";
21
+ import { toast } from "sonner";
8
22
  import type { GagentsHookConfig } from "../hooks/types";
9
23
 
10
24
  export interface AgentDetailPageProps {
@@ -21,7 +35,26 @@ export function AgentDetailPage({
21
35
  renderChatLink,
22
36
  }: AgentDetailPageProps) {
23
37
  const { data: agent, isLoading } = useAgent(config, agentId);
38
+ const publishAgent = usePublishAgent(config);
24
39
  const [editOpen, setEditOpen] = useState(false);
40
+ const [publishOpen, setPublishOpen] = useState(false);
41
+ const [publishNotes, setPublishNotes] = useState("");
42
+
43
+ async function handlePublish() {
44
+ if (!agent) return;
45
+ try {
46
+ const result = await publishAgent.mutateAsync({ id: agent.id, changeNotes: publishNotes.trim() });
47
+ setPublishOpen(false);
48
+ setPublishNotes("");
49
+ if (result.message?.includes("Sem alterações")) {
50
+ toast.info(result.message);
51
+ } else {
52
+ toast.success(result.message || "Agente publicado");
53
+ }
54
+ } catch (err) {
55
+ toast.error(err instanceof Error ? err.message : "Erro ao publicar agente");
56
+ }
57
+ }
25
58
 
26
59
  if (isLoading) {
27
60
  return (
@@ -80,15 +113,29 @@ export function AgentDetailPage({
80
113
  </div>
81
114
  </div>
82
115
 
83
- <Button
84
- variant="outline"
85
- size="sm"
86
- className="shrink-0 self-start"
87
- onClick={() => setEditOpen(true)}
88
- >
89
- <Pencil className="mr-2 h-4 w-4" />
90
- Editar
91
- </Button>
116
+ <div className="flex gap-2 shrink-0 self-start">
117
+ <Button
118
+ variant="default"
119
+ size="sm"
120
+ onClick={() => setPublishOpen(true)}
121
+ disabled={publishAgent.isPending}
122
+ >
123
+ {publishAgent.isPending ? (
124
+ <Loader2 className="mr-2 h-4 w-4 animate-spin" />
125
+ ) : (
126
+ <Upload className="mr-2 h-4 w-4" />
127
+ )}
128
+ Publicar
129
+ </Button>
130
+ <Button
131
+ variant="outline"
132
+ size="sm"
133
+ onClick={() => setEditOpen(true)}
134
+ >
135
+ <Pencil className="mr-2 h-4 w-4" />
136
+ Editar
137
+ </Button>
138
+ </div>
92
139
  </div>
93
140
  </div>
94
141
 
@@ -107,6 +154,37 @@ export function AgentDetailPage({
107
154
  onOpenChange={setEditOpen}
108
155
  />
109
156
  )}
157
+
158
+ <AlertDialog open={publishOpen} onOpenChange={setPublishOpen}>
159
+ <AlertDialogContent>
160
+ <AlertDialogHeader>
161
+ <AlertDialogTitle>Publicar nova versão do agente?</AlertDialogTitle>
162
+ <AlertDialogDescription>
163
+ O prompt será actualizado com todas as configurações actuais e uma nova versão será criada.
164
+ </AlertDialogDescription>
165
+ </AlertDialogHeader>
166
+ <div className="py-2">
167
+ <Input
168
+ value={publishNotes}
169
+ onChange={(e) => setPublishNotes(e.target.value)}
170
+ placeholder="O que mudou? (opcional)"
171
+ onKeyDown={(e) => {
172
+ if (e.key === "Enter") {
173
+ e.preventDefault();
174
+ handlePublish();
175
+ }
176
+ }}
177
+ />
178
+ </div>
179
+ <AlertDialogFooter>
180
+ <AlertDialogCancel onClick={() => { setPublishNotes(""); }}>Cancelar</AlertDialogCancel>
181
+ <AlertDialogAction onClick={handlePublish} disabled={publishAgent.isPending}>
182
+ {publishAgent.isPending && <Loader2 className="mr-2 h-4 w-4 animate-spin" />}
183
+ Publicar
184
+ </AlertDialogAction>
185
+ </AlertDialogFooter>
186
+ </AlertDialogContent>
187
+ </AlertDialog>
110
188
  </div>
111
189
  );
112
190
  }