Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option to show the endpoints in group view #26

Merged
merged 17 commits into from
Nov 3, 2023
8 changes: 5 additions & 3 deletions src/app/dashboard/endpoints/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React from 'react';
import { OutletHeader } from '@/components/outlet/header/outlet-header'
import { OutletBody } from '@/components/outlet/outlet-body';
import { EndpointListCard } from '@/components/card/endpoints-list';
import { EndpointList } from '@/components/card/endpoints-list';
import {EndpointTableHeader} from '@/components/endpoints/endpoint-list-container'
import { EndpointHeaderActions } from '@/components/endpoints/endpoint-header-actions'
import { cookies } from 'next/headers'

Expand All @@ -15,7 +16,7 @@ async function getData() {
console.log({ theme })
// TODO: FIX it. I has to use some dynamic method to avoid automatic rendering of this page during build //

const url = process.env.APP_HOST + '/api/endpoints'
const url = process.env.APP_HOST + '/api/endpoints/?groupby=1' // '/api/endpoints/?groupby=1'
const res = await fetch(url)
// The return value is *not* serialized
// You can return Date, Map, Set, etc.
Expand All @@ -35,8 +36,9 @@ const Page = async () => {
<>
<OutletHeader title='Endpoints' subtitle="Api endpoints which are pointed to a record(JSON) or a target host for reverse proxy" actionChildren={<EndpointHeaderActions />} />
<OutletBody>
<EndpointTableHeader />
{data.data.map((ep: any) => (
<EndpointListCard data={ep} key={ep.id} />
<EndpointList data={ep} key={ep.name} />
))}
</OutletBody>
</>
Expand Down
6 changes: 3 additions & 3 deletions src/components/card/collections-list/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ const CollectionListCard: React.FC<Props> = (prop) => {
return (
<>
<div className={S.cardWrapper}>
<div>{name}</div>
<div>
<div>
<div className={S.cardMoxyDetails}>
<div className={S.cardLeftDetails} style={{width: "100%"}}>{name}</div>
<div className={S.cardRightOptions}>
<MoreOption defaultValues={{
id: id,
name: name,
Expand Down
124 changes: 75 additions & 49 deletions src/components/card/endpoints-list/index.tsx
Original file line number Diff line number Diff line change
@@ -1,68 +1,94 @@
import S from '../style.module.css';
import Image from 'next/image'
import { MoreOption } from './more-option';
import React from 'react';

interface Props {
interface Item {
id: string
endpoint: string,
moxyType: 'proxy' | 'mock',
mockDetails: {
collectionId: string
}
proxyDetails: {
protocal: "https" | 'https',
targetHost: string
}
}

type EndpointListCardProps = Item

interface GroupListProps {
data: {
id: string
endpoint: string,
moxyType: 'proxy' | 'mock',
mockDetails: {
collectionId: string
}
proxyDetails: {
protocal: "https" | 'https',
targetHost: string
}
name: string,
items: Array<Item>
}
}

const EndpointListCard: React.FC<Props> = (prop) => {
const { id, endpoint, mockDetails, moxyType, proxyDetails } = prop.data;
const EndpointList: React.FC<GroupListProps> = ({ data }) => {
const { name, items } = data;

console.log('prop.data', prop.data)
return (
<>
{items.length > 1 && <div>
<h1 className={S.groupNameText}>/{name}</h1>
</div>}
<div className={S.cardWrapper} >
{items.map(i => (
<EndpointListCard
key={i.id}
id={i.id}
endpoint={i.endpoint}
mockDetails={i.mockDetails}
moxyType={i.moxyType}
proxyDetails={i.proxyDetails} />
))
}
</div>
</>
)
}

const EndpointListCard: React.FC<EndpointListCardProps> = ({ id, endpoint, mockDetails, moxyType, proxyDetails }) => {

return (
<>
<div className={S.cardWrapper}>
<div className={S.cardMoxyDetails}>
<div className={S.cardLeftDetails} >
<div className={S.cardLabel}>Route</div>
<div title={endpoint} className={S.cardUrl}>{endpoint}</div>
</div>
<div className={S.cardCenterIcon}>
<Image src="/icons/arrow.svg" alt="" width="38" height="17" />
</div>
<div className={S.cardRightDetails}>
<div className={S.cardLabel}>Target</div>
<div className={S.cardTargetDetails}>
{moxyType === "mock" &&
<>
<Image className={S.cardTargetIcon} src="/icons/collection.svg" alt="" width="26" height="26" />
<div title={mockDetails?.collectionId} className={S.cardUrl}>{mockDetails?.collectionId}</div>
</>
}
{moxyType === "proxy" &&
<>
<Image className={S.cardTargetIcon} src="/icons/proxy.svg" alt="" width="26" height="26" />
<div title={proxyDetails.targetHost} className={S.cardUrl}>{proxyDetails.targetHost}</div>
</>
}
</div>
</div>
<div className={S.cardRightOptions}>
<MoreOption defaultValues={{
id: id,
endpoint: endpoint,
moxy: moxyType,
targetUrl: proxyDetails.targetHost,
collectionId: mockDetails?.collectionId
}} />
<div className={S.cardMoxyDetails}>
<div className={S.cardLeftDetails} >
<div title={endpoint} className={S.cardUrl}>{endpoint}</div>
</div>
<div className={S.cardCenterIcon}>
<Image src="/icons/arrow.svg" alt="" width="38" height="17" />
</div>
<div className={S.cardRightDetails}>
<div className={S.cardTargetDetails}>
{moxyType === "mock" &&
<>
<Image className={S.cardTargetIcon} src="/icons/collection.svg" alt="" width="26" height="26" />
<div title={mockDetails?.collectionId} className={S.cardUrl}>{mockDetails?.collectionId}</div>
</>
}
{moxyType === "proxy" &&
<>
<Image className={S.cardTargetIcon} src="/icons/proxy.svg" alt="" width="26" height="26" />
<div title={proxyDetails.targetHost} className={S.cardUrl}>{proxyDetails.targetHost}</div>
</>
}
</div>
</div>
<div className={S.cardRightOptions}>
<MoreOption defaultValues={{
id: id,
endpoint: endpoint,
moxy: moxyType,
targetUrl: proxyDetails.targetHost,
collectionId: mockDetails?.collectionId
}} />
</div>
</div>
</>
)
}

export { EndpointListCard }

export { EndpointList }
20 changes: 16 additions & 4 deletions src/components/card/style.module.css
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
.cardWrapper {
margin-bottom: 14px;
padding: 16px;
margin-bottom: 16px;
display: flex;
justify-content: space-between;
align-items: center;
border-radius: 4px;
border: 1px solid #B8BEDD;
flex-direction: column;
}

.cardMoxyDetails {
display: flex;
align-items: center;
width: 100%;
border-bottom: 1px solid #F0E6EFDD;
padding: 16px 14px
}

.cardMoxyDetails:last-child {
border-bottom: 0;
}

.cardLeftDetails {
Expand All @@ -20,12 +26,11 @@

.cardCenterIcon {
width: 4%;
align-self: flex-end;
}

.cardRightDetails {
width: 46%;
padding-left : 12px;
padding-left: 12px;
}

.cardRightOptions {
Expand Down Expand Up @@ -63,5 +68,12 @@
font-weight: 400;
line-height: normal;
white-space: nowrap;
}

.groupNameText {
color: #392F5A;
font-size: 14px;
font-style: normal;
font-weight: 600;
margin-bottom: 6px;
}
14 changes: 14 additions & 0 deletions src/components/endpoints/endpoint-list-container/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import React from "react";
import S from './styles.module.css';

const EndpointTableHeader = () =>{

return(
<div className={S.tableContainer}>
<div className={S.tableHeader}>Route</div>
<div className={S.tableHeader}>Target</div>
</div>)

}

export {EndpointTableHeader}
13 changes: 13 additions & 0 deletions src/components/endpoints/endpoint-list-container/styles.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.tableContainer {
display: flex;
align-items: center;
}

.tableHeader {
width: 50%;
margin-bottom: 16px;
color: #B8BEDD;
font-size: 14px;
font-weight: 600;
line-height: normal;
}
2 changes: 1 addition & 1 deletion src/helpers/db/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ class DB<Type extends Record<any, any>> {
const filePath = this.dbPath + collectionPath

// add record entry in db
collections.push({
collections.unshift({
id: value.id,
name: value.name,
path: collectionPath
Expand Down
34 changes: 28 additions & 6 deletions src/helpers/utils/entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ if (queries.endpoint?.length) {
/**
* /moxy/v1/users/get --> /v1/users/get
*/
const getEndpointPathFromURL = ({ url, moxyPrefix = '/moxy' }: getEndpointPathFromURL):{
pathname:string, params: Record<string, string>
const getEndpointPathFromURL = ({ url, moxyPrefix = '/moxy' }: getEndpointPathFromURL): {
pathname: string, params: Record<string, string>
} => {
if (!url) {
throw ('url is missing for getEndpointPathFromURL()')
}
}
const { pathname, searchParams } = new URL(url.replace(moxyPrefix, ''), 'http://fake-base-host.com');
const params = Object.fromEntries(searchParams.entries())
return {pathname, params};

return { pathname, params };
}

interface MatchEndpointPathToDB {
Expand All @@ -35,4 +35,26 @@ const matchEndpointPathToDB = async ({ pathname }: MatchEndpointPathToDB) => {
return endpoints.data.filter(ep => ep.endpoint === pathname)[0] || {};
}

export { getEndpointPathFromURL, matchEndpointPathToDB }
const findEndpointGroup = (allEndpoints) => {
const group = []
const makeGroupName = (n: string) => {
return n.split('/')[1]
}

allEndpoints.data.forEach((d) => {
const g = makeGroupName(d.endpoint);
const itemIndex = group.findIndex(({ name }) => name === g);
if (itemIndex > -1) {
group[itemIndex].items.push(d)
}
else {
group.push({
name: g,
items: [d]
})
}
})
return group;
}

export { getEndpointPathFromURL, matchEndpointPathToDB, findEndpointGroup }
18 changes: 14 additions & 4 deletions src/pages/api/endpoints/index.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,23 @@
import type { NextApiRequest, NextApiResponse } from 'next'
import {readEndpointsFromDB} from '@/helpers/db/selectors';
import { createEndpoint, deleteEndpoint } from '@/helpers/endpoint';
import {findEndpointGroup} from '@/helpers/utils/entrypoint';

const getData = async() => {
const getData = async({groupby}) => {
const data = await readEndpointsFromDB()

if(groupby==="1") {
const groupedEndpoints = findEndpointGroup(data)
return {data:groupedEndpoints}
}

return data;
}

const handler = async (req:NextApiRequest,res:NextApiResponse) => {

const { body } = req;

const { body, query } = req;
/** Delete an endpoint */
if (req.method === 'DELETE') {
const id = body.id;
Expand All @@ -25,12 +32,15 @@ const handler = async (req:NextApiRequest,res:NextApiResponse) => {

/** Get Endpoints */
if (req.method === 'GET') {
const data = await getData()
const {groupby} = query;

const data = await getData({groupby})
res.status(200).json(data)
}

/** Create a new Endpoint */
if (req.method === 'POST') {

try {
const a = await createEndpoint({ ...body.data })
res.send({success: true})
Expand Down