mirror of
https://github.com/Portabase/portabase.git
synced 2026-07-14 11:16:13 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
527a090f1b | ||
|
|
370b86337f | ||
|
|
1a72be323b | ||
|
|
bf252f22f2 | ||
|
|
937d92f686 | ||
|
|
5572957731 | ||
|
|
d2db5722b7 | ||
|
|
5404185a6c | ||
|
|
800f2dfbbb | ||
|
|
ed0b5410f6 | ||
|
|
ae72e262aa | ||
|
|
c4c7050c3f | ||
|
|
81e5227270 | ||
|
|
39319d9162 | ||
|
|
12206fa856 | ||
|
|
9d8c6e26f1 | ||
|
|
eb624672e6 | ||
|
|
1b026b5f08 | ||
|
|
095444610d |
@@ -18,6 +18,20 @@ jobs:
|
|||||||
secrets:
|
secrets:
|
||||||
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME_2 }}
|
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME_2 }}
|
||||||
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD_2 }}
|
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD_2 }}
|
||||||
|
publish_release:
|
||||||
|
needs: docker_publish
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Publish GitHub Release
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh release edit ${{ github.ref_name }} --draft=false
|
||||||
|
|
||||||
discord_notification:
|
discord_notification:
|
||||||
needs: docker_publish
|
needs: docker_publish
|
||||||
|
|||||||
+3
-1
@@ -9,7 +9,9 @@
|
|||||||
},
|
},
|
||||||
"github": {
|
"github": {
|
||||||
"release": true,
|
"release": true,
|
||||||
"tokenRef": "GITHUB_TOKEN"
|
"tokenRef": "GITHUB_TOKEN",
|
||||||
|
"draft": true,
|
||||||
|
"push": true
|
||||||
},
|
},
|
||||||
"plugins": {
|
"plugins": {
|
||||||
"@release-it/conventional-changelog": {
|
"@release-it/conventional-changelog": {
|
||||||
|
|||||||
+1
-1
@@ -31,5 +31,5 @@ keywords:
|
|||||||
- web-ui
|
- web-ui
|
||||||
- agent
|
- agent
|
||||||
license: Apache-2.0
|
license: Apache-2.0
|
||||||
version: 1.4.13
|
version: 1.4.19
|
||||||
date-released: '2026-03-02'
|
date-released: '2026-03-02'
|
||||||
|
|||||||
+1
-2
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "portabase",
|
"name": "portabase",
|
||||||
"version": "1.4.13",
|
"version": "1.4.19",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "next dev --turbopack -p 8887",
|
"dev": "next dev --turbopack -p 8887",
|
||||||
@@ -50,7 +50,6 @@
|
|||||||
"@t3-oss/env-nextjs": "^0.13.10",
|
"@t3-oss/env-nextjs": "^0.13.10",
|
||||||
"@tanstack/react-query": "^5.90.21",
|
"@tanstack/react-query": "^5.90.21",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"@types/express": "^5.0.6",
|
|
||||||
"@types/nodemailer": "^6.4.23",
|
"@types/nodemailer": "^6.4.23",
|
||||||
"@types/ws": "^8.18.1",
|
"@types/ws": "^8.18.1",
|
||||||
"@zenstackhq/runtime": "2.14.2",
|
"@zenstackhq/runtime": "2.14.2",
|
||||||
|
|||||||
Generated
-67
@@ -113,9 +113,6 @@ importers:
|
|||||||
'@tanstack/react-table':
|
'@tanstack/react-table':
|
||||||
specifier: ^8.21.3
|
specifier: ^8.21.3
|
||||||
version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
version: 8.21.3(react-dom@19.2.4(react@19.2.4))(react@19.2.4)
|
||||||
'@types/express':
|
|
||||||
specifier: ^5.0.6
|
|
||||||
version: 5.0.6
|
|
||||||
'@types/nodemailer':
|
'@types/nodemailer':
|
||||||
specifier: ^6.4.23
|
specifier: ^6.4.23
|
||||||
version: 6.4.23
|
version: 6.4.23
|
||||||
@@ -3143,12 +3140,6 @@ packages:
|
|||||||
'@tybys/wasm-util@0.10.1':
|
'@tybys/wasm-util@0.10.1':
|
||||||
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
|
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
|
||||||
|
|
||||||
'@types/body-parser@1.19.6':
|
|
||||||
resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==}
|
|
||||||
|
|
||||||
'@types/connect@3.4.38':
|
|
||||||
resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==}
|
|
||||||
|
|
||||||
'@types/cors@2.8.19':
|
'@types/cors@2.8.19':
|
||||||
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
|
resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==}
|
||||||
|
|
||||||
@@ -3191,15 +3182,6 @@ packages:
|
|||||||
'@types/estree@1.0.8':
|
'@types/estree@1.0.8':
|
||||||
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==}
|
||||||
|
|
||||||
'@types/express-serve-static-core@5.1.1':
|
|
||||||
resolution: {integrity: sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A==}
|
|
||||||
|
|
||||||
'@types/express@5.0.6':
|
|
||||||
resolution: {integrity: sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA==}
|
|
||||||
|
|
||||||
'@types/http-errors@2.0.5':
|
|
||||||
resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==}
|
|
||||||
|
|
||||||
'@types/json-schema@7.0.15':
|
'@types/json-schema@7.0.15':
|
||||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||||
|
|
||||||
@@ -3237,12 +3219,6 @@ packages:
|
|||||||
'@types/prismjs@1.26.6':
|
'@types/prismjs@1.26.6':
|
||||||
resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==}
|
resolution: {integrity: sha512-vqlvI7qlMvcCBbVe0AKAb4f97//Hy0EBTaiW8AalRnG/xAN5zOiWWyrNqNXeq8+KAuvRewjCVY1+IPxk4RdNYw==}
|
||||||
|
|
||||||
'@types/qs@6.14.0':
|
|
||||||
resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==}
|
|
||||||
|
|
||||||
'@types/range-parser@1.2.7':
|
|
||||||
resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==}
|
|
||||||
|
|
||||||
'@types/react-dom@19.0.4':
|
'@types/react-dom@19.0.4':
|
||||||
resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==}
|
resolution: {integrity: sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
@@ -3259,12 +3235,6 @@ packages:
|
|||||||
'@types/react@19.2.14':
|
'@types/react@19.2.14':
|
||||||
resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
|
resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
|
||||||
|
|
||||||
'@types/send@1.2.1':
|
|
||||||
resolution: {integrity: sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ==}
|
|
||||||
|
|
||||||
'@types/serve-static@2.2.0':
|
|
||||||
resolution: {integrity: sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ==}
|
|
||||||
|
|
||||||
'@types/webpack@5.28.5':
|
'@types/webpack@5.28.5':
|
||||||
resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==}
|
resolution: {integrity: sha512-wR87cgvxj3p6D0Crt1r5avwqffqPXUkNlnQ1mjU93G7gCuFjufZR4I6j8cz5g1F1tTYpfOOFvly+cmIQwL9wvw==}
|
||||||
|
|
||||||
@@ -10490,15 +10460,6 @@ snapshots:
|
|||||||
tslib: 2.8.1
|
tslib: 2.8.1
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
'@types/body-parser@1.19.6':
|
|
||||||
dependencies:
|
|
||||||
'@types/connect': 3.4.38
|
|
||||||
'@types/node': 22.19.11
|
|
||||||
|
|
||||||
'@types/connect@3.4.38':
|
|
||||||
dependencies:
|
|
||||||
'@types/node': 22.19.11
|
|
||||||
|
|
||||||
'@types/cors@2.8.19':
|
'@types/cors@2.8.19':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.19.11
|
'@types/node': 22.19.11
|
||||||
@@ -10543,21 +10504,6 @@ snapshots:
|
|||||||
|
|
||||||
'@types/estree@1.0.8': {}
|
'@types/estree@1.0.8': {}
|
||||||
|
|
||||||
'@types/express-serve-static-core@5.1.1':
|
|
||||||
dependencies:
|
|
||||||
'@types/node': 22.19.11
|
|
||||||
'@types/qs': 6.14.0
|
|
||||||
'@types/range-parser': 1.2.7
|
|
||||||
'@types/send': 1.2.1
|
|
||||||
|
|
||||||
'@types/express@5.0.6':
|
|
||||||
dependencies:
|
|
||||||
'@types/body-parser': 1.19.6
|
|
||||||
'@types/express-serve-static-core': 5.1.1
|
|
||||||
'@types/serve-static': 2.2.0
|
|
||||||
|
|
||||||
'@types/http-errors@2.0.5': {}
|
|
||||||
|
|
||||||
'@types/json-schema@7.0.15': {}
|
'@types/json-schema@7.0.15': {}
|
||||||
|
|
||||||
'@types/json5@0.0.29': {}
|
'@types/json5@0.0.29': {}
|
||||||
@@ -10598,10 +10544,6 @@ snapshots:
|
|||||||
|
|
||||||
'@types/prismjs@1.26.6': {}
|
'@types/prismjs@1.26.6': {}
|
||||||
|
|
||||||
'@types/qs@6.14.0': {}
|
|
||||||
|
|
||||||
'@types/range-parser@1.2.7': {}
|
|
||||||
|
|
||||||
'@types/react-dom@19.0.4(@types/react@19.0.10)':
|
'@types/react-dom@19.0.4(@types/react@19.0.10)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/react': 19.0.10
|
'@types/react': 19.0.10
|
||||||
@@ -10618,15 +10560,6 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
csstype: 3.2.3
|
csstype: 3.2.3
|
||||||
|
|
||||||
'@types/send@1.2.1':
|
|
||||||
dependencies:
|
|
||||||
'@types/node': 22.19.11
|
|
||||||
|
|
||||||
'@types/serve-static@2.2.0':
|
|
||||||
dependencies:
|
|
||||||
'@types/http-errors': 2.0.5
|
|
||||||
'@types/node': 22.19.11
|
|
||||||
|
|
||||||
'@types/webpack@5.28.5(esbuild@0.25.10)':
|
'@types/webpack@5.28.5(esbuild@0.25.10)':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 22.19.11
|
'@types/node': 22.19.11
|
||||||
|
|||||||
+232
-53
@@ -1,62 +1,241 @@
|
|||||||
"use client"
|
"use client";
|
||||||
import {Eye} from "lucide-react";
|
|
||||||
|
|
||||||
import {useState} from "react";
|
|
||||||
import {
|
import {
|
||||||
Dialog,
|
AlertCircle,
|
||||||
DialogContent,
|
Braces,
|
||||||
DialogDescription,
|
Database,
|
||||||
DialogHeader,
|
ExternalLink,
|
||||||
DialogTitle,
|
Eye,
|
||||||
DialogTrigger
|
Hash,
|
||||||
|
Server,
|
||||||
|
Sparkles,
|
||||||
|
} from "lucide-react";
|
||||||
|
import { useState } from "react";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle,
|
||||||
|
DialogTrigger,
|
||||||
} from "@/components/ui/dialog";
|
} from "@/components/ui/dialog";
|
||||||
import {Button} from "@/components/ui/button";
|
import type { NotificationLogWithRelations } from "@/db/services/notification-log";
|
||||||
import {Separator} from "@/components/ui/separator";
|
|
||||||
import {NotificationLogWithRelations} from "@/db/services/notification-log";
|
|
||||||
|
|
||||||
type NotificationLogModalProps = {
|
type NotificationLogModalProps = {
|
||||||
notificationLog: NotificationLogWithRelations;
|
notificationLog: NotificationLogWithRelations;
|
||||||
}
|
};
|
||||||
|
|
||||||
export const NotificationLogModal = ({notificationLog}: NotificationLogModalProps) => {
|
const getTroubleshootingForError = (errorMsg?: any) => {
|
||||||
const [open, setOpen] = useState(false);
|
if (!errorMsg || String(errorMsg).toLowerCase() === "null") return null;
|
||||||
|
|
||||||
return (
|
const msg = String(errorMsg).toLowerCase();
|
||||||
<Dialog open={open} onOpenChange={setOpen}>
|
|
||||||
<DialogTrigger asChild>
|
|
||||||
<Button variant="outline" onClick={() => setOpen(true)} className="relative">
|
|
||||||
<Eye/>
|
|
||||||
</Button>
|
|
||||||
</DialogTrigger>
|
|
||||||
<DialogContent>
|
|
||||||
<DialogHeader>
|
|
||||||
<DialogTitle>Notification details</DialogTitle>
|
|
||||||
<DialogDescription>
|
|
||||||
Details of the notification sent
|
|
||||||
</DialogDescription>
|
|
||||||
<Separator className="mt-3 mb-3"/>
|
|
||||||
|
|
||||||
<div className="space-y-2 mb-4">
|
if (msg.includes("database connection") || msg.includes("agent")) {
|
||||||
<div>
|
return {
|
||||||
<span className="font-semibold">Title:</span>{" "}
|
title: "Agent Connection Issue",
|
||||||
<span>{notificationLog.content.title}</span>
|
resolution:
|
||||||
</div>
|
"It appears the agent cannot reach the database. Please ensure that your agent is actively running, your PostgreSQL credentials are correct, and port 5432 is open on your firewall.",
|
||||||
<div>
|
docLink:
|
||||||
<span className="font-semibold">Message:</span>{" "}
|
"https://portabase.io/docs/agent/troubleshooting/agent-connection",
|
||||||
<span>{notificationLog.content.message}</span>
|
};
|
||||||
</div>
|
}
|
||||||
|
|
||||||
|
if (msg.includes("timeout")) {
|
||||||
|
return {
|
||||||
|
title: "Timeout",
|
||||||
|
resolution:
|
||||||
|
"The agent is taking too long to respond. This could be due to high server load, network issues, or a large database.",
|
||||||
|
docLink: "https://portabase.io/docs/agent/troubleshooting/timeout",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
title: "Unexpected Execution Error",
|
||||||
|
resolution:
|
||||||
|
"An unexpected error occurred during execution. Please review the raw system logs or contact support if the issue persists.",
|
||||||
|
docLink: "https://discord.gg/Wgv7xZ8fWJ",
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const getIconForKey = (key: string, value: any) => {
|
||||||
|
const isActualError =
|
||||||
|
key.toLowerCase().includes("error") &&
|
||||||
|
value !== null &&
|
||||||
|
String(value).toLowerCase() !== "null";
|
||||||
|
|
||||||
|
if (key.toLowerCase().includes("id"))
|
||||||
|
return <Hash className="w-3.5 h-3.5 text-muted-foreground" />;
|
||||||
|
if (key.toLowerCase().includes("host"))
|
||||||
|
return <Server className="w-3.5 h-3.5 text-muted-foreground" />;
|
||||||
|
if (isActualError)
|
||||||
|
return <AlertCircle className="w-3.5 h-3.5 text-destructive" />;
|
||||||
|
return <Database className="w-3.5 h-3.5 text-muted-foreground" />;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NotificationLogModal = ({
|
||||||
|
notificationLog,
|
||||||
|
}: NotificationLogModalProps) => {
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
|
||||||
|
// TODO : to be fixed
|
||||||
|
// @ts-ignore
|
||||||
|
const payloadError = notificationLog.payload?.error;
|
||||||
|
const troubleshooting = getTroubleshootingForError(payloadError);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog open={open} onOpenChange={setOpen}>
|
||||||
|
<DialogTrigger asChild>
|
||||||
|
<Button
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => setOpen(true)}
|
||||||
|
className="relative"
|
||||||
|
>
|
||||||
|
<Eye className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
</DialogTrigger>
|
||||||
|
<DialogContent className="sm:max-w-xl bg-background">
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Notification Details</DialogTitle>
|
||||||
|
<DialogDescription>Execution logs and payload data</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
|
||||||
|
<div className="space-y-4 mt-2 max-h-[70vh] overflow-y-auto px-1 pb-2">
|
||||||
|
<div className="relative border rounded-xl bg-card shadow-sm flex flex-col">
|
||||||
|
<div className="bg-primary/5 border-b px-4 py-2.5 flex items-center gap-2 rounded-t-xl">
|
||||||
|
<div className="p-1 bg-primary/10 rounded-md">
|
||||||
|
<Database className="w-4 h-4 text-primary" />
|
||||||
|
</div>
|
||||||
|
<span className="font-semibold text-sm text-primary">
|
||||||
|
Event Trigger
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="p-4 flex flex-col gap-4">
|
||||||
|
<div className="flex flex-col sm:flex-row sm:items-start justify-between gap-1 sm:gap-4">
|
||||||
|
<span className="text-xs font-medium text-muted-foreground min-w-20 pt-0.5">
|
||||||
|
Title
|
||||||
|
</span>
|
||||||
|
<span className="text-sm sm:text-right flex-1 wrap-break-words">
|
||||||
|
{notificationLog.content.title}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col sm:flex-row sm:items-start justify-between gap-1 sm:gap-4">
|
||||||
|
<span className="text-xs font-medium text-muted-foreground min-w-20 pt-0.5">
|
||||||
|
Message
|
||||||
|
</span>
|
||||||
|
<span className="text-sm sm:text-right flex-1 wrap-break-word text-muted-foreground">
|
||||||
|
{notificationLog.content.message}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{notificationLog.payload && (
|
||||||
|
<div className="absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary rounded-full border-2 border-background z-10" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="w-px h-6 bg-border mx-auto -my-4 relative z-0" />
|
||||||
|
|
||||||
|
{notificationLog.payload &&
|
||||||
|
Object.keys(notificationLog.payload).length > 0 && (
|
||||||
|
<div className="relative border rounded-xl bg-card shadow-sm flex flex-col">
|
||||||
|
<div className="absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary rounded-full border-2 border-background z-10" />
|
||||||
|
|
||||||
|
<div className="bg-primary/5 border-b px-4 py-2.5 flex items-center justify-between rounded-t-xl">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="p-1 bg-primary/10 rounded-md">
|
||||||
|
<Braces className="w-4 h-4 text-primary" />
|
||||||
</div>
|
</div>
|
||||||
|
<span className="font-semibold text-sm text-primary">
|
||||||
|
JSON Payload
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{notificationLog.payload && (
|
<div className="flex flex-col">
|
||||||
<>
|
{Object.entries(notificationLog.payload).map(
|
||||||
<Separator className="mb-3" />
|
([key, value], index, arr) => {
|
||||||
<div className="text-sm font-mono bg-gray-100 dark:bg-gray-800 dark:text-gray-200 p-4 rounded-md overflow-auto">
|
const isActualError =
|
||||||
{JSON.stringify(notificationLog.payload, null, 2)}
|
key === "error" &&
|
||||||
</div>
|
value !== null &&
|
||||||
</>
|
String(value).toLowerCase() !== "null";
|
||||||
)}
|
|
||||||
</DialogHeader>
|
return (
|
||||||
</DialogContent>
|
<div
|
||||||
</Dialog>
|
key={key}
|
||||||
)
|
className={`flex flex-col sm:flex-row sm:items-center justify-between gap-2 px-4 py-3 hover:bg-muted/50 transition-colors ${
|
||||||
}
|
index !== arr.length - 1
|
||||||
|
? "border-b border-border/50"
|
||||||
|
: ""
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-2 min-w-[150px]">
|
||||||
|
{getIconForKey(key, value)}
|
||||||
|
<span className="text-sm font-medium">{key}</span>
|
||||||
|
</div>
|
||||||
|
<div className="flex-1 sm:text-right">
|
||||||
|
{isActualError ? (
|
||||||
|
<span className="inline-flex items-center px-2 py-1 rounded-md bg-destructive/10 text-destructive text-xs font-mono break-all">
|
||||||
|
{String(value)}
|
||||||
|
</span>
|
||||||
|
) : (
|
||||||
|
<span className="text-sm text-muted-foreground font-mono bg-muted px-2 py-1 rounded-md break-all">
|
||||||
|
{String(value)}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{troubleshooting && (
|
||||||
|
<div className="absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-primary rounded-full border-2 border-background z-10" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{troubleshooting && (
|
||||||
|
<>
|
||||||
|
<div className="w-px h-6 bg-border mx-auto -my-4 relative z-0" />
|
||||||
|
|
||||||
|
<div className="relative border border-destructive/20 rounded-xl bg-gradient-to-b from-destructive/5 to-transparent shadow-sm flex flex-col">
|
||||||
|
<div className="absolute -top-1.5 left-1/2 -translate-x-1/2 w-3 h-3 bg-destructive rounded-full border-2 border-background z-10" />
|
||||||
|
|
||||||
|
<div className="bg-destructive/10 border-b border-destructive/10 px-4 py-2.5 flex items-center justify-between rounded-t-xl">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<div className="p-1 bg-destructive/20 rounded-md">
|
||||||
|
<Sparkles className="w-4 h-4 text-destructive" />
|
||||||
|
</div>
|
||||||
|
<span className="font-semibold text-sm text-destructive">
|
||||||
|
Suggested Resolution
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="p-4 flex flex-col gap-2">
|
||||||
|
<h4 className="text-sm font-semibold text-foreground">
|
||||||
|
{troubleshooting.title}
|
||||||
|
</h4>
|
||||||
|
<p className="text-sm text-muted-foreground leading-relaxed">
|
||||||
|
{troubleshooting.resolution}
|
||||||
|
</p>
|
||||||
|
<div className="mt-2">
|
||||||
|
<a
|
||||||
|
href={troubleshooting.docLink}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="inline-flex items-center gap-1.5 text-xs font-semibold text-destructive hover:text-destructive/80 transition-colors"
|
||||||
|
>
|
||||||
|
Read the documentation{" "}
|
||||||
|
<ExternalLink className="w-3.5 h-3.5" />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user