chore: auto-commit (23 archivos)

- app.md
- backend/dist/assets/index-CFDWXN9Z.js
- backend/dist/index.html
- backend/handlers.go
- backend/main.go
- backend/users.go
- e2e/smoke_live.sh
- frontend/src/App.tsx
- frontend/src/api.ts
- frontend/src/components/CardChatPanel.tsx
- ...

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-21 18:22:44 +02:00
parent 2524340759
commit c9e15513c7
22 changed files with 2380 additions and 179 deletions
+39 -10
View File
@@ -55,6 +55,7 @@ import {
IconChevronRight,
IconLayoutKanban,
IconLogout,
IconPlug,
IconMenu2,
IconMessageChatbot,
IconMoodSmile,
@@ -82,6 +83,7 @@ import { ColorPickerGrid, CustomColorModal } from "./components/ColorPickerGrid"
import { AVATAR_COLORS } from "./components/colors";
import { colorBg, colorBorder } from "./components/colors";
import { NotificationsBell } from "./components/NotificationsBell";
import { ModulesModal } from "./components/ModulesModal";
import { useEventStream } from "./hooks/useEventStream";
import type { Board, Card, CardColor, Column, ColumnLocation, Notification, User } from "./types";
@@ -341,6 +343,8 @@ export function App() {
.catch(() => setAppVersion(""));
}, []);
const [modulesOpen, setModulesOpen] = useState(false);
const reloadNotifs = useCallback(async () => {
try {
const [list, c] = await Promise.all([api.listNotifications(false), api.unreadNotificationCount()]);
@@ -719,7 +723,7 @@ export function App() {
});
}, [reload, users, auth.user, requesterOptions, tagOptions]);
const openEditCard = useCallback((card: Card) => {
const openEditCard = useCallback((card: Card, options?: { highlightMessageId?: string }) => {
const id = modals.open({
title: "Editar tarjeta",
size: "85%",
@@ -730,6 +734,7 @@ export function App() {
currentUserId={auth.user?.id}
requesterOptions={requesterOptions}
tagOptions={tagOptions}
highlightMessageId={options?.highlightMessageId}
onCancel={() => modals.close(id)}
onSubmit={async (v) => {
try {
@@ -1178,17 +1183,30 @@ export function App() {
<NotificationsBell
unreadCount={notifUnread}
notifications={notifs}
onOpenCard={async (cardId) => {
const card = board?.cards.find((c) => c.id === cardId);
if (card) {
setActiveCard(card);
} else {
// Card may be archived/trashed/missing locally — refetch and retry.
onOpenCard={async (cardId, messageId) => {
// Resolve the card across all possible buckets: live
// board, refreshed board, archive, trash. Notifications
// can point at any of them.
const find = (cs?: Card[]) => cs?.find((c) => c.id === cardId);
let card = find(board?.cards);
if (!card) {
await reload();
const b = await api.getBoard();
const c2 = b.cards.find((c) => c.id === cardId);
if (c2) setActiveCard(c2);
const fresh = await api.getBoard();
card = find(fresh.cards);
}
if (!card) {
const archived = await api.listArchive();
card = find(archived);
}
if (!card) {
const trashed = await api.listTrash();
card = find(trashed);
}
if (!card) {
notifications.show({ color: "red", message: "Card no encontrada" });
return;
}
openEditCard(card, { highlightMessageId: messageId });
}}
onChanged={reloadNotifs}
/>
@@ -1240,6 +1258,14 @@ export function App() {
/>
</Box>
<Menu.Divider />
{auth.user.is_admin && (
<Menu.Item
leftSection={<IconPlug size={14} />}
onClick={() => setModulesOpen(true)}
>
Modulos
</Menu.Item>
)}
<Menu.Item
leftSection={<IconLogout size={14} />}
color="red"
@@ -1250,6 +1276,9 @@ export function App() {
</Menu.Dropdown>
</Menu>
)}
{auth.user?.is_admin && (
<ModulesModal opened={modulesOpen} onClose={() => setModulesOpen(false)} />
)}
</Group>
</Group>
</AppShell.Header>