Added new features

This commit is contained in:
Laux Dev
2026-02-26 16:27:44 +08:00
parent bd94bb4618
commit ccd0caf14d
8 changed files with 901 additions and 236 deletions

View File

@@ -13,7 +13,7 @@ const TopHeader = (props) => {
return (
<div className={styles.container}>
<div className={styles.title}>
{pathName.includes("/view") && (
{pathName.includes("/view") && props.state === "view" && (
<div onClick={() => router.back()}>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -114,7 +114,39 @@ const TopHeader = (props) => {
) : (
""
)}
{(pathName === "/projects/view" || !props.state) && (
{pathName === "/projects/view" && (
<div
className={styles.button}
onClick={() => props.trigger(!props.triggerState)}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="20"
height="20"
viewBox="0 0 20 20"
fill="none"
>
<path
d="M10 4.41016V15.5907"
stroke="currentColor"
strokeOpacity={1}
strokeWidth={1.5}
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M4.41016 10H15.5907"
stroke="currentColor"
strokeOpacity={1}
strokeWidth={1.5}
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<p>{props.buttonText}</p>
</div>
)}
{!props.state && (
<div className={styles.button} onClick={handleNavigateToAdd}>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -171,7 +203,7 @@ const TopHeader = (props) => {
""
)}
{/* Projects 3 dots menu */}
{pathName.includes("/projects/view") && (
{pathName === "/projects/view" && (
<div
className={styles.menu}
onClick={() => setTriggerDropDownMenu(!triggerDropDownMenu)}

View File

@@ -21,6 +21,18 @@
border: 0.5px solid #8187ff;
cursor: pointer;
}
.title > div:hover {
border-radius: 100px;
border: 0.5px solid #959aff;
background: linear-gradient(
180deg,
rgba(149, 154, 255, 0.25) 0%,
rgba(88, 91, 151, 0.25) 100%
);
}
.title > div:hover path {
stroke: white;
}
.title > p {
color: #d2d3e1;
font-size: 24px;

View File

@@ -10,7 +10,7 @@ const inter = Inter({
});
export const metadata = {
title: "Create Next App",
title: "Internal Developer Platform",
description: "Generated by create next app",
};

View File

@@ -0,0 +1,150 @@
"use client";
import React from "react";
import styles from "./styles.module.css";
import { useRouter, usePathname } from "next/navigation";
const AddServicesModal = (props) => {
const router = useRouter();
const pathName = usePathname();
const servicesList = [
{
title: "Start from Scratch",
linkTo: "add-from-scratch",
detail:
"Create a new service manually by configuring all the settings yourself",
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
>
<path
d="M9.61111 10.8885L4.5 15.9996L9.61111 21.1107M22.3889 10.8885L27.5 15.9996L22.3889 21.1107M18.5556 5.77734L13.4444 26.2218"
stroke="white"
strokeOpacity="1"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
isReleased: true,
},
{
title: "Choose Gitea Repository",
detail: "Choose a repository from your linked Gitea Account",
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
>
<path
d="M4.5 18.5556C5.56056 19.3759 7.15394 19.8551 8.97222 19.8333C10.7905 19.8551 12.3839 19.3759 13.4444 18.5556C14.505 17.7352 16.0984 17.2561 17.9167 17.2778C19.7349 17.2561 21.3283 17.7352 22.3889 18.5556M10.8889 4.5C10.4845 4.79027 10.1568 5.17463 9.9342 5.61988C9.71157 6.06512 9.60069 6.55787 9.61111 7.05556C9.60069 7.55324 9.71157 8.04599 9.9342 8.49124C10.1568 8.93648 10.4845 9.32084 10.8889 9.61111M16 4.5C15.5956 4.79027 15.2679 5.17463 15.0453 5.61988C14.8227 6.06512 14.7118 6.55787 14.7222 7.05556C14.7118 7.55324 14.8227 8.04599 15.0453 8.49124C15.2679 8.93648 15.5956 9.32084 16 9.61111M22.0643 22.0388C22.635 22.3007 23.2613 22.4185 23.8881 22.3818C24.5149 22.345 25.1231 22.1548 25.6592 21.8279C26.1953 21.501 26.6429 21.0474 26.9627 20.507C27.2825 19.9666 27.4646 19.356 27.493 18.7287C27.5215 18.1015 27.3954 17.4768 27.1259 16.9097C26.8564 16.3425 26.4517 15.8503 25.9474 15.4762C25.4431 15.1021 24.8546 14.8577 24.2336 14.7643C23.6127 14.6709 22.9784 14.7315 22.3863 14.9407M4.5 13.4444H22.3889V19.8333C22.3889 21.8667 21.5812 23.8167 20.1434 25.2545C18.7056 26.6923 16.7555 27.5 14.7222 27.5H12.1667C10.1333 27.5 8.18329 26.6923 6.74551 25.2545C5.30774 23.8167 4.5 21.8667 4.5 19.8333V13.4444Z"
stroke="white"
strokeOpacity="1"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
isReleased: true,
},
{
title: "Link GitHub Repository",
detail: "Import and deploy a service from your GitHub repository",
icon: (
<svg
xmlns="http://www.w3.org/2000/svg"
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
>
<path
d="M12.1667 24.9448C6.67222 26.7337 6.67222 21.7503 4.5 21.1115M19.8333 27.5003V23.0281C19.8333 21.7503 19.9611 21.2392 19.1944 20.4726C22.7722 20.0892 26.2222 18.6837 26.2222 12.8059C26.2207 11.2789 25.6249 9.81246 24.5611 8.71701C25.06 7.39063 25.0141 5.92076 24.4333 4.62812C24.4333 4.62812 23.0278 4.24479 19.9611 6.28923C17.3637 5.61276 14.6363 5.61276 12.0389 6.28923C8.97222 4.24479 7.56667 4.62812 7.56667 4.62812C6.98589 5.92076 6.93996 7.39063 7.43889 8.71701C6.37508 9.81246 5.77933 11.2789 5.77778 12.8059C5.77778 18.6837 9.22778 20.0892 12.8056 20.4726C12.0389 21.2392 12.0389 22.0059 12.1667 23.0281V27.5003"
stroke="white"
strokeOpacity="1"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
),
isReleased: false,
},
];
return (
<div className={styles.container}>
<div className={styles.modal}>
<div className={styles.header}>
<div>
<p>Create New Services</p>
<div>
<p>Choose how you want to create your service</p>
</div>
</div>
<svg
onClick={() => props.trigger(!props.triggerState)}
xmlns="http://www.w3.org/2000/svg"
width="28"
height="28"
viewBox="0 0 28 28"
fill="none"
>
<path
d="M20.7077 7.29199L7.29102 20.7087"
stroke="white"
strokeOpacity="1"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
<path
d="M7.29102 7.29199L20.7077 20.7087"
stroke="white"
strokeOpacity="1"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
</div>
<div className={styles.content}>
{servicesList.map((service, key) => {
return (
<div
className={`${styles.list} ${service.isReleased ? styles.isReleased : styles.isComingSoon}`}
key={key}
onClick={() => router.push(`${pathName}/${service.linkTo}`)}
>
<div>
<div className={styles.iconContainer}>{service.icon}</div>
<div className={styles.listDetails}>
<div>
<p>{service.title}</p>
{!service.isReleased && (
<div>
<p>Coming soon</p>
</div>
)}
</div>
<p>{service.detail}</p>
</div>
</div>
</div>
);
})}
</div>
</div>
</div>
);
};
export default AddServicesModal;

View File

@@ -0,0 +1,159 @@
.container {
width: 100vw;
height: 100vh;
position: absolute;
top: 0;
left: 0;
z-index: 10;
display: flex;
align-items: center;
justify-content: center;
background-color: #00000037;
}
.modal {
display: inline-flex;
padding: 24px 24px 32px 24px;
flex-direction: column;
align-items: flex-start;
gap: 48px;
border-radius: 8px;
background: #21232f;
animation-name: dropDownAnimation;
animation-duration: 200ms;
}
@keyframes dropDownAnimation {
0% {
opacity: 0;
transform: translateY(-10%);
}
100% {
opacity: 1;
transform: translateY(0);
}
}
.header {
display: flex;
justify-content: space-between;
align-items: flex-start;
align-self: stretch;
}
.header > svg {
cursor: pointer;
}
.header > div {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
flex: 1 0 0;
}
.header > div > p {
color: #d2d3e1;
font-size: 24px;
font-style: normal;
font-weight: 500;
line-height: normal;
letter-spacing: 0.24px;
}
.header > div > div {
display: flex;
align-items: center;
gap: 4px;
align-self: stretch;
color: #85869b;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.14px;
}
.content {
display: flex;
width: 545px;
flex-direction: column;
align-items: flex-start;
gap: 16px;
}
.list {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 10px;
align-self: stretch;
cursor: pointer;
transition: all 150ms;
}
.isComingSoon {
opacity: 0.5;
}
.isReleased:hover {
border-radius: 8px;
background: #2e3242;
}
.isReleased:hover .iconContainer {
border-radius: 6px;
border: 1px solid #959aff;
background: linear-gradient(180deg, #959aff 0%, #585b97 100%);
}
.list > div {
display: flex;
padding: 10px;
align-items: center;
gap: 24px;
align-self: stretch;
}
.iconContainer {
display: flex;
align-items: center;
justify-content: center;
border-radius: 6px;
padding: 10px;
border: 0.5px solid #959aff;
}
.listDetails {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 8px;
}
.listDetails > p {
color: #85869b;
font-size: 13px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.14px;
}
.listDetails > div {
display: flex;
align-items: center;
gap: 10px;
}
.listDetails > div > p {
color: #d2d3e1;
font-size: 18px;
font-style: normal;
font-weight: 500;
line-height: normal;
letter-spacing: 0.18px;
}
.listDetails > div > div {
display: flex;
padding: 4px 8px;
justify-content: center;
align-items: center;
gap: 10px;
border-radius: 4px;
background: #3c4a87;
}
.listDetails > div > div > p {
color: #d2d3e1;
font-size: 14px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.14px;
}

View File

@@ -0,0 +1,98 @@
import React from "react";
import globalStyle from "@/app/globalStyle.module.css";
import TopHeader from "@/app/components/topHeader/TopHeader";
import styles from "./styles.module.css";
const AddServices = () => {
return (
<div className={globalStyle.section}>
<div className={globalStyle.mainContainer}>
<div className={globalStyle.container}>
<TopHeader
buttonText="Save"
cancelButtonText="Cancel"
state="add"
topbarTitle="Create New Services"
/>
<div className={styles.contentContainer}>
<div className={styles.fieldsContainerCreateNew}>
<div className={styles.projectDetails}>
<div className={styles.projectDetailsHeader}>
<p>Project Details</p>
</div>
<div className={styles.fieldsCreateNew}>
<div>
<div>
<p>
Repository <span>(Optional)</span>
</p>
<label className={styles.repositoryForm} htmlFor="#repo">
+ Link Repository
</label>
</div>
</div>
<div>
<div>
<p>Name</p>
<input type="text" placeholder="Enter service name" />
</div>
<div>
<p>Version</p>
<input type="text" placeholder="Service version" />
</div>
</div>
<div>
<div>
<p>
Image <span>(Optional)</span>
</p>
<input type="text" placeholder="Enter image name" />
</div>
</div>
<div>
<div>
<p>Port</p>
<input type="text" placeholder="Enter port" />
</div>
</div>
<div>
<div>
<p>Ingress</p>
<select name="" id="">
<option value="">Select</option>
</select>
</div>
<div>
<p>Ingress</p>
<select name="" id="">
<option value="">Select</option>
</select>
</div>
</div>
</div>
</div>
<div className={styles.resource}></div>
<div className={styles.additionalDetails}>
<div>
<div>
<div className={styles.header}>
<p>Auto Scaling</p>
<div></div>
</div>
<div>
<div></div>
</div>
</div>
</div>
<div></div>
<div></div>
</div>
</div>
<div className={styles.variables}></div>
</div>
</div>
</div>
</div>
);
};
export default AddServices;

View File

@@ -0,0 +1,121 @@
.contentContainer {
display: flex;
align-items: flex-start;
flex: 1 0 0;
align-self: stretch;
}
.fieldsContainerCreateNew {
display: flex;
padding-top: 36px;
flex-direction: column;
align-items: flex-start;
gap: 36px;
background: #191a24;
height: calc(100vh - 175px);
overflow-y: scroll;
scrollbar-width: none;
}
.projectDetails {
display: flex;
padding: 0 36px;
flex-direction: column;
align-items: flex-start;
gap: 10px;
align-self: stretch;
}
.projectDetailsHeader {
display: flex;
padding-bottom: 24px;
align-items: flex-start;
gap: 17px;
align-self: stretch;
}
.projectDetailsHeader p {
color: #d2d3e1;
font-size: 20px;
font-style: normal;
font-weight: 500;
line-height: normal;
letter-spacing: 0.2px;
}
.fieldsCreateNew {
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 16px;
align-self: stretch;
}
.fieldsCreateNew > div {
display: flex;
justify-content: center;
align-items: center;
gap: 16px;
align-self: stretch;
}
.fieldsCreateNew > div:nth-child(1) {
display: flex;
padding: 16px 0;
justify-content: center;
align-items: center;
gap: 4px;
align-self: stretch;
}
.fieldsCreateNew > div > div {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 12px;
flex: 1 0 0;
}
.fieldsCreateNew > div > div p {
color: #d2d3e1;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.16px;
}
.fieldsCreateNew > div > div p > span {
color: #85869b;
}
.fieldsCreateNew > div > div input,
.fieldsCreateNew > div > div select {
display: flex;
padding: 12px;
flex-direction: column;
align-items: flex-start;
gap: 10px;
align-self: stretch;
border-radius: 4px;
border: 1px solid #4b4f6d;
background-color: transparent;
color: white;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.16px;
}
.fieldsCreateNew > div > div input::placeholder {
color: #85869b;
}
.repositoryForm {
display: flex;
padding: 12px;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 10px;
align-self: stretch;
border-radius: 4px;
border: 1px dashed #5980f1;
color: #5980f1;
text-align: center;
font-size: 16px;
font-style: normal;
font-weight: 400;
line-height: normal;
letter-spacing: 0.16px;
}

View File

@@ -1,8 +1,11 @@
import React from "react";
"use client";
import React, { useState } from "react";
import globalStyle from "../../globalStyle.module.css";
import TopHeader from "@/app/components/topHeader/TopHeader";
import styles from "./styles.module.css";
import AddServicesModal from "./AddServicesModal/AddServicesModal";
const AddProject = () => {
const [triggerAddServicesModal, setTriggerAddServicesModal] = useState(false);
const sampleData = [
{
name: "accounting-service",
@@ -52,8 +55,95 @@ const AddProject = () => {
ingress: "",
ports: "3000:3000, 50054:50054",
},
{
name: "accounting-service",
version: "v1",
health: {
overall: "Healthy",
liveness: "Unreachable",
readiness: "Ready",
},
status: {
deployment: "Healthy",
replicas: "1/1",
},
image: "xuru.isaachybrid.com/698d24e36c2855a6f0d8cf9b/accounting-service",
ingress: "",
ports: "3000:3000, 50054:50054",
},
{
name: "accounting-service",
version: "v1",
health: {
overall: "Healthy",
liveness: "Unreachable",
readiness: "Ready",
},
status: {
deployment: "Healthy",
replicas: "1/1",
},
image: "xuru.isaachybrid.com/698d24e36c2855a6f0d8cf9b/accounting-service",
ingress: "",
ports: "3000:3000, 50054:50054",
},
{
name: "accounting-service",
version: "v1",
health: {
overall: "Healthy",
liveness: "Unreachable",
readiness: "Ready",
},
status: {
deployment: "Healthy",
replicas: "1/1",
},
image: "xuru.isaachybrid.com/698d24e36c2855a6f0d8cf9b/accounting-service",
ingress: "",
ports: "3000:3000, 50054:50054",
},
{
name: "accounting-service",
version: "v1",
health: {
overall: "Healthy",
liveness: "Unreachable",
readiness: "Ready",
},
status: {
deployment: "Healthy",
replicas: "1/1",
},
image: "xuru.isaachybrid.com/698d24e36c2855a6f0d8cf9b/accounting-service",
ingress: "",
ports: "3000:3000, 50054:50054",
},
{
name: "accounting-service",
version: "v1",
health: {
overall: "Healthy",
liveness: "Unreachable",
readiness: "Ready",
},
status: {
deployment: "Healthy",
replicas: "1/1",
},
image: "xuru.isaachybrid.com/698d24e36c2855a6f0d8cf9b/accounting-service",
ingress: "",
ports: "3000:3000, 50054:50054",
},
];
return (
<>
{triggerAddServicesModal && (
<AddServicesModal
trigger={setTriggerAddServicesModal}
triggerState={triggerAddServicesModal}
/>
)}
<div className={globalStyle.section}>
<div className={globalStyle.mainContainer}>
<div className={globalStyle.container}>
@@ -62,6 +152,8 @@ const AddProject = () => {
cancelButtonText="Cancel"
state="view"
topbarTitle="Services"
trigger={setTriggerAddServicesModal}
triggerState={triggerAddServicesModal}
/>
<div className={styles.tableContainer}>
<table className={styles.table}>
@@ -303,6 +395,7 @@ const AddProject = () => {
</div>
</div>
</div>
</>
);
};