@axlotl-lab/navigrator
Version:
A powerful local domain manager for development environments. Navigrator helps you manage local domains and SSL certificates with a simple web interface.
529 lines (528 loc) • 33 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
const react_1 = __importStar(require("react"));
require("./styles.css");
function App() {
const [domains, setDomains] = (0, react_1.useState)([]);
const [certificates, setCertificates] = (0, react_1.useState)([]);
const [proxies, setProxies] = (0, react_1.useState)([]);
const [statuses, setStatuses] = (0, react_1.useState)({});
const [newDomain, setNewDomain] = (0, react_1.useState)('');
const [loading, setLoading] = (0, react_1.useState)(true);
const [error, setError] = (0, react_1.useState)(null);
const [notification, setNotification] = (0, react_1.useState)(null);
const [activeTab, setActiveTab] = (0, react_1.useState)('domains');
const [confirmImport, setConfirmImport] = (0, react_1.useState)(false);
const [confirmDeleteCertificate, setConfirmDeleteCertificate] = (0, react_1.useState)(null);
const [confirmDeleteProxy, setConfirmDeleteProxy] = (0, react_1.useState)(null);
const [newProxy, setNewProxy] = (0, react_1.useState)({
domain: '',
target: '',
port: 443
});
const [editProxy, setEditProxy] = (0, react_1.useState)(null);
(0, react_1.useEffect)(() => {
fetchData();
}, []);
const fetchData = () => __awaiter(this, void 0, void 0, function* () {
setLoading(true);
setError(null);
try {
yield Promise.all([
fetchHosts(),
fetchCertificates(),
fetchProxies()
]);
setLoading(false);
}
catch (error) {
setError('Failed to load data. Please check if the server is running with admin privileges.');
setLoading(false);
}
});
const fetchHosts = () => __awaiter(this, void 0, void 0, function* () {
const response = yield fetch('/api/hosts');
if (!response.ok)
throw new Error('Failed to fetch hosts');
const data = yield response.json();
setDomains(data.hosts);
yield Promise.all(data.hosts.map((host) => fetchDomainStatus(host.domain)));
});
const fetchCertificates = () => __awaiter(this, void 0, void 0, function* () {
const response = yield fetch('/api/certificates');
if (!response.ok)
throw new Error('Failed to fetch certificates');
const data = yield response.json();
setCertificates(data.certificates);
});
const fetchProxies = () => __awaiter(this, void 0, void 0, function* () {
const response = yield fetch('/api/proxies');
if (!response.ok)
throw new Error('Failed to fetch proxies');
const data = yield response.json();
setProxies(data.proxies);
});
const fetchDomainStatus = (domain) => __awaiter(this, void 0, void 0, function* () {
const response = yield fetch(`/api/status/${domain}`);
if (!response.ok)
return;
const data = yield response.json();
setStatuses(prev => (Object.assign(Object.assign({}, prev), { [domain]: data.status })));
});
const addDomain = (e) => __awaiter(this, void 0, void 0, function* () {
e.preventDefault();
if (!newDomain)
return;
setLoading(true);
try {
const hostResponse = yield fetch('/api/hosts', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ domain: newDomain })
});
if (!hostResponse.ok)
throw new Error('Failed to add host');
const certResponse = yield fetch('/api/certificates', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ domain: newDomain })
});
if (!certResponse.ok)
throw new Error('Failed to create certificate');
yield fetchData();
showNotification(`Domain ${newDomain} added successfully`, 'success');
setNewDomain('');
}
catch (error) {
showNotification(`Error adding domain: ${error === null || error === void 0 ? void 0 : error.message}`, 'error');
}
finally {
setLoading(false);
}
});
const adoptDomain = (domain, ip) => __awaiter(this, void 0, void 0, function* () {
setLoading(true);
try {
const response = yield fetch(`/api/hosts/${domain}/adopt`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ ip })
});
if (!response.ok)
throw new Error('Failed to adopt host');
yield fetchData();
showNotification(`Domain ${domain} adopted successfully`, 'success');
}
catch (error) {
showNotification(`Error adopting domain: ${error === null || error === void 0 ? void 0 : error.message}`, 'error');
}
finally {
setLoading(false);
}
});
const importAllDomains = () => __awaiter(this, void 0, void 0, function* () {
setLoading(true);
setConfirmImport(false);
try {
const response = yield fetch('/api/hosts/import-all', {
method: 'POST'
});
if (!response.ok)
throw new Error('Failed to import hosts');
const data = yield response.json();
yield fetchData();
showNotification(data.message, 'success');
}
catch (error) {
showNotification(`Error importing domains: ${error === null || error === void 0 ? void 0 : error.message}`, 'error');
}
finally {
setLoading(false);
}
});
const removeDomain = (domain) => __awaiter(this, void 0, void 0, function* () {
if (!confirm(`Are you sure you want to remove ${domain}?`))
return;
setLoading(true);
try {
const response = yield fetch(`/api/hosts/${domain}`, {
method: 'DELETE'
});
if (!response.ok)
throw new Error('Failed to remove host');
const data = yield response.json();
yield fetchData();
showNotification(data.message, 'success');
}
catch (error) {
showNotification(`Error removing domain: ${error === null || error === void 0 ? void 0 : error.message} `, 'error');
}
finally {
setLoading(false);
}
});
const toggleDomainState = (domain, disable) => __awaiter(this, void 0, void 0, function* () {
setLoading(true);
try {
const response = yield fetch(`/api/hosts/${domain}/toggle`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ disabled: disable })
});
if (!response.ok)
throw new Error('Failed to toggle domain state');
yield fetchData();
const state = disable ? 'disabled' : 'enabled';
showNotification(`Domain ${domain} ${state} successfully`, 'success');
}
catch (error) {
showNotification(`Error updating domain state: ${error === null || error === void 0 ? void 0 : error.message} `, 'error');
}
finally {
setLoading(false);
}
});
const deleteCertificate = (domain) => __awaiter(this, void 0, void 0, function* () {
setConfirmDeleteCertificate(null);
setLoading(true);
try {
const response = yield fetch(`/api/certificates/${domain}`, {
method: 'DELETE'
});
if (!response.ok)
throw new Error('Failed to delete certificate');
yield fetchData();
showNotification(`Certificate for ${domain} deleted successfully`, 'success');
}
catch (error) {
showNotification(`Error deleting certificate: ${error === null || error === void 0 ? void 0 : error.message}`, 'error');
}
finally {
setLoading(false);
}
});
const addProxy = (e) => __awaiter(this, void 0, void 0, function* () {
e.preventDefault();
if (!newProxy.domain || !newProxy.target)
return;
setLoading(true);
try {
const response = yield fetch('/api/proxies', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(newProxy)
});
if (!response.ok) {
const errorData = yield response.json();
throw new Error(errorData.error || 'Failed to add proxy');
}
yield fetchProxies();
showNotification(`Proxy for ${newProxy.domain} added successfully`, 'success');
setNewProxy({
domain: '',
target: '',
port: 443
});
}
catch (error) {
showNotification(`Error adding proxy: ${error === null || error === void 0 ? void 0 : error.message}`, 'error');
}
finally {
setLoading(false);
}
});
const updateProxy = (e) => __awaiter(this, void 0, void 0, function* () {
e.preventDefault();
if (!editProxy)
return;
setLoading(true);
try {
const response = yield fetch(`/api/proxies/${editProxy.domain}`, {
method: 'PATCH',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
target: editProxy.target,
port: editProxy.port
})
});
if (!response.ok)
throw new Error('Failed to update proxy');
yield fetchProxies();
showNotification(`Proxy for ${editProxy.domain} updated successfully`, 'success');
setEditProxy(null);
}
catch (error) {
showNotification(`Error updating proxy: ${error === null || error === void 0 ? void 0 : error.message}`, 'error');
}
finally {
setLoading(false);
}
});
const deleteProxy = (domain) => __awaiter(this, void 0, void 0, function* () {
setConfirmDeleteProxy(null);
setLoading(true);
try {
const response = yield fetch(`/api/proxies/${domain}`, {
method: 'DELETE'
});
if (!response.ok)
throw new Error('Failed to delete proxy');
yield fetchProxies();
showNotification(`Proxy for ${domain} deleted successfully`, 'success');
}
catch (error) {
showNotification(`Error deleting proxy: ${error === null || error === void 0 ? void 0 : error.message}`, 'error');
}
finally {
setLoading(false);
}
});
const toggleProxy = (domain, shouldStart) => __awaiter(this, void 0, void 0, function* () {
setLoading(true);
try {
const endpoint = shouldStart ? 'start' : 'stop';
const response = yield fetch(`/api/proxies/${domain}/${endpoint}`, {
method: 'POST'
});
if (!response.ok) {
const errorData = yield response.json();
throw new Error(errorData.error || `Failed to ${endpoint} proxy`);
}
yield fetchProxies();
const action = shouldStart ? 'started' : 'stopped';
showNotification(`Proxy for ${domain} ${action} successfully`, 'success');
}
catch (error) {
showNotification(`Error toggling proxy: ${error === null || error === void 0 ? void 0 : error.message}`, 'error');
}
finally {
setLoading(false);
}
});
const showNotification = (message, type) => {
setNotification({ message, type });
setTimeout(() => setNotification(null), 3000);
};
const refreshCertificate = (domain) => __awaiter(this, void 0, void 0, function* () {
setLoading(true);
try {
const response = yield fetch('/api/certificates', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ domain })
});
if (!response.ok)
throw new Error('Failed to refresh certificate');
yield fetchData();
showNotification(`Certificate for ${domain} refreshed successfully`, 'success');
}
catch (error) {
showNotification(`Error refreshing certificate: ${error === null || error === void 0 ? void 0 : error.message} `, 'error');
}
finally {
setLoading(false);
}
});
return (react_1.default.createElement("div", { className: "app-container" },
react_1.default.createElement("header", { className: "app-header" },
react_1.default.createElement("h1", null, "@axlotl-lab/navigrator"),
react_1.default.createElement("p", { className: "subtitle" }, "Local Domain Manager")),
loading && react_1.default.createElement("div", { className: "loading" }, "Loading..."),
error && (react_1.default.createElement("div", { className: "error-banner" },
react_1.default.createElement("p", null, error),
react_1.default.createElement("button", { onClick: fetchData }, "Retry"))),
notification && (react_1.default.createElement("div", { className: `notification ${notification.type} ` }, notification.message)),
confirmImport && (react_1.default.createElement("div", { className: "confirmation-dialog" },
react_1.default.createElement("div", { className: "confirmation-content" },
react_1.default.createElement("h3", null, "Import All Local Domains"),
react_1.default.createElement("p", null, "This will mark all local domains as managed by Navigrator. Are you sure?"),
react_1.default.createElement("div", { className: "confirmation-actions" },
react_1.default.createElement("button", { className: "button danger", onClick: () => setConfirmImport(false) }, "Cancel"),
react_1.default.createElement("button", { className: "button success", onClick: () => importAllDomains() }, "Confirm Import"))))),
confirmDeleteCertificate && (react_1.default.createElement("div", { className: "confirmation-dialog" },
react_1.default.createElement("div", { className: "confirmation-content" },
react_1.default.createElement("h3", null, "Delete Certificate"),
react_1.default.createElement("p", null,
"Are you sure you want to delete the certificate for ",
confirmDeleteCertificate,
"?"),
react_1.default.createElement("p", { className: "warning-text" }, "This action cannot be undone."),
react_1.default.createElement("div", { className: "confirmation-actions" },
react_1.default.createElement("button", { className: "button secondary", onClick: () => setConfirmDeleteCertificate(null) }, "Cancel"),
react_1.default.createElement("button", { className: "button danger", onClick: () => deleteCertificate(confirmDeleteCertificate) }, "Delete Certificate"))))),
confirmDeleteProxy && (react_1.default.createElement("div", { className: "confirmation-dialog" },
react_1.default.createElement("div", { className: "confirmation-content" },
react_1.default.createElement("h3", null, "Delete Proxy"),
react_1.default.createElement("p", null,
"Are you sure you want to delete the proxy for ",
confirmDeleteProxy,
"?"),
react_1.default.createElement("p", { className: "warning-text" }, "If the proxy is running, it will be stopped."),
react_1.default.createElement("div", { className: "confirmation-actions" },
react_1.default.createElement("button", { className: "button secondary", onClick: () => setConfirmDeleteProxy(null) }, "Cancel"),
react_1.default.createElement("button", { className: "button danger", onClick: () => deleteProxy(confirmDeleteProxy) }, "Delete Proxy"))))),
react_1.default.createElement("div", { className: "tabs" },
react_1.default.createElement("button", { className: activeTab === 'domains' ? 'active' : '', onClick: () => setActiveTab('domains') }, "Domains"),
react_1.default.createElement("button", { className: activeTab === 'certificates' ? 'active' : '', onClick: () => setActiveTab('certificates') }, "Certificates"),
react_1.default.createElement("button", { className: activeTab === 'proxies' ? 'active' : '', onClick: () => setActiveTab('proxies') }, "Proxies")),
react_1.default.createElement("div", { className: "tab-content" },
activeTab === 'domains' && (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement("form", { className: "add-domain-form", onSubmit: addDomain },
react_1.default.createElement("h2", null, "Add New Domain"),
react_1.default.createElement("div", { className: "form-row" },
react_1.default.createElement("input", { type: "text", placeholder: "Enter domain (e.g. myapp.local)", value: newDomain, onChange: (e) => setNewDomain(e.target.value), disabled: loading }),
react_1.default.createElement("button", { type: "submit", disabled: loading || !newDomain }, "Add Domain")),
react_1.default.createElement("p", { className: "help-text" }, "All domains will point to 127.0.0.1 and include a local SSL certificate")),
react_1.default.createElement("div", { className: "domains-list" },
react_1.default.createElement("div", { className: "domains-header" },
react_1.default.createElement("h2", null, "Your Local Domains"),
react_1.default.createElement("button", { className: "button secondary import-button", onClick: () => setConfirmImport(true), disabled: loading, title: "Import all local domains to manage them with Navigrator" }, "Import All Domains")),
domains.length === 0 ? (react_1.default.createElement("p", { className: "no-data" }, "No domains configured yet")) : (react_1.default.createElement("table", null,
react_1.default.createElement("thead", null,
react_1.default.createElement("tr", null,
react_1.default.createElement("th", null, "Domain"),
react_1.default.createElement("th", null, "Certificate"),
react_1.default.createElement("th", null, "State"),
react_1.default.createElement("th", null, "Actions"))),
react_1.default.createElement("tbody", null, domains.map((domain) => {
var _a, _b;
return (react_1.default.createElement("tr", { key: domain.domain, className: domain.isDisabled ? 'disabled-row' : '' },
react_1.default.createElement("td", null, domain.domain),
react_1.default.createElement("td", null,
react_1.default.createElement("span", { className: `status ${((_a = statuses[domain.domain]) === null || _a === void 0 ? void 0 : _a.certificateValid) ? 'valid' : 'invalid'} ` }, ((_b = statuses[domain.domain]) === null || _b === void 0 ? void 0 : _b.certificateValid) ? 'Valid' : 'Invalid/Missing')),
react_1.default.createElement("td", null,
react_1.default.createElement("span", { className: `status ${domain.isDisabled ? 'warning' : 'valid'}` }, domain.isDisabled ? 'Disabled' : 'Enabled')),
react_1.default.createElement("td", { className: "actions-cell" }, domain.isCreatedByUs ? (react_1.default.createElement(react_1.default.Fragment, null,
react_1.default.createElement("button", { onClick: () => toggleDomainState(domain.domain, !domain.isDisabled), className: `button ${domain.isDisabled ? 'success' : 'warning'}`, disabled: loading, title: domain.isDisabled ? 'Enable domain' : 'Disable domain' }, domain.isDisabled ? 'Enable' : 'Disable'),
react_1.default.createElement("button", { onClick: () => refreshCertificate(domain.domain), className: "button secondary", disabled: loading, title: "Refresh SSL certificate" }, "Refresh Cert"),
react_1.default.createElement("button", { onClick: () => removeDomain(domain.domain), className: "button danger", disabled: loading, title: "Remove domain" }, "Remove"))) : (react_1.default.createElement("button", { onClick: () => adoptDomain(domain.domain, domain.ip), className: "button primary adopt-button", disabled: loading, title: "Start managing this domain with Navigrator" }, "Adopt")))));
}))))))),
activeTab === 'certificates' && (react_1.default.createElement("div", { className: "certificates-list" },
react_1.default.createElement("h2", null, "SSL Certificates"),
certificates.length === 0 ? (react_1.default.createElement("p", { className: "no-data" }, "No certificates generated yet")) : (react_1.default.createElement("table", null,
react_1.default.createElement("thead", null,
react_1.default.createElement("tr", null,
react_1.default.createElement("th", null, "Domain"),
react_1.default.createElement("th", null, "Status"),
react_1.default.createElement("th", null, "Issuer"),
react_1.default.createElement("th", null, "Valid Until"),
react_1.default.createElement("th", null, "Actions"))),
react_1.default.createElement("tbody", null, certificates.map((cert) => (react_1.default.createElement("tr", { key: cert.domain },
react_1.default.createElement("td", null, cert.domain),
react_1.default.createElement("td", null,
react_1.default.createElement("span", { className: `status ${cert.isValid ? 'valid' : 'invalid'} ` }, cert.isValid ? 'Valid' : 'Invalid')),
react_1.default.createElement("td", null, cert.issuer),
react_1.default.createElement("td", null, new Date(cert.validTo).toLocaleDateString()),
react_1.default.createElement("td", { className: "actions-cell" },
react_1.default.createElement("button", { onClick: () => refreshCertificate(cert.domain), className: "button secondary", disabled: loading, title: "Refresh certificate" }, "Refresh"),
react_1.default.createElement("button", { onClick: () => setConfirmDeleteCertificate(cert.domain), className: "button danger", disabled: loading, title: "Delete certificate" }, "Delete")))))))))),
activeTab === 'proxies' && (react_1.default.createElement(react_1.default.Fragment, null,
editProxy ? (react_1.default.createElement("form", { className: "add-domain-form", onSubmit: updateProxy },
react_1.default.createElement("h2", null,
"Edit Proxy for ",
editProxy.domain),
react_1.default.createElement("div", { className: "form-row" },
react_1.default.createElement("input", { type: "text", placeholder: "Target URL (e.g. localhost:3000)", value: editProxy.target, onChange: (e) => setEditProxy(Object.assign(Object.assign({}, editProxy), { target: e.target.value })), disabled: loading }),
react_1.default.createElement("input", { type: "number", placeholder: "Port (default: 443)", value: editProxy.port, onChange: (e) => setEditProxy(Object.assign(Object.assign({}, editProxy), { port: parseInt(e.target.value) || 443 })), disabled: loading, className: "port-input" }),
react_1.default.createElement("button", { type: "submit", disabled: loading || !editProxy.target }, "Update Proxy"),
react_1.default.createElement("button", { type: "button", className: "button secondary", onClick: () => setEditProxy(null), disabled: loading }, "Cancel")))) : (react_1.default.createElement("form", { className: "add-domain-form", onSubmit: addProxy },
react_1.default.createElement("h2", null, "Create HTTPS Proxy"),
react_1.default.createElement("div", { className: "form-row form-row-multi" },
react_1.default.createElement("div", { className: "input-group" },
react_1.default.createElement("label", { htmlFor: "proxy-domain" }, "Domain"),
react_1.default.createElement("select", { id: "proxy-domain", value: newProxy.domain, onChange: (e) => setNewProxy(Object.assign(Object.assign({}, newProxy), { domain: e.target.value })), disabled: loading, required: true },
react_1.default.createElement("option", { value: "" }, "Select a domain"),
domains
.filter(domain => {
var _a;
return !domain.isDisabled &&
((_a = statuses[domain.domain]) === null || _a === void 0 ? void 0 : _a.certificateValid) &&
!proxies.find(p => p.domain === domain.domain);
})
.map(domain => (react_1.default.createElement("option", { key: domain.domain, value: domain.domain }, domain.domain))))),
react_1.default.createElement("div", { className: "input-group" },
react_1.default.createElement("label", { htmlFor: "proxy-target" }, "Target URL"),
react_1.default.createElement("input", { id: "proxy-target", type: "text", placeholder: "localhost:3000", value: newProxy.target, onChange: (e) => setNewProxy(Object.assign(Object.assign({}, newProxy), { target: e.target.value })), disabled: loading, required: true })),
react_1.default.createElement("div", { className: "input-group" },
react_1.default.createElement("label", { htmlFor: "proxy-port" }, "HTTPS Port"),
react_1.default.createElement("input", { id: "proxy-port", type: "number", placeholder: "443", value: newProxy.port, onChange: (e) => setNewProxy(Object.assign(Object.assign({}, newProxy), { port: parseInt(e.target.value) || 443 })), disabled: loading, min: "1", max: "65535", className: "port-input" })),
react_1.default.createElement("button", { type: "submit", disabled: loading || !newProxy.domain || !newProxy.target, className: "button primary create-proxy-button" }, "Create Proxy")),
react_1.default.createElement("p", { className: "help-text" }, "Create a secure HTTPS proxy to your local development server. Traffic to your domain will be forwarded to the target URL."))),
react_1.default.createElement("div", { className: "proxies-list" },
react_1.default.createElement("h2", null, "Your Proxies"),
proxies.length === 0 ? (react_1.default.createElement("p", { className: "no-data" }, "No proxies configured yet")) : (react_1.default.createElement("table", null,
react_1.default.createElement("thead", null,
react_1.default.createElement("tr", null,
react_1.default.createElement("th", null, "Domain"),
react_1.default.createElement("th", null, "Target"),
react_1.default.createElement("th", null, "Port"),
react_1.default.createElement("th", null, "Status"),
react_1.default.createElement("th", null, "Actions"))),
react_1.default.createElement("tbody", null, proxies.map((proxy) => (react_1.default.createElement("tr", { key: proxy.domain },
react_1.default.createElement("td", null, proxy.domain),
react_1.default.createElement("td", null, proxy.target),
react_1.default.createElement("td", null, proxy.port),
react_1.default.createElement("td", null,
react_1.default.createElement("span", { className: `status ${proxy.isRunning ? 'valid' : 'warning'}` }, proxy.isRunning ? 'Running' : 'Stopped')),
react_1.default.createElement("td", { className: "actions-cell" },
proxy.isRunning ? (react_1.default.createElement("button", { onClick: () => toggleProxy(proxy.domain, false), className: "button warning", disabled: loading, title: "Stop proxy" }, "Stop")) : (react_1.default.createElement("button", { onClick: () => toggleProxy(proxy.domain, true), className: "button success", disabled: loading, title: "Start proxy" }, "Start")),
react_1.default.createElement("button", { onClick: () => setEditProxy(proxy), className: "button secondary", disabled: loading || proxy.isRunning, title: proxy.isRunning ? "Stop proxy before editing" : "Edit proxy configuration" }, "Edit"),
react_1.default.createElement("button", { onClick: () => setConfirmDeleteProxy(proxy.domain), className: "button danger", disabled: loading, title: "Delete proxy" }, "Delete"))))))))))))));
}
exports.default = App;