From b0b6920c5cb9cc7efaae7a75a4f5af1c6098a717 Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 19:50:38 +0200 Subject: [PATCH 01/10] fix bug where image name does not contain tag but contains repo --- api/src/utils/services.js | 6 +++--- api/src/utils/startup.js | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/api/src/utils/services.js b/api/src/utils/services.js index e63de9c..d695d6c 100644 --- a/api/src/utils/services.js +++ b/api/src/utils/services.js @@ -54,11 +54,11 @@ const createService = async (serviceRequest, image) => { }; const parseResolvedName = (resolvedName) => { - const regex = /^(.+)\/(.+):(.+)$|^(.+):(.+)$|^(.+)/; + const regex = /^(.+)\/(.+):(.+)$|^(.+):(.+)$|^(.+)\/(.+)|^(.+)$/; const match = regex.exec(resolvedName); - const repository = match[1] ?? "_"; - const imageName = match[2] ?? match[4] ?? match[6]; + const repository = match[1] ?? match[6] ?? "_"; + const imageName = match[2] ?? match[4] ?? match[7]; const tag = match[3] ?? match[5] ?? "latest"; return { diff --git a/api/src/utils/startup.js b/api/src/utils/startup.js index 7186c35..8a88e98 100644 --- a/api/src/utils/startup.js +++ b/api/src/utils/startup.js @@ -41,9 +41,19 @@ const createContainers = async (images) => { ) { return Promise.resolve(); } - const image = images.find( - (image) => image.resolvedName === container.Image - ); + const image = images.find((image) => { + const { repository, imageName, tag } = parseResolvedName( + container.Image + ); + console.log(repository, imageName, tag); + if ( + image.repository === repository && + image.name === imageName && + image.tag === tag + ) { + return true; + } + }); if (image === undefined) { return Promise.resolve(); From ab446c72b214db2368fd9dd541f4d1d1bcecefc4 Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 19:59:01 +0200 Subject: [PATCH 02/10] get already created docker container envs --- api/src/models/Service.js | 5 +++++ api/src/utils/docker.js | 11 +++++++++++ api/src/utils/startup.js | 14 ++++++++++++-- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/api/src/models/Service.js b/api/src/models/Service.js index 22fc512..4e9d48f 100644 --- a/api/src/models/Service.js +++ b/api/src/models/Service.js @@ -28,6 +28,11 @@ const ServiceSchema = new mongoose.Schema({ type: [{ from: String, to: String }], required: false, }, + environments: { + type: [{ key: String, value: String }], + required: false, + default: [], + }, order: { type: Number, required: true, diff --git a/api/src/utils/docker.js b/api/src/utils/docker.js index 3d724d0..cecbd20 100644 --- a/api/src/utils/docker.js +++ b/api/src/utils/docker.js @@ -96,6 +96,15 @@ const updateContainer = async (service, image) => { await service.save(); }; +const getContainer = (containerId) => { + return docker.getContainer(containerId); +}; + +const inspectContainer = async (containerId) => { + const container = docker.getContainer(containerId); + return await container.inspect(); +}; + const getAllContainers = async () => { const containers = await docker.listContainers({ all: true, @@ -117,4 +126,6 @@ module.exports = { updateContainer, getAllContainers, getAllImages, + getContainer, + inspectContainer, }; diff --git a/api/src/utils/startup.js b/api/src/utils/startup.js index 8a88e98..7ada9d3 100644 --- a/api/src/utils/startup.js +++ b/api/src/utils/startup.js @@ -8,7 +8,11 @@ const { parseRedirectLabels, parseTraefikerLabels, } = require("./services"); -const { getAllContainers, getAllImages } = require("./docker"); +const { + getAllContainers, + getAllImages, + inspectContainer, +} = require("./docker"); const createImages = async () => { const images = await getAllImages(); @@ -45,7 +49,6 @@ const createContainers = async (images) => { const { repository, imageName, tag } = parseResolvedName( container.Image ); - console.log(repository, imageName, tag); if ( image.repository === repository && image.name === imageName && @@ -69,12 +72,19 @@ const createContainers = async (images) => { const redirects = parseRedirectLabels(labels); const traefikerLabels = parseTraefikerLabels(labels); + const inspectData = await inspectContainer(container.Id); + const environments = inspectData.Config.Env.map((env) => { + const [key, value] = env.split("="); + return { key: key, value: value }; + }); + const service = new Service({ name: serviceName, status: container.State == "running" ? "running" : "stopped", image: image._id, hosts: hosts, redirects: redirects, + environments, order: i, tag: traefikerLabels.tag === "" ? serviceName : traefikerLabels.tag, containerId: container.Id, From fff984d2321dafae8d4721f947eefd6b04afd03b Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 20:02:46 +0200 Subject: [PATCH 03/10] re add service settings modal --- client/src/pages/dashboard/index.tsx | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/client/src/pages/dashboard/index.tsx b/client/src/pages/dashboard/index.tsx index 01789d2..8fcd468 100644 --- a/client/src/pages/dashboard/index.tsx +++ b/client/src/pages/dashboard/index.tsx @@ -4,10 +4,6 @@ import DashboardHeader from "../../components/dashboard/DashboardHeader"; import DashboardTable from "../../components/dashboard/table/DashboardTable"; import Navbar from "../../components/navbar/Navbar"; import { resetServerContext } from "react-beautiful-dnd"; -import FileEditorModal from "../../components/code-editor/FileEditorModal"; -import { useRecoilValue } from "recoil"; -import { isEditingFileState, loadingFlagsState } from "../../atoms/atoms"; -import SpinnerModal from "../../components/loading/SpinnerModal"; import ServiceSettingsModal from "../../components/service-settings/ServiceSettingsModal"; const Dashboard: NextPage = () => { @@ -26,25 +22,25 @@ const Dashboard: NextPage = () => {
-
+
@@ -53,6 +49,7 @@ const Dashboard: NextPage = () => {
+
); From 79b71c2138c136a10c4c1cdf973ea13e6e63ef3c Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 20:05:03 +0200 Subject: [PATCH 04/10] refactor modal atom --- client/src/atoms/atoms.ts | 6 +++--- .../dashboard/table/DashboardTableBody.tsx | 8 ++++---- .../service-settings/ServiceSettingsModal.tsx | 20 +++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/client/src/atoms/atoms.ts b/client/src/atoms/atoms.ts index 6b8f4b6..d11bed8 100644 --- a/client/src/atoms/atoms.ts +++ b/client/src/atoms/atoms.ts @@ -32,10 +32,10 @@ export const loadingFlagsState = atom({ }, }); -export const redirectsModalState = atom({ - key: "isAddingRedirects", +export const settingsModalState = atom({ + key: "isEditingSettings", default: { - isAddingRedirects: false, + isEditingSettings: false, service: {}, }, }); diff --git a/client/src/components/dashboard/table/DashboardTableBody.tsx b/client/src/components/dashboard/table/DashboardTableBody.tsx index a5d84fd..5214d0f 100644 --- a/client/src/components/dashboard/table/DashboardTableBody.tsx +++ b/client/src/components/dashboard/table/DashboardTableBody.tsx @@ -4,7 +4,7 @@ import { useRecoilState } from "recoil"; import { isCreatingServiceState, loadingFlagsState, - redirectsModalState, + settingsModalState, servicesState, } from "../../../atoms/atoms"; @@ -50,7 +50,7 @@ function DashboardTableBody({ columns }: Props) { isCreatingServiceState ); const [loadingFlags, setLoadingFlags] = useRecoilState(loadingFlagsState); - const [, setRedirectsModalOptions] = useRecoilState(redirectsModalState); + const [, setSettingsModalOptions] = useRecoilState(settingsModalState); const [serviceUnderEditing, setServiceUnderEditing] = useState< Service | undefined @@ -136,8 +136,8 @@ function DashboardTableBody({ columns }: Props) { }; const redirectsClicked = (service: Service) => { - setRedirectsModalOptions({ - isAddingRedirects: true, + setSettingsModalOptions({ + isEditingSettings: true, service: service, }); }; diff --git a/client/src/components/service-settings/ServiceSettingsModal.tsx b/client/src/components/service-settings/ServiceSettingsModal.tsx index 959edd6..9887482 100644 --- a/client/src/components/service-settings/ServiceSettingsModal.tsx +++ b/client/src/components/service-settings/ServiceSettingsModal.tsx @@ -2,25 +2,25 @@ import { Dialog } from "@headlessui/react"; import axios from "axios"; import { useEffect, useState } from "react"; import { useRecoilState, useRecoilValue } from "recoil"; -import { redirectsModalState } from "../../atoms/atoms"; +import { settingsModalState } from "../../atoms/atoms"; import { Service } from "../../types/Service"; import { Redirect } from "../../types/Redirect"; import UrlRedirectsTable from "./table/UrlRedirectsTable"; import { updateService } from "../../utils/api"; function ServiceSettingsModal() { - const [redirectsModalOptions, setRedirectsModalOptions] = - useRecoilState(redirectsModalState); + const [settingsModalOptions, setSettingsModalOptions] = + useRecoilState(settingsModalState); const [service, setService] = useState( - redirectsModalOptions.service + settingsModalOptions.service ); const [redirects, setRedirects] = useState(); useEffect(() => { - setService(redirectsModalOptions.service); - setRedirects(redirectsModalOptions.service.redirects); - }, [redirectsModalOptions.service]); + setService(settingsModalOptions.service); + setRedirects(settingsModalOptions.service.redirects); + }, [settingsModalOptions.service]); const saveClicked = async () => { closeModal(); @@ -38,9 +38,9 @@ function ServiceSettingsModal() { }; const closeModal = () => { - setRedirectsModalOptions((state) => ({ + setSettingsModalOptions((state) => ({ ...state, - isAddingRedirects: false, + isEditingSettings: false, })); }; @@ -77,7 +77,7 @@ function ServiceSettingsModal() { return ( {}} className="fixed inset-0 z-10 overflow-y-auto" > From bc8c43d7ddfe3f7be098f24a46f39823ff5f25d1 Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 20:19:19 +0200 Subject: [PATCH 05/10] add env vars UGLY table --- .../service-settings/ServiceSettingsModal.tsx | 57 +++++++++++++- .../env-vars/EnvironmentsTable.tsx | 78 +++++++++++++++++++ .../env-vars/EnvironmentsTableRow.tsx | 63 +++++++++++++++ .../UrlRedirectsTable.tsx | 0 .../UrlRedirectsTableRow.tsx | 0 client/src/types/Environment.ts | 5 ++ client/src/types/Service.ts | 2 + 7 files changed, 204 insertions(+), 1 deletion(-) create mode 100644 client/src/components/service-settings/env-vars/EnvironmentsTable.tsx create mode 100644 client/src/components/service-settings/env-vars/EnvironmentsTableRow.tsx rename client/src/components/service-settings/{table => url-redirects}/UrlRedirectsTable.tsx (100%) rename client/src/components/service-settings/{table => url-redirects}/UrlRedirectsTableRow.tsx (100%) create mode 100644 client/src/types/Environment.ts diff --git a/client/src/components/service-settings/ServiceSettingsModal.tsx b/client/src/components/service-settings/ServiceSettingsModal.tsx index 9887482..e3aa4d8 100644 --- a/client/src/components/service-settings/ServiceSettingsModal.tsx +++ b/client/src/components/service-settings/ServiceSettingsModal.tsx @@ -5,8 +5,10 @@ import { useRecoilState, useRecoilValue } from "recoil"; import { settingsModalState } from "../../atoms/atoms"; import { Service } from "../../types/Service"; import { Redirect } from "../../types/Redirect"; -import UrlRedirectsTable from "./table/UrlRedirectsTable"; +import UrlRedirectsTable from "./url-redirects/UrlRedirectsTable"; import { updateService } from "../../utils/api"; +import EnvironmentsTable from "./env-vars/EnvironmentsTable"; +import Environment from "../../types/Environment"; function ServiceSettingsModal() { const [settingsModalOptions, setSettingsModalOptions] = @@ -16,10 +18,14 @@ function ServiceSettingsModal() { settingsModalOptions.service ); const [redirects, setRedirects] = useState(); + const [environments, setEnvironments] = useState< + Environment[] | undefined + >(); useEffect(() => { setService(settingsModalOptions.service); setRedirects(settingsModalOptions.service.redirects); + setEnvironments(settingsModalOptions.service.environments); }, [settingsModalOptions.service]); const saveClicked = async () => { @@ -31,6 +37,16 @@ function ServiceSettingsModal() { to: redirect.to, }; }); + + const noIdsEnvironments = environments!.map((environment) => { + return { + key: environment.key, + value: environment.value, + }; + }); + + console.log(noIdsEnvironments); + await updateService({ ...service, redirects: noIdsRedirects, @@ -75,6 +91,39 @@ function ServiceSettingsModal() { setRedirects(newRedirects); }; + const addNewEnvironment = () => { + setEnvironments((prevEnvironments) => { + return [ + ...prevEnvironments!, + { + _id: prevEnvironments + ? `${prevEnvironments.length + 1}` + : "0", + key: "", + value: "", + }, + ]; + }); + }; + + const updateEnvironment = (environment: Environment) => { + setEnvironments((prevEnvironments) => { + return prevEnvironments!.map((prevEnvironment) => { + if (prevEnvironment._id == environment._id) { + return environment; + } + return prevEnvironment; + }); + }); + }; + + const deleteEnvironment = (environment: Environment) => { + const newEnvironments = environments!.filter((prevEnvironment) => { + return prevEnvironment._id !== environment._id; + }); + setEnvironments(newEnvironments); + }; + return ( +
+ + + ); +} + +export default EnvironmentsTableRow; diff --git a/client/src/components/service-settings/table/UrlRedirectsTable.tsx b/client/src/components/service-settings/url-redirects/UrlRedirectsTable.tsx similarity index 100% rename from client/src/components/service-settings/table/UrlRedirectsTable.tsx rename to client/src/components/service-settings/url-redirects/UrlRedirectsTable.tsx diff --git a/client/src/components/service-settings/table/UrlRedirectsTableRow.tsx b/client/src/components/service-settings/url-redirects/UrlRedirectsTableRow.tsx similarity index 100% rename from client/src/components/service-settings/table/UrlRedirectsTableRow.tsx rename to client/src/components/service-settings/url-redirects/UrlRedirectsTableRow.tsx diff --git a/client/src/types/Environment.ts b/client/src/types/Environment.ts new file mode 100644 index 0000000..0584313 --- /dev/null +++ b/client/src/types/Environment.ts @@ -0,0 +1,5 @@ +export default interface Environment { + _id?: string; + key: string; + value: string; +} diff --git a/client/src/types/Service.ts b/client/src/types/Service.ts index d2ac0b4..6e4bbdb 100644 --- a/client/src/types/Service.ts +++ b/client/src/types/Service.ts @@ -1,3 +1,4 @@ +import Environment from "./Environment"; import { Image } from "./Image"; import { Redirect } from "./Redirect"; @@ -9,5 +10,6 @@ export interface Service { hosts: string[]; order: number; redirects?: Redirect[]; + environments?: Environment[]; status: string; } From 70ff089c1f89418ee98a789a8fc1eaa564458df6 Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 20:35:33 +0200 Subject: [PATCH 06/10] modify env vars + persist old container port binding --- api/src/models/Service.js | 8 ++++++++ api/src/routes/services.js | 7 ++++++- api/src/utils/docker.js | 15 ++++++++++++++- .../service-settings/ServiceSettingsModal.tsx | 3 +-- client/src/utils/api.ts | 1 + 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/api/src/models/Service.js b/api/src/models/Service.js index 4e9d48f..c7a76d0 100644 --- a/api/src/models/Service.js +++ b/api/src/models/Service.js @@ -82,6 +82,14 @@ ServiceSchema.methods.getServiceLabels = function () { return labels; }; +ServiceSchema.methods.getEnvironments = function () { + const environments = this.environments.map((environment) => { + return `${environment.key}=${environment.value}`; + }); + + return environments; +}; + const transformHostsToLabel = (service) => { const label = `traefik.http.routers.${service.name}.rule`; const hosts = service.hosts.map((host) => { diff --git a/api/src/routes/services.js b/api/src/routes/services.js index 083697c..d3254e0 100644 --- a/api/src/routes/services.js +++ b/api/src/routes/services.js @@ -124,13 +124,18 @@ router.put("/:name", async (req, res) => { service.redirects = redirects; } + const environments = updateRequest.environments; + if (environments) { + service.environments = environments; + } + const tag = updateRequest.tag; if (tag) { service.tag = tag; } await service.save(); - if (hosts || image || redirects || tag) { + if (hosts || image || redirects || environments || tag) { await updateContainer(service, service.image); await startContainer(service); } diff --git a/api/src/utils/docker.js b/api/src/utils/docker.js index cecbd20..f12a871 100644 --- a/api/src/utils/docker.js +++ b/api/src/utils/docker.js @@ -75,12 +75,23 @@ const updateContainer = async (service, image) => { containerLabels[element.split("=")[0]] = element.split("=")[1]; }); + const environments = service.getEnvironments(); + + const portBindings = {}; + oldContainer.Ports.forEach((port) => { + const { PrivatePort, PublicPort, Type } = port; + portBindings[`${PrivatePort}/${Type}`] = [ + { + HostPort: `${PublicPort}`, + }, + ]; + }); + Object.keys(containerLabels).map((key) => { if (!containerLabels[key] || containerLabels[key] === "") { delete containerLabels[key]; } }); - await deleteContainer(service); const container = await docker.createContainer({ @@ -89,7 +100,9 @@ const updateContainer = async (service, image) => { Labels: containerLabels, HostConfig: { NetworkMode: service.network, + PortBindings: portBindings, }, + Env: environments, }); service.containerId = container.id; service.status = "created"; diff --git a/client/src/components/service-settings/ServiceSettingsModal.tsx b/client/src/components/service-settings/ServiceSettingsModal.tsx index e3aa4d8..96c7d68 100644 --- a/client/src/components/service-settings/ServiceSettingsModal.tsx +++ b/client/src/components/service-settings/ServiceSettingsModal.tsx @@ -45,11 +45,10 @@ function ServiceSettingsModal() { }; }); - console.log(noIdsEnvironments); - await updateService({ ...service, redirects: noIdsRedirects, + environments: noIdsEnvironments, }); }; diff --git a/client/src/utils/api.ts b/client/src/utils/api.ts index 8c33a4c..e597089 100644 --- a/client/src/utils/api.ts +++ b/client/src/utils/api.ts @@ -27,6 +27,7 @@ const updateService = async (service: Service) => { hosts: service.hosts, image: service.image.resolvedName, redirects: service.redirects, + environments: service.environments, tag: service.tag, }); }; From 7012209577cc42d9c15eac9b09aff75f96b00f8d Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 20:45:27 +0200 Subject: [PATCH 07/10] fix something --- api/package.json | 1 + api/src/server.js | 2 ++ api/src/utils/services.js | 3 +-- api/yarn.lock | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/api/package.json b/api/package.json index feda064..36b24c3 100644 --- a/api/package.json +++ b/api/package.json @@ -24,6 +24,7 @@ "express": "^4.17.2", "jsonwebtoken": "^8.5.1", "mongoose": "^6.2.0", + "morgan": "^1.10.0", "passport": "^0.5.2", "passport-jwt": "^4.0.0", "socket.io": "^4.4.1" diff --git a/api/src/server.js b/api/src/server.js index 4a7be0e..f19e58a 100644 --- a/api/src/server.js +++ b/api/src/server.js @@ -3,6 +3,7 @@ const path = require("path"); const dotenv = require("dotenv"); const passport = require("passport"); const cors = require("cors"); +const morgan = require("morgan"); const connectDB = require("./config/db"); const setupPassport = require("./config/passport"); @@ -24,6 +25,7 @@ app.use( }) ); +app.use(morgan("common")); app.use(passport.initialize()); app.use(express.json()); diff --git a/api/src/utils/services.js b/api/src/utils/services.js index d695d6c..0566854 100644 --- a/api/src/utils/services.js +++ b/api/src/utils/services.js @@ -4,7 +4,6 @@ const { deleteContainer } = require("./docker"); const getOrCreateImage = async (resolvedName) => { const { repository, imageName, tag } = parseResolvedName(resolvedName); - if (!imageName || !tag || !repository) { return -1; } @@ -58,7 +57,7 @@ const parseResolvedName = (resolvedName) => { const match = regex.exec(resolvedName); const repository = match[1] ?? match[6] ?? "_"; - const imageName = match[2] ?? match[4] ?? match[7]; + const imageName = match[2] ?? match[4] ?? match[7] ?? match[8]; const tag = match[3] ?? match[5] ?? "latest"; return { diff --git a/api/yarn.lock b/api/yarn.lock index 2d6ef83..6a42926 100644 --- a/api/yarn.lock +++ b/api/yarn.lock @@ -178,6 +178,13 @@ base64id@2.0.0, base64id@~2.0.0: resolved "https://registry.yarnpkg.com/base64id/-/base64id-2.0.0.tgz#2770ac6bc47d312af97a8bf9a634342e0cd25cb6" integrity sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog== +basic-auth@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a" + integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg== + dependencies: + safe-buffer "5.1.2" + bcrypt-pbkdf@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" @@ -480,6 +487,11 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +depd@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -1317,6 +1329,17 @@ mongoose@^6.2.0: regexp-clone "1.0.0" sift "13.5.2" +morgan@^1.10.0: + version "1.10.0" + resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.10.0.tgz#091778abc1fc47cd3509824653dae1faab6b17d7" + integrity sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ== + dependencies: + basic-auth "~2.0.1" + debug "2.6.9" + depd "~2.0.0" + on-finished "~2.3.0" + on-headers "~1.0.2" + mpath@0.8.4: version "0.8.4" resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.4.tgz#6b566d9581621d9e931dd3b142ed3618e7599313" @@ -1404,6 +1427,11 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" +on-headers@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" + integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== + once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" @@ -1628,6 +1656,11 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +safe-buffer@5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" From 595a21cbf5321c4db481ef5dff871ec0c67ff14e Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 21:36:23 +0200 Subject: [PATCH 08/10] create a all-purpose settings table --- .../service-settings/ServiceSettingsModal.tsx | 53 ++-------- .../service-settings/env-table/EnvTable.tsx | 82 ++++++++++++++++ .../env-vars/EnvironmentsTableRow.tsx | 63 ------------ .../SettingsTable.tsx} | 61 ++++++------ .../settings-table/SettingsTableRow.tsx | 96 +++++++++++++++++++ 5 files changed, 221 insertions(+), 134 deletions(-) create mode 100644 client/src/components/service-settings/env-table/EnvTable.tsx delete mode 100644 client/src/components/service-settings/env-vars/EnvironmentsTableRow.tsx rename client/src/components/service-settings/{env-vars/EnvironmentsTable.tsx => settings-table/SettingsTable.tsx} (58%) create mode 100644 client/src/components/service-settings/settings-table/SettingsTableRow.tsx diff --git a/client/src/components/service-settings/ServiceSettingsModal.tsx b/client/src/components/service-settings/ServiceSettingsModal.tsx index 96c7d68..162b4c9 100644 --- a/client/src/components/service-settings/ServiceSettingsModal.tsx +++ b/client/src/components/service-settings/ServiceSettingsModal.tsx @@ -7,8 +7,8 @@ import { Service } from "../../types/Service"; import { Redirect } from "../../types/Redirect"; import UrlRedirectsTable from "./url-redirects/UrlRedirectsTable"; import { updateService } from "../../utils/api"; -import EnvironmentsTable from "./env-vars/EnvironmentsTable"; import Environment from "../../types/Environment"; +import EnvTable from "./env-table/EnvTable"; function ServiceSettingsModal() { const [settingsModalOptions, setSettingsModalOptions] = @@ -17,15 +17,13 @@ function ServiceSettingsModal() { const [service, setService] = useState( settingsModalOptions.service ); - const [redirects, setRedirects] = useState(); - const [environments, setEnvironments] = useState< - Environment[] | undefined - >(); + const [redirects, setRedirects] = useState(); + const [environments, setEnvironments] = useState([]); useEffect(() => { setService(settingsModalOptions.service); setRedirects(settingsModalOptions.service.redirects); - setEnvironments(settingsModalOptions.service.environments); + setEnvironments(settingsModalOptions.service.environments ?? []); }, [settingsModalOptions.service]); const saveClicked = async () => { @@ -90,39 +88,6 @@ function ServiceSettingsModal() { setRedirects(newRedirects); }; - const addNewEnvironment = () => { - setEnvironments((prevEnvironments) => { - return [ - ...prevEnvironments!, - { - _id: prevEnvironments - ? `${prevEnvironments.length + 1}` - : "0", - key: "", - value: "", - }, - ]; - }); - }; - - const updateEnvironment = (environment: Environment) => { - setEnvironments((prevEnvironments) => { - return prevEnvironments!.map((prevEnvironment) => { - if (prevEnvironment._id == environment._id) { - return environment; - } - return prevEnvironment; - }); - }); - }; - - const deleteEnvironment = (environment: Environment) => { - const newEnvironments = environments!.filter((prevEnvironment) => { - return prevEnvironment._id !== environment._id; - }); - setEnvironments(newEnvironments); - }; - return ( - { + setEnvironments(data); + }} />
- - - ); -} - -export default EnvironmentsTableRow; diff --git a/client/src/components/service-settings/env-vars/EnvironmentsTable.tsx b/client/src/components/service-settings/settings-table/SettingsTable.tsx similarity index 58% rename from client/src/components/service-settings/env-vars/EnvironmentsTable.tsx rename to client/src/components/service-settings/settings-table/SettingsTable.tsx index a76e0d1..f7a23e8 100644 --- a/client/src/components/service-settings/env-vars/EnvironmentsTable.tsx +++ b/client/src/components/service-settings/settings-table/SettingsTable.tsx @@ -1,19 +1,31 @@ -import { PlusCircleIcon, PlusIcon, TrashIcon } from "@heroicons/react/solid"; +import { PlusCircleIcon } from "@heroicons/react/solid"; import Environment from "../../../types/Environment"; import { Redirect } from "../../../types/Redirect"; -import EnvironmentsTableRow from "./EnvironmentsTableRow"; +import SettingsTableRow from "./SettingsTableRow"; -function EnvironmentsTable(props: { - environments: Environment[]; - handleUpdateEnvironment: (environment: Environment) => void; - handleAddNewEnvironment: () => void; - handleDeleteEnvironment: (environment: Environment) => void; -}) { - const columns = [ - { name: "Key", screenReaderOnly: false }, - { name: "Value", screenReaderOnly: false }, - ]; +interface Props { + data: Redirect[] | Environment[]; + columns: { + name: string; + }[]; + placeholderText: { + columnA: string; + columnB: string; + notFound: string; + }; + handleUpdateData: (data: Redirect | Environment) => void; + handleAddNewData: () => void; + handleDeleteData: (data: Redirect | Environment) => void; +} +function SettingsTable({ + data, + columns, + placeholderText, + handleUpdateData, + handleAddNewData, + handleDeleteData, +}: Props) { return ( @@ -33,11 +45,10 @@ function EnvironmentsTable(props: { })} - {props.environments !== undefined && - props.environments.length !== 0 ? ( - props.environments!.map((environment: Environment, i) => ( - ( + )) ) : ( @@ -66,7 +73,7 @@ function EnvironmentsTable(props: { colSpan={2} className="text-md border-white-600 border px-4 py-1 text-center font-medium tracking-wider text-white" > - No Env. Vars found. + {placeholderText.notFound} )} @@ -75,4 +82,4 @@ function EnvironmentsTable(props: { ); } -export default EnvironmentsTable; +export default SettingsTable; diff --git a/client/src/components/service-settings/settings-table/SettingsTableRow.tsx b/client/src/components/service-settings/settings-table/SettingsTableRow.tsx new file mode 100644 index 0000000..66ddddb --- /dev/null +++ b/client/src/components/service-settings/settings-table/SettingsTableRow.tsx @@ -0,0 +1,96 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import { TrashIcon } from "@heroicons/react/solid"; +import { useEffect, useState } from "react"; +import Environment from "../../../types/Environment"; +import { Redirect } from "../../../types/Redirect"; + +interface Props { + data: Redirect | Environment; + placeholderText: { + columnA: string; + columnB: string; + }; + handleUpdateData: (data: Redirect | Environment) => void; + handleDeleteData: (data: Redirect | Environment) => void; +} + +function SettingsTableRow({ + data, + placeholderText, + handleUpdateData, + handleDeleteData, +}: Props) { + const [columnA, setColumnA] = useState(""); + const [columnB, setColumnB] = useState(""); + + useEffect(() => { + if ("from" in data) { + const redirect = data as Redirect; + setColumnA(redirect.from); + setColumnB(redirect.to); + } else if ("key" in data) { + const environment = data as Environment; + setColumnA(environment.key); + setColumnB(environment.value); + } + }, [data]); + + useEffect(() => { + if ("from" in data) { + const redirect = data as Redirect; + handleUpdateData({ + ...redirect, + from: columnA!, + to: columnB!, + }); + } else if ("key" in data) { + const environment = data as Environment; + handleUpdateData({ + ...environment, + key: columnA!, + value: columnB!, + }); + } + }, [columnA, columnB]); + + return ( + + + + + + ); +} + +export default SettingsTableRow; From 212ecc6ae41a3b38298848e8188a6291fe5de63c Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 22:06:46 +0200 Subject: [PATCH 09/10] move redirs table to all encompassing all mighty table --- api/src/utils/docker.js | 34 +++++--- .../service-settings/ServiceSettingsModal.tsx | 47 ++--------- .../service-settings/env-table/EnvTable.tsx | 6 +- .../redirs-table/RedirsTable.tsx | 79 +++++++++++++++++++ .../settings-table/SettingsTable.tsx | 4 +- .../settings-table/SettingsTableRow.tsx | 2 +- .../url-redirects/UrlRedirectsTable.tsx | 73 ----------------- .../url-redirects/UrlRedirectsTableRow.tsx | 62 --------------- client/src/pages/dashboard/index.tsx | 8 +- 9 files changed, 122 insertions(+), 193 deletions(-) create mode 100644 client/src/components/service-settings/redirs-table/RedirsTable.tsx delete mode 100644 client/src/components/service-settings/url-redirects/UrlRedirectsTable.tsx delete mode 100644 client/src/components/service-settings/url-redirects/UrlRedirectsTableRow.tsx diff --git a/api/src/utils/docker.js b/api/src/utils/docker.js index f12a871..5ecb2b5 100644 --- a/api/src/utils/docker.js +++ b/api/src/utils/docker.js @@ -78,14 +78,27 @@ const updateContainer = async (service, image) => { const environments = service.getEnvironments(); const portBindings = {}; - oldContainer.Ports.forEach((port) => { - const { PrivatePort, PublicPort, Type } = port; - portBindings[`${PrivatePort}/${Type}`] = [ - { - HostPort: `${PublicPort}`, - }, - ]; - }); + if (oldContainer.Ports.length > 0) { + oldContainer.Ports.forEach((port) => { + const { PrivatePort, PublicPort, Type } = port; + if (PrivatePort === undefined || PublicPort === undefined) { + return; + } + portBindings[`${PrivatePort}/${Type}`] = [ + { + HostPort: `${PublicPort}`, + }, + ]; + }); + } + + const hostConfig = { + NetworkMode: service.network, + }; + + if (portBindings && Object.keys(portBindings).length > 0) { + hostConfig.PortBindings = portBindings; + } Object.keys(containerLabels).map((key) => { if (!containerLabels[key] || containerLabels[key] === "") { @@ -98,10 +111,7 @@ const updateContainer = async (service, image) => { Image: image.resolvedName, name: service.name, Labels: containerLabels, - HostConfig: { - NetworkMode: service.network, - PortBindings: portBindings, - }, + HostConfig: hostConfig, Env: environments, }); service.containerId = container.id; diff --git a/client/src/components/service-settings/ServiceSettingsModal.tsx b/client/src/components/service-settings/ServiceSettingsModal.tsx index 162b4c9..75a8e76 100644 --- a/client/src/components/service-settings/ServiceSettingsModal.tsx +++ b/client/src/components/service-settings/ServiceSettingsModal.tsx @@ -5,10 +5,10 @@ import { useRecoilState, useRecoilValue } from "recoil"; import { settingsModalState } from "../../atoms/atoms"; import { Service } from "../../types/Service"; import { Redirect } from "../../types/Redirect"; -import UrlRedirectsTable from "./url-redirects/UrlRedirectsTable"; import { updateService } from "../../utils/api"; import Environment from "../../types/Environment"; import EnvTable from "./env-table/EnvTable"; +import RedirsTable from "./redirs-table/RedirsTable"; function ServiceSettingsModal() { const [settingsModalOptions, setSettingsModalOptions] = @@ -17,12 +17,12 @@ function ServiceSettingsModal() { const [service, setService] = useState( settingsModalOptions.service ); - const [redirects, setRedirects] = useState(); + const [redirects, setRedirects] = useState([]); const [environments, setEnvironments] = useState([]); useEffect(() => { setService(settingsModalOptions.service); - setRedirects(settingsModalOptions.service.redirects); + setRedirects(settingsModalOptions.service.redirects ?? []); setEnvironments(settingsModalOptions.service.environments ?? []); }, [settingsModalOptions.service]); @@ -57,37 +57,6 @@ function ServiceSettingsModal() { })); }; - const addNewRedirect = () => { - setRedirects((prevRedirects) => { - return [ - ...prevRedirects!, - { - _id: prevRedirects ? `${prevRedirects.length + 1}` : "0", - from: "", - to: "", - }, - ]; - }); - }; - - const updateRedirect = (redirect: Redirect) => { - setRedirects((prevRedirects) => { - return prevRedirects!.map((prevRedirect) => { - if (prevRedirect._id == redirect._id) { - return redirect; - } - return prevRedirect; - }); - }); - }; - - const deleteRedirect = (redirect: Redirect) => { - const newRedirects = redirects!.filter((prevRedirect) => { - return prevRedirect._id !== redirect._id; - }); - setRedirects(newRedirects); - }; - return ( - { + setRedirects(data); + }} /> { - handleUpdateData(envs); - }, [envs]); + setEnvs(environments); + }, []); useEffect(() => { - setEnvs(envs); + handleUpdateData(envs); }, [envs]); const addNewEnvironment = () => { diff --git a/client/src/components/service-settings/redirs-table/RedirsTable.tsx b/client/src/components/service-settings/redirs-table/RedirsTable.tsx new file mode 100644 index 0000000..0b57a02 --- /dev/null +++ b/client/src/components/service-settings/redirs-table/RedirsTable.tsx @@ -0,0 +1,79 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +import React, { useEffect, useState } from "react"; +import Environment from "../../../types/Environment"; +import { Redirect } from "../../../types/Redirect"; +import SettingsTable from "../settings-table/SettingsTable"; + +interface Props { + redirects: Redirect[]; + handleUpdateData: (data: Redirect[]) => void; +} + +function RedirsTable({ redirects, handleUpdateData }: Props) { + const [redirs, setRedirs] = useState([]); + + const columns = [{ name: "From (Regex)" }, { name: "To" }]; + + const placeholderText = { + columnA: "From..", + columnB: "To..", + notFound: "No redirects found", + }; + + useEffect(() => { + setRedirs(redirects); + }, []); + + useEffect(() => { + handleUpdateData(redirs); + }, [redirs]); + + const addNewRedirect = () => { + setRedirs((prevRedirs) => { + return [ + ...prevRedirs!, + { + _id: prevRedirs ? `${prevRedirs.length + 1}` : "0", + from: "", + to: "", + }, + ]; + }); + }; + + const updateRedirect = (redirect: Redirect) => { + setRedirs((prevRedirs) => { + return prevRedirs!.map((prevRedir) => { + if (prevRedir._id == redirect._id) { + return redirect; + } + return prevRedir; + }); + }); + }; + + const deleteRedirect = (redirect: Redirect) => { + const newRedir = redirs!.filter((prevRedir) => { + return prevRedir._id !== redirect._id; + }); + setRedirs(newRedir); + }; + return ( + { + const redir = data as Redirect; + updateRedirect(redir); + }} + handleAddNewData={addNewRedirect} + handleDeleteData={(data: Environment | Redirect) => { + const redir = data as Redirect; + deleteRedirect(redir); + }} + /> + ); +} + +export default RedirsTable; diff --git a/client/src/components/service-settings/settings-table/SettingsTable.tsx b/client/src/components/service-settings/settings-table/SettingsTable.tsx index f7a23e8..e4e6360 100644 --- a/client/src/components/service-settings/settings-table/SettingsTable.tsx +++ b/client/src/components/service-settings/settings-table/SettingsTable.tsx @@ -27,7 +27,7 @@ function SettingsTable({ handleDeleteData, }: Props) { return ( -
- Add New Redirect
+ { + setColumnA(e.target.value); + }} + /> + + { + setColumnB(e.target.value); + }} + /> + + +
+
{columns.map((column) => { @@ -44,7 +44,7 @@ function SettingsTable({ ); })} - - - - - - ); -} - -export default UrlRedirectsTableRow; diff --git a/client/src/pages/dashboard/index.tsx b/client/src/pages/dashboard/index.tsx index 8fcd468..915840c 100644 --- a/client/src/pages/dashboard/index.tsx +++ b/client/src/pages/dashboard/index.tsx @@ -5,8 +5,12 @@ import DashboardTable from "../../components/dashboard/table/DashboardTable"; import Navbar from "../../components/navbar/Navbar"; import { resetServerContext } from "react-beautiful-dnd"; import ServiceSettingsModal from "../../components/service-settings/ServiceSettingsModal"; +import { useRecoilState } from "recoil"; +import { settingsModalState } from "../../atoms/atoms"; const Dashboard: NextPage = () => { + const [settingsModalOptions, setSettingsModalOptions] = + useRecoilState(settingsModalState); return (
@@ -49,7 +53,9 @@ const Dashboard: NextPage = () => {
- + {settingsModalOptions.isEditingSettings ? ( + + ) : null} ); From e2313024eb2af3cf25b97fa48a6cff59568633ee Mon Sep 17 00:00:00 2001 From: haidousm Date: Thu, 10 Feb 2022 22:08:51 +0200 Subject: [PATCH 10/10] update settings icon --- .../dashboard/table/DashboardTable.tsx | 2 +- .../dashboard/table/DashboardTableRow.tsx | 33 +++++++++---------- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/client/src/components/dashboard/table/DashboardTable.tsx b/client/src/components/dashboard/table/DashboardTable.tsx index dd2137f..1a8a5e1 100644 --- a/client/src/components/dashboard/table/DashboardTable.tsx +++ b/client/src/components/dashboard/table/DashboardTable.tsx @@ -6,10 +6,10 @@ function DashboardTable() { { name: "Service Tag", screenReaderOnly: false }, { name: "Image Name", screenReaderOnly: false }, { name: "Service Hosts", screenReaderOnly: false }, - { name: "Add Redirects", screenReaderOnly: true }, { name: "Run/Stop", screenReaderOnly: true }, { name: "Edit", screenReaderOnly: true }, { name: "Delete", screenReaderOnly: true }, + { name: "Config", screenReaderOnly: true }, { name: "Order", screenReaderOnly: true }, ]; diff --git a/client/src/components/dashboard/table/DashboardTableRow.tsx b/client/src/components/dashboard/table/DashboardTableRow.tsx index 047a391..9b4b2df 100644 --- a/client/src/components/dashboard/table/DashboardTableRow.tsx +++ b/client/src/components/dashboard/table/DashboardTableRow.tsx @@ -1,6 +1,6 @@ import { Service } from "../../../types/Service"; import { Draggable } from "react-beautiful-dnd"; -import { MenuIcon, SwitchHorizontalIcon } from "@heroicons/react/solid"; +import { CogIcon, MenuIcon } from "@heroicons/react/solid"; import seedrandom from "seedrandom"; interface Props { @@ -158,21 +158,7 @@ function DashboardTableRow({ ))} - + - +
+
- { - setFromUrl(e.target.value); - }} - /> - - { - setToUrl(e.target.value); - }} - /> - - -
- - + +