Commit 2d605175 authored by Dimitrios Gogos's avatar Dimitrios Gogos
Browse files

fix: update Dockerfile and README

parent 692e285d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -2,8 +2,8 @@ FROM node:20-slim

WORKDIR /app

COPY package.json package-lock.json ./
RUN npm ci
COPY package.json package-lock.json* ./
RUN npm install --legacy-peer-deps

COPY . .

+47 −22
Original line number Diff line number Diff line
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
# OOP Developer Portal

## Getting Started
A web-based developer portal for the **Open Operator Platform (OOP)**. It lets developers discover edge APIs, register application profiles, and deploy containerised workloads onto an edge Kubernetes cluster — all through a browser UI backed by the Open Exposure Gateway (OEG).

First, run the development server:
---

```bash
npm run dev
```
## Available pages

### API Catalogue
Browse the APIs exposed by the OEG platform:
- **Edge Cloud Zones Discovery** — find available edge zones with their capacity and location metadata.
- **Quality on Demand (QoD)** — manage guaranteed-bandwidth sessions for latency-sensitive apps.
- **Federation Management** — manage inter-operator federation agreements and shared edge zones.

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
Each API card shows the protocol, version, and status. Clicking a card opens a live **Swagger UI** so you can try the API directly from the browser.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
### My Applications — Profile tab
Manage application profiles registered with the OEG:
- **Create** a new profile by providing the app name, version, package type (HELM / CONTAINER), image path, port specs, and resource requirements.
- **Deploy** a registered profile to an edge cloud zone via a zone-selection dialog — this triggers a real Kubernetes Deployment on the cluster.
- **Delete** a profile to remove it from the registry.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
### My Applications — Deployments tab
See what is actually running on the cluster right now:
- Lists every live app instance returned by `GET /appinstances` from the OEG.
- Shows name, provider, App ID, Instance ID, and a live **status chip** (`READY` in green, `FAILED` in red) derived directly from the Kubernetes Deployment's `available_replicas` / `ready_replicas` counters.

## Local Development
## Local development

**Prerequisites:** Node 20+, a running OEG reachable at `http://localhost:32263`.

```bash
npm install       # install dependencies
npm run dev       # start dev server at http://localhost:3000
cd portal/portal-gui
npm install --legacy-peer-deps   # install dependencies
npm run dev                      # dev server at http://localhost:3000
npm run build                    # production build
npm run lint      # run linter
npm run lint                     # ESLint
```

## Learn More
Set `OEG_SERVICE_URL` to point at a non-default OEG endpoint:

```bash
OEG_SERVICE_URL=http://my-oeg:32263/oeg/1.0.0 npm run dev
```

To learn more about Next.js, take a look at the following resources:
---

- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
## Docker

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
```bash
docker build -t portal:0.1.0 .
docker run -p 3000:3000 \
  -e OEG_SERVICE_URL=http://host.docker.internal:32263/oeg/1.0.0 \
  portal:0.1.0
```

## Deploy
## Helm (kind cluster)

The application is deployed via Helm on a kind cluster and exposed through a Kubernetes NodePort service.
The portal is shipped as a sub-chart inside `helm/oop-platform-chart`. It is deployed automatically when you install the platform chart:

```bash
docker build -t portal-gui:latest .
helm upgrade --install oop-platform ./helm/oop-platform-chart \
  -f helm/environments/kind/values.yaml
```

The portal is then reachable on the NodePort defined in `helm/oop-platform-chart/charts/portal/values.yaml`.
+18 −24
Original line number Diff line number Diff line
@@ -59,7 +59,6 @@
      "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
      "dev": true,
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "@babel/code-frame": "^7.29.0",
        "@babel/generator": "^7.29.0",
@@ -165,7 +164,7 @@
      "version": "7.27.1",
      "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz",
      "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==",
      "devOptional": true,
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=6.9.0"
@@ -175,7 +174,7 @@
      "version": "7.28.5",
      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz",
      "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==",
      "devOptional": true,
      "dev": true,
      "license": "MIT",
      "engines": {
        "node": ">=6.9.0"
@@ -280,7 +279,7 @@
      "version": "7.29.0",
      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
      "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
      "devOptional": true,
      "dev": true,
      "license": "MIT",
      "dependencies": {
        "@babel/helper-string-parser": "^7.27.1",
@@ -2179,6 +2178,18 @@
        "node": "^18 || ^20 || >= 21"
      }
    },
    "node_modules/@swagger-api/apidom-parser-adapter-yaml-1-2/node_modules/tree-sitter": {
      "version": "0.22.4",
      "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.22.4.tgz",
      "integrity": "sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg==",
      "hasInstallScript": true,
      "license": "MIT",
      "optional": true,
      "dependencies": {
        "node-addon-api": "^8.3.0",
        "node-gyp-build": "^4.8.4"
      }
    },
    "node_modules/@swagger-api/apidom-reference": {
      "version": "1.6.0",
      "resolved": "https://registry.npmjs.org/@swagger-api/apidom-reference/-/apidom-reference-1.6.0.tgz",
@@ -2368,7 +2379,6 @@
      "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
      "integrity": "sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==",
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "csstype": "^3.2.2"
      }
@@ -2456,7 +2466,6 @@
      "integrity": "sha512-klQbnPAAiGYFyI02+znpBRLyjL4/BrBd0nyWkdC0s/6xFLkXYQ8OoRrSkqacS1ddVxf/LDyODIKbQ5TgKAf/Fg==",
      "dev": true,
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "@typescript-eslint/scope-manager": "8.56.1",
        "@typescript-eslint/types": "8.56.1",
@@ -2982,7 +2991,6 @@
      "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==",
      "dev": true,
      "license": "MIT",
      "peer": true,
      "bin": {
        "acorn": "bin/acorn"
      },
@@ -3297,9 +3305,8 @@
      "version": "1.0.0",
      "resolved": "https://registry.npmjs.org/babel-plugin-react-compiler/-/babel-plugin-react-compiler-1.0.0.tgz",
      "integrity": "sha512-Ixm8tFfoKKIPYdCCKYTsqv+Fd4IJ0DQqMyEimo+pxUOMUR9cVPlwTrFt9Avu+3cb6Zp3mAzl+t1MrG2fxxKsxw==",
      "devOptional": true,
      "dev": true,
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "@babel/types": "^7.26.0"
      }
@@ -3388,7 +3395,6 @@
        }
      ],
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "baseline-browser-mapping": "^2.9.0",
        "caniuse-lite": "^1.0.30001759",
@@ -4132,7 +4138,6 @@
      "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==",
      "dev": true,
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "@eslint-community/eslint-utils": "^4.8.0",
        "@eslint-community/regexpp": "^4.12.1",
@@ -4318,7 +4323,6 @@
      "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
      "dev": true,
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "@rtsao/scc": "^1.1.0",
        "array-includes": "^3.1.9",
@@ -5130,8 +5134,7 @@
      "version": "5.1.4",
      "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.4.tgz",
      "integrity": "sha512-p6u1bG3YSnINT5RQmx/yRZBpenIl30kVxkTLDyHLIMk0gict704Q9n+thfDI7lTRm9vXdDYutVzXhzcThxTnXA==",
      "license": "MIT",
      "peer": true
      "license": "MIT"
    },
    "node_modules/import-fresh": {
      "version": "3.3.1",
@@ -6596,7 +6599,6 @@
      "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.30.1.tgz",
      "integrity": "sha512-tEF5I22zJnuclswcZMc8bDIrwRHRzf+NqVEmqg50ShAZMP7MWeR/RGDthfM/p+BlqvF2fXAzpn8i+SJcYD3alw==",
      "license": "MIT",
      "peer": true,
      "funding": {
        "type": "opencollective",
        "url": "https://opencollective.com/ramda"
@@ -6645,7 +6647,6 @@
      "resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
      "integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
      "license": "MIT",
      "peer": true,
      "engines": {
        "node": ">=0.10.0"
      }
@@ -6655,7 +6656,6 @@
      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
      "integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "scheduler": "^0.27.0"
      },
@@ -6795,8 +6795,7 @@
      "version": "5.0.1",
      "resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
      "integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
      "license": "MIT",
      "peer": true
      "license": "MIT"
    },
    "node_modules/reflect.getprototypeof": {
      "version": "1.0.10",
@@ -7112,7 +7111,6 @@
      "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz",
      "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==",
      "license": "MIT",
      "peer": true,
      "dependencies": {
        "chokidar": "^4.0.0",
        "immutable": "^5.0.2",
@@ -7721,7 +7719,6 @@
      "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz",
      "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==",
      "license": "MIT",
      "peer": true,
      "engines": {
        "node": ">=0.10.0"
      }
@@ -7811,7 +7808,6 @@
      "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
      "dev": true,
      "license": "MIT",
      "peer": true,
      "engines": {
        "node": ">=12"
      },
@@ -8078,7 +8074,6 @@
      "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
      "dev": true,
      "license": "Apache-2.0",
      "peer": true,
      "bin": {
        "tsc": "bin/tsc",
        "tsserver": "bin/tsserver"
@@ -8460,7 +8455,6 @@
      "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==",
      "dev": true,
      "license": "MIT",
      "peer": true,
      "funding": {
        "url": "https://github.com/sponsors/colinhacks"
      }
+5 −10
Original line number Diff line number Diff line
@@ -59,7 +59,8 @@ export const useFilters = (apis: IApi[]): UseFiltersReturn => {
    [apis]
  );
  const providers = useMemo(
    () => Array.from(new Set(apis.map((a) => a.provider))),
    () => [] as string[],
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [apis]
  );
  const functionalities = useMemo(
@@ -75,11 +76,8 @@ export const useFilters = (apis: IApi[]): UseFiltersReturn => {
    [categories, apis]
  );
  const providerCounts = useMemo(
    () =>
      Object.fromEntries(
        providers.map((p) => [p, apis.filter((a) => a.provider === p).length])
      ),
    [providers, apis]
    () => ({}) as Record<string, number>,
    [providers]
  );
  const functionalityCounts = useMemo(
    () =>
@@ -101,9 +99,7 @@ export const useFilters = (apis: IApi[]): UseFiltersReturn => {
        const matchesCategory =
          selectedCategories.length === 0 ||
          selectedCategories.includes(api.category);
        const matchesProvider =
          selectedProviders.length === 0 ||
          selectedProviders.includes(api.provider);
        const matchesProvider = selectedProviders.length === 0;
        const matchesFunc =
          selectedFunctionalities.length === 0 ||
          api.functionalities.some((f) => selectedFunctionalities.includes(f));
@@ -113,7 +109,6 @@ export const useFilters = (apis: IApi[]): UseFiltersReturn => {
      })
      .sort((a, b) => {
        if (sort === "titleAsc") return a.title.localeCompare(b.title);
        if (sort === "size") return a.size - b.size;
        return 0;
      });
  }, [