189 lines
7.4 KiB
JavaScript
189 lines
7.4 KiB
JavaScript
$(function() {
|
|
function TailscaleFunnelViewModel(parameters) {
|
|
var self = this;
|
|
|
|
self.settings = parameters[0];
|
|
|
|
// Status observables
|
|
self.funnelStatus = ko.observable("Checking...");
|
|
self.funnelEnabled = ko.observable(false);
|
|
self.publicUrl = ko.observable("Not available");
|
|
self.tailscaleInstalled = ko.observable(true);
|
|
self.tailscaleRunning = ko.observable(true);
|
|
|
|
// Button states
|
|
self.refreshInProgress = ko.observable(false);
|
|
self.toggleInProgress = ko.observable(false);
|
|
|
|
// Initialize
|
|
self.onStartup = function() {
|
|
self.refreshStatus();
|
|
};
|
|
|
|
// Refresh the status
|
|
self.refreshStatus = function() {
|
|
if (self.refreshInProgress()) {
|
|
return;
|
|
}
|
|
|
|
self.refreshInProgress(true);
|
|
self.funnelStatus("Checking...");
|
|
|
|
$.ajax({
|
|
url: PLUGIN_BASEURL + "tailscale_funnel/status",
|
|
type: "GET",
|
|
dataType: "json",
|
|
success: function(response) {
|
|
if (response.status === "success") {
|
|
self.tailscaleInstalled(response.data.tailscale_installed);
|
|
self.tailscaleRunning(response.data.tailscale_running);
|
|
|
|
if (response.data.tailscale_installed && response.data.tailscale_running) {
|
|
self.funnelEnabled(response.data.funnel_enabled);
|
|
self.funnelStatus(response.data.funnel_enabled ? "Enabled" : "Disabled");
|
|
self.publicUrl(response.data.public_url || "Not available");
|
|
} else if (!response.data.tailscale_installed) {
|
|
self.funnelStatus("Tailscale not installed");
|
|
} else if (!response.data.tailscale_running) {
|
|
self.funnelStatus("Tailscale not running");
|
|
}
|
|
} else {
|
|
self.funnelStatus("Error: " + response.message);
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
self.funnelStatus("Error: " + error);
|
|
},
|
|
complete: function() {
|
|
self.refreshInProgress(false);
|
|
}
|
|
});
|
|
};
|
|
|
|
// Toggle funnel on/off
|
|
self.toggleFunnel = function() {
|
|
if (self.toggleInProgress()) {
|
|
return;
|
|
}
|
|
|
|
var enable = !self.funnelEnabled();
|
|
|
|
// Show confirmation if required
|
|
if (self.settings.settings.plugins.tailscale_funnel.confirm_enable() && enable) {
|
|
if (!confirm("Enabling Funnel will make your OctoPrint instance accessible from the public internet. Do you want to continue?")) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
self.toggleInProgress(true);
|
|
self.funnelStatus(enable ? "Enabling..." : "Disabling...");
|
|
|
|
var action = enable ? "enable" : "disable";
|
|
|
|
$.ajax({
|
|
url: PLUGIN_BASEURL + "tailscale_funnel/" + action,
|
|
type: "POST",
|
|
dataType: "json",
|
|
success: function(response) {
|
|
if (response.status === "success") {
|
|
self.funnelEnabled(enable);
|
|
self.funnelStatus(enable ? "Enabled" : "Disabled");
|
|
|
|
if (enable && response.data && response.data.public_url) {
|
|
self.publicUrl(response.data.public_url);
|
|
} else if (!enable) {
|
|
self.publicUrl("Not available");
|
|
}
|
|
|
|
// Show success message
|
|
new PNotify({
|
|
title: "Tailscale Funnel",
|
|
text: response.message,
|
|
type: "success"
|
|
});
|
|
} else {
|
|
self.funnelStatus("Error");
|
|
// Show error message
|
|
new PNotify({
|
|
title: "Tailscale Funnel Error",
|
|
text: response.message,
|
|
type: "error"
|
|
});
|
|
}
|
|
},
|
|
error: function(xhr, status, error) {
|
|
self.funnelStatus("Error");
|
|
// Show error message
|
|
new PNotify({
|
|
title: "Tailscale Funnel Error",
|
|
text: "Failed to " + action + " Funnel: " + error,
|
|
type: "error"
|
|
});
|
|
},
|
|
complete: function() {
|
|
self.toggleInProgress(false);
|
|
}
|
|
});
|
|
};
|
|
|
|
// Copy URL to clipboard
|
|
self.copyUrlToClipboard = function() {
|
|
if (self.publicUrl() && self.publicUrl() !== "Not available") {
|
|
navigator.clipboard.writeText(self.publicUrl()).then(function() {
|
|
new PNotify({
|
|
title: "Copied to Clipboard",
|
|
text: "Public URL copied to clipboard",
|
|
type: "success"
|
|
});
|
|
}, function() {
|
|
// Fallback for older browsers
|
|
var textArea = document.createElement("textarea");
|
|
textArea.value = self.publicUrl();
|
|
document.body.appendChild(textArea);
|
|
textArea.select();
|
|
try {
|
|
document.execCommand("copy");
|
|
new PNotify({
|
|
title: "Copied to Clipboard",
|
|
text: "Public URL copied to clipboard",
|
|
type: "success"
|
|
});
|
|
} catch (err) {
|
|
new PNotify({
|
|
title: "Copy Failed",
|
|
text: "Failed to copy URL to clipboard",
|
|
type: "error"
|
|
});
|
|
}
|
|
document.body.removeChild(textArea);
|
|
});
|
|
}
|
|
};
|
|
|
|
// Handle messages from the backend
|
|
self.onDataUpdaterPluginMessage = function(plugin, data) {
|
|
if (plugin !== "tailscale_funnel") {
|
|
return;
|
|
}
|
|
|
|
if (data.type === "funnel_status_change") {
|
|
self.funnelEnabled(data.enabled);
|
|
self.funnelStatus(data.enabled ? "Enabled" : "Disabled");
|
|
|
|
if (data.enabled) {
|
|
// Refresh to get the public URL
|
|
self.refreshStatus();
|
|
} else {
|
|
self.publicUrl("Not available");
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
// Register the ViewModel
|
|
OCTOPRINT_VIEWMODELS.push({
|
|
construct: TailscaleFunnelViewModel,
|
|
dependencies: ["settingsViewModel"],
|
|
elements: []
|
|
});
|
|
}); |