diff --git a/ApiDocs/nodemon.json b/ApiDocs/nodemon.json new file mode 100644 index 0000000000..c62054f0d8 --- /dev/null +++ b/ApiDocs/nodemon.json @@ -0,0 +1,5 @@ +{ + "watch": ["./", "../Common", "../CommonServer", "../Model"], + "ext": "ts,json,tsx,env,js,jsx,ejs", + "exec": "node --inspect=0.0.0.0:9229 --require ts-node/register Index.ts" +} \ No newline at end of file diff --git a/ApiDocs/package.json b/ApiDocs/package.json index 52800c55da..f875708f08 100755 --- a/ApiDocs/package.json +++ b/ApiDocs/package.json @@ -32,10 +32,8 @@ "preinstall": "npx npm-force-resolutions || echo 'No package-lock.json file. Skipping force resolutions'", "start": "node --require ts-node/register Index.ts", "compile": "tsc", - "dev": "ts-node-dev server.js", - "test": "mocha --exit test/index.ts", - "audit": "npm audit --audit-level=low", - "dep-check": "depcheck ./ --skip-missing=true --ignores='babel-*,browserslist,ejs,path'" + "dev": "npx nodemon", + "test": "jest" }, "resolutions": {}, "devDependencies": { @@ -45,4 +43,4 @@ "npm-force-resolutions": "0.0.10", "ts-node-dev": "^1.1.8" } -} +} \ No newline at end of file diff --git a/Dashboard/src/App.tsx b/Dashboard/src/App.tsx index b2253d5cde..78895b6f89 100644 --- a/Dashboard/src/App.tsx +++ b/Dashboard/src/App.tsx @@ -18,10 +18,14 @@ import OngoingScheduledEvents from './Pages/Home/OngingScheduledMaintenance'; import useAsyncEffect from 'use-async-effect'; import Workflows from './Pages/Workflow/Workflows'; +import WorkflowsVariables from './Pages/Workflow/Variable'; +import WorkflowsLogs from './Pages/Workflow/Logs'; import WorkflowLogs from './Pages/Workflow/View/Logs'; import WorkflowDelete from './Pages/Workflow/View/Delete'; import WorkflowBuilder from './Pages/Workflow/View/Builder'; import WorkflowOverview from './Pages/Workflow/View/Index'; +import WorkflowVariables from './Pages/Workflow/View/Variable'; + import StatusPages from './Pages/StatusPages/StatusPages'; import StatusPagesView from './Pages/StatusPages/View/Index'; @@ -188,7 +192,7 @@ const App: FunctionComponent = () => { } catch (err) { setError( (err as HTTPErrorResponse).message || - 'Server Error. Please try again' + 'Server Error. Please try again' ); } @@ -273,7 +277,7 @@ const App: FunctionComponent = () => { { { { { { } /> + + + } + /> + + + } + /> + + + } + /> + { { { { { { { { { { { { { { { { { { { { { { { { { { { { { { = ( ? props.usernameClassName : '' } - >{`${ - (user['name']?.toString() as string) || + >{`${(user['name']?.toString() as string) || (user['email']?.toString() as string) || '' - }`}{' '} + }`}{' '} {props.suffix && ( diff --git a/Dashboard/src/Pages/Workflow/SideMenu.tsx b/Dashboard/src/Pages/Workflow/SideMenu.tsx index e700494f1c..e04c9b13cf 100644 --- a/Dashboard/src/Pages/Workflow/SideMenu.tsx +++ b/Dashboard/src/Pages/Workflow/SideMenu.tsx @@ -16,7 +16,7 @@ const DashboardSideMenu: FunctionComponent = (): ReactElement => { RouteMap[PageMap.WORKFLOWS] as Route ), }} - icon={IconProp.Info} + icon={IconProp.Workflow} /> { RouteMap[PageMap.WORKFLOWS_VARIABLES] as Route ), }} - icon={IconProp.Workflow} + icon={IconProp.Variable} /> = ( icon={IconProp.Workflow} /> + + + + = ( }} icon={IconProp.Logs} /> - - + + + = ( ]} showRefreshButton={true} showFilterButton={true} - viewPageRoute={Navigation.getCurrentRoute()} + viewPageRoute={Navigation.getCurrentRoute().addRoute(new Route("/workflow"))} columns={[ { field: { diff --git a/Dashboard/src/Utils/RouteMap.ts b/Dashboard/src/Utils/RouteMap.ts index 1078d7799e..f08193bf97 100644 --- a/Dashboard/src/Utils/RouteMap.ts +++ b/Dashboard/src/Utils/RouteMap.ts @@ -274,19 +274,19 @@ const RouteMap: Dictionary = { ), [PageMap.WORKFLOW_BUILDER]: new Route( - `/dashboard/${RouteParams.ProjectID}/workflows/${RouteParams.ModelID}/builder` + `/dashboard/${RouteParams.ProjectID}/workflows/workflow/${RouteParams.ModelID}/builder` ), [PageMap.WORKFLOW_VIEW]: new Route( - `/dashboard/${RouteParams.ProjectID}/workflows/${RouteParams.ModelID}` + `/dashboard/${RouteParams.ProjectID}/workflows/workflow/${RouteParams.ModelID}` ), [PageMap.WORKFLOW_LOGS]: new Route( - `/dashboard/${RouteParams.ProjectID}/workflows/${RouteParams.ModelID}/logs` + `/dashboard/${RouteParams.ProjectID}/workflows/workflow/${RouteParams.ModelID}/logs` ), [PageMap.WORKFLOW_DELETE]: new Route( - `/dashboard/${RouteParams.ProjectID}/workflows/${RouteParams.ModelID}/delete` + `/dashboard/${RouteParams.ProjectID}/workflows/workflow/${RouteParams.ModelID}/delete` ), // logout. @@ -298,7 +298,7 @@ export class RouteUtil { if ( route.toString() === RouteMap[PageMap.USER_PROFILE]?.toString() || route.toString() === - RouteMap[PageMap.PROJECT_INVITATIONS]?.toString() || + RouteMap[PageMap.PROJECT_INVITATIONS]?.toString() || route.toString() === RouteMap[PageMap.ACTIVE_INCIDENTS]?.toString() ) { return true; diff --git a/Model/Models/WorkflowVariable.ts b/Model/Models/WorkflowVariable.ts index 59c5a63cfd..2053262aaa 100644 --- a/Model/Models/WorkflowVariable.ts +++ b/Model/Models/WorkflowVariable.ts @@ -40,11 +40,11 @@ import BaseModel from 'Common/Models/BaseModel'; Permission.CanEditWorkflowVariable, ], }) -@CrudApiEndpoint(new Route('/workflow-secret')) +@CrudApiEndpoint(new Route('/workflow-variable')) @Entity({ name: 'WorkflowVariable', }) -@SingularPluralName('Workflow Secret', 'Workflow Secrets') +@SingularPluralName('Workflow Variable', 'Workflow Variables') export default class Workflow extends BaseModel { @ColumnAccessControl({ create: [ diff --git a/Nginx/default.tpl.conf b/Nginx/default.tpl.conf index d9a0681690..21178c6642 100644 --- a/Nginx/default.tpl.conf +++ b/Nginx/default.tpl.conf @@ -18,6 +18,10 @@ upstream workflow { server workflow:3099 weight=10 max_fails=3 fail_timeout=30s; } +upstream api-docs { + server api-docs:1445 weight=10 max_fails=3 fail_timeout=30s; +} + upstream alert { server alert:3088 weight=10 max_fails=3 fail_timeout=30s; } @@ -242,6 +246,19 @@ server { proxy_pass http://identity; } + location /docs { + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # enable WebSockets (for ws://sockjs not connected error in the accounts source: https://stackoverflow.com/questions/41381444/websocket-connection-failed-error-during-websocket-handshake-unexpected-respon) + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_pass http://api-docs; + } + location /alert { diff --git a/docker-compose.tpl.yml b/docker-compose.tpl.yml index a7ae8f3e6b..d0736b6d19 100644 --- a/docker-compose.tpl.yml +++ b/docker-compose.tpl.yml @@ -485,6 +485,40 @@ services: - /usr/src/Model/node_modules/ {{ end }} + api-docs: + ports: + - '1445:1445' + {{ if eq .Env.ENVIRONMENT "development" }} + - '9178:9229' # Debugging port. + {{ end }} + restart: always + env_file: + - ./Common/.env + - ./CommonServer/.env + - ./ApiDocs/.env + {{ if or (eq .Env.ENVIRONMENT "development") (eq .Env.ENVIRONMENT "ci") }} + build: + network: host + context: . + dockerfile: ./ApiDocs/Dockerfile + {{ else }} + image: oneuptime/api-docs:{{ .Env.APP_TAG }} + {{ end }} + {{ if eq .Env.ENVIRONMENT "development" }} + volumes: + - ./ApiDocs:/usr/src/app + # Use node modules of the container and not host system. + # https://stackoverflow.com/questions/29181032/add-a-volume-to-docker-but-exclude-a-sub-folder + - /usr/src/app/node_modules/ + - ./Common:/usr/src/Common + - ./Model:/usr/src/Model + - ./CommonServer:/usr/src/CommonServer + - ./CommonUI:/usr/src/CommonUI + - /usr/src/Common/node_modules/ + - /usr/src/CommonUI/node_modules/ + - /usr/src/CommonServer/node_modules/ + - /usr/src/Model/node_modules/ + {{ end }} nginx: depends_on: