diff --git a/frontend/src/app/components/topHeader/TopHeader.jsx b/frontend/src/app/components/topHeader/TopHeader.jsx index 24b63ae..d1235bd 100644 --- a/frontend/src/app/components/topHeader/TopHeader.jsx +++ b/frontend/src/app/components/topHeader/TopHeader.jsx @@ -13,7 +13,7 @@ const TopHeader = (props) => { return (
- {pathName.includes("/view") && ( + {pathName.includes("/view") && props.state === "view" && (
router.back()}> { ) : ( "" )} - {(pathName === "/projects/view" || !props.state) && ( + {pathName === "/projects/view" && ( +
props.trigger(!props.triggerState)} + > + + + + +

{props.buttonText}

+
+ )} + {!props.state && (
{ "" )} {/* Projects 3 dots menu */} - {pathName.includes("/projects/view") && ( + {pathName === "/projects/view" && (
setTriggerDropDownMenu(!triggerDropDownMenu)} diff --git a/frontend/src/app/components/topHeader/styles.module.css b/frontend/src/app/components/topHeader/styles.module.css index 73c9e42..2e358cb 100644 --- a/frontend/src/app/components/topHeader/styles.module.css +++ b/frontend/src/app/components/topHeader/styles.module.css @@ -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; diff --git a/frontend/src/app/layout.js b/frontend/src/app/layout.js index 93f1bd0..55e5e89 100644 --- a/frontend/src/app/layout.js +++ b/frontend/src/app/layout.js @@ -10,7 +10,7 @@ const inter = Inter({ }); export const metadata = { - title: "Create Next App", + title: "Internal Developer Platform", description: "Generated by create next app", }; diff --git a/frontend/src/app/projects/view/AddServicesModal/AddServicesModal.jsx b/frontend/src/app/projects/view/AddServicesModal/AddServicesModal.jsx new file mode 100644 index 0000000..3ed0def --- /dev/null +++ b/frontend/src/app/projects/view/AddServicesModal/AddServicesModal.jsx @@ -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: ( + + + + ), + isReleased: true, + }, + { + title: "Choose Gitea Repository", + detail: "Choose a repository from your linked Gitea Account", + icon: ( + + + + ), + isReleased: true, + }, + { + title: "Link GitHub Repository", + detail: "Import and deploy a service from your GitHub repository", + icon: ( + + + + ), + isReleased: false, + }, + ]; + + return ( +
+
+
+
+

Create New Services

+
+

Choose how you want to create your service

+
+
+ props.trigger(!props.triggerState)} + xmlns="http://www.w3.org/2000/svg" + width="28" + height="28" + viewBox="0 0 28 28" + fill="none" + > + + + +
+
+ {servicesList.map((service, key) => { + return ( +
router.push(`${pathName}/${service.linkTo}`)} + > +
+
{service.icon}
+
+
+

{service.title}

+ {!service.isReleased && ( +
+

Coming soon

+
+ )} +
+

{service.detail}

+
+
+
+ ); + })} +
+
+
+ ); +}; + +export default AddServicesModal; diff --git a/frontend/src/app/projects/view/AddServicesModal/styles.module.css b/frontend/src/app/projects/view/AddServicesModal/styles.module.css new file mode 100644 index 0000000..377c64c --- /dev/null +++ b/frontend/src/app/projects/view/AddServicesModal/styles.module.css @@ -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; +} diff --git a/frontend/src/app/projects/view/add-from-scratch/page.jsx b/frontend/src/app/projects/view/add-from-scratch/page.jsx new file mode 100644 index 0000000..43b1626 --- /dev/null +++ b/frontend/src/app/projects/view/add-from-scratch/page.jsx @@ -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 ( +
+
+
+ +
+
+
+
+

Project Details

+
+
+
+
+

+ Repository (Optional) +

+ +
+
+
+
+

Name

+ +
+
+

Version

+ +
+
+
+
+

+ Image (Optional) +

+ +
+
+
+
+

Port

+ +
+
+
+
+

Ingress

+ +
+
+

Ingress

+ +
+
+
+
+
+
+
+
+
+

Auto Scaling

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ); +}; + +export default AddServices; diff --git a/frontend/src/app/projects/view/add-from-scratch/styles.module.css b/frontend/src/app/projects/view/add-from-scratch/styles.module.css new file mode 100644 index 0000000..1cbad83 --- /dev/null +++ b/frontend/src/app/projects/view/add-from-scratch/styles.module.css @@ -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; +} diff --git a/frontend/src/app/projects/view/page.jsx b/frontend/src/app/projects/view/page.jsx index a182c49..df5182a 100644 --- a/frontend/src/app/projects/view/page.jsx +++ b/frontend/src/app/projects/view/page.jsx @@ -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,257 +55,347 @@ 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 ( -
-
-
- -
- - - - - - - - - - - - - - - {sampleData.map((services, index) => { - return ( - - - - + + ); + })} + +
NameVersionHealthStatusImageIngressPortActions
{services.name} - {services.version} - -
-
+ <> + {triggerAddServicesModal && ( + + )} +
+
+
+ +
+ + + + + + + + + + + + + + + {sampleData.map((services, index) => { + return ( + + + + - + - - - - + + + + - - ); - })} - -
NameVersionHealthStatusImageIngressPortActions
{services.name} + {services.version} + +
- - - -

Overall

+
+ + + +

Overall

+
+

{services.health.overall}

-

{services.health.overall}

-
-
- - - -

Liveness

+
+ + + +

Liveness

+
+

{services.health.liveness}

-

{services.health.liveness}

-
-
- - - -

Readiness

+
+ + + +

Readiness

+
+

{services.health.readiness}

-

{services.health.readiness}

- -
-
-
+
+
- - - -

Deployment

+
+ + + +

Deployment

+
+

{services.status.deployment}

-

{services.status.deployment}

-
-
- - - - - - - - -

Replicas

+
+ + + + + + + + +

Replicas

+
+

{services.status.replicas}

-

{services.status.replicas}

- -
{services.image}{services.ingress}{services.ports} -
-
- +
{services.image}{services.ingress}{services.ports} +
+
+ +
+
+ +
-
- -
- -
+
+
-
+ ); };