diff --git a/backend/app.py b/backend/app.py index e1ce946..7230a3f 100644 --- a/backend/app.py +++ b/backend/app.py @@ -8,6 +8,7 @@ from utils import * from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jose import JWTError, jwt from passlib.context import CryptContext +from fastapi_socketio import SocketManager ON_DOCKER = len(sys.argv) > 1 and sys.argv[1] == "DOCKER" DEBUG = len(sys.argv) > 1 and sys.argv[1] == "DEBUG" @@ -30,14 +31,22 @@ oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/login", auto_error=False) crypto = CryptContext(schemes=["bcrypt"], deprecated="auto") app = FastAPI(debug=DEBUG, redoc_url=None) +sio = SocketManager(app, "/sock", socketio_path="") def APP_STATUS(): return "init" if conf.get("password") is None else "run" def JWT_SECRET(): return conf.get("secret") +async def refresh_frontend(): + await sio.emit("update","Refresh") + +@sio.on("update") +async def updater(): pass + @app.on_event("startup") async def startup_event(): db.init() - await firewall.init() + await firewall.init(refresh_frontend) + await refresh_frontend() if not JWT_SECRET(): conf.put("secret", secrets.token_hex(32)) @app.on_event("shutdown") @@ -117,6 +126,7 @@ async def change_password(form: PasswordChangeForm, auth: bool = Depends(is_logg hash_psw = crypto.hash(form.password) conf.put("password",hash_psw) + await refresh_frontend() return {"status":"ok", "access_token": create_access_token({"logged_in": True})} @@ -128,6 +138,7 @@ async def set_password(form: PasswordForm): return {"status":"Cannot insert an empty password!"} hash_psw = crypto.hash(form.password) conf.put("password",hash_psw) + await refresh_frontend() return {"status":"ok", "access_token": create_access_token({"logged_in": True})} class GeneralStatModel(BaseModel): @@ -189,12 +200,14 @@ class StatusMessageModel(BaseModel): async def service_stop(service_port: int, auth: bool = Depends(is_loggined)): """Request the stop of a specific service""" await firewall.get(service_port).next(STATUS.STOP) + await refresh_frontend() return {'status': 'ok'} @app.get('/api/service/{service_port}/start', response_model=StatusMessageModel) async def service_start(service_port: int, auth: bool = Depends(is_loggined)): """Request the start of a specific service""" await firewall.get(service_port).next(STATUS.ACTIVE) + await refresh_frontend() return {'status': 'ok'} @app.get('/api/service/{service_port}/delete', response_model=StatusMessageModel) @@ -203,6 +216,7 @@ async def service_delete(service_port: int, auth: bool = Depends(is_loggined)): db.query('DELETE FROM services WHERE port = ?;', service_port) db.query('DELETE FROM regexes WHERE service_port = ?;', service_port) await firewall.remove(service_port) + await refresh_frontend() return {'status': 'ok'} class RenameForm(BaseModel): @@ -213,6 +227,7 @@ async def service_rename(service_port: int, form: RenameForm, auth: bool = Depen """Request to change the name of a specific service""" if not form.name: return {'status': 'The name cannot be empty!'} db.query('UPDATE services SET name=? WHERE port = ?;', form.name, service_port) + await refresh_frontend() return {'status': 'ok'} class RegexModel(BaseModel): @@ -254,6 +269,7 @@ async def regex_delete(regex_id: int, auth: bool = Depends(is_loggined)): if len(res) != 0: db.query('DELETE FROM regexes WHERE regex_id = ?;', regex_id) await firewall.get(res[0]["service_port"]).update_filters() + await refresh_frontend() return {'status': 'ok'} @@ -264,6 +280,7 @@ async def regex_enable(regex_id: int, auth: bool = Depends(is_loggined)): if len(res) != 0: db.query('UPDATE regexes SET active=1 WHERE regex_id = ?;', regex_id) await firewall.get(res[0]["service_port"]).update_filters() + await refresh_frontend() return {'status': 'ok'} @app.get('/api/regex/{regex_id}/disable', response_model=StatusMessageModel) @@ -273,6 +290,7 @@ async def regex_disable(regex_id: int, auth: bool = Depends(is_loggined)): if len(res) != 0: db.query('UPDATE regexes SET active=0 WHERE regex_id = ?;', regex_id) await firewall.get(res[0]["service_port"]).update_filters() + await refresh_frontend() return {'status': 'ok'} class RegexAddForm(BaseModel): @@ -297,6 +315,7 @@ async def add_new_regex(form: RegexAddForm, auth: bool = Depends(is_loggined)): return {'status': 'An identical regex already exists'} await firewall.get(form.service_port).update_filters() + await refresh_frontend() return {'status': 'ok'} class ServiceAddForm(BaseModel): @@ -312,6 +331,7 @@ async def add_new_service(form: ServiceAddForm, auth: bool = Depends(is_loggined except sqlite3.IntegrityError: return {'status': 'Name or/and ports of the service has been already assigned to another service'} await firewall.reload() + await refresh_frontend() return {'status': 'ok'} diff --git a/backend/requirements.txt b/backend/requirements.txt index d61d54b..daaf765 100755 --- a/backend/requirements.txt +++ b/backend/requirements.txt @@ -5,4 +5,5 @@ passlib[bcrypt] python-jose[cryptography] NetfilterQueue scapy -python-pcre \ No newline at end of file +python-pcre +fastapi-socketio \ No newline at end of file diff --git a/backend/utils.py b/backend/utils.py index fc36caf..f5763dd 100755 --- a/backend/utils.py +++ b/backend/utils.py @@ -177,9 +177,9 @@ class ProxyManager: self.lock = asyncio.Lock() self.updater_task = None - def init_updater(self): + def init_updater(self, callback = None): if not self.updater_task: - self.updater_task = asyncio.create_task(self._stats_updater()) + self.updater_task = asyncio.create_task(self._stats_updater(callback)) def close_updater(self): if self.updater_task: self.updater_task.cancel() @@ -196,11 +196,11 @@ class ProxyManager: await self.proxy_table[port].next(STATUS.STOP) del self.proxy_table[port] - async def init(self): + async def init(self, callback = None): + self.init_updater(callback) await self.reload() async def reload(self): - self.init_updater() async with self.lock: for srv in self.db.query('SELECT port, status FROM services;'): srv_port, req_status = srv["port"], srv["status"] @@ -210,7 +210,7 @@ class ProxyManager: self.proxy_table[srv_port] = ServiceManager(srv_port,self.db) await self.proxy_table[srv_port].next(req_status) - async def _stats_updater(self): + async def _stats_updater(self, callback): try: while True: try: @@ -218,7 +218,10 @@ class ProxyManager: self.proxy_table[key].update_stats() except Exception: traceback.print_exc() - await asyncio.sleep(1) + if callback: + if asyncio.iscoroutinefunction(callback): await callback() + else: callback() + await asyncio.sleep(5) except asyncio.CancelledError: self.updater_task = None return diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 7a16314..1e1d005 100755 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -29,6 +29,7 @@ "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", "sass": "^1.52.3", + "socket.io-client": "^4.5.1", "typescript": "^4.7.3", "web-vitals": "^2.1.4" } @@ -3164,6 +3165,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "node_modules/@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -6403,6 +6409,46 @@ "node": ">= 0.8" } }, + "node_modules/engine.io-client": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz", + "integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", @@ -13217,6 +13263,32 @@ "node": ">=8" } }, + "node_modules/socket.io-client": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz", + "integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.2.1", + "socket.io-parser": "~4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -15144,6 +15216,14 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", @@ -17365,6 +17445,11 @@ "@sinonjs/commons": "^1.7.0" } }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==" + }, "@surma/rollup-plugin-off-main-thread": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz", @@ -19740,6 +19825,31 @@ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" }, + "engine.io-client": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.2.2.tgz", + "integrity": "sha512-8ZQmx0LQGRTYkHuogVZuGSpDqYZtCM/nv8zQ68VZ+JkOpazJ7ICdsSpaO6iXwvaU30oFg5QJOJWj8zWqhbKjkQ==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.0.3", + "ws": "~8.2.3", + "xmlhttprequest-ssl": "~2.0.0" + }, + "dependencies": { + "ws": { + "version": "8.2.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", + "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.4.tgz", + "integrity": "sha512-+nVFp+5z1E3HcToEnO7ZIj3g+3k9389DvWtvJZz0T6/eOCPIyyxehFcedoYrZQrp0LgQbD9pPXhpMBKMd5QURg==" + }, "enhanced-resolve": { "version": "5.9.3", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", @@ -24538,6 +24648,26 @@ "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==" }, + "socket.io-client": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.5.1.tgz", + "integrity": "sha512-e6nLVgiRYatS+AHXnOnGi4ocOpubvOUCGhyWw8v+/FxW8saHkinG6Dfhi9TU0Kt/8mwJIAASxvw6eujQmjdZVA==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.2.1", + "socket.io-parser": "~4.2.0" + } + }, + "socket.io-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.1.tgz", + "integrity": "sha512-V4GrkLy+HeF1F/en3SpUaM+7XxYXpuMUWLGde1kSSh5nQMN4hLrbPIkD+otwh6q9R6NOQBN4AMaOZ2zVjui82g==", + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, "sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -26008,6 +26138,11 @@ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==" }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" + }, "xtend": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", diff --git a/frontend/package.json b/frontend/package.json index 389c4c8..16658e2 100755 --- a/frontend/package.json +++ b/frontend/package.json @@ -24,6 +24,7 @@ "react-router-dom": "^6.3.0", "react-scripts": "5.0.1", "sass": "^1.52.3", + "socket.io-client": "^4.5.1", "typescript": "^4.7.3", "web-vitals": "^2.1.4" }, diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 0bcf120..697a393 100755 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -5,9 +5,12 @@ import { ImCross } from 'react-icons/im'; import { Navigate, Outlet, Route, Routes } from 'react-router-dom'; import MainLayout from './components/MainLayout'; import { PasswordSend, ServerStatusResponse } from './js/models'; -import { fireUpdateRequest, getstatus, login, setpassword } from './js/utils'; +import { errorNotify, fireUpdateRequest, getstatus, login, setpassword } from './js/utils'; import HomePage from './pages/HomePage'; import ServiceDetails from './pages/ServiceDetails'; +import io from 'socket.io-client'; + +const socket = io({transports: ["websocket", "polling"], path:"/sock" }); function App() { @@ -29,11 +32,19 @@ function App() { }) } - useEffect(getStatus,[]) - useEffect(()=>{ - const updater = setInterval(fireUpdateRequest,2000) - return () => clearInterval(updater) + getStatus() + socket.on("update", () => { + fireUpdateRequest() + }) + socket.on("connect_error", (err) => { + errorNotify("Socket.Io connection failed! ",`Error message: [${err.message}]`) + getStatus() + }); + return () => { + socket.off("update") + socket.off("connect_error") + } },[]) const form = useForm({ diff --git a/frontend/src/components/AddNewRegex.tsx b/frontend/src/components/AddNewRegex.tsx index 9f34b09..099ef16 100755 --- a/frontend/src/components/AddNewRegex.tsx +++ b/frontend/src/components/AddNewRegex.tsx @@ -2,7 +2,7 @@ import { Button, Group, Space, TextInput, Notification, Switch, NativeSelect, Mo import { useForm } from '@mantine/hooks'; import React, { useState } from 'react'; import { RegexAddForm } from '../js/models'; -import { addregex, b64decode, b64encode, fireUpdateRequest, okNotify } from '../js/utils'; +import { addregex, b64decode, b64encode, okNotify } from '../js/utils'; import { ImCross } from "react-icons/im" import FilterTypeSelector from './FilterTypeSelector'; @@ -58,7 +58,6 @@ function AddNewRegex({ opened, onClose, service }:{ opened:boolean, onClose:()=> if (!res){ setSubmitLoading(false) close(); - fireUpdateRequest(); okNotify(`Regex ${b64decode(request.regex)} has been added`, `Successfully added ${request.is_case_sensitive?"case sensitive":"case insensitive"} ${request.is_blacklist?"blacklist":"whitelist"} regex to ${request.service_port} service`) }else if (res.toLowerCase() === "invalid regex"){ setSubmitLoading(false) diff --git a/frontend/src/components/AddNewService.tsx b/frontend/src/components/AddNewService.tsx index 9e73475..22b999d 100755 --- a/frontend/src/components/AddNewService.tsx +++ b/frontend/src/components/AddNewService.tsx @@ -1,7 +1,7 @@ import { Button, Group, NumberInput, Space, TextInput, Notification, Modal, Switch } from '@mantine/core'; import { useForm } from '@mantine/hooks'; import React, { useState } from 'react'; -import { addservice, fireUpdateRequest, okNotify, startservice } from '../js/utils'; +import { addservice, okNotify, startservice } from '../js/utils'; import { ImCross } from "react-icons/im" type ServiceAddForm = { @@ -39,7 +39,6 @@ function AddNewService({ opened, onClose }:{ opened:boolean, onClose:()=>void }) if (res.status === "ok"){ setSubmitLoading(false) close(); - fireUpdateRequest(); if (autostart) startservice(port) okNotify(`Service ${name} has been added`, `Successfully added service with port ${port}`) }else{ diff --git a/frontend/src/components/RegexView/index.tsx b/frontend/src/components/RegexView/index.tsx index 19e1aa9..82da7b5 100755 --- a/frontend/src/components/RegexView/index.tsx +++ b/frontend/src/components/RegexView/index.tsx @@ -1,7 +1,7 @@ import { Grid, Text, Title, Badge, Space, ActionIcon, Tooltip } from '@mantine/core'; import React, { useState } from 'react'; import { RegexFilter } from '../../js/models'; -import { activateregex, b64decode, deactivateregex, deleteregex, errorNotify, fireUpdateRequest, okNotify } from '../../js/utils'; +import { activateregex, b64decode, deactivateregex, deleteregex, errorNotify, okNotify } from '../../js/utils'; import style from "./index.module.scss"; import { BsTrashFill } from "react-icons/bs" import YesNoModal from '../YesNoModal'; @@ -25,7 +25,6 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) { deleteregex(regexInfo.id).then(res => { if(!res){ okNotify(`Regex ${regex_expr} deleted successfully!`,`Regex '${regex_expr}' ID:${regexInfo.id} has been deleted!`) - fireUpdateRequest() }else{ errorNotify(`Regex ${regex_expr} deleation failed!`,`Error: ${res}`) } @@ -37,7 +36,6 @@ function RegexView({ regexInfo }:{ regexInfo:RegexFilter }) { (regexInfo.active?deactivateregex:activateregex)(regexInfo.id).then(res => { if(!res){ okNotify(`Regex ${regex_expr} ${regexInfo.active?"deactivated":"activated"} successfully!`,`Regex '${regex_expr}' ID:${regexInfo.id} has been ${regexInfo.active?"deactivated":"activated"}!`) - fireUpdateRequest() }else{ errorNotify(`Regex ${regex_expr} ${regexInfo.active?"deactivation":"activation"} failed!`,`Error: ${res}`) } diff --git a/frontend/src/components/ServiceRow/RenameForm.tsx b/frontend/src/components/ServiceRow/RenameForm.tsx index 14a6a27..ca15dd3 100644 --- a/frontend/src/components/ServiceRow/RenameForm.tsx +++ b/frontend/src/components/ServiceRow/RenameForm.tsx @@ -1,7 +1,7 @@ import { Button, Group, Space, TextInput, Notification, Modal } from '@mantine/core'; import { useForm } from '@mantine/hooks'; import React, { useEffect, useState } from 'react'; -import { fireUpdateRequest, okNotify, renameservice } from '../../js/utils'; +import { okNotify, renameservice } from '../../js/utils'; import { ImCross } from "react-icons/im" import { Service } from '../../js/models'; @@ -29,7 +29,6 @@ function RenameForm({ opened, onClose, service }:{ opened:boolean, onClose:()=>v if (!res){ setSubmitLoading(false) close(); - fireUpdateRequest(); okNotify(`Service ${service.name} has been renamed in ${ name }`, `Successfully renamed service on port ${service.port}`) }else{ setSubmitLoading(false) diff --git a/frontend/src/components/ServiceRow/index.tsx b/frontend/src/components/ServiceRow/index.tsx index f65b3b9..e8e2704 100755 --- a/frontend/src/components/ServiceRow/index.tsx +++ b/frontend/src/components/ServiceRow/index.tsx @@ -5,7 +5,7 @@ import { Service } from '../../js/models'; import { MdOutlineArrowForwardIos } from "react-icons/md" import style from "./index.module.scss"; import YesNoModal from '../YesNoModal'; -import { deleteservice, errorNotify, fireUpdateRequest, okNotify, startservice, stopservice } from '../../js/utils'; +import { deleteservice, errorNotify, okNotify, startservice, stopservice } from '../../js/utils'; import { BsTrashFill } from 'react-icons/bs'; import { BiRename } from 'react-icons/bi' import RenameForm from './RenameForm'; @@ -28,7 +28,6 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) await stopservice(service.port).then(res => { if(!res){ okNotify(`Service ${service.name} stopped successfully!`,`The service on ${service.port} has been stopped!`) - fireUpdateRequest(); }else{ errorNotify(`An error as occurred during the stopping of the service ${service.port}`,`Error: ${res}`) } @@ -43,7 +42,6 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) await startservice(service.port).then(res => { if(!res){ okNotify(`Service ${service.name} started successfully!`,`The service on ${service.port} has been started!`) - fireUpdateRequest(); }else{ errorNotify(`An error as occurred during the starting of the service ${service.port}`,`Error: ${res}`) } @@ -57,7 +55,6 @@ function ServiceRow({ service, onClick }:{ service:Service, onClick?:()=>void }) deleteservice(service.port).then(res => { if (!res){ okNotify("Service delete complete!",`The service ${service.name} has been deleted!`) - fireUpdateRequest(); }else errorNotify("An error occurred while deleting a service",`Error: ${res}`) }).catch(err => {