├── .babelrc
├── .gitignore
├── LICENSE
├── README.md
├── app-js
├── app.js
├── components
│ ├── About.js
│ ├── App.js
│ ├── ConnectForm.js
│ ├── Dashboard.js
│ ├── ExternalLink.js
│ ├── ServerDetails.js
│ ├── ServerList.js
│ ├── Storage.js
│ └── SubscriptionForm.js
└── utils
│ └── PleskUtils.js
├── build
├── icon.icns
└── icon.ico
├── css
└── app.css
├── docs
├── .keep
├── _config.yml
├── assets
│ └── css
│ │ └── style.scss
├── images
│ └── shot.png
└── index.md
├── index.html
├── js
└── .keep
├── main.js
└── package.json
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["es2015", "stage-0", "react"]
3 | }
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | /dist
3 | /js/bundle.js
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright 1999-2017. Parallels IP Holdings GmbH.
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Plesk Desktop
2 |
3 | Desktop app for Plesk servers management.
4 |
5 | Additional details: https://plesk.github.io/desktop/
6 |
7 | # Development Environment
8 |
9 | Installation instructions:
10 | * clone the repo
11 | * install Node
12 | * npm install
13 | * npm run watch (on a separate console)
14 | * npm start
15 |
--------------------------------------------------------------------------------
/app-js/app.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './components/App';
4 |
5 | ReactDOM.render(
6 | ,
7 | document.getElementById('container')
8 | );
9 |
--------------------------------------------------------------------------------
/app-js/components/About.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ExternalLink from './ExternalLink';
3 |
4 | export default class About extends React.Component {
5 | render() {
6 | return (
7 |
8 |
About
9 |
10 | GitHub: https://github.com/plesk/desktop
11 | Wiki: https://github.com/plesk/desktop/wiki
12 | Ticket: https://github.com/plesk/desktop/issues/new
13 |
14 |
15 | );
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/app-js/components/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { HashRouter as Router, Route, Link } from 'react-router-dom';
3 | import Storage from './Storage';
4 | import Dashboard from './Dashboard';
5 | import ServerDetails from './ServerDetails';
6 | import ServerList from './ServerList';
7 | import ConnectForm from './ConnectForm';
8 | import SubscriptionForm from './SubscriptionForm';
9 | import About from "./About";
10 |
11 | export default class App extends React.Component {
12 | render() {
13 | return (
14 |
15 |
16 |
17 |
18 |
19 |
22 |
Servers
23 |
24 |
25 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | );
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/app-js/components/ConnectForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import PleskUtils from '../utils/PleskUtils';
4 |
5 | class ConnectForm extends React.Component {
6 | render() {
7 | return (
8 |
9 |
Add a New Server
10 |
24 |
25 | );
26 | }
27 |
28 | handleSubmit(event) {
29 | event.preventDefault();
30 | let host = event.target.querySelector('#host');
31 | let pw = event.target.querySelector('#pw');
32 |
33 | if (!host) {
34 | alert('Please define the host');
35 | return;
36 | }
37 |
38 | PleskUtils.connectServer(host.value, 'admin', pw.value, this.context.storage, () => {
39 | const serverName = host.value;
40 | const server = this.context.storage.servers[serverName];
41 | PleskUtils.syncServerState({
42 | server,
43 | serverName,
44 | callback: (webspaces) => {
45 | this.context.storage.findSubscriptions(serverName, webspaces.map((webspace) => {
46 | return {
47 | domain: webspace.data[0].gen_info[0].name[0],
48 | domainId: webspace.id[0]
49 | };
50 | }));
51 | }
52 | });
53 |
54 | this.props.history.push('/');
55 | });
56 |
57 | }
58 | }
59 |
60 | ConnectForm.contextTypes = {
61 | storage: PropTypes.object,
62 | };
63 |
64 | export default ConnectForm;
65 |
--------------------------------------------------------------------------------
/app-js/components/Dashboard.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Link } from 'react-router-dom';
4 |
5 | class Dashboard extends React.Component {
6 | render() {
7 | return (
8 |
9 |
Dashboard
10 |
11 |
12 | Connect a Server
13 |
14 |
15 |
16 |
17 |
18 | Servers |
19 | {Object.keys(this.context.storage.servers).length} |
20 |
21 |
22 |
23 |
24 | );
25 | }
26 | }
27 |
28 | Dashboard.contextTypes = {
29 | storage: PropTypes.object,
30 | };
31 |
32 | export default Dashboard;
33 |
--------------------------------------------------------------------------------
/app-js/components/ExternalLink.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 |
3 | const addExternalProps = ({ href, ...props }) => {
4 | const electron = window.require && window.require('electron');
5 | if (electron) {
6 | return {
7 | ...props,
8 | href: '#',
9 | onClick: event => {
10 | event.preventDefault();
11 | electron.shell.openExternal(href);
12 | },
13 | }
14 | }
15 |
16 | return {
17 | ...props,
18 | href,
19 | target: '_blank',
20 | }
21 | };
22 |
23 | const ExternalLink = props => (
24 |
25 | );
26 |
27 | export default ExternalLink;
28 |
--------------------------------------------------------------------------------
/app-js/components/ServerDetails.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Link } from 'react-router-dom';
4 | import ExternalLink from './ExternalLink';
5 | import PleskUtils from '../utils/PleskUtils';
6 |
7 | class ServerDetails extends React.Component {
8 | constructor(props) {
9 | super(props);
10 | this.state = { serverLoginGeneration: false };
11 | }
12 |
13 | render() {
14 | const { serverName } = this.props.match.params;
15 | const { servers } = this.context.storage;
16 | const server = servers[serverName];
17 | const domains = server && server.domains || [];
18 |
19 | return (
20 |
21 |
38 |
39 |
40 |
41 |
42 |
43 | Version |
44 | {server && server.details && server.details.version} |
45 |
46 |
47 | OS |
48 | {server && server.details && `${server.details.os} ${server.details.osVersion}`} |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 | Subscriptions |
58 | {server && server.domains && server.domains.length || 0} |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | Create Subscription
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 | Subscription |
78 | Actions |
79 |
80 |
81 |
82 | {domains.map((domain) => {
83 | return (
84 |
85 | {domain.domain} |
86 |
87 |
88 |
89 | Login
90 |
91 |
92 |
93 | Remove
94 |
95 | |
96 |
97 | );
98 | })}
99 |
100 |
101 |
102 |
103 |
104 | );
105 | }
106 |
107 | handleLogin(event) {
108 | event.preventDefault();
109 | const serverName = this.props.match.params.serverName;
110 | const server = this.context.storage.servers[serverName];
111 | const domainId = event.target.getAttribute('data-id');
112 |
113 | if (!domainId) {
114 | this.setState({ serverLoginGeneration: true });
115 | }
116 |
117 | PleskUtils.generateLoginUrl({
118 | server,
119 | serverName,
120 | callback: (url) => {
121 | if (domainId) {
122 | url = `${url}&success_redirect_url=/admin/subscription/overview/id/${domainId}`;
123 | } else {
124 | this.setState({ serverLoginGeneration: false });
125 | }
126 |
127 | const electron = window.require('electron');
128 | electron.shell.openExternal(url);
129 | }
130 | });
131 | }
132 |
133 | handleDisconnect(event) {
134 | event.preventDefault();
135 | const {serverName} = this.props.match.params;
136 | this.context.storage.disconnectServer(serverName);
137 | this.props.history.push('/');
138 | }
139 |
140 | handleSync(event) {
141 | event.preventDefault();
142 | const serverName = this.props.match.params.serverName;
143 | const server = this.context.storage.servers[serverName];
144 | PleskUtils.syncServerState({
145 | server,
146 | serverName,
147 | callback: (webspaces) => {
148 | this.context.storage.findSubscriptions(serverName, webspaces.map((webspace) => {
149 | return {
150 | domain: webspace.data[0].gen_info[0].name[0],
151 | domainId: webspace.id[0]
152 | };
153 | }));
154 | }
155 | });
156 | }
157 |
158 | handleRemoveSubscription(event) {
159 | event.preventDefault();
160 | const domain = event.target.getAttribute('data-id');
161 | const serverName = this.props.match.params.serverName;
162 | const server = this.context.storage.servers[serverName];
163 |
164 | PleskUtils.subscription.remove({
165 | server,
166 | serverName,
167 | domain,
168 | callback: () => {
169 | this.context.storage.removeSubscription(serverName, domain);
170 | }
171 | });
172 | }
173 | }
174 |
175 | ServerDetails.contextTypes = {
176 | storage: PropTypes.object,
177 | };
178 |
179 | export default ServerDetails;
180 |
--------------------------------------------------------------------------------
/app-js/components/ServerList.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import { Link } from 'react-router-dom';
4 |
5 | class ServerList extends React.Component {
6 | render() {
7 | const { servers } = this.context.storage;
8 |
9 | return (
10 |
11 | {Object.keys(servers).map((name) => {
12 | const serverDetails = servers[name].details || {};
13 | return (
14 | -
15 |
16 |
17 | {name}
18 | {`${serverDetails.version}, ${serverDetails.os} ${serverDetails.osVersion}`}
19 |
20 |
21 | );
22 | })}
23 |
24 | );
25 | }
26 | }
27 |
28 | ServerList.contextTypes = {
29 | storage: PropTypes.object,
30 | };
31 |
32 | export default ServerList;
33 |
--------------------------------------------------------------------------------
/app-js/components/Storage.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import PropTypes from 'prop-types';
3 |
4 | const storage = window.require && window.require('electron-json-storage') || {
5 | set: (key, json, callback) => {
6 | localStorage.setItem(key, JSON.stringify(json));
7 | callback();
8 | },
9 | get: (key, callback) => {
10 | const json = JSON.parse(localStorage.getItem(key)) || {};
11 | callback(null, json);
12 | },
13 | };
14 |
15 | class Storage extends Component {
16 | constructor() {
17 | super();
18 |
19 | this.state = {
20 | servers: {},
21 | };
22 | }
23 |
24 | componentDidMount() {
25 | storage.get('servers', (error, servers) => {
26 | this.setState({ servers });
27 | });
28 | }
29 |
30 | render() {
31 | return this.props.children;
32 | }
33 |
34 | getChildContext() {
35 | return {
36 | storage: {
37 | servers: this.state.servers,
38 | connectServer: this.connectServer.bind(this),
39 | disconnectServer: this.disconnectServer.bind(this),
40 | addSubscription: this.addSubscription.bind(this),
41 | removeSubscription: this.removeSubscription.bind(this),
42 | findSubscriptions: this.findSubscriptions.bind(this)
43 | },
44 | };
45 | }
46 |
47 | connectServer(host, login, password, details) {
48 | const { servers } = this.state;
49 | servers[host] = { login, password, details };
50 | this.saveServersState(servers);
51 | }
52 |
53 | disconnectServer(host) {
54 | const { servers } = this.state;
55 | delete servers[host];
56 | this.saveServersState(servers);
57 | }
58 |
59 | addSubscription(host, domain, domainId, login, password, ip) {
60 | const { servers } = this.state;
61 | servers[host].domains = servers[host].domains || [];
62 | servers[host].domains.push({
63 | domainId: domainId,
64 | domain: domain,
65 | login: login,
66 | password: password,
67 | ip: ip
68 | });
69 | this.saveServersState(servers);
70 | }
71 |
72 | removeSubscription(host, domain) {
73 | const { servers } = this.state;
74 | servers[host].domains = servers[host].domains || [];
75 | servers[host].domains = servers[host].domains.filter((item) => domain !== item.domain);
76 | this.saveServersState(servers);
77 | }
78 |
79 | findSubscriptions(host, domains) {
80 | const { servers } = this.state;
81 | servers[host].domains = [];
82 | domains.forEach(({ domain, domainId }) => {
83 | this.addSubscription(host, domain, domainId, '', '', '');
84 | });
85 | this.saveServersState(servers);
86 | }
87 |
88 | saveServersState(servers) {
89 | storage.set('servers', servers, (error) => {
90 | if (error) {
91 | throw error;
92 | }
93 | this.setState({ servers });
94 | });
95 | }
96 | }
97 |
98 | Storage.childContextTypes = {
99 | storage: PropTypes.object,
100 | };
101 |
102 | export default Storage;
103 |
--------------------------------------------------------------------------------
/app-js/components/SubscriptionForm.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import PropTypes from 'prop-types';
3 | import PleskUtils from '../utils/PleskUtils';
4 |
5 | class SubscriptionForm extends React.Component {
6 | constructor(props) {
7 | super(props);
8 | this.state = { loading: false };
9 | }
10 |
11 | render() {
12 | return (
13 |
14 |
Add a New Subscription
15 |
36 |
37 | );
38 | }
39 |
40 | handleSubmit(event) {
41 | event.preventDefault();
42 |
43 | const domain = event.target.querySelector('#domain').value;
44 | const domainLogin = event.target.querySelector('#login').value;
45 | const password = event.target.querySelector('#pw').value;
46 | const serverName = this.props.match.params.serverName;
47 | const server = this.context.storage.servers[serverName];
48 |
49 | this.setState({ loading: true });
50 |
51 | PleskUtils.subscription.create({
52 | server,
53 | serverName,
54 | domain,
55 | domainLogin,
56 | password,
57 | callback: (error, result) => {
58 | this.setState({ loading: false });
59 |
60 | if (error) {
61 | console.log(error);
62 | return;
63 | }
64 | if (result.packet.system) {
65 | alert(result.packet.system[0].errtext[0]);
66 | return;
67 | }
68 | if ('error' === result.packet.webspace[0].add[0].result[0].status[0]) {
69 | alert(result.packet.webspace[0].add[0].result[0].errtext[0]);
70 | return;
71 | }
72 | const ip = !server.details.isMultiServer ? serverName : result.packet.webspace[0].add[0].result[0].ip[0];
73 | const domainId = result.packet.webspace[0].add[0].result[0].id[0];
74 | this.context.storage.addSubscription(serverName, domain, domainId, domainLogin, password, ip);
75 | this.props.history.push(`/server/show/${serverName}`);
76 | },
77 | });
78 | }
79 | }
80 |
81 | SubscriptionForm.contextTypes = {
82 | storage: PropTypes.object,
83 | };
84 |
85 | export default SubscriptionForm;
86 |
--------------------------------------------------------------------------------
/app-js/utils/PleskUtils.js:
--------------------------------------------------------------------------------
1 | import PleskApi from 'plesk-api-client';
2 | import { parseString } from 'xml2js';
3 |
4 | const Subscription = {
5 | _getMultiServerRequestSettings() {
6 | return (
7 | `
8 |
9 | plesk_rpc_forwarding_to_ext
10 | plesk-multi-server
11 |
12 |
13 | ext-plesk-multi-server:ipv4
14 | shared
15 |
16 |
17 | ext-plesk-multi-server:sync
18 | true
19 |
20 | `
21 | );
22 | },
23 |
24 | _getSubscriptionCreationPacket(requestSettings, domain, domainLogin, domainPassword, ipAddress) {
25 | return (
26 | `
27 | ${requestSettings}
28 |
29 |
30 |
31 | ${domain}
32 | ${ipAddress}
33 |
34 |
35 |
36 |
37 | ftp_login
38 | ${domainLogin}
39 |
40 |
41 | ftp_password
42 | ${domainPassword}
43 |
44 | ${ipAddress}
45 |
46 |
47 | Default domain
48 |
49 |
50 | `
51 | );
52 | },
53 |
54 | create({ domain, domainLogin, password, server, serverName, callback }) {
55 | if (!domain) {
56 | alert('Please define the domain name.');
57 | return;
58 | }
59 |
60 | const client = new PleskApi.Client(serverName);
61 | client.setCredentials(server.login, server.password);
62 |
63 | new Promise((resolve) => {
64 | client
65 | .request('')
66 | .then((response) => {
67 | parseString(response, (error, result) => {
68 | resolve(result.packet.ip[0].get[0].result[0].addresses[0].ip_info[0].ip_address[0]);
69 | });
70 | });
71 | })
72 | .then((ipAddress) => {
73 | const requestSettings = server.details.isMultiServer ? this._getMultiServerRequestSettings() : '';
74 | const request = this._getSubscriptionCreationPacket(requestSettings, domain, domainLogin, password, ipAddress);
75 |
76 | client
77 | .request(request)
78 | .then((response) => {
79 | parseString(response, callback);
80 | })
81 | .catch((error) => {
82 | alert(error.message);
83 | });
84 | });
85 | },
86 |
87 | remove({ domain, server, serverName, callback }) {
88 | const client = new PleskApi.Client(serverName);
89 | client.setCredentials(server.login, server.password);
90 |
91 | const request =
92 | `
93 |
94 |
95 |
96 | ${domain}
97 |
98 |
99 |
100 | `;
101 |
102 | new Promise((resolve) => {
103 | client
104 | .request(request)
105 | .then(callback)
106 | .catch((error) => {
107 | alert(error.message);
108 | });
109 | });
110 | }
111 | }
112 |
113 | const PleskUtils = {
114 | subscription: Subscription,
115 |
116 | connectServer(host, login, password, storage, callback) {
117 | const request =
118 | `
119 |
120 | `;
121 |
122 | const client = new PleskApi.Client(host);
123 | client.setCredentials(login, password);
124 | client.request(request)
125 | .then((response) => {
126 | parseString(response, (error, result) => {
127 | if (error) {
128 | console.log(error);
129 | return;
130 | }
131 |
132 | if (result.packet.system) {
133 | alert(result.packet.system[0].errtext[0]);
134 | return;
135 | }
136 |
137 | const stats = result.packet.server[0].get[0].result[0].stat[0];
138 | storage.connectServer(host, 'admin', password, {
139 | isMultiServer: false, // TODO: add detection of Plesk MultiServer instance
140 | version: stats.version[0].plesk_version[0],
141 | os: stats.version[0].plesk_os[0],
142 | osVersion: stats.version[0].plesk_os_version[0]
143 | });
144 |
145 | callback();
146 | });
147 | })
148 | .catch((error) => {
149 | alert(error.message);
150 | });
151 | },
152 |
153 | syncServerState({ server, serverName, callback }) {
154 | const client = new PleskApi.Client(serverName);
155 | client.setCredentials(server.login, server.password);
156 |
157 | const request = (
158 | `
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 | `
168 | );
169 |
170 | client.request(request)
171 | .then((response) => {
172 | parseString(response, (error, result) => {
173 | const webspaces = result.packet.webspace[0].get[0].result;
174 | callback(webspaces);
175 | })
176 | });
177 | },
178 |
179 | generateLoginUrl({ server, serverName, callback }) {
180 | const client = new PleskApi.Client(serverName);
181 | client.setCredentials(server.login, server.password);
182 |
183 | const request = (
184 | `
185 |
186 |
187 | ${server.login}
188 |
189 |
190 |
191 |
192 |
193 |
194 | `
195 | );
196 |
197 | client.request(request)
198 | .then((response) => {
199 | parseString(response, (error, result) => {
200 | const sessionId = result.packet.server[0].create_session[0].result[0].id[0];
201 | const loginUrl = `https://${serverName}:8443/enterprise/rsession_init.php?PLESKSESSID=${sessionId}`;
202 | callback(loginUrl);
203 | })
204 | });
205 | }
206 | }
207 |
208 | export default PleskUtils;
209 |
--------------------------------------------------------------------------------
/build/icon.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/plesk/desktop/24cb63cc6a7b458f556b5b5dbadc7d86ea2fb6dd/build/icon.icns
--------------------------------------------------------------------------------
/build/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/plesk/desktop/24cb63cc6a7b458f556b5b5dbadc7d86ea2fb6dd/build/icon.ico
--------------------------------------------------------------------------------
/css/app.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding-top: 0px;
3 | }
4 |
5 | .sidebar {
6 | position: fixed;
7 | top: 1px;
8 | bottom: 0;
9 | left: 0;
10 | z-index: 1000;
11 | display: block;
12 | padding: 20px;
13 | overflow-x: hidden;
14 | overflow-y: auto;
15 | background-color: #f5f5f5;
16 | border-right: 1px solid #eee;
17 | }
18 |
19 | .nav-sidebar {
20 | margin-right: -21px;
21 | margin-bottom: 20px;
22 | margin-left: -20px;
23 | }
24 | .nav-sidebar > li > a {
25 | padding-right: 20px;
26 | padding-left: 20px;
27 | white-space: nowrap;
28 | }
29 | .nav-sidebar > .active > a,
30 | .nav-sidebar > .active > a:hover,
31 | .nav-sidebar > .active > a:focus {
32 | color: #fff;
33 | background-color: #428bca;
34 | }
35 |
36 | .top-buffer {
37 | margin-top:20px;
38 | }
39 |
40 | .main {
41 | padding: 20px;
42 | }
43 | @media (min-width: 768px) {
44 | .main {
45 | padding-right: 40px;
46 | padding-left: 40px;
47 | }
48 | }
49 | .main .page-header {
50 | margin-top: 0;
51 | }
52 | .sidebar .plesk-version {
53 | color: #555;
54 | }
55 |
--------------------------------------------------------------------------------
/docs/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/plesk/desktop/24cb63cc6a7b458f556b5b5dbadc7d86ea2fb6dd/docs/.keep
--------------------------------------------------------------------------------
/docs/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-hacker
2 | title: Plesk Desktop
3 | description: Desktop app for Plesk servers management.
4 |
--------------------------------------------------------------------------------
/docs/assets/css/style.scss:
--------------------------------------------------------------------------------
1 | ---
2 | ---
3 |
4 | @import "{{ site.theme }}";
5 |
6 | header h1:before { content: ""; }
7 | header h1 { margin: 0; }
8 |
--------------------------------------------------------------------------------
/docs/images/shot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/plesk/desktop/24cb63cc6a7b458f556b5b5dbadc7d86ea2fb6dd/docs/images/shot.png
--------------------------------------------------------------------------------
/docs/index.md:
--------------------------------------------------------------------------------
1 | # Overview
2 |
3 | Desktop app for Plesk servers management.
4 |
5 | 
6 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Plesk Desktop
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/js/.keep:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/plesk/desktop/24cb63cc6a7b458f556b5b5dbadc7d86ea2fb6dd/js/.keep
--------------------------------------------------------------------------------
/main.js:
--------------------------------------------------------------------------------
1 | const electron = require('electron');
2 | const app = electron.app;
3 | const BrowserWindow = electron.BrowserWindow;
4 | const path = require('path');
5 | const url = require('url');
6 |
7 | let mainWindow;
8 |
9 | function createWindow() {
10 | mainWindow = new BrowserWindow({ width: 1020, height: 625 });
11 |
12 | mainWindow.loadURL(url.format({
13 | pathname: path.join(__dirname, 'index.html'),
14 | protocol: 'file:',
15 | slashes: true
16 | }));
17 |
18 | mainWindow.on('closed', () => {
19 | mainWindow = null;
20 | });
21 | }
22 |
23 | app.commandLine.appendSwitch('ignore-certificate-errors');
24 |
25 | app.on('ready', createWindow);
26 |
27 | app.on('window-all-closed', () => {
28 | if (process.platform !== 'darwin') {
29 | app.quit();
30 | }
31 | });
32 |
33 | app.on('activate', () => {
34 | if (mainWindow === null) {
35 | createWindow();
36 | }
37 | });
38 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "plesk-desktop",
3 | "version": "0.0.1",
4 | "description": "Desktop app for Plesk servers management.",
5 | "main": "main.js",
6 | "scripts": {
7 | "start": "electron .",
8 | "watch": "watchify app-js/app.js -t babelify -o js/bundle.js",
9 | "dist:osx": "build --dist --platform darwin",
10 | "dist:win32": "build --dist --platform win32"
11 | },
12 | "author": "Plesk",
13 | "license": "Apache-2.0",
14 | "repository": {
15 | "type": "git",
16 | "url": "git@github.com:plesk/desktop.git"
17 | },
18 | "build": {
19 | "app-bundle-id": "com.plesk.plesk-desktop",
20 | "app-category-type": "public.app-category.developer-tools",
21 | "productName": "Plesk Desktop",
22 | "osx": {
23 | "title": "Plesk Desktop",
24 | "window": {
25 | "position": {
26 | "x": 250,
27 | "y": 250
28 | }
29 | }
30 | }
31 | },
32 | "devDependencies": {
33 | "electron": "~1.6.2",
34 | "electron-builder": "^3.25.0",
35 | "electron-prebuilt": "^1.4.13",
36 | "watchify": "^3.9.0"
37 | },
38 | "dependencies": {
39 | "babel-preset-es2015": "^6.24.0",
40 | "babel-preset-react": "^6.23.0",
41 | "babel-preset-stage-0": "^6.22.0",
42 | "babelify": "^7.3.0",
43 | "bootstrap": "^3.3.7",
44 | "electron-json-storage": "^3.0.2",
45 | "font-awesome": "^4.7.0",
46 | "plesk-api-client": "^1.0.3",
47 | "prop-types": "^15.5.8",
48 | "react": "^15.4.2",
49 | "react-dom": "^15.4.2",
50 | "react-router-dom": "^4.0.0",
51 | "xml2js": "^0.4.17"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------