mirror of
https://github.com/Dokploy/dokploy
synced 2025-06-26 18:27:59 +00:00
v0.1.0 (#112)
* feat: add schema for registry and routes * feat: add docker registry upload * feat: add show cluster * refactor: set the registry url in image in case we have a registry asociated * feat: add update registry and fix the docker url markup * chore: remove --advertise-ip on swarm script * refactor: remove listen address of swarm initialize * feat: add table to show nodes and add dropdown to add manager & workers * refactor: improve interface for cluster * refactor: improve UI * feat: add experimental swarm settings * refactor: remove comments * refactor: prettify json of each setting * refactor: add interface tooltip * refactor: delete static form self registry * refactor: allow to se a empty registry * fix: remove text area warnings * feat: add network swarm json * refactor: update ui * revert: go back to swarm init config * refactor: remove initialization on server, only on setup script * Update LICENSE.MD * feat: appearance theme support system config * refactor: remove logs * fix(README-ru): hyperlink-ed docs url * feat: (#107) webhook listener filter docker events based on image tag. Fixes #107 * refactor: simplify comparison docker tags * refactor: remove return in res status * refactor: prevent to updates download automatically * feat: support code editor (#105) * feat: support code editor * Update codeblock * refactor: remove unused class --------- Co-authored-by: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com> * fix: select the right image from sourcetype (#109) * chore: bump minor version --------- Co-authored-by: hehehai <riverhohai@gmail.com> Co-authored-by: Bayram Tagiev <bayram.tagiev.a@gmail.com> Co-authored-by: Paulo Santana <30875229+hikinine@users.noreply.github.com>
This commit is contained in:
@@ -12,8 +12,8 @@ export default function Custom404({ statusCode }: Props) {
|
||||
<div className="container mx-auto h-screen items-center justify-center flex">
|
||||
<div className="-mx-4 flex">
|
||||
<div className="w-full px-4">
|
||||
<div className="mx-auto max-w-[400px] text-center">
|
||||
<h2 className="mb-2 text-[50px] font-bold leading-none text-white sm:text-[80px] md:text-[100px]">
|
||||
<div className="mx-auto max-w-[700px] text-center">
|
||||
<h2 className="mb-2 text-[50px] font-bold leading-none text-white sm:text-[80px]">
|
||||
{statusCode
|
||||
? `An error ${statusCode} occurred on server`
|
||||
: "An error occurred on client"}
|
||||
|
||||
@@ -35,7 +35,25 @@ export default async function handler(
|
||||
const deploymentTitle = extractCommitMessage(req.headers, req.body);
|
||||
|
||||
const sourceType = application.sourceType;
|
||||
if (sourceType === "github") {
|
||||
|
||||
if (sourceType === "docker") {
|
||||
const applicationDockerTag = extractImageTag(application.dockerImage);
|
||||
const webhookDockerTag = extractImageTagFromRequest(
|
||||
req.headers,
|
||||
req.body,
|
||||
);
|
||||
if (
|
||||
applicationDockerTag &&
|
||||
webhookDockerTag &&
|
||||
webhookDockerTag !== applicationDockerTag
|
||||
) {
|
||||
res.status(301).json({
|
||||
message: `Application Image Tag (${applicationDockerTag}) doesn't match request event payload Image Tag (${webhookDockerTag}).`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (sourceType === "github") {
|
||||
const branchName = extractBranchName(req.headers, req.body);
|
||||
if (!branchName || branchName !== application.branch) {
|
||||
res.status(301).json({ message: "Branch Not Match" });
|
||||
@@ -79,6 +97,36 @@ export default async function handler(
|
||||
res.status(400).json({ message: "Error To Deploy Application", error });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last part of the image name, which is the tag
|
||||
* Example: "my-image" => null
|
||||
* Example: "my-image:latest" => "latest"
|
||||
* Example: "my-image:1.0.0" => "1.0.0"
|
||||
* Example: "myregistryhost:5000/fedora/httpd:version1.0" => "version1.0"
|
||||
* @link https://docs.docker.com/reference/cli/docker/image/tag/
|
||||
*/
|
||||
function extractImageTag(dockerImage: string | null) {
|
||||
if (!dockerImage || typeof dockerImage !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const tag = dockerImage.split(":").pop();
|
||||
return tag === dockerImage ? "latest" : tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* @link https://docs.docker.com/docker-hub/webhooks/#example-webhook-payload
|
||||
*/
|
||||
function extractImageTagFromRequest(headers: any, body: any): string | null {
|
||||
if (headers["user-agent"]?.includes("Go-http-client")) {
|
||||
if (body.push_data && body.repository) {
|
||||
return body.push_data.tag;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function extractCommitMessage(headers: any, body: any) {
|
||||
// GitHub
|
||||
if (headers["x-github-event"]) {
|
||||
|
||||
@@ -212,7 +212,7 @@ const Project = (
|
||||
}}
|
||||
className="group relative cursor-pointer bg-transparent transition-colors hover:bg-card h-fit"
|
||||
>
|
||||
<div className="absolute -right-1 -top-1">
|
||||
<div className="absolute -right-1 -top-2">
|
||||
<StatusTooltip status={service.status} />
|
||||
</div>
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { ShowClusterSettings } from "@/components/dashboard/application/advanced/cluster/show-cluster-settings";
|
||||
import { AddCommand } from "@/components/dashboard/application/advanced/general/add-command";
|
||||
import { ShowPorts } from "@/components/dashboard/application/advanced/ports/show-port";
|
||||
import { ShowRedirects } from "@/components/dashboard/application/advanced/redirects/show-redirects";
|
||||
@@ -134,7 +135,7 @@ const Service = (
|
||||
<TabsTrigger value="domains">Domains</TabsTrigger>
|
||||
<TabsTrigger value="advanced">Advanced</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="flex flex-row gap-2">
|
||||
<UpdateApplication applicationId={applicationId} />
|
||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
||||
<DeleteApplication applicationId={applicationId} />
|
||||
@@ -175,6 +176,7 @@ const Service = (
|
||||
<TabsContent value="advanced">
|
||||
<div className="flex flex-col gap-4 pt-2.5">
|
||||
<AddCommand applicationId={applicationId} />
|
||||
<ShowClusterSettings applicationId={applicationId} />
|
||||
<ShowApplicationResources applicationId={applicationId} />
|
||||
<ShowVolumes applicationId={applicationId} />
|
||||
<ShowRedirects applicationId={applicationId} />
|
||||
|
||||
@@ -116,7 +116,7 @@ const Mariadb = (
|
||||
<TabsTrigger value="logs">Logs</TabsTrigger>
|
||||
<TabsTrigger value="advanced">Advanced</TabsTrigger>
|
||||
</TabsList>
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="flex flex-row gap-2">
|
||||
<UpdateMariadb mariadbId={mariadbId} />
|
||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
||||
<DeleteMariadb mariadbId={mariadbId} />
|
||||
|
||||
@@ -118,7 +118,7 @@ const Mongo = (
|
||||
<TabsTrigger value="advanced">Advanced</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="flex flex-row gap-2">
|
||||
<UpdateMongo mongoId={mongoId} />
|
||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
||||
<DeleteMongo mongoId={mongoId} />
|
||||
|
||||
@@ -117,7 +117,7 @@ const MySql = (
|
||||
<TabsTrigger value="advanced">Advanced</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="flex flex-row gap-2">
|
||||
<UpdateMysql mysqlId={mysqlId} />
|
||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
||||
<DeleteMysql mysqlId={mysqlId} />
|
||||
|
||||
@@ -118,7 +118,7 @@ const Postgresql = (
|
||||
<TabsTrigger value="advanced">Advanced</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="flex flex-row gap-2">
|
||||
<UpdatePostgres postgresId={postgresId} />
|
||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
||||
<DeletePostgres postgresId={postgresId} />
|
||||
|
||||
@@ -116,7 +116,7 @@ const Redis = (
|
||||
<TabsTrigger value="advanced">Advanced</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<div className="flex flex-row gap-4">
|
||||
<div className="flex flex-row gap-2">
|
||||
<UpdateRedis redisId={redisId} />
|
||||
{(auth?.rol === "admin" || user?.canDeleteServices) && (
|
||||
<DeleteRedis redisId={redisId} />
|
||||
|
||||
43
pages/dashboard/settings/cluster.tsx
Normal file
43
pages/dashboard/settings/cluster.tsx
Normal file
@@ -0,0 +1,43 @@
|
||||
import { ShowRegistry } from "@/components/dashboard/settings/cluster/registry/show-registry";
|
||||
import { ShowNodes } from "@/components/dashboard/settings/cluster/nodes/show-nodes";
|
||||
import { DashboardLayout } from "@/components/layouts/dashboard-layout";
|
||||
import { SettingsLayout } from "@/components/layouts/settings-layout";
|
||||
import { validateRequest } from "@/server/auth/auth";
|
||||
import type { GetServerSidePropsContext } from "next";
|
||||
import React, { type ReactElement } from "react";
|
||||
|
||||
const Page = () => {
|
||||
return (
|
||||
<div className="flex flex-col gap-4 w-full">
|
||||
<ShowRegistry />
|
||||
<ShowNodes />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Page;
|
||||
|
||||
Page.getLayout = (page: ReactElement) => {
|
||||
return (
|
||||
<DashboardLayout tab={"settings"}>
|
||||
<SettingsLayout>{page}</SettingsLayout>
|
||||
</DashboardLayout>
|
||||
);
|
||||
};
|
||||
export async function getServerSideProps(
|
||||
ctx: GetServerSidePropsContext<{ serviceId: string }>,
|
||||
) {
|
||||
const { user, session } = await validateRequest(ctx.req, ctx.res);
|
||||
if (!user || user.rol === "user") {
|
||||
return {
|
||||
redirect: {
|
||||
permanent: true,
|
||||
destination: "/",
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
props: {},
|
||||
};
|
||||
}
|
||||
@@ -193,7 +193,7 @@ export default function Home({ hasAdmin }: Props) {
|
||||
<div className="mt-4 text-sm flex flex-row justify-center gap-2">
|
||||
<Link
|
||||
className="hover:underline text-muted-foreground"
|
||||
href="https://docs.dokploy.com/reset-password"
|
||||
href="https://docs.dokploy.com/get-started/reset-password"
|
||||
target="_blank"
|
||||
>
|
||||
Lost your password?
|
||||
|
||||
Reference in New Issue
Block a user