mirror of https://github.com/ctk-hq/ctk
commit
a039052621
@ -0,0 +1,20 @@
|
||||
# vi:syntax=nginx
|
||||
|
||||
server {
|
||||
listen 8080;
|
||||
listen [::]:8080;
|
||||
server_name localhost;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
# vi:syntax=nginx
|
||||
|
||||
upstream django {
|
||||
server backend:9000;
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name localhost;
|
||||
|
||||
charset utf-8;
|
||||
|
||||
location /static {
|
||||
alias /home/server/static;
|
||||
}
|
||||
|
||||
location /admin {
|
||||
uwsgi_pass django;
|
||||
include /home/config/uwsgi/uwsgi_params;
|
||||
}
|
||||
|
||||
location /api {
|
||||
uwsgi_pass django;
|
||||
include /home/config/uwsgi/uwsgi_params;
|
||||
}
|
||||
|
||||
location / {
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
error_page 500 502 503 504 /50x.html;
|
||||
location = /50x.html {
|
||||
root /usr/share/nginx/html;
|
||||
}
|
||||
}
|
@ -1,43 +0,0 @@
|
||||
worker_processes 4;
|
||||
pid /run/nginx.pid;
|
||||
|
||||
events {
|
||||
worker_connections 768;
|
||||
# multi_accept on;
|
||||
}
|
||||
|
||||
http {
|
||||
# Basic Settings
|
||||
tcp_nopush on;
|
||||
tcp_nodelay on;
|
||||
#keepalive_timeout 65;
|
||||
types_hash_max_size 2048;
|
||||
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /var/log/nginx/access.log ;
|
||||
|
||||
sendfile on;
|
||||
#tcp_nopush on;
|
||||
client_max_body_size 20M;
|
||||
|
||||
keepalive_timeout 0;
|
||||
|
||||
uwsgi_read_timeout 86400;
|
||||
uwsgi_send_timeout 86400;
|
||||
|
||||
# Gzip Settings
|
||||
|
||||
gzip on;
|
||||
gzip_disable "msie6";
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default upgrade;
|
||||
'' close;
|
||||
}
|
||||
|
||||
# Virtual Host Configs
|
||||
include /etc/nginx/conf.d/*.conf;
|
||||
#include /etc/nginx/sites-enabled/*;
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
uwsgi_param QUERY_STRING $query_string;
|
||||
uwsgi_param REQUEST_METHOD $request_method;
|
||||
uwsgi_param CONTENT_TYPE $content_type;
|
||||
uwsgi_param CONTENT_LENGTH $content_length;
|
||||
|
||||
uwsgi_param REQUEST_URI $request_uri;
|
||||
uwsgi_param PATH_INFO $document_uri;
|
||||
uwsgi_param DOCUMENT_ROOT $document_root;
|
||||
uwsgi_param SERVER_PROTOCOL $server_protocol;
|
||||
uwsgi_param HTTPS $https if_not_empty;
|
||||
|
||||
uwsgi_param REMOTE_ADDR $remote_addr;
|
||||
uwsgi_param REMOTE_PORT $remote_port;
|
||||
uwsgi_param SERVER_PORT $server_port;
|
||||
uwsgi_param SERVER_NAME $server_name;
|
@ -0,0 +1,155 @@
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import YAML from "yaml";
|
||||
import { debounce } from "lodash";
|
||||
import { manifestTypes } from "../../constants";
|
||||
import { generatePayload } from "../../utils/generators";
|
||||
import { checkHttpStatus } from "../../services/helpers";
|
||||
import { generateHttp } from "../../services/generate";
|
||||
import { toaster } from "../../utils";
|
||||
import eventBus from "../../events/eventBus";
|
||||
import ManifestSelect from "./ManifestSelect";
|
||||
import CodeEditor from "../CodeEditor";
|
||||
import useWindowDimensions from "../../hooks/useWindowDimensions";
|
||||
|
||||
const CodeBox = () => {
|
||||
const versionRef = useRef<string>();
|
||||
const manifestRef = useRef<string>();
|
||||
const [language, setLanguage] = useState("yaml");
|
||||
const [version, setVersion] = useState("3");
|
||||
const [copyText, setCopyText] = useState("Copy");
|
||||
const [generatedCode, setGeneratedCode] = useState<string>("");
|
||||
const [formattedCode, setFormattedCode] = useState<string>("");
|
||||
const [manifest, setManifest] = useState(manifestTypes.DOCKER_COMPOSE);
|
||||
const { height } = useWindowDimensions();
|
||||
|
||||
versionRef.current = version;
|
||||
manifestRef.current = manifest;
|
||||
|
||||
const getCode = (payload: any, manifest: string) => {
|
||||
generateHttp(JSON.stringify(payload), manifest)
|
||||
.then(checkHttpStatus)
|
||||
.then((data) => {
|
||||
if (data["code"]) {
|
||||
setGeneratedCode(data["code"]);
|
||||
} else {
|
||||
setGeneratedCode("");
|
||||
}
|
||||
|
||||
if (data["error"]) {
|
||||
setGeneratedCode("");
|
||||
toaster(`error ${data["error"]}`, "error");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
const debouncedOnGraphUpdate = useMemo(
|
||||
() =>
|
||||
debounce((payload, manifest) => {
|
||||
getCode(payload, manifest);
|
||||
}, 600),
|
||||
[]
|
||||
);
|
||||
|
||||
const versionChange = (e: any) => {
|
||||
setVersion(e.target.value);
|
||||
};
|
||||
|
||||
const copy = () => {
|
||||
navigator.clipboard.writeText(formattedCode);
|
||||
setCopyText("Copied");
|
||||
|
||||
setTimeout(() => {
|
||||
setCopyText("Copy");
|
||||
}, 300);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (language === "json") {
|
||||
setFormattedCode(
|
||||
JSON.stringify(YAML.parseAllDocuments(generatedCode), null, 2)
|
||||
);
|
||||
}
|
||||
|
||||
if (language === "yaml") {
|
||||
setFormattedCode(generatedCode);
|
||||
}
|
||||
}, [language, generatedCode]);
|
||||
|
||||
useEffect(() => {
|
||||
eventBus.dispatch("GENERATE", {
|
||||
message: {
|
||||
id: ""
|
||||
}
|
||||
});
|
||||
}, [version, manifest]);
|
||||
|
||||
useEffect(() => {
|
||||
eventBus.on("FETCH_CODE", (data) => {
|
||||
const graphData = data.detail.message;
|
||||
graphData.version = versionRef.current;
|
||||
debouncedOnGraphUpdate(generatePayload(graphData), manifestRef.current);
|
||||
});
|
||||
|
||||
return () => {
|
||||
eventBus.remove("FETCH_CODE", () => undefined);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div
|
||||
className={`absolute top-0 left-0 right-0 z-10 flex justify-end p-1 space-x-2 group-hover:visible invisible`}
|
||||
>
|
||||
<select
|
||||
id="version"
|
||||
onChange={versionChange}
|
||||
value={version}
|
||||
className="input-util w-min pr-8"
|
||||
>
|
||||
<option value="1">v 1</option>
|
||||
<option value="2">v 2</option>
|
||||
<option value="3">v 3</option>
|
||||
</select>
|
||||
|
||||
<button
|
||||
className={`btn-util ${
|
||||
language === "json" ? `btn-util-selected` : ``
|
||||
}`}
|
||||
onClick={() => setLanguage("json")}
|
||||
>
|
||||
json
|
||||
</button>
|
||||
<button
|
||||
className={`btn-util ${
|
||||
language === "yaml" ? `btn-util-selected` : ``
|
||||
}`}
|
||||
onClick={() => setLanguage("yaml")}
|
||||
>
|
||||
yaml
|
||||
</button>
|
||||
<button className="btn-util" type="button" onClick={copy}>
|
||||
{copyText}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className={`absolute top-10 left-0 right-0 z-10 flex justify-end p-1 space-x-2 group-hover:visible invisible`}
|
||||
>
|
||||
<ManifestSelect setManifest={setManifest} />
|
||||
</div>
|
||||
|
||||
<CodeEditor
|
||||
data={formattedCode}
|
||||
language={language}
|
||||
onChange={() => {
|
||||
return;
|
||||
}}
|
||||
disabled={true}
|
||||
lineWrapping={false}
|
||||
height={height - 64}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default CodeBox;
|
@ -0,0 +1,113 @@
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { CallbackFunction, IProject } from "../../types";
|
||||
import Spinner from "../global/Spinner";
|
||||
import VisibilitySwitch from "../global/VisibilitySwitch";
|
||||
|
||||
interface IHeaderProps {
|
||||
onSave: CallbackFunction;
|
||||
isLoading: boolean;
|
||||
projectData: IProject;
|
||||
isAuthenticated: boolean;
|
||||
}
|
||||
|
||||
const Header = (props: IHeaderProps) => {
|
||||
const { onSave, isLoading, projectData, isAuthenticated } = props;
|
||||
const [visibility, setVisibility] = useState(false);
|
||||
const [projectName, setProjectName] = useState("Untitled");
|
||||
|
||||
const visibilityRef = useRef(false);
|
||||
const projectNameRef = useRef("Untitled");
|
||||
|
||||
const handleNameChange = useCallback((e: any) => {
|
||||
setProjectName(e.target.value);
|
||||
projectNameRef.current = e.target.value;
|
||||
}, []);
|
||||
|
||||
const handleSave = useCallback(() => {
|
||||
const data: any = {
|
||||
name: projectNameRef.current,
|
||||
visibility: +visibilityRef.current
|
||||
};
|
||||
|
||||
onSave(data);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (!projectData) {
|
||||
return;
|
||||
}
|
||||
|
||||
setProjectName(projectData.name);
|
||||
setVisibility(Boolean(projectData.visibility));
|
||||
|
||||
visibilityRef.current = Boolean(projectData.visibility);
|
||||
projectNameRef.current = projectData.name;
|
||||
}, [projectData]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="px-4 py-3 border-b border-gray-200">
|
||||
<form
|
||||
className="flex flex-col space-y-2 md:space-y-0 md:flex-row md:justify-between items-center"
|
||||
autoComplete="off"
|
||||
>
|
||||
<input
|
||||
className={`
|
||||
bg-gray-100
|
||||
appearance-none
|
||||
w-full
|
||||
md:w-1/2
|
||||
lg:w-1/3
|
||||
block
|
||||
text-gray-700
|
||||
border
|
||||
border-gray-100
|
||||
dark:bg-gray-900
|
||||
dark:text-white
|
||||
dark:border-gray-900
|
||||
rounded
|
||||
py-2
|
||||
px-3
|
||||
leading-tight
|
||||
focus:outline-none
|
||||
focus:border-indigo-400
|
||||
focus:ring-0
|
||||
`}
|
||||
type="text"
|
||||
placeholder="Project name"
|
||||
autoComplete="off"
|
||||
id="name"
|
||||
name="name"
|
||||
onChange={handleNameChange}
|
||||
value={projectName}
|
||||
/>
|
||||
|
||||
<div className="flex flex-col space-y-2 w-full justify-end mb-4 md:flex-row md:space-y-0 md:space-x-2 md:mb-0">
|
||||
{isAuthenticated && (
|
||||
<VisibilitySwitch
|
||||
isVisible={visibility}
|
||||
onToggle={() => {
|
||||
setVisibility(!visibility);
|
||||
visibilityRef.current = !visibility;
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
|
||||
<button
|
||||
onClick={() => handleSave()}
|
||||
type="button"
|
||||
className="btn-util text-white bg-green-600 hover:bg-green-700 sm:w-auto"
|
||||
>
|
||||
<div className="flex justify-center items-center space-x-2 mx-auto">
|
||||
{isLoading && <Spinner className="w-4 h-4 text-green-300" />}
|
||||
<span>Save</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
@ -0,0 +1,61 @@
|
||||
import { styled } from "@mui/material";
|
||||
import { useCallback, useState } from "react";
|
||||
import { manifestTypes } from "../../constants";
|
||||
import DcLogo from "../global/dc-logo";
|
||||
import K8sLogo from "../global/k8s-logo";
|
||||
|
||||
interface IButtonProps {
|
||||
selected: boolean;
|
||||
}
|
||||
|
||||
const Button = styled("button", {
|
||||
shouldForwardProp: (name) => name !== "selected"
|
||||
})<IButtonProps>`
|
||||
filter: grayscale(${({ selected }) => (selected ? "0%" : "100%")});
|
||||
opacity: ${({ selected }) => (selected ? "100%" : "80%")};
|
||||
|
||||
&:hover {
|
||||
filter: grayscale(0%);
|
||||
}
|
||||
`;
|
||||
|
||||
interface IManifestSelectProps {
|
||||
setManifest: any;
|
||||
}
|
||||
|
||||
const ManifestSelect = (props: IManifestSelectProps) => {
|
||||
const { setManifest } = props;
|
||||
const [selected, setSelected] = useState(manifestTypes.DOCKER_COMPOSE);
|
||||
|
||||
const handleK8s = useCallback(() => {
|
||||
setManifest(manifestTypes.KUBERNETES);
|
||||
setSelected(manifestTypes.KUBERNETES);
|
||||
}, []);
|
||||
|
||||
const handleDC = useCallback(() => {
|
||||
setManifest(manifestTypes.DOCKER_COMPOSE);
|
||||
setSelected(manifestTypes.DOCKER_COMPOSE);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button
|
||||
selected={selected === manifestTypes.KUBERNETES}
|
||||
type="button"
|
||||
onClick={handleK8s}
|
||||
>
|
||||
<K8sLogo />
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
selected={selected === manifestTypes.DOCKER_COMPOSE}
|
||||
type="button"
|
||||
onClick={handleDC}
|
||||
>
|
||||
<DcLogo />
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManifestSelect;
|
@ -0,0 +1,29 @@
|
||||
const DcLogo = () => {
|
||||
return (
|
||||
<svg
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 1024 1024"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<g clipPath="url(#clip0_213_31)">
|
||||
<path
|
||||
d="M512 1024C794.77 1024 1024 794.77 1024 512C1024 229.23 794.77 0 512 0C229.23 0 0 229.23 0 512C0 794.77 229.23 1024 512 1024Z"
|
||||
fill="#0091E2"
|
||||
/>
|
||||
<path
|
||||
d="M827.3 461.5C825.7 460.2 811.2 449.3 780.6 449.3C772.5 449.3 764.4 449.9 756.4 451.4C750.5 410.7 716.9 390.9 715.4 390L707.2 385.2L701.8 393C695 403.5 690.1 415 687.2 427.2C681.7 450.4 685 472.2 696.8 490.8C682.6 498.7 659.7 500.7 655.1 500.8H277C267.1 500.8 259.1 508.8 259.1 518.7C258.7 551.8 264.3 584.7 275.6 615.8C288.6 650 308 675.1 333.2 690.5C361.4 707.8 407.3 717.7 459.4 717.7C482.9 717.8 506.4 715.6 529.5 711.3C561.6 705.4 592.5 694.2 620.9 678.1C644.3 664.5 665.4 647.3 683.3 627C713.2 593.1 731.1 555.3 744.4 521.8H749.7C782.5 521.8 802.7 508.7 813.8 497.7C821.2 490.7 827 482.2 830.7 472.7L833 465.8L827.3 461.5V461.5ZM312 489.9H362.7C365.1 489.9 367.1 487.9 367.1 485.5V440.4C367.1 438 365.1 436 362.7 435.9H312C309.6 435.9 307.6 437.9 307.6 440.3V485.5C307.6 488 309.6 489.9 312 489.9M381.9 489.9H432.6C435 489.9 437 487.9 437 485.5V440.4C437 438 435 436 432.6 435.9H381.9C379.4 435.9 377.4 437.9 377.4 440.4V485.5C377.4 488 379.4 489.9 381.9 489.9ZM452.7 490H503.4C505.8 490 507.8 488 507.8 485.6V440.5C507.8 438.1 505.8 436.1 503.4 436H452.7C450.3 436 448.3 438 448.3 440.4V485.6C448.3 488 450.3 489.9 452.7 490M522.8 490H573.5C575.9 490 577.9 488 578 485.6V440.5C578 438 576 436 573.5 436H522.8C520.4 436 518.4 438 518.4 440.4V485.6C518.4 488 520.3 490 522.8 490M381.8 425H432.5C434.9 425 436.9 423 436.9 420.5V375.4C436.9 373 434.9 371 432.5 371H381.8C379.3 371 377.4 373 377.3 375.4V420.5C377.4 423 379.4 425 381.8 425ZM452.7 425H503.4C505.8 425 507.8 423 507.8 420.5V375.4C507.8 373 505.8 371 503.4 371H452.7C450.3 371 448.3 373 448.3 375.4V420.5C448.3 423 450.3 425 452.7 425ZM522.8 425H573.5C576 425 577.9 423 578 420.5V375.4C578 372.9 576 371 573.5 371H522.8C520.4 371 518.4 373 518.4 375.4V420.5C518.4 423 520.3 425 522.8 425ZM522.8 360.1H573.5C576 360.1 578 358.1 578 355.6V310.4C578 308 576 306 573.5 306H522.8C520.4 306 518.4 308 518.4 310.4V355.6C518.4 358.1 520.3 360.1 522.8 360.1ZM593.4 490H644.1C646.5 490 648.5 488 648.5 485.6V440.5C648.5 438 646.5 436.1 644.1 436H593.4C591 436 589 438 589 440.4V485.6C589 488 591 490 593.4 490"
|
||||
fill="white"
|
||||
/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_213_31">
|
||||
<rect width="1024" height="1024" fill="white" />
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
);
|
||||
};
|
||||
|
||||
export default DcLogo;
|
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue