Plesk extension for managing PM2-powered Node.js applications with process control, monitoring, deployment automation, and seamless server integration.
Manage Node.js applications with PM2 from Plesk, with admin, reseller, and customer scoped access.
Overview
Node Manager (PM2) is a Plesk extension for managing Node.js applications with PM2 without SSH.
It is built for hosting panels where admins need a clean process manager for SSR apps, API servers, queues, websocket servers, and other long-running Node.js services while keeping customers scoped to their own subscriptions.
The page is maintained in docs/index.html and uses the screenshots stored in docs/screenshots. It covers installation, access control, process management, runtime setup, file editing, logs, deployment, ecosystem config, metrics, backups, settings, and troubleshooting.
PM2 process list with start, stop, restart, reload, delete, and scaling controls.
Domain-scoped dashboard for admin, reseller, and customer users.
Runtime detection for Node.js, npm, PM2, Git, and PM2 home.
Admin PM2 install/update action for detected Plesk Node.js runtimes.
Live stdout/stderr log viewer with download and clear actions.
Environment variable manager with secret storage support.
Git deployment actions with optional npm install and zero-downtime reload.
PM2 ecosystem config editor.
CPU and memory metrics history with graph and pagination.
Backup and restore for extension-managed PM2 metadata.
Plesk service-plan permissions and process limits.
Complete Option Reference
The extension is domain scoped. All relative paths are resolved from the selected domain application root, and customer/reseller actions depend on Plesk service-plan permissions.
Top Actions
Info: Opens the extension information page with version, runtime, storage, permissions, and operational paths.
Refresh: Reloads domains, process state, runtime status, metrics, and visible tab data.
New Process: Opens the create-process page for the selected domain.
Domain Context
Domain: Selects the domain or subdomain workspace.
Subscription user: Shows the system user that owns the selected domain.
Application root: Shows the absolute document/application root used for relative process paths.
Permissions: Shows the current user's effective Node Manager permission level.
Processes Tab
Process row: Opens the process detail drawer.
Start: Starts a stopped PM2 process.
Stop: Stops a running process.
Restart: Restarts the process with PM2.
Reload: Performs a PM2 reload where supported.
Scale: Updates the process instance count.
Delete: Removes the PM2 process and extension metadata after confirmation.
Create Process Page
Name: PM2 application name.
Script path: JavaScript entry file. Browse opens the domain-scoped file picker, and selecting a file fills this field.
Working directory: Process working directory. Browse opens directories inside the selected domain root.
Environment: PM2 environment name, such as production.
Instances: Number of PM2 instances to run.
Max restarts: Optional restart limit passed to PM2.
Restart delay, ms: Optional delay before PM2 restarts the process.
Git branch: Deployment branch used by the Deploy tab.
Autorestart if the process exits: Enables or disables PM2 autorestart.
Create and Start: Creates the config and starts the process.
File Picker And Editor
Document root: Returns to the selected domain root.
Up: Moves one directory up, but never outside the selected domain root.
Open: Opens a directory inside the picker.
Select: Selects a file or directory for the active form field.
Edit: Opens editable files in a Plesk drawer with the CodeEditor component.
Save: Writes the edited file content.
Close: Closes the drawer, with confirmation when changes are unsaved.
Runtime Tab
Use detected paths: Applies detected Node.js, npm, PM2, Git, and PM2 home values to settings.
Install or update PM2: Installs or updates PM2 using the detected runtime. The button is disabled while the action is running.
Runtime table: Shows Node.js, npm, PM2, and Git status, detected version, and resolved path.
PM2 home: Shows the PM2 home directory used for managed processes.
Settings Tab
Node binary path: Absolute path to node.
npm binary path: Absolute path to npm.
PM2 binary path: Absolute path to pm2.
Git binary path: Absolute path to git.
PM2 home: Directory used by PM2 for process state.
Extra PATH: Additional PATH entries for PM2 commands.
Polling interval: Process and metrics refresh interval.
Max log bytes: Maximum bytes read from stdout/stderr in the log drawer.
Metrics retention days: How long sampled CPU and memory metrics are kept.
Deployment timeout: Maximum deployment command runtime.
Save Settings: Persists settings for the extension.
Backups Tab
Create Backup: Exports extension-managed metadata and settings.
Restore: Imports a previous backup.
Delete: Removes a backup archive.
Backup list: Shows backup name, creation time, size, and available actions.
Process Detail Drawer
Logs: View stdout or stderr, refresh, clear by truncating the log file, and download logs.
Env: Add, edit, save, mark secret, or delete environment variables.
Deploy: Pull from Git, optionally run npm install, choose production dependencies, and reload after deployment.
Ecosystem: Edit the PM2 ecosystem configuration, save it, or save and start the process.
Metrics: View CPU and memory chart data plus the latest five metric samples by default.
Requirements
Plesk Obsidian 18.0.34 or newer on Linux.
Physical hosting enabled for domains that will run Node.js apps.
Plesk Node.js extension or another Node.js/npm runtime available on the server.
SQLite PDO extension available to the Plesk PHP runtime.
Git installed for deployment features.
PM2 installed globally or installed from the extension runtime page by an administrator.
Installation
Install the latest runner-built package directly from GitHub:
plesk bin extension --install-url https://github.com/ghostcompiler/node-manager-pm2/releases/download/latest/node-manager-pm2.zip
This URL points to the rolling latest release asset. The Package Latest workflow rebuilds node-manager-pm2.zip from the current main branch on every push and whenever it is started manually, so the install command stays stable and does not depend on a hardcoded version number.
Pinned version installs are also available after publishing a versioned release:
plesk bin extension --install-url https://github.com/ghostcompiler/node-manager-pm2/releases/download/v1.0.0/node-manager-pm2-1.0.0.zip
Build the extension ZIP locally:
./packaging/build.sh
Install the locally built archive through Plesk CLI:
plesk bin extension --install node-manager-pm2-1.0.0.zip
Or install through Plesk UI:
Open Plesk Admin.
Go to Extensions.
Click Upload Extension.
Upload node-manager-pm2-1.0.0.zip.
Open Node Manager (PM2) from the Plesk sidebar or a domain page.
Testing
Run the same local checks used by the CI runner:
npm ci --ignore-scripts --legacy-peer-deps
npm run build
find plib htdocs -type f \( -name '*.php' -o -name '*.phtml'\) -print0 | xargs -0 -n1 php -l
xmllint --noout meta.xml
node -e "JSON.parse(require('fs').readFileSync('packaging/manifest.json', 'utf8'))"
sh -n packaging/build.sh
sh -n sbin/pm2-helper
./packaging/build.sh
zip -T node-manager-pm2-1.0.0.zip
GitHub Actions runners are included:
CI runs on every branch push, pull request, and manual dispatch. It validates PHP, JavaScript, documentation screenshots, metadata, shell scripts, builds the extension, tests the ZIP, and uploads package artifacts.
Package Latest runs on main and manual dispatch. It builds and publishes the stable node-manager-pm2.zip asset to the rolling latest GitHub release.
Release runs on v<version> tags and manual dispatch. It verifies the tag matches meta.xml, builds node-manager-pm2-<version>.zip, and publishes the versioned release.
Pages runs when documentation changes on main and manual dispatch. It validates docs/index.html screenshot references and deploys the docs/ folder to GitHub Pages.
First Run
Open the affected service plan or subscription.
Enable Node Manager (PM2) access.
Enable the needed action permissions: control, logs, and manage.
Set Maximum PM2 applications to a non-zero value for subscriptions that can create processes.
Sync existing subscriptions if Plesk marks them as customized or out of sync.
Open Node Manager (PM2) as admin, reseller, or customer.
Review the Runtime tab and install PM2 if needed.
Example SSR Process
For a subdomain such as assets.example.com where the app root is:
/var/www/vhosts/example.com/assets.example.com
Use:
Name: assets-ssr
Script path: server.js
Working directory: .
Environment: production
Instances: 1
Autorestart: enabled
The extension resolves relative paths from the selected domain application root, so server.js becomes:
Resellers and customers only see domains where Node Manager access is enabled.
Customer and reseller access is controlled by Plesk service plan permissions.
Process script and working-directory paths are locked inside the selected domain application root.
PM2 commands run under the selected domain system user when Plesk pm_ApiCli::callDomain() is available.
The extension stores PM2 metadata and secrets in SQLite under the Plesk module var directory.
Development Notes
PHP classes live in plib/library/NodeManagerPm2.
Authenticated UI and JSON APIs are served by plib/controllers/IndexController.php.
The Plesk React UI Library bundle lives in frontend/ and is built to
htdocs/dist/node-manager-pm2-ui.js.
The public deployment webhook lives at htdocs/public/webhook.php.
Persistent state is stored in SQLite under the module var directory.
Package configuration lives in packaging/manifest.json and packaging/build.sh.
See docs/INSTALL.md, docs/SECURITY.md, docs/API.md, and docs/ARCHITECTURE.md for operational details.
Development Environment
Built using ServBay
Mac M4 Tested
macOS Apple Silicon
Powered by ServBay
Filesmain
Repository Files
Loading file structure...
Select a file from the repository tree to inspect its code.
htdocs/dist/node-manager-pm2-ui.js
define(["plesk-ui-library"],e=>(()=>{var t={362(e,t,n){"use strict";var r=n(441);function a(){}function o(){}o.resetWarningCache=a,e.exports=function(){function e(e,t,n,a,o,l){if(l!==r){var c=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw c.name="Invariant Violation",c}}function t(){return e}e.isRequired=e;var n={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:o,resetWarningCache:a};return n.PropTypes=n,n}},688(e,t,n){e.exports=n(362)()},441(e){"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},280(t){"use strict";t.exports=e}},n={};function r(e){var a=n[e];if(void 0!==a)return a.exports;var o=n[e]={exports:{}};return t[e](o,o.exports,r),o.exports}var a={};return(()=>{"use strict";var e=a;Object.defineProperty(e,"__esModule",{value:!0}),e.mount=e.default=void 0;var t,n=r(280),o=r(280),l=r(280),c=(t=r(688))&&t.__esModule?t:{default:t};function i(e){return i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},i(e)}function s(){return s=Object.assign?Object.assign.bind():function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)({}).hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},s.apply(null,arguments)}function m(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=n){var r,a,o,l,c=[],i=!0,s=!1;try{if(o=(n=n.call(e)).next,0===t){if(Object(n)!==n)return;i=!1}else for(;!(i=(r=o.call(n)).done)&&(c.push(r.value),c.length!==t);i=!0);}catch(e){s=!0,a=e}finally{try{if(!i&&null!=n.return&&(l=n.return(),Object(l)!==l))return}finally{if(s)throw a}}return c}}(e,t)||function(e,t){if(e){if("string"==typeof e)return u(e,t);var n={}.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?u(e,t):void 0}}(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function u(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}function d(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter(function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable})),n.push.apply(n,r)}return n}function p(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?d(Object(n),!0).forEach(function(t){f(e,t,n[t])}):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):d(Object(n)).forEach(function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))})}return e}function f(e,t,n){return(t=function(e){var t=function(e){if("object"!=i(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var n=t.call(e,"string");if("object"!=i(n))return n;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==i(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var h={admin:!1,canInstallPm2:!1,canManage:!1,canControl:!1,canLogs:!1},v={name:"",scriptPath:"",cwd:".",envName:"production",instances:1,autorestart:!0,maxRestarts:"",restartDelay:"",gitRepo:"",gitBranch:"main"},E={npmInstall:!0,production:!0,reload:!0},g={open:!1,loading:!1,field:"",mode:"file",title:"",currentPath:"",currentValue:".",parentValue:null,rootPath:"",homePath:"",entries:[],error:""},y=[10,25,100,"all"],b=[5,10,25,100,"all"],N=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=new URLSearchParams;Object.keys(t).forEach(function(e){null!==t[e]&&void 0!==t[e]&&""!==t[e]&&n.set(e,t[e])});var r=n.toString();return r?"".concat(e).concat(-1===e.indexOf("?")?"?":"&").concat(r):e},k=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=p({credentials:"same-origin",headers:p({"X-Requested-With":"XMLHttpRequest"},t.headers||{})},t);return fetch(e,n).then(function(e){return e.text().then(function(t){var n;try{n=t?JSON.parse(t):{}}catch(t){n={success:!1,error:{message:"".concat(e.status," ").concat(e.statusText,". The server returned a non-JSON response. Check the Plesk extension log for PHP errors.")}}}return e.ok||!1===n.success||(n={success:!1,error:{message:"".concat(e.status," ").concat(e.statusText)}}),{data:n}})})},w=function(e){if(!e.data||!e.data.success){var t=e.data&&e.data.error?e.data.error.message:"Request failed.";throw new Error(t)}return e.data.data},S=function(e){var t=Number(e||0);return t<1024?"".concat(t," B"):t<1048576?"".concat((t/1024).toFixed(1)," KB"):t<1073741824?"".concat((t/1048576).toFixed(1)," MB"):"".concat((t/1073741824).toFixed(1)," GB")},P=function(e){var t=String(e||"").toLowerCase();return"online"===t||"ready"===t?"success":"stopped"===t||"waiting restart"===t?"warning":"errored"===t||"missing"===t?"danger":"info"},C=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:10,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:y,a=m((0,n.useState)(1),2),o=a[0],c=a[1],i=m((0,n.useState)(t),2),s=i[0],u=i[1],d=function(e,t){return e.length&&"all"!==t?Math.max(1,Math.ceil(e.length/t)):1}(e,s);(0,n.useEffect)(function(){o>d&&c(d)},[o,d]);var p=(0,n.useMemo)(function(){return function(e,t,n){if("all"===n)return e;var r=(t-1)*n;return e.slice(r,r+n)}(e,o,s)},[e,o,s]);return{pagination:e.length?(0,n.createElement)(l.Pagination,{current:o,itemsPerPage:s,itemsPerPageOptions:r,onItemsPerPageChange:function(e){u(e),c(1)},onSelect:c,total:d}):null,visibleRows:p}},B=function(e){var t=e.message,r=e.intent;return t?(0,n.createElement)("div",{className:"nm-ui-message nm-ui-message-".concat(r)},t):null};B.propTypes={intent:c.default.string,message:c.default.string},B.defaultProps={intent:"info",message:""};var I=function(e){var t=e.active,r=e.items,a=e.onSelect,o=r.filter(function(e){return!e.hidden});return o.length?(0,n.createElement)("div",{className:"nm-tabs",role:"tablist"},o.map(function(e){return(0,n.createElement)("button",{key:e.key,type:"button",className:"nm-tab".concat(e.key===t?" nm-tab-active":""),onClick:function(){return a(e.key)},role:"tab","aria-selected":e.key===t?"true":"false"},e.title)})):null};I.propTypes={active:c.default.string.isRequired,items:c.default.arrayOf(c.default.shape({hidden:c.default.bool,key:c.default.string,title:c.default.string})).isRequired,onSelect:c.default.func.isRequired};var M=function(e){var t=e.title,r=e.description,a=e.icon;return(0,n.createElement)("div",{className:"nm-empty-view"},(0,n.createElement)(l.Icon,{name:a}),(0,n.createElement)("div",null,(0,n.createElement)("strong",null,t),r&&(0,n.createElement)("span",null,r)))};M.propTypes={description:c.default.string,icon:c.default.string,title:c.default.string.isRequired},M.defaultProps={description:"",icon:"info-circle"};var O=function(e){var t=e.className;return(0,n.createElement)("span",{className:"nm-skeleton ".concat(t||"")})};O.propTypes={className:c.default.string},O.defaultProps={className:""};var R=function(){return(0,n.createElement)("div",{className:"nm-skeleton-stack","aria-label":"Loading PM2 workspace","aria-busy":"true"},(0,n.createElement)("div",{className:"nm-panel nm-domain-card"},(0,n.createElement)("div",{className:"nm-domain-grid"},(0,n.createElement)("div",{className:"nm-field"},(0,n.createElement)(O,{className:"nm-skeleton-label"}),(0,n.createElement)(O,{className:"nm-skeleton-input"})),(0,n.createElement)("div",{className:"nm-field"},(0,n.createElement)(O,{className:"nm-skeleton-label"}),(0,n.createElement)(O,{className:"nm-skeleton-text"})),(0,n.createElement)("div",{className:"nm-field nm-field-root"},(0,n.createElement)(O,{className:"nm-skeleton-label"}),(0,n.createElement)(O,{className:"nm-skeleton-path"})),(0,n.createElement)("div",{className:"nm-field"},(0,n.createElement)(O,{className:"nm-skeleton-label"}),(0,n.createElement)(O,{className:"nm-skeleton-short"})))),(0,n.createElement)("div",{className:"nm-skeleton-tabs"},(0,n.createElement)(O,{className:"nm-skeleton-tab"}),(0,n.createElement)(O,{className:"nm-skeleton-tab"}),(0,n.createElement)(O,{className:"nm-skeleton-tab"}),(0,n.createElement)(O,{className:"nm-skeleton-tab"})),(0,n.createElement)("div",{className:"nm-stat-grid"},[0,1,2,3,4].map(function(e){return(0,n.createElement)("div",{className:"nm-stat-card",key:e},(0,n.createElement)(O,{className:"nm-skeleton-label"}),(0,n.createElement)(O,{className:"nm-skeleton-number"}))})),(0,n.createElement)("div",{className:"nm-panel nm-skeleton-table"},[0,1,2,3,4].map(function(e){return(0,n.createElement)("div",{className:"nm-skeleton-row",key:e},(0,n.createElement)(O,{className:"nm-skeleton-cell-wide"}),(0,n.createElement)(O,{className:"nm-skeleton-cell"}),(0,n.createElement)(O,{className:"nm-skeleton-cell"}),(0,n.createElement)(O,{className:"nm-skeleton-cell"}))})))},x=function(e){var t=e.metrics.slice(-48),r=t.reduce(function(e,t){return Math.max(e,Number(t.memory||0))},1),a=function(e,n){if(!t.length)return"";if(1===t.length){var r=164-Math.max(0,Math.min(Number(t[0][e]||0),n||1))/Math.max(n||1,1)*140;return"0,".concat(r.toFixed(1)," 600,").concat(r.toFixed(1))}var a=Math.max(n||1,1);return t.map(function(n,r){var o=r/(t.length-1)*600,l=164-Math.max(0,Math.min(Number(n[e]||0),a))/a*140;return"".concat(o.toFixed(1),",").concat(l.toFixed(1))}).join(" ")};return(0,n.createElement)("div",{className:"nm-panel nm-view-card"},(0,n.createElement)("div",{className:"nm-panel-header"},(0,n.createElement)("div",null,(0,n.createElement)("h3",null,"CPU and memory"),(0,n.createElement)("p",{className:"nm-muted"},t.length," sample",1===t.length?"":"s")),(0,n.createElement)("div",{className:"nm-metric-legend"},(0,n.createElement)("span",null,(0,n.createElement)("i",{className:"nm-legend-cpu"})," CPU"),(0,n.createElement)("span",null,(0,n.createElement)("i",{className:"nm-legend-memory"})," Memory"))),(0,n.createElement)("svg",{className:"nm-metric-chart",viewBox:"0 0 600 180",preserveAspectRatio:"none","aria-hidden":"true"},[24,59,94,129,164].map(function(e){return(0,n.createElement)("line",{key:e,x1:"0",y1:e,x2:"600",y2:e,className:"grid"})}),t.length>0&&(0,n.createElement)("polyline",{points:a("memory",r),className:"memory"}),t.length>0&&(0,n.createElement)("polyline",{points:a("cpu",100),className:"cpu"})),!t.length&&(0,n.createElement)("p",{className:"nm-muted"},"No metrics collected yet."))};x.propTypes={metrics:c.default.arrayOf(c.default.object).isRequired};var T=function(e){var t=e.metrics,r=C(t.slice().reverse(),5,b),a=r.pagination,o=r.visibleRows,c=[{key:"collected_at",title:"Time",width:"44%"},{key:"status",title:"Status",width:"20%",render:function(e){return(0,n.createElement)(l.Status,{intent:P(e.status),compact:!0},e.status||"unknown")}},{key:"cpu",title:"CPU",width:"14%",render:function(e){return"".concat(e.cpu||0,"%")}},{key:"memory",title:"Memory",width:"22%",render:function(e){return S(e.memory)}}];return(0,n.createElement)("div",{className:"nm-detail-stack"},(0,n.createElement)(x,{metrics:t}),(0,n.createElement)(l.List,{columns:c,data:o,emptyView:(0,n.createElement)(M,{title:"No metrics found",description:"Metrics are collected while process status is refreshed.",icon:"graph"}),emptyViewMode:"items",pagination:a,rowKey:"id",totalRows:t.length}))};T.propTypes={metrics:c.default.arrayOf(c.default.object).isRequired};var L=function(e){return(0,n.createElement)("input",s({className:"nm-native-input"},e))},j=function(e){var t=e.config,r=t.endpoints||{},a=(0,n.useRef)(null),o=(0,n.useRef)(null),c=(0,n.useRef)(null),i=(0,n.useRef)(""),s=(0,n.useRef)(""),u=(0,n.useRef)({}),d=m((0,n.useState)(!0),2),y=d[0],b=d[1],x=m((0,n.useState)(!1),2),j=x[0],A=x[1],D=m((0,n.useState)(""),2),V=D[0],_=D[1],U=m((0,n.useState)({}),2),q=U[0],F=U[1],Y=m((0,n.useState)(!0),2),z=Y[0],W=Y[1],G=m((0,n.useState)(""),2),H=G[0],K=G[1],J=m((0,n.useState)([]),2),X=J[0],$=J[1],Q=m((0,n.useState)(t.initialDomainId||null),2),Z=Q[0],ee=Q[1],te=m((0,n.useState)(Boolean(t.domainLocked)),2),ne=te[0],re=te[1],ae=m((0,n.useState)(h),2),oe=ae[0],le=ae[1],ce=m((0,n.useState)({}),2),ie=ce[0],se=ce[1],me=m((0,n.useState)(null),2),ue=me[0],de=me[1],pe=m((0,n.useState)([]),2),fe=pe[0],he=pe[1],ve=m((0,n.useState)([]),2),Ee=ve[0],ge=ve[1],ye=m((0,n.useState)("processes"),2),be=ye[0],Ne=ye[1],ke=m((0,n.useState)(!1),2),we=ke[0],Se=ke[1],Pe=m((0,n.useState)(v),2),Ce=Pe[0],Be=Pe[1],Ie=m((0,n.useState)(g),2),Me=Ie[0],Oe=Ie[1],Re=m((0,n.useState)(null),2),xe=Re[0],Te=Re[1],Le=m((0,n.useState)("logs"),2),je=Le[0],Ae=Le[1],De=m((0,n.useState)("stdout"),2),Ve=De[0],_e=De[1],Ue=m((0,n.useState)(12e4),1)[0],qe=m((0,n.useState)(""),2),Fe=qe[0],Ye=qe[1],ze=m((0,n.useState)(null),2),We=ze[0],Ge=ze[1],He=m((0,n.useState)([]),2),Ke=He[0],Je=He[1],Xe=m((0,n.useState)([]),2),$e=Xe[0],Qe=Xe[1],Ze=m((0,n.useState)({name:"",value:"",isSecret:!1}),2),et=Ze[0],tt=Ze[1],nt=m((0,n.useState)({path:"",content:""}),2),rt=nt[0],at=nt[1],ot=m((0,n.useState)(E),2),lt=ot[0],ct=ot[1],it=m((0,n.useState)({enabled:!1,url:"",token:""}),2),st=it[0],mt=it[1],ut=m((0,n.useState)([]),2),dt=ut[0],pt=ut[1],ft=m((0,n.useState)({open:!1,path:"",value:"",content:"",originalContent:"",loading:!1,saving:!1,error:""}),2),ht=ft[0],vt=ft[1],Et=(0,n.useMemo)(function(){var e=String(Z||"");return X.find(function(t){return String(t.id)===e})||null},[X,Z]),gt=Boolean(ue&&ue.ready),yt=Boolean(ue&&ue.nodeReady),bt=Boolean(ue&&ue.pm2Ready),Nt=Boolean(ue&&!gt),kt=Et&&Et.permissions?Et.permissions:{},wt=Boolean(oe.admin||oe.canManage||kt.manage),St=Boolean(oe.admin||oe.canControl||kt.control),Pt=Boolean(oe.admin||oe.canLogs||kt.logs),Ct=Et&&(Et.documentRoot||Et.homePath)||"",Bt=xe&&xe.appId?xe.appId:"",It=(0,n.useMemo)(function(){var e=0,t=0,n=0,r=0;return Ee.forEach(function(a){"online"===a.status&&(e+=1),t+=Number(a.memory||0),n+=Number(a.cpu||0),r+=Number(a.restarts||0)}),{total:Ee.length,online:e,memory:t,cpu:Math.round(100*n)/100,restarts:r}},[Ee]),Mt=C(Ee,10);function Ot(e,t){a.current&&"function"==typeof a.current.add&&a.current.add({intent:e,message:t})}function Rt(e){Ot("danger",e&&e.message?e.message:"Request failed.")}function xt(e){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=function(){var e=document.querySelector('meta[name="forgery_protection_token"], meta#forgery_protection_token');if(e&&e.getAttribute("content"))return e.getAttribute("content");var t=document.querySelector('input[name="forgery_protection_token"]');return t&&t.value?t.value:""}(),a=r&&!n.forgery_protection_token?p(p({},n),{},{forgery_protection_token:r}):n,o={"Content-Type":"application/json","X-Node-Manager-CSRF":t.csrf||""};return r&&(o["X-Forgery-Protection-Token"]=r),k(e,{method:"POST",headers:o,body:JSON.stringify(a)})}function Tt(e){return k(e,{method:"GET"})}function Lt(){return b(!0),Tt(N(r.bootstrap,{domainId:t.initialDomainId||"",contextDomainId:t.domainContextId||""})).then(w).then(function(e){var n=e.domains||[],r=!1!==e.accessEnabled,a=e.runtime||null;return $(n),W(r),K(e.accessMessage||""),ee(e.selectedDomainId),re(Boolean(e.domainLocked||t.domainLocked)),le(e.permissions||h),se(e.settings||{}),de(a),he(e.alerts||[]),r?a&&a.ready?(Ne("processes"),At(!0,e.selectedDomainId)):(ge([]),Te(null),Ne("runtime"),null):(ge([]),Te(null),Ne("disabled"),null)}).catch(Rt).finally(function(){return b(!1)})}function jt(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:Z;return e?xt(r.runtime,{domainId:e}).then(w).then(function(e){return de(e.runtime||null),e.runtime&&e.runtime.ready||Ne("runtime"),e.runtime||null}).catch(Rt):Promise.resolve(null)}function At(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Z;return t?(e||A(!0),Tt(N(r.processes,{domainId:t})).then(w).then(function(e){var t=e.processes||[];return ge(t),Te(function(e){return e?t.find(function(t){return t.pm2Name===e.pm2Name})||null:e}),t}).catch(Rt).finally(function(){e||A(!1)})):Promise.resolve(null)}function Dt(){return s.current?Promise.resolve(null):(s.current="paths",_("paths"),A(!0),xt(r.runtime,{domainId:Z,applyDetectedPaths:!0}).then(w).then(function(e){return de(e.runtime||null),se(e.settings||ie),Ot("success","Detected runtime paths applied."),e.runtime&&e.runtime.ready?At(!0):null}).catch(Rt).finally(function(){s.current="",_(""),A(!1)}))}function Vt(){return s.current?Promise.resolve(null):(s.current="pm2",_("pm2"),A(!0),xt(r.runtime,{domainId:Z,installPm2:!0}).then(w).then(function(e){return de(e.runtime||null),Ot("success","PM2 install/update completed."),e.runtime&&e.runtime.ready?(Ne("processes"),At(!0)):null}).catch(Rt).finally(function(){s.current="",_(""),A(!1)}))}function _t(e){if(Se(!1),!gt&&"runtime"!==e)return Ne("runtime"),void Rt(new Error("Install PM2 before opening this section."));Ne(e)}function Ut(e,t){if("delete"===t&&!wt)return Rt(new Error("You do not have permission to delete PM2 applications for this domain.")),Promise.resolve();if("delete"!==t&&!St)return Rt(new Error("You do not have permission to control PM2 processes for this domain.")),Promise.resolve();var n="".concat(e.pm2Name,":").concat(t);return u.current[n]?Promise.resolve():(u.current[n]=!0,F(function(e){return p(p({},e),{},f({},n,!0))}),A(!0),xt(r.process,{domainId:Z,pm2Name:e.pm2Name,action:t}).then(w).then(function(){return Ot("success","Action completed."),At(!0)}).catch(Rt).finally(function(){delete u.current[n],F(function(e){var t=p({},e);return delete t[n],t}),A(!1)}))}function qt(e,t){if(!St)return Rt(new Error("You do not have permission to scale PM2 processes for this domain.")),Promise.resolve();var n=Math.max(1,Number(e.instances||1)+t);return A(!0),xt(r.process,{domainId:Z,pm2Name:e.pm2Name,action:"scale",instances:n}).then(w).then(function(){return Ot("success","Scale updated."),At(!0)}).catch(Rt).finally(function(){return A(!1)})}function Ft(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;Te(e),Yt(t||(Pt?"logs":"metrics"),e)}function Yt(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:xe;t&&("env"!==e&&"deploy"!==e&&"ecosystem"!==e||t.appId?Ae(e):Rt(new Error("This PM2 process was not created or imported by Node Manager for this domain yet. Delete and recreate it from this domain to manage environment, deployment, and ecosystem settings.")))}function zt(){var e=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return xe&&Pt?Tt(N(r.logs,{domainId:Z,pm2Name:xe.pm2Name,stream:Ve,bytes:Ue})).then(w).then(function(t){return Ye(t.content||""),Ge(t),e||window.setTimeout(function(){var e=document.querySelector(".nm-terminal");e&&(e.scrollTop=e.scrollHeight)},0),t}).catch(Rt):Promise.resolve(null)}function Wt(e){wt?xt(r.ecosystem,{domainId:Z,appId:Bt,content:rt.content,start:Boolean(e)}).then(w).then(function(t){return at(t||rt),Ot("success",e?"Ecosystem started.":"Ecosystem saved."),At(!0)}).catch(Rt):Rt(new Error("You do not have permission to edit ecosystem configs for this domain."))}function Gt(e){wt?xt(r.webhook,{domainId:Z,appId:Bt,enabled:e}).then(w).then(function(e){mt({enabled:Boolean(e.enabled),url:e.url||"",token:e.token||""}),Ot("success","Webhook updated.")}).catch(Rt):Rt(new Error("You do not have permission to manage webhooks for this domain."))}function Ht(){return xt(r.backup,{}).then(w).then(function(e){return pt(e.backups||[]),e.backups||[]}).catch(Rt)}function Kt(e,t){Be(function(n){return p(p({},n),{},f({},e,t))})}function Jt(e,t){if(wt){var n="directory"===t?"Select working directory":"Select script file";Oe(p(p({},g),{},{open:!0,field:e,mode:t,title:n})),$t(function(e,t){var n=Ce[e]||"";if(!n)return".";if("directory"===t)return n;var r=n.lastIndexOf("/");return-1===r?".":0===r?"/":n.slice(0,r)}(e,t),t)}else Rt(new Error("You do not have permission to browse files for this domain."))}function Xt(){Oe(g)}function $t(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:Me.mode;return Oe(function(e){return p(p({},e),{},{loading:!0,error:""})}),Tt(N(r.browse,{domainId:Z,mode:t,path:e||"."})).then(w).then(function(e){Oe(function(t){return p(p({},t),{},{currentPath:e.currentPath||"",currentValue:e.currentValue||".",parentValue:e.parentValue||null,rootPath:e.rootPath||"",homePath:e.homePath||"",entries:e.entries||[],loading:!1})})}).catch(function(e){Oe(function(t){return p(p({},t),{},{error:e&&e.message?e.message:"Unable to browse files.",loading:!1})})})}function Qt(e){"directory"!==e.type?e.selectable&&(Kt(Me.field,e.value),Xt()):$t(e.value)}function Zt(){vt({open:!1,path:"",value:"",content:"",originalContent:"",loading:!1,saving:!1,error:""})}(0,n.useEffect)(function(){return Lt(),function(){o.current&&clearInterval(o.current),c.current&&clearInterval(c.current)}},[]),(0,n.useEffect)(function(){if(fe.length){var e="".concat(fe.length," alert").concat(1===fe.length?"":"s",": ").concat(fe.slice(0,3).map(function(e){return e.message}).join(" "));i.current!==e&&(i.current=e,Ot("warning",e))}else i.current=""},[fe]),(0,n.useEffect)(function(){if(o.current&&(clearInterval(o.current),o.current=null),z&>&&"processes"===be){var e=Math.max(3e3,Number(ie.pollInterval||5e3));return o.current=setInterval(function(){return At(!0)},e),function(){o.current&&clearInterval(o.current),o.current=null}}},[z,gt,be,Z,ie.pollInterval]),(0,n.useEffect)(function(){"backups"===be&>&&oe.admin&&Ht()},[be,gt,oe.admin]),(0,n.useEffect)(function(){if(c.current&&(clearInterval(c.current),c.current=null),xe)return"logs"===je&&(zt(),c.current=setInterval(function(){return zt(!0)},2500)),"metrics"===je&&(xe?Tt(N(r.metrics,{domainId:Z,pm2Name:xe.pm2Name})).then(w).then(function(e){return Je(e.metrics||[]),e.metrics||[]}).catch(function(){return null}):Promise.resolve(null)),"env"===je&&(Bt&&wt?Tt(N(r.env,{domainId:Z,appId:Bt})).then(w).then(function(e){return Qe(e.env||[]),e.env||[]}).catch(Rt):Promise.resolve(null)),"ecosystem"===je&&(Bt&&wt?Tt(N(r.ecosystem,{domainId:Z,appId:Bt})).then(w).then(function(e){return at(e||{path:"",content:""}),e}).catch(Rt):Promise.resolve(null)),xe.appId||(Qe([]),at({path:"",content:""})),function(){c.current&&clearInterval(c.current),c.current=null}},[xe?xe.pm2Name:"",je,Ve]);var en=["node","npm","pm2","git"].map(function(e){return p({key:e},ue&&ue.items&&ue.items[e]?ue.items[e]:{})}),tn=z?[{key:"processes",title:"Processes",hidden:!gt},{key:"runtime",title:"Runtime"},{key:"settings",title:"Settings",hidden:!gt||!oe.admin},{key:"backups",title:"Backups",hidden:!gt||!oe.admin}]:[],nn=[{key:"name",title:"Name",type:"title",width:"30%",render:function(e){return(0,n.createElement)("span",null,(0,n.createElement)("strong",null,e.name||e.pm2Name),(0,n.createElement)("small",{className:"nm-muted nm-path"},e.scriptPath||"-"))}},{key:"status",title:"Status",width:130,render:function(e){return(0,n.createElement)(l.Status,{intent:P(e.status),compact:!0},e.status||"unknown")}},{key:"execMode",title:"Mode",width:120},{key:"cpu",title:"CPU",width:90,render:function(e){return"".concat(e.cpu||0,"%")}},{key:"memory",title:"Memory",width:110,render:function(e){return S(e.memory)}},{key:"uptime",title:"Uptime",width:100,render:function(e){return t=e.uptime,n=Number(t||0),r=Math.floor(n/86400),a=Math.floor(n%86400/3600),o=Math.floor(n%3600/60),r?"".concat(r,"d ").concat(a,"h"):a?"".concat(a,"h ").concat(o,"m"):"".concat(o,"m");var t,n,r,a,o}},{key:"restarts",title:"Restarts",width:100},{key:"instances",title:"Instances",type:"controls",width:150,render:function(e){return(0,n.createElement)("div",{className:"nm-inline-actions",onClick:function(e){return e.stopPropagation()}},St&&(0,n.createElement)(l.Button,{icon:"minus",tooltip:"Decrease instances",tooltipAsLabel:!0,onClick:function(){return qt(e,-1)}}),(0,n.createElement)("strong",null,e.instances||1),St&&(0,n.createElement)(l.Button,{icon:"plus",tooltip:"Increase instances",tooltipAsLabel:!0,onClick:function(){return qt(e,1)}}))}},{key:"actions",title:"Actions",type:"actions",width:280,render:function(e){return(0,n.createElement)("div",{onClick:function(e){return e.stopPropagation()}},(0,n.createElement)(l.ListActions,null,Pt&&(0,n.createElement)(l.ListAction,{onClick:function(){return Ft(e,"logs")}},"Logs"),St&&(0,n.createElement)(l.ListAction,{disabled:Boolean(q["".concat(e.pm2Name,":start")]),onClick:function(){return Ut(e,"start")}},"Start"),St&&(0,n.createElement)(l.ListAction,{disabled:Boolean(q["".concat(e.pm2Name,":stop")]),onClick:function(){return Ut(e,"stop")}},"Stop"),St&&(0,n.createElement)(l.ListAction,{disabled:Boolean(q["".concat(e.pm2Name,":restart")]),onClick:function(){return Ut(e,"restart")}},"Restart"),St&&(0,n.createElement)(l.ListAction,{disabled:Boolean(q["".concat(e.pm2Name,":reload")]),onClick:function(){return Ut(e,"reload")}},"Reload"),wt&&(0,n.createElement)(l.ListAction,{disabled:Boolean(q["".concat(e.pm2Name,":delete")]),onClick:function(){return Ut(e,"delete")}},"Delete")))}}],rn=[{key:"name",title:"Runtime",width:"18%",render:function(e){return{node:"Node.js",npm:"npm",pm2:"PM2",git:"Git"}[t=e.key]||t;var t}},{key:"status",title:"Status",width:120,render:function(e){return(0,n.createElement)(l.Status,{intent:e.available?"success":"danger",compact:!0},e.available?"Ready":"Missing")}},{key:"version",title:"Detected version",width:"30%",render:function(e){return e.version||"Not detected"}},{key:"path",title:"Path",render:function(e){return(0,n.createElement)("span",null,e.path||e.launcher||e.detected||"-",e.error&&(0,n.createElement)("small",{className:"nm-error-line"},e.error))}}],an=[{key:"name",title:"Name",type:"title",width:"30%"},{key:"value",title:"Value",render:function(e){return e.is_secret?"Stored encrypted":e.value}},{key:"actions",title:"Actions",type:"actions",width:90,render:function(e){return(0,n.createElement)(l.ListActions,null,(0,n.createElement)(l.ListAction,{onClick:function(){return function(e){wt?xt(r.env,{domainId:Z,appId:Bt,name:e.name,delete:!0}).then(w).then(function(e){Qe(e.env||[]),Ot("success","Environment updated.")}).catch(Rt):Rt(new Error("You do not have permission to edit environment variables for this domain."))}(e)}},"Delete"))}}],on=[{key:"name",title:"Name",type:"title"},{key:"size",title:"Size",width:120,render:function(e){return S(e.size)}},{key:"createdAt",title:"Created",width:220},{key:"actions",title:"Actions",type:"actions",width:100,render:function(e){return(0,n.createElement)(l.ListActions,null,(0,n.createElement)(l.ListAction,{onClick:function(){return t=e,void xt(r.backup,{restore:t.name}).then(w).then(function(){return Ot("success","Backup restored."),Lt()}).catch(Rt);var t}},"Restore"))}}];return(0,n.createElement)(n.Fragment,null,(0,n.createElement)(l.Toaster,{ref:a,position:"top-end"}),(0,n.createElement)("div",{className:"nm-app nm-ui"},(0,n.createElement)("div",{className:"nm-top-actions"},(0,n.createElement)(l.Button,{icon:"info-circle",component:"a",href:t.infoUrl||"#"},"Info"),(0,n.createElement)(l.Button,{icon:"refresh",disabled:y,onClick:function(){return z?(A(!0),jt().then(function(e){return e&&e.ready?At(!0):null}).finally(function(){return A(!1)})):Lt()},state:j?"loading":void 0},"Refresh"),gt&&wt&&(0,n.createElement)(l.Button,{icon:"plus",intent:"primary",onClick:function(){return Se(!0)}},"New Process")),y?(0,n.createElement)(R,null):(0,n.createElement)(n.Fragment,null,!z&&(0,n.createElement)("div",{className:"nm-panel nm-state-panel"},(0,n.createElement)(l.Icon,{name:"lock-closed"}),(0,n.createElement)("div",null,(0,n.createElement)("h3",null,"Node Manager (PM2) is not enabled"),(0,n.createElement)("p",null,H||"Ask the server administrator to enable Node Manager (PM2) for this subscription or service plan."))),z&&(0,n.createElement)("div",{className:"nm-panel nm-domain-card"},(0,n.createElement)("div",{className:"nm-domain-grid"},(0,n.createElement)("label",{className:"nm-field nm-field-domain"},(0,n.createElement)("span",null,"Domain"),ne?(0,n.createElement)(L,{readOnly:!0,value:Et?Et.name:"Selected domain"}):(0,n.createElement)("select",{className:"nm-native-input",value:null==Z?"":String(Z),onChange:function(e){return n=e.target.value,void(ne?ee(t.domainContextId||Z):(Se(!1),ee(n),Te(null),Ye(""),jt(n).then(function(e){e&&e.ready?(Ne("processes"),At(!1,n)):(Ne("runtime"),ge([]))})));var n}},X.map(function(e){return(0,n.createElement)("option",{key:e.id,value:String(e.id)},e.name)}))),(0,n.createElement)("div",{className:"nm-field"},(0,n.createElement)("span",null,"Subscription user"),(0,n.createElement)("strong",null,Et?Et.systemUser:"-")),(0,n.createElement)("div",{className:"nm-field nm-field-root"},(0,n.createElement)("span",null,"Application root"),(0,n.createElement)("strong",{className:"nm-path"},Ct||"-")),(0,n.createElement)("div",{className:"nm-field"},(0,n.createElement)("span",null,"Permissions"),(0,n.createElement)("strong",null,wt?"Manage":St?"Control":Pt?"Logs":"Access")))),z&&we&&(0,n.createElement)("div",{className:"nm-panel nm-view-card"},(0,n.createElement)("div",{className:"nm-panel-header"},(0,n.createElement)("div",null,(0,n.createElement)("h3",null,"Create PM2 process"),Ct&&(0,n.createElement)("p",{className:"nm-muted"},"Relative paths use ",Ct,".")),(0,n.createElement)("div",{className:"nm-card-actions"},(0,n.createElement)(l.Button,{onClick:function(){return Se(!1)}},"Cancel"),(0,n.createElement)(l.Button,{intent:"primary",onClick:function(){if(!j)return gt?void(wt?(A(!0),xt(r.createProcess,p(p({},Ce),{},{domainId:Z})).then(w).then(function(){return Ot("success","Process created."),Be(v),Se(!1),Ne("processes"),At(!0)}).catch(Rt).finally(function(){return A(!1)})):Rt(new Error("You do not have permission to create PM2 applications for this domain."))):(Ne("runtime"),void Rt(new Error("Complete runtime setup before creating a PM2 process.")))},state:j?"loading":void 0},"Create and Start"))),(0,n.createElement)("div",{className:"nm-form-grid"},(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Name"),(0,n.createElement)(L,{value:Ce.name,placeholder:"assets-ssr",onChange:function(e){return Kt("name",e.target.value)}})),(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Script path"),(0,n.createElement)("div",{className:"nm-input-action"},(0,n.createElement)(L,{value:Ce.scriptPath,placeholder:"server.js",onChange:function(e){return Kt("scriptPath",e.target.value)}}),(0,n.createElement)(l.Button,{icon:"folder",onClick:function(){return Jt("scriptPath","file")}},"Browse"))),(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Working directory"),(0,n.createElement)("div",{className:"nm-input-action"},(0,n.createElement)(L,{value:Ce.cwd,placeholder:".",onChange:function(e){return Kt("cwd",e.target.value)}}),(0,n.createElement)(l.Button,{icon:"folder-open",onClick:function(){return Jt("cwd","directory")}},"Browse"))),(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Environment"),(0,n.createElement)(L,{value:Ce.envName,placeholder:"production",onChange:function(e){return Kt("envName",e.target.value)}})),(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Instances"),(0,n.createElement)(L,{type:"number",min:"1",value:Ce.instances,onChange:function(e){return Kt("instances",e.target.value)}})),(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Max restarts"),(0,n.createElement)(L,{type:"number",min:"0",value:Ce.maxRestarts,onChange:function(e){return Kt("maxRestarts",e.target.value)}})),(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Restart delay, ms"),(0,n.createElement)(L,{type:"number",min:"0",value:Ce.restartDelay,onChange:function(e){return Kt("restartDelay",e.target.value)}})),(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Git repository"),(0,n.createElement)(L,{value:Ce.gitRepo,placeholder:"https://...",onChange:function(e){return Kt("gitRepo",e.target.value)}})),(0,n.createElement)("label",{className:"nm-field"},(0,n.createElement)("span",null,"Git branch"),(0,n.createElement)(L,{value:Ce.gitBranch,placeholder:"main",onChange:function(e){return Kt("gitBranch",e.target.value)}})),(0,n.createElement)("div",{className:"nm-field nm-field-wide"},(0,n.createElement)(l.Switch,{checked:Boolean(Ce.autorestart),onChange:function(e){return Kt("autorestart",e)}},"Autorestart if the process exits")))),z&&!we&&Nt&&(0,n.createElement)("div",{className:"nm-panel nm-setup-panel"},(0,n.createElement)(l.Icon,{name:"warning-triangle"}),(0,n.createElement)("div",null,(0,n.createElement)("h3",null,"Runtime setup required"),(0,n.createElement)("p",null,yt?bt?"Some runtime checks failed. Review detected paths before creating processes.":"PM2 is not installed for the detected Node.js runtime. Administrators can install it from this page.":"Node.js and npm were not found for this subscription. Enable Plesk Node.js support or configure the paths below.")),(0,n.createElement)("div",{className:"nm-card-actions"},oe.admin&&(0,n.createElement)(l.Button,{disabled:Boolean(V),onClick:Dt,state:"paths"===V?"loading":void 0},"Use detected paths"),oe.canInstallPm2&&yt&&!bt&&(0,n.createElement)(l.Button,{disabled:Boolean(V),intent:"primary",onClick:Vt,state:"pm2"===V?"loading":void 0},"Install PM2"),(0,n.createElement)(l.Button,{onClick:function(){return _t("runtime")}},"Review runtime"))),z&&!we&&(0,n.createElement)(I,{active:be,items:tn,onSelect:_t}),z&&!we&&"processes"===be&>&&(0,n.createElement)("div",{className:"nm-view-stack"},(0,n.createElement)("div",{className:"nm-stat-grid"},(0,n.createElement)("div",{className:"nm-stat-card"},(0,n.createElement)("span",null,"Total"),(0,n.createElement)("strong",null,It.total)),(0,n.createElement)("div",{className:"nm-stat-card"},(0,n.createElement)("span",null,"Online"),(0,n.createElement)("strong",null,It.online)),(0,n.createElement)("div",{className:"nm-stat-card"},(0,n.createElement)("span",null,"CPU"),(0,n.createElement)("strong",null,It.cpu,"%")),(0,n.createElement)("div",{className:"nm-stat-card"},(0,n.createElement)("span",null,"Memory"),(0,n.createElement)("strong",null,S(It.memory))),(0,n.createElement)("div",{className:"nm-stat-card"},(0,n.createElement)("span",null,"Restarts"),(0,n.createElement)("strong",null,It.restarts))),(0,n.createElement)(l.List,{columns:nn,data:Mt.visibleRows,emptyView:(0,n.createElement)(M,{title:"No PM2 processes found for this domain",description:"Create a process when your app is ready to run under PM2.",icon:"server"}),emptyViewMode:"items",pagination:Mt.pagination,rowKey:"pm2Name",rowProps:function(e){return{onClick:function(){return Ft(e)},className:xe&&xe.pm2Name===e.pm2Name?"nm-selected-row":""}},totalRows:Ee.length})),z&&!we&&"runtime"===be&&(0,n.createElement)("div",{className:"nm-panel nm-view-card"},(0,n.createElement)("div",{className:"nm-panel-header"},(0,n.createElement)("h3",null,"Runtime"),(0,n.createElement)("div",{className:"nm-card-actions"},oe.admin&&(0,n.createElement)(l.Button,{disabled:Boolean(V),onClick:Dt,state:"paths"===V?"loading":void 0},"Use detected paths"),oe.canInstallPm2&&yt&&(0,n.createElement)(l.Button,{disabled:Boolean(V),intent:"primary",onClick:Vt,state:"pm2"===V?"loading":void 0},"Install or update PM2"))),(0,n.createElement)(l.List,{columns:rn,data:en,emptyView:(0,n.createElement)(M,{title:"No runtime information",icon:"info-circle"}),emptyViewMode:"items",rowKey:"key"}),(0,n.createElement)("div",{className:"nm-field nm-pm2-home"},(0,n.createElement)("span",null,"PM2 home"),(0,n.createElement)("strong",{className:"nm-path"},ue&&ue.pm2Home?ue.pm2Home:"-"))),z&&!we&&"settings"===be&>&&oe.admin&&(0,n.createElement)("div",{className:"nm-panel nm-view-card"},(0,n.createElement)("div",{className:"nm-panel-header"},(0,n.createElement)("h3",null,"Settings")),(0,n.createElement)("div",{className:"nm-form-grid"},Object.keys(ie||{}).map(function(e){return(0,n.createElement)("label",{className:"nm-field",key:e},(0,n.createElement)("span",null,function(e){return{pm2Binary:"PM2 binary",nodeBinary:"Node.js binary",npmBinary:"npm binary",gitBinary:"Git binary",extraPath:"Extra PATH entries",pollInterval:"Polling interval, ms",maxLogBytes:"Max log bytes",metricsRetentionDays:"Metrics retention, days",deploymentTimeout:"Deployment timeout, seconds"}[e]||e}(e)),(0,n.createElement)(L,{value:null===ie[e]||void 0===ie[e]?"":ie[e],onChange:function(t){return se(function(n){return p(p({},n),{},f({},e,t.target.value))})}}))})),(0,n.createElement)("div",{className:"nm-card-actions"},(0,n.createElement)(l.Button,{intent:"primary",onClick:function(){xt(r.settings,ie).then(w).then(function(e){return se(e.settings||ie),Ot("success","Settings saved."),jt()}).catch(Rt)}},"Save Settings"))),z&&!we&&"backups"===be&>&&oe.admin&&(0,n.createElement)("div",{className:"nm-panel nm-view-card"},(0,n.createElement)("div",{className:"nm-panel-header"},(0,n.createElement)("h3",null,"Backups"),(0,n.createElement)("div",{className:"nm-card-actions"},(0,n.createElement)(l.Button,{icon:"plus",intent:"primary",onClick:function(){xt(r.backup,{create:!0}).then(w).then(function(){return Ot("success","Backup created."),Ht()}).catch(Rt)}},"Create Backup"))),(0,n.createElement)(l.List,{columns:on,data:dt,emptyView:(0,n.createElement)(M,{title:"No backups created yet",icon:"backup"}),emptyViewMode:"items",rowKey:"name"})))),(0,n.createElement)(l.Dialog,{isOpen:Me.open,onClose:Xt,size:"lg",title:Me.title||"Select path",subtitle:Me.currentPath||Ct,cancelButton:{children:"Close"}},(0,n.createElement)(B,{message:Me.error,intent:"danger"}),(0,n.createElement)(l.Toolbar,null,(0,n.createElement)(l.ToolbarGroup,{title:"Browse actions",groupable:!1},(0,n.createElement)(l.Button,{icon:"home",onClick:function(){return $t(".")}},"Document root"),(0,n.createElement)(l.Button,{icon:"arrow-up",disabled:!Me.parentValue,onClick:function(){return $t(Me.parentValue)}},"Up"),"directory"===Me.mode&&(0,n.createElement)(l.Button,{intent:"primary",icon:"check-mark",onClick:function(){"directory"===Me.mode&&(Kt(Me.field,Me.currentValue||"."),Xt())}},"Use this directory"))),(0,n.createElement)(l.List,{columns:[{key:"name",title:"Name",type:"title",render:function(e){return(0,n.createElement)("div",{className:"nm-picker-name"},(0,n.createElement)("button",{className:"nm-picker-link",type:"button",onClick:function(){return Qt(e)}},(0,n.createElement)(l.Icon,{name:"directory"===e.type?"folder":"file"})," ",e.name),(0,n.createElement)("span",{className:"nm-picker-actions"},"directory"===e.type&&(0,n.createElement)(l.Button,{icon:"folder-open",onClick:function(){return $t(e.value)}},"Open"),"file"===e.type&&e.selectable&&(0,n.createElement)(l.Button,{icon:"check-mark",intent:"primary",onClick:function(){return Qt(e)}},"Select"),"file"===e.type&&e.editable&&(0,n.createElement)(l.Button,{icon:"pencil",onClick:function(){var t;(t=e)&&"file"===t.type&&(vt({open:!0,path:t.value,value:t.value,content:"",originalContent:"",loading:!0,saving:!1,error:""}),Xt(),xt(r.file,{domainId:Z,path:t.value}).then(w).then(function(e){vt(function(n){return p(p({},n),{},{path:e.path||n.path,value:e.value||t.value,content:e.content||"",originalContent:e.content||"",loading:!1})})}).catch(function(e){vt(function(t){return p(p({},t),{},{error:e&&e.message?e.message:"Unable to open file.",loading:!1})})}))}},"Edit")))}},{key:"type",title:"Type",width:120},{key:"modifiedAt",title:"Modified",width:190}],data:Me.entries,emptyView:(0,n.createElement)(M,{title:Me.loading?"Loading...":"No files found",icon:"folder"}),emptyViewMode:"items",rowKey:"path"})),(0,n.createElement)(l.Drawer,{title:"Edit file",subtitle:ht.value||"",isOpen:ht.open,placement:"right",size:"lg",className:"nm-file-editor-drawer",closingConfirmation:ht.content!==ht.originalContent&&!ht.saving,onClose:Zt,form:{values:{content:ht.content||""},state:ht.saving?"submit":void 0,submitButton:{children:"Save",disabled:ht.loading},cancelButton:{children:"Close"},applyButton:!1,onFieldChange:function(e,t){"content"===e&&vt(function(e){return p(p({},e),{},{content:t})})},onSubmit:function(e){return t=e.content||"",vt(function(e){return p(p({},e),{},{saving:!0,error:""})}),void xt(r.file,{domainId:Z,path:ht.value,content:t}).then(w).then(function(e){vt(function(n){return p(p({},n),{},{path:e.path||n.path,value:e.value||n.value,content:e.content||t,saving:!1})}),Ot("success","File saved."),Zt()}).catch(function(e){vt(function(t){return p(p({},t),{},{error:e&&e.message?e.message:"Unable to save file.",saving:!1})})});var t}},"data-type":"file-editor"},(0,n.createElement)("div",{className:"nm-file-editor-drawer-body"},ht.error&&(0,n.createElement)(B,{message:ht.error,intent:"danger"}),ht.loading?(0,n.createElement)("div",{className:"nm-file-editor-loading"},(0,n.createElement)(O,{className:"nm-skeleton-label"}),(0,n.createElement)(O,{className:"nm-skeleton-path"}),(0,n.createElement)(O,{className:"nm-skeleton-path"})):(0,n.createElement)(l.FormField,{name:"content",label:null,vertical:!0},function(e){var t=e.setValue,r=e.getValue;return(0,n.createElement)(l.CodeEditor,{fileName:ht.value||"file",onChange:function(e){return t(e)},options:{lineNumbers:!0,lineWrapping:!0,viewportMargin:1/0}},r("")||"")}))),(0,n.createElement)(l.Drawer,{isOpen:Boolean(xe),onClose:function(){c.current&&clearInterval(c.current),c.current=null,Te(null),Ye("")},size:"lg",placement:"right",className:"nm-process-drawer",title:xe?(0,n.createElement)("div",{className:"nm-process-drawer-title"},(0,n.createElement)("span",null,xe.name),(0,n.createElement)(l.Status,{intent:P(xe.status),compact:!0},xe.status||"unknown")):"",subtitle:xe&&(xe.cwd||xe.scriptPath)||"",form:{submitButton:!1,applyButton:!1,cancelButton:{children:"Close"}}},xe&&(0,n.createElement)("div",{className:"nm-detail-stack nm-process-detail-stack"},(0,n.createElement)(I,{active:je,onSelect:Yt,items:[{key:"logs",title:"Logs",hidden:!Pt},{key:"env",title:"Env",hidden:!wt},{key:"deploy",title:"Deploy",hidden:!wt},{key:"ecosystem",title:"Ecosystem",hidden:!wt},{key:"metrics",title:"Metrics"}]}),"logs"===je&&(0,n.createElement)("div",{className:"nm-detail-stack nm-process-pane nm-process-logs"},(0,n.createElement)(l.Toolbar,null,(0,n.createElement)(l.ToolbarGroup,{title:"Log actions",groupable:!1},(0,n.createElement)(l.Select,{value:Ve,onChange:function(e){return _e(e||"stdout")},size:"sm"},(0,n.createElement)(l.SelectOption,{value:"stdout"},"stdout"),(0,n.createElement)(l.SelectOption,{value:"stderr"},"stderr")),(0,n.createElement)(l.Button,{icon:"refresh",onClick:function(){return zt()}},"Refresh"),wt&&(0,n.createElement)(l.Button,{icon:"remove",onClick:function(){xe&&(wt?xt(r.clearLogs,{domainId:Z,pm2Name:xe.pm2Name,stream:Ve}).then(w).then(function(){return Ye(""),Ge(function(e){return e?p(p({},e),{},{content:"",size:0,truncated:!1}):{size:0,truncated:!1}}),Ot("success","Logs cleared."),zt(!0)}).catch(Rt):Rt(new Error("You do not have permission to clear PM2 logs for this domain.")))}},"Clear"),(0,n.createElement)(l.Button,{icon:"download",component:"a",href:xe&&Pt?N(r.downloadLogs,{domainId:Z,pm2Name:xe.pm2Name,stream:Ve}):"#"},"Download"),We&&(0,n.createElement)("span",{className:"nm-muted"},S(We.size)))),(0,n.createElement)("pre",{className:"nm-terminal"},Fe)),"env"===je&&(0,n.createElement)("div",{className:"nm-detail-stack nm-process-pane"},(0,n.createElement)("div",{className:"nm-env-editor"},(0,n.createElement)(L,{placeholder:"NAME",value:et.name,onChange:function(e){return tt(function(t){return p(p({},t),{},{name:e.target.value})})}}),(0,n.createElement)(L,{placeholder:"value",type:et.isSecret?"password":"text",value:et.value,onChange:function(e){return tt(function(t){return p(p({},t),{},{value:e.target.value})})}}),(0,n.createElement)(l.Switch,{checked:Boolean(et.isSecret),onChange:function(e){return tt(function(t){return p(p({},t),{},{isSecret:e})})}},"Secret"),(0,n.createElement)(l.Button,{intent:"primary",onClick:function(){Bt&&(wt?xt(r.env,{domainId:Z,appId:Bt,name:et.name,value:et.value,isSecret:et.isSecret}).then(w).then(function(e){Qe(e.env||[]),tt({name:"",value:"",isSecret:!1}),Ot("success","Environment updated.")}).catch(Rt):Rt(new Error("You do not have permission to edit environment variables for this domain.")))}},"Save")),(0,n.createElement)(l.List,{columns:an,data:$e,emptyView:(0,n.createElement)(M,{title:"No environment variables",icon:"key"}),emptyViewMode:"items",rowKey:"name"})),"deploy"===je&&(0,n.createElement)("div",{className:"nm-detail-stack nm-process-pane"},(0,n.createElement)("div",{className:"nm-switch-grid"},(0,n.createElement)(l.Switch,{checked:lt.npmInstall,onChange:function(e){return ct(function(t){return p(p({},t),{},{npmInstall:e})})}},"npm install"),(0,n.createElement)(l.Switch,{checked:lt.production,onChange:function(e){return ct(function(t){return p(p({},t),{},{production:e})})}},"production dependencies only"),(0,n.createElement)(l.Switch,{checked:lt.reload,onChange:function(e){return ct(function(t){return p(p({},t),{},{reload:e})})}},"zero-downtime reload")),(0,n.createElement)("div",{className:"nm-card-actions"},(0,n.createElement)(l.Button,{intent:"primary",icon:"upload",onClick:function(){wt?Bt&&(A(!0),xt(r.deploy,p(p({},lt),{},{domainId:Z,appId:Bt})).then(w).then(function(e){return Ot("success",e.message||"Deployment completed."),At(!0)}).catch(Rt).finally(function(){return A(!1)})):Rt(new Error("You do not have permission to deploy PM2 applications for this domain."))},state:j?"loading":void 0},"Deploy Latest"),(0,n.createElement)(l.Button,{onClick:function(){return Gt(!0)}},"Enable Webhook"),(0,n.createElement)(l.Button,{onClick:function(){return Gt(!1)}},"Disable Webhook")),st.url&&(0,n.createElement)(L,{readOnly:!0,value:st.url})),"ecosystem"===je&&(0,n.createElement)("div",{className:"nm-detail-stack nm-process-pane nm-process-ecosystem"},(0,n.createElement)(l.Toolbar,null,(0,n.createElement)(l.ToolbarGroup,{title:"Ecosystem actions",groupable:!1},(0,n.createElement)("span",{className:"nm-muted nm-path"},rt.path||"-"),(0,n.createElement)(l.Button,{onClick:function(){return Wt(!1)}},"Save"),(0,n.createElement)(l.Button,{intent:"primary",onClick:function(){return Wt(!0)}},"Save and Start"))),(0,n.createElement)(l.CodeEditor,{fileName:"ecosystem.config.js",onChange:function(e){return at(function(t){return p(p({},t),{},{content:e})})},options:{lineNumbers:!0,lineWrapping:!0,viewportMargin:1/0}},rt.content||"")),"metrics"===je&&(0,n.createElement)("div",{className:"nm-process-pane nm-process-metrics"},(0,n.createElement)(T,{metrics:Ke})))))};j.propTypes={config:c.default.shape({csrf:c.default.string,domainContextId:c.default.oneOfType([c.default.string,c.default.number]),domainLocked:c.default.bool,endpoints:c.default.object,info:c.default.object,infoUrl:c.default.string,initialDomainId:c.default.oneOfType([c.default.string,c.default.number])}).isRequired};var A=function(e){return(0,n.createElement)(j,{config:e})},D=e.mount=function(e){var t=document.getElementById(e);t&&"1"!==t.dataset.nmUiMounted&&(t.dataset.nmUiMounted="1",(0,o.createRoot)(t).render((0,n.createElement)(A,function(e){try{return JSON.parse(e.getAttribute("data-nm-ui-props")||"{}")}catch(e){return{}}}(t))))};e.default={mount:D}})(),a})());
//# sourceMappingURL=node-manager-pm2-ui.js.map