mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
Merge pull request #1967 from Dokploy/feat/add-chatwoot
Feat/add chatwoot
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { api } from "@/utils/api";
|
import { api } from "@/utils/api";
|
||||||
import { ImpersonationBar } from "../dashboard/impersonation/impersonation-bar";
|
import { ImpersonationBar } from "../dashboard/impersonation/impersonation-bar";
|
||||||
import Page from "./side";
|
import Page from "./side";
|
||||||
|
import { ChatwootWidget } from "../shared/ChatwootWidget";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
@@ -9,10 +10,15 @@ interface Props {
|
|||||||
|
|
||||||
export const DashboardLayout = ({ children }: Props) => {
|
export const DashboardLayout = ({ children }: Props) => {
|
||||||
const { data: haveRootAccess } = api.user.haveRootAccess.useQuery();
|
const { data: haveRootAccess } = api.user.haveRootAccess.useQuery();
|
||||||
|
const { data: isCloud } = api.settings.isCloud.useQuery();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Page>{children}</Page>
|
<Page>{children}</Page>
|
||||||
|
{isCloud === true && (
|
||||||
|
<ChatwootWidget websiteToken="USCpQRKzHvFMssf3p6Eacae5" />
|
||||||
|
)}
|
||||||
|
|
||||||
{haveRootAccess === true && <ImpersonationBar />}
|
{haveRootAccess === true && <ImpersonationBar />}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
import Page from "./side";
|
|
||||||
|
|
||||||
interface Props {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const ProjectLayout = ({ children }: Props) => {
|
|
||||||
return <Page>{children}</Page>;
|
|
||||||
};
|
|
||||||
69
apps/dokploy/components/shared/ChatwootWidget.tsx
Normal file
69
apps/dokploy/components/shared/ChatwootWidget.tsx
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import Script from "next/script";
|
||||||
|
import { useEffect } from "react";
|
||||||
|
|
||||||
|
interface ChatwootWidgetProps {
|
||||||
|
websiteToken: string;
|
||||||
|
baseUrl?: string;
|
||||||
|
settings?: {
|
||||||
|
position?: "left" | "right";
|
||||||
|
type?: "standard" | "expanded_bubble";
|
||||||
|
launcherTitle?: string;
|
||||||
|
darkMode?: boolean;
|
||||||
|
hideMessageBubble?: boolean;
|
||||||
|
placement?: "right" | "left";
|
||||||
|
showPopoutButton?: boolean;
|
||||||
|
widgetStyle?: "standard" | "bubble";
|
||||||
|
};
|
||||||
|
user?: {
|
||||||
|
identifier: string;
|
||||||
|
name?: string;
|
||||||
|
email?: string;
|
||||||
|
phoneNumber?: string;
|
||||||
|
avatarUrl?: string;
|
||||||
|
customAttributes?: Record<string, any>;
|
||||||
|
identifierHash?: string;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ChatwootWidget = ({
|
||||||
|
websiteToken,
|
||||||
|
baseUrl = "https://app.chatwoot.com",
|
||||||
|
settings = {
|
||||||
|
position: "right",
|
||||||
|
type: "standard",
|
||||||
|
launcherTitle: "Chat with us",
|
||||||
|
},
|
||||||
|
user,
|
||||||
|
}: ChatwootWidgetProps) => {
|
||||||
|
useEffect(() => {
|
||||||
|
// Configurar los settings de Chatwoot
|
||||||
|
window.chatwootSettings = {
|
||||||
|
position: "right",
|
||||||
|
};
|
||||||
|
|
||||||
|
(window as any).chatwootSDKReady = () => {
|
||||||
|
window.chatwootSDK?.run({ websiteToken, baseUrl });
|
||||||
|
|
||||||
|
const trySetUser = () => {
|
||||||
|
if (window.$chatwoot && user) {
|
||||||
|
window.$chatwoot.setUser(user.identifier, {
|
||||||
|
email: user.email,
|
||||||
|
name: user.name,
|
||||||
|
avatar_url: user.avatarUrl,
|
||||||
|
phone_number: user.phoneNumber,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
trySetUser();
|
||||||
|
};
|
||||||
|
}, [websiteToken, baseUrl, user, settings]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Script
|
||||||
|
src={`${baseUrl}/packs/js/sdk.js`}
|
||||||
|
strategy="lazyOnload"
|
||||||
|
onLoad={() => (window as any).chatwootSDKReady?.()}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
@@ -17,7 +17,6 @@ const inter = Inter({ subsets: ["latin"] });
|
|||||||
|
|
||||||
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
|
||||||
getLayout?: (page: ReactElement) => ReactNode;
|
getLayout?: (page: ReactElement) => ReactNode;
|
||||||
// session: Session | null;
|
|
||||||
theme?: string;
|
theme?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -33,11 +32,13 @@ const MyApp = ({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<style jsx global>{`
|
<style jsx global>
|
||||||
:root {
|
{`
|
||||||
--font-inter: ${inter.style.fontFamily};
|
:root {
|
||||||
}
|
--font-inter: ${inter.style.fontFamily};
|
||||||
`}</style>
|
}
|
||||||
|
`}
|
||||||
|
</style>
|
||||||
<Head>
|
<Head>
|
||||||
<title>Dokploy</title>
|
<title>Dokploy</title>
|
||||||
</Head>
|
</Head>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
PostgresqlIcon,
|
PostgresqlIcon,
|
||||||
RedisIcon,
|
RedisIcon,
|
||||||
} from "@/components/icons/data-tools-icons";
|
} from "@/components/icons/data-tools-icons";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { DateTooltip } from "@/components/shared/date-tooltip";
|
import { DateTooltip } from "@/components/shared/date-tooltip";
|
||||||
import { DialogAction } from "@/components/shared/dialog-action";
|
import { DialogAction } from "@/components/shared/dialog-action";
|
||||||
@@ -1064,7 +1064,7 @@ const Project = (
|
|||||||
|
|
||||||
export default Project;
|
export default Project;
|
||||||
Project.getLayout = (page: ReactElement) => {
|
Project.getLayout = (page: ReactElement) => {
|
||||||
return <ProjectLayout>{page}</ProjectLayout>;
|
return <DashboardLayout>{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import { UpdateApplication } from "@/components/dashboard/application/update-app
|
|||||||
import { DeleteService } from "@/components/dashboard/compose/delete-service";
|
import { DeleteService } from "@/components/dashboard/compose/delete-service";
|
||||||
import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring";
|
import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-container-monitoring";
|
||||||
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -363,7 +363,7 @@ const Service = (
|
|||||||
|
|
||||||
export default Service;
|
export default Service;
|
||||||
Service.getLayout = (page: ReactElement) => {
|
Service.getLayout = (page: ReactElement) => {
|
||||||
return <ProjectLayout>{page}</ProjectLayout>;
|
return <DashboardLayout>{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import { UpdateCompose } from "@/components/dashboard/compose/update-compose";
|
|||||||
import { ShowBackups } from "@/components/dashboard/database/backups/show-backups";
|
import { ShowBackups } from "@/components/dashboard/database/backups/show-backups";
|
||||||
import { ComposeFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-compose-monitoring";
|
import { ComposeFreeMonitoring } from "@/components/dashboard/monitoring/free/container/show-free-compose-monitoring";
|
||||||
import { ComposePaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-compose-monitoring";
|
import { ComposePaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-compose-monitoring";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -366,7 +366,7 @@ const Service = (
|
|||||||
|
|
||||||
export default Service;
|
export default Service;
|
||||||
Service.getLayout = (page: ReactElement) => {
|
Service.getLayout = (page: ReactElement) => {
|
||||||
return <ProjectLayout>{page}</ProjectLayout>;
|
return <DashboardLayout>{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/
|
|||||||
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
||||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||||
import { MariadbIcon } from "@/components/icons/data-tools-icons";
|
import { MariadbIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -294,7 +294,7 @@ const Mariadb = (
|
|||||||
|
|
||||||
export default Mariadb;
|
export default Mariadb;
|
||||||
Mariadb.getLayout = (page: ReactElement) => {
|
Mariadb.getLayout = (page: ReactElement) => {
|
||||||
return <ProjectLayout>{page}</ProjectLayout>;
|
return <DashboardLayout>{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ContainerFreeMonitoring } from "@/components/dashboard/monitoring/free/
|
|||||||
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
import { ContainerPaidMonitoring } from "@/components/dashboard/monitoring/paid/container/show-paid-container-monitoring";
|
||||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||||
import { MongodbIcon } from "@/components/icons/data-tools-icons";
|
import { MongodbIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -296,7 +296,7 @@ const Mongo = (
|
|||||||
|
|
||||||
export default Mongo;
|
export default Mongo;
|
||||||
Mongo.getLayout = (page: ReactElement) => {
|
Mongo.getLayout = (page: ReactElement) => {
|
||||||
return <ProjectLayout>{page}</ProjectLayout>;
|
return <DashboardLayout>{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ShowInternalMysqlCredentials } from "@/components/dashboard/mysql/gener
|
|||||||
import { UpdateMysql } from "@/components/dashboard/mysql/update-mysql";
|
import { UpdateMysql } from "@/components/dashboard/mysql/update-mysql";
|
||||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||||
import { MysqlIcon } from "@/components/icons/data-tools-icons";
|
import { MysqlIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -280,7 +280,7 @@ const MySql = (
|
|||||||
|
|
||||||
export default MySql;
|
export default MySql;
|
||||||
MySql.getLayout = (page: ReactElement) => {
|
MySql.getLayout = (page: ReactElement) => {
|
||||||
return <ProjectLayout>{page}</ProjectLayout>;
|
return <DashboardLayout>{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import { ShowInternalPostgresCredentials } from "@/components/dashboard/postgres
|
|||||||
import { UpdatePostgres } from "@/components/dashboard/postgres/update-postgres";
|
import { UpdatePostgres } from "@/components/dashboard/postgres/update-postgres";
|
||||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||||
import { PostgresqlIcon } from "@/components/icons/data-tools-icons";
|
import { PostgresqlIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -278,7 +278,7 @@ const Postgresql = (
|
|||||||
|
|
||||||
export default Postgresql;
|
export default Postgresql;
|
||||||
Postgresql.getLayout = (page: ReactElement) => {
|
Postgresql.getLayout = (page: ReactElement) => {
|
||||||
return <ProjectLayout>{page}</ProjectLayout>;
|
return <DashboardLayout>{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import { ShowInternalRedisCredentials } from "@/components/dashboard/redis/gener
|
|||||||
import { UpdateRedis } from "@/components/dashboard/redis/update-redis";
|
import { UpdateRedis } from "@/components/dashboard/redis/update-redis";
|
||||||
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
import { ShowDatabaseAdvancedSettings } from "@/components/dashboard/shared/show-database-advanced-settings";
|
||||||
import { RedisIcon } from "@/components/icons/data-tools-icons";
|
import { RedisIcon } from "@/components/icons/data-tools-icons";
|
||||||
import { ProjectLayout } from "@/components/layouts/project-layout";
|
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||||
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
import { BreadcrumbSidebar } from "@/components/shared/breadcrumb-sidebar";
|
||||||
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
import { StatusTooltip } from "@/components/shared/status-tooltip";
|
||||||
import { Badge } from "@/components/ui/badge";
|
import { Badge } from "@/components/ui/badge";
|
||||||
@@ -285,7 +285,7 @@ const Redis = (
|
|||||||
|
|
||||||
export default Redis;
|
export default Redis;
|
||||||
Redis.getLayout = (page: ReactElement) => {
|
Redis.getLayout = (page: ReactElement) => {
|
||||||
return <ProjectLayout>{page}</ProjectLayout>;
|
return <DashboardLayout>{page}</DashboardLayout>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function getServerSideProps(
|
export async function getServerSideProps(
|
||||||
|
|||||||
39
apps/dokploy/types/chatwoot.d.ts
vendored
Normal file
39
apps/dokploy/types/chatwoot.d.ts
vendored
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
chatwootSettings?: {
|
||||||
|
hideMessageBubble?: boolean;
|
||||||
|
showUnreadMessagesDialog?: boolean;
|
||||||
|
position?: "left" | "right";
|
||||||
|
locale?: string;
|
||||||
|
useBrowserLanguage?: boolean;
|
||||||
|
type?: "standard" | "expanded_bubble";
|
||||||
|
darkMode?: "light" | "auto";
|
||||||
|
launcherTitle?: string;
|
||||||
|
showPopoutButton?: boolean;
|
||||||
|
baseDomain?: string;
|
||||||
|
};
|
||||||
|
chatwootSDK?: {
|
||||||
|
run: (config: {
|
||||||
|
websiteToken: string;
|
||||||
|
baseUrl: string;
|
||||||
|
}) => void;
|
||||||
|
};
|
||||||
|
$chatwoot?: {
|
||||||
|
setUser: (
|
||||||
|
identifier: string,
|
||||||
|
userAttributes: Record<string, any>,
|
||||||
|
) => void;
|
||||||
|
setCustomAttributes: (attributes: Record<string, any>) => void;
|
||||||
|
reset: () => void;
|
||||||
|
toggle: (state?: "open" | "close") => void;
|
||||||
|
popoutChatWindow: () => void;
|
||||||
|
toggleBubbleVisibility: (visibility: "show" | "hide") => void;
|
||||||
|
setLocale: (locale: string) => void;
|
||||||
|
setLabel: (label: string) => void;
|
||||||
|
removeLabel: (label: string) => void;
|
||||||
|
};
|
||||||
|
chatwootSDKReady?: () => void;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {};
|
||||||
1548
pnpm-lock.yaml
generated
1548
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user