+
diff --git a/vscode-plugin/media/wizard.js b/vscode-plugin/media/wizard.js
deleted file mode 100644
index 78429a81c..000000000
--- a/vscode-plugin/media/wizard.js
+++ /dev/null
@@ -1,377 +0,0 @@
-window.addEventListener('message', event => {
- const message = event.data; // The JSON data our extension sent
- switch (message.command) {
- case 'test_connection_success':
- showConnectionSuccessStatus(message.clientVersion, message.serverVersion);
- break;
- case 'test_connection_failure':
- showConnectionFailureStatus();
- break;
- case 'check_connection_success':
- showConnectionSuccessStatus(message.clientVersion, message.serverVersion);
- nextStep();
- break;
- case 'check_connection_failure':
- showConnectionFailureStatus();
- openModal();
- break;
- default:
- console.log(`ERROR: Unknown message: ${message.command}`);
- break;
- }
-});
-
-function $(id) {
- return document.getElementById(id);
-}
-
-/*
- * Communication with VSCode via API
- */
-const vscode = acquireVsCodeApi();
-function DbgMessage(message) {
- vscode.postMessage({
- command: 'dbg_message',
- message: message
- });
-}
-
-const os = getVarValue("os");
-console.log(`OS Platform: ${os}`);
-
-let nonLocalGRPCPort = getVarValue("defaultPort");
-let nonLocalHost = getVarValue("sftpHost");
-let nonLocalRemoteDir = getVarValue("sftpDir");
-let currentTabIndex = 0;
-
-function onStart() {
- DbgMessage("OnStart");
- const hostInput = $('hostInput');
- const portInput = $('portInput');
- const mappingInput = $('mappingInput');
- if (hostInput.value === "localhost"
- && portInput.value === getVarValue("defaultPort")
- && mappingInput.value === getVarValue("projectDir")) {
- $('useLocalHost').checked = true;
- hostInput.disabled = true;
- portInput.disabled = true;
- mappingInput.disabled = true;
- }
- if (os === 'win32') {
- removeElementByClassName('installer-tab');
- removeElementByClassName('installer-step');
- }
- showTab(currentTabIndex);
-}
-
-onStart();
-
-function showTab(tabIndex) {
- const prevButton = $("prevBtn");
- const nextButton = $("nextBtn");
-
- const tabElements = document.getElementsByClassName("utbot-form__tab");
- const currentTabElement = tabElements[tabIndex];
- currentTabElement.classList.add('active');
-
- // Show previous button if necessary
- if (tabIndex === 0) {
- prevButton.classList.remove('active');
- } else {
- prevButton.classList.add('active');
- }
-
- // Set nextButton title according to tab number
- if (tabIndex === tabElements.length - 1) {
- nextButton.innerHTML = "Finish";
- } else {
- nextButton.innerHTML = "Next";
- }
- fixStepIndicator(tabIndex);
-}
-
-let checkHostTimer = null;
-function showProgress(toShow) {
- showElement($("connection_loader"), toShow);
- if (toShow) {
- showElement($("connection_success"), false);
- showElement($("connection_warning"), false);
- showElement($("connection_failure"), false);
- }
-}
-
-function showElement(el, toShow) {
- if (toShow) {
- el.classList.add('active');
- }
- else {
- el.classList.remove('active');
- }
-}
-
-function restartCheckingConnection() {
- if (checkHostTimer != null) {
- clearTimeout(checkHostTimer);
- checkHostTimer = null;
- showProgress(false);
- }
- checkHostTimer = setTimeout(testConnection, 250, false);
- showProgress(true);
-}
-
-function isConnectionTab() {
- const tab = document.getElementsByClassName("connection-tab");
- if (!tab || tab.length !== 1) {
- console.log("Something is wrong: connection-tab");
- return;
- }
- return tab[0].classList.contains("active");
-}
-
-function nextButtonHandler() {
- if (isConnectionTab()) {
- testConnection(true);
- }
- else {
- nextStep();
- if (isConnectionTab()) {
- testConnection(false);
- }
- }
-}
-
-function prevButtonHandler() {
- prevStep();
-}
-
-function nextStep() {
- return nextPrev(1);
-}
-
-function prevStep() {
- return nextPrev(-1);
-}
-
-function showConnectionSuccessStatus(clientVersion, serverVersion) {
- showProgress(false);
- if (clientVersion !== serverVersion) {
- const connectionWarning = $("connection_warning");
- connectionWarning.innerText =
- connectionWarning.getAttribute("format").toString()
- + " "
- + `Server: ${serverVersion}, Client: ${clientVersion}`;
- showElement($("connection_success"), false);
- showElement(connectionWarning, true);
- }
- else {
- showElement($("connection_success"), true);
- showElement($("connection_warning"), false);
- }
- showElement($("connection_failure"), false);
-}
-
-function showConnectionFailureStatus() {
- showProgress(false);
- showElement($("connection_success"), false);
- showElement($("connection_warning"), false);
- showElement($("connection_failure"), true);
-}
-
-function showConnectionLoadingStatus() {
- showProgress(true);
-}
-
-function nextPrev(tabShift) {
- if (tabShift !== 1 && tabShift !== -1) {
- return false;
- }
- let tabElements = document.getElementsByClassName("utbot-form__tab");
- let currentTabElement = tabElements[currentTabIndex];
- if (tabShift === 1 && !validateForm()) {
- return false;
- }
- let actionToPerform = currentTabElement.getAttribute("vs-message-callback");
- if (actionToPerform) {
- eval(actionToPerform)
- }
- currentTabElement.classList.remove('active');
-
- currentTabIndex = currentTabIndex + tabShift;
- if (currentTabIndex >= tabElements.length) {
- closeWizard();
- return false;
- }
-
- restoreOriginalStateOfSomeElements();
- showTab(currentTabIndex);
-}
-
-function validateForm() {
- // This function deals with validation of the form fields
- let valid = true;
- let tabElements = document.getElementsByClassName("utbot-form__tab");
- let tabInputs = tabElements[currentTabIndex].getElementsByTagName("input");
- for (let i = 0; i < tabInputs.length; i++) {
- let tabInput = tabInputs[i];
- if (tabInput.value === "") {
- tabInput.value = tabInput.placeholder;
- }
- if (tabInput.value === "" || !tabInput.checkValidity()) {
- // TODO: custom validators
- tabInput.classList.add("invalid");
- valid = false;
- }
- }
- if (valid) {
- document.getElementsByClassName("utbot-form__steps_step")[currentTabIndex].classList.add("finish");
- }
- return valid;
-}
-
-function fixStepIndicator(tabIndex) {
- let steps = document.getElementsByClassName("utbot-form__steps_step");
- for (let i = 0; i < steps.length; i++) {
- steps[i].classList.remove("active");
- if (i > tabIndex) {
- steps[tabIndex].classList.remove('finish');
- }
- }
- steps[tabIndex].classList.add("active");
-}
-
-function closeModal() {
- let modal = document.getElementsByClassName("utbot-modal");
- if (!modal || modal.length !== 1) {
- console.log("Something is wrong, can't close modal");
- return;
- }
- modal[0].classList.remove("active");
-}
-
-function openModal() {
- let modal = document.getElementsByClassName("utbot-modal");
- if (!modal || modal.length !== 1) {
- console.log("Something is wrong, can't open modal");
- return;
- }
- modal[0].classList.add("active");
-}
-
-function closeModalAndGoToNextStep() {
- closeModal();
- nextStep();
-}
-
-function restoreOriginalStateOfSomeElements() {
- const button = $("runInstallerBtn");
- const messageBlock = document.getElementsByClassName("utbot-form__tab_installer_message")[0]
- if (button !== undefined && button !== null) {
- button.disabled = false;
- }
- if (messageBlock !== undefined && messageBlock !== null) {
- messageBlock.classList.remove("active");
- }
-}
-
-function getVarValue(name) {
- DbgMessage("var = " + document.getElementsByClassName("utbot-vars")[0].getAttribute(name));
- return document.getElementsByClassName("utbot-vars")[0].getAttribute(name);
-}
-
-function removeElementByClassName(className) {
- const removableElements = document.getElementsByClassName(className);
- for (let i = 0; i < removableElements.length; i++) {
- const parentNode = removableElements[i].parentNode;
- if (parentNode !== undefined || parentNode !== null) {
- parentNode.removeChild(removableElements[i]);
- }
- }
-}
-
-function handleOnOffDefaultConfigurationOnLocalhost() {
- const mappingInput = $('mappingInput');
- const hostInput = $('hostInput');
- const portInput = $('portInput');
- const useLocalhost = $('useLocalHost').checked;
- if (useLocalhost) {
- DbgMessage("Local host is used!");
-
- nonLocalHost = hostInput.value;
- hostInput.value = "localhost";
-
- nonLocalGRPCPort = portInput.value;
- portInput.value = getVarValue("defaultPort");
-
- nonLocalRemoteDir = mappingInput.value;
- mappingInput.value = getVarValue("projectDir");
- }
- else {
- DbgMessage("Local host is not used!");
- hostInput.value = nonLocalHost;
- portInput.value = nonLocalGRPCPort;
- mappingInput.value = nonLocalRemoteDir;
- }
- mappingInput.disabled= useLocalhost;
- hostInput.disabled = useLocalhost;
- portInput.disabled = useLocalhost;
-
- restartCheckingConnection();
-}
-
-function sendServerSetup() {
- vscode.postMessage({
- command: 'set_server_setup',
- host: $('hostInput').value,
- port: parseInt($('portInput').value),
- mappingPath: $('mappingInput').value,
- });
-}
-
-function sendBuildInfo() {
- const buildDirInputElement = $('buildDirectory');
- const cmakeOptionsInputElement = $('cmakeOptions');
- vscode.postMessage({
- command: 'set_build_info',
- buildDirectory: buildDirInputElement.value,
- cmakeOptions: cmakeOptionsInputElement.value
- });
-}
-
-/**
- * Request to test the connection with host
- */
-function testConnection(withNextContinuation) {
- const hostInputElement = $('hostInput');
- const portInputElement = $('portInput');
- showProgress(true);
- vscode.postMessage({
- command: (withNextContinuation ? 'check_connection' : 'test_connection'),
- host: hostInputElement.value,
- port: parseInt(portInputElement.value)
- });
-}
-
-/**
- * Request to run installation script.
- */
-function runInstaller() {
- const button = $("runInstallerBtn");
- const messageBlock = document.getElementsByClassName("utbot-form__tab_installer_message")[0]
- button.disabled = true;
- messageBlock.classList.add("active");
- vscode.postMessage({
- command: 'run_installer'
- });
-}
-
-function closeWizard() {
- vscode.postMessage({ command: 'close_wizard' });
-}
-
-function openSFTPSettings(paramKey) {
- DbgMessage("openSFTPSettings");
- vscode.postMessage({
- command: 'openSFTPSettings',
- key: paramKey
- });
-}
\ No newline at end of file
diff --git a/vscode-plugin/media/wizard.css b/vscode-plugin/media/wizardHTML.css
similarity index 86%
rename from vscode-plugin/media/wizard.css
rename to vscode-plugin/media/wizardHTML.css
index 9512ccd10..a088d8763 100644
--- a/vscode-plugin/media/wizard.css
+++ b/vscode-plugin/media/wizardHTML.css
@@ -61,20 +61,44 @@
}
/* By default turn off connection status */
-#connection_loader,
-#connection_success,
-#connection_warning,
-#connection_failure {
+#GRPC_connection_loader,
+#GRPC_connection_success,
+#GRPC_connection_warning,
+#GRPC_connection_failure,
+#SFTP_connection_loader,
+#SFTP_connection_success,
+#SFTP_connection_warning,
+#SFTP_connection_failure {
display: none;
}
-#connection_loader.active,
-#connection_success.active,
-#connection_warning.active,
-#connection_failure.active {
+#GRPC_connection_loader.active,
+#GRPC_connection_success.active,
+#GRPC_connection_warning.active,
+#GRPC_connection_failure.active,
+#SFTP_connection_loader.active,
+#SFTP_connection_success.active,
+#SFTP_connection_warning.active,
+#SFTP_connection_failure.active {
display: inline-block;
}
+/* plugin status */
+#SFTP_installed,
+#SFTP_not_installed,
+#SARIF_installed,
+#SARIF_not_installed {
+ display: none;
+}
+
+#SFTP_installed.active,
+#SFTP_not_installed.active,
+#SARIF_installed.active,
+#SARIF_not_installed.active {
+ display: inline-block;
+}
+
+
.utbot-form__steps_step.finish {
background-color: var(--vscode-editorInfo-foreground);
}
@@ -286,7 +310,14 @@
display: block;
}
-
.utbot-vars {
display: none;
}
+
+a.invalid,
+input.invalid,
+textarea.invalid{
+ outline-style: solid;
+ outline-width: thin;
+ outline-color: #FF4136
+}
diff --git a/vscode-plugin/media/wizardHTML.js b/vscode-plugin/media/wizardHTML.js
new file mode 100644
index 000000000..479ab253a
--- /dev/null
+++ b/vscode-plugin/media/wizardHTML.js
@@ -0,0 +1,482 @@
+
+// external declaration in HTML
+// const GRPC_PREFIX = "GRPC_";
+// const SFTP_PREFIX = "SFTP_";
+
+window.addEventListener('message', event => {
+ const message = event.data; // The JSON data our extension sent
+ //DbgMessage("addEventListener : " + message.command);
+ if (message.command === "checkPlugins") {
+ showPluginStatus("SFTP_", message.sftpPluginInstalled);
+ showPluginStatus("SARIF_", message.sarifPluginInstalled);
+ return;
+ }
+ let prefix = "";
+ if (message.command.startsWith(GRPC_PREFIX)) {
+ prefix = GRPC_PREFIX;
+ }
+ else if (message.command.startsWith(SFTP_PREFIX)) {
+ prefix = SFTP_PREFIX;
+ }
+ //DbgMessage("addEventListener prefix : " + prefix);
+ if (message.command.endsWith('test_connection_success')) {
+ showConnectionSuccessStatus(prefix, message.clientVersion, message.serverVersion);
+ //DbgMessage("addEventListener res : test_connection_success");
+ }
+ else if (message.command.endsWith('test_connection_failure')) {
+ showConnectionFailureStatus(prefix);
+ //DbgMessage("addEventListener res : test_connection_failure");
+ }
+ else {
+ console.log(`ERROR: Unknown message: ${message.command}`);
+ }
+});
+
+function $(id) {
+ return document.getElementById(id);
+}
+
+/*
+ * Communication with VSCode via API
+ */
+const vscode = acquireVsCodeApi();
+function DbgMessage(message) {
+ vscode.postMessage({
+ command: 'dbg_message',
+ message: message
+ });
+}
+
+const os = getVarValue("os");
+console.log(`OS Platform: ${os}`);
+
+let nonLocalGRPCPort = getVarValue("defaultGRPCPort");
+let nonLocalSFTPPort = getVarValue("defaultSFTPPort");
+let nonLocalHost = getVarValue("serverHost");
+let nonLocalRemoteDir = getVarValue("serverDir");
+let currentTabIndex = 0;
+
+function showProgress(prefix, toShow) {
+ showElement($(prefix + "connection_loader"), toShow);
+ if (toShow) {
+ showElement($(prefix + "connection_success"), false);
+ showElement($(prefix + "connection_warning"), false);
+ showElement($(prefix + "connection_failure"), false);
+ }
+}
+
+function showElement(el, toShow) {
+ if (!el)
+ return;
+
+ if (toShow) {
+ el.classList.add('active');
+ }
+ else {
+ el.classList.remove('active');
+ }
+}
+
+function isActive(el) {
+ if (!el)
+ return true;
+ return el.classList.contains("active");
+}
+
+function isConnectionPortValid(el, prefix) {
+ let valid = isActive($(prefix + "connection_success")) || isActive($(prefix + "connection_warning"))
+ setValid(el, valid);
+ return valid;
+}
+
+
+const mapTimerId = {};
+function restartCheckingConnection(prefix, pause) {
+ if (mapTimerId[prefix] != null) {
+ clearTimeout(mapTimerId[prefix]);
+ showProgress(prefix, false);
+ }
+ mapTimerId[prefix] = setTimeout(testConnection, pause, prefix);
+}
+
+const pluginId = "plugin";
+function restartCheckingPlugin(pause) {
+ if (mapTimerId[pluginId] != null) {
+ clearTimeout(mapTimerId[pluginId]);
+ }
+ mapTimerId[pluginId] = setTimeout(testPlugin, pause);
+}
+
+function testPlugin() {
+ vscode.postMessage({
+ command: 'check_plugins'
+ });
+}
+
+function isTabWithClass(clazz) {
+ const tab = document.getElementsByClassName(clazz);
+ if (!tab || tab.length !== 1) {
+ DbgMessage("Something is wrong: " + clazz);
+ return false;
+ }
+ return isActive(tab[0]);
+}
+
+function isConnectionTab() {
+ return isTabWithClass("connection-tab");
+}
+
+function isStartTab() {
+ return isTabWithClass("start-tab");
+}
+
+function onStart() {
+ const hostInput = $('hostInput');
+ const portGRPCInput = $('portGRPCInput');
+ const portSFTPInput = $('portSFTPInput');
+ const serverPath = $('serverPath');
+
+ // DbgMessage("hostInput.value : " + hostInput.value);
+ // DbgMessage("portGRPCInput.value : " + portGRPCInput.value + " " + getVarValue("defaultGRPCPort"));
+ // DbgMessage("serverPath.value : " + serverPath.value + " " + getVarValue("projectDir"));
+
+ if (hostInput.value === "localhost"
+ && portGRPCInput.value === getVarValue("defaultGRPCPort")
+ && serverPath.value === getVarValue("projectDir")) {
+ $('useLocalHost').checked = true;
+ hostInput.disabled = true;
+ portGRPCInput.disabled = true;
+
+ portSFTPInput.disabled = true;
+ portSFTPInput.value = "";
+
+ serverPath.disabled = true;
+ }
+ if (os === 'win32') {
+ removeElementByClassName('installer-tab');
+ removeElementByClassName('installer-step');
+ }
+ restartCheckingPlugin(0);
+ showTab(currentTabIndex);
+}
+
+onStart();
+
+function showTab(tabIndex) {
+ const prevButton = $("prevBtn");
+ const nextButton = $("nextBtn");
+
+ const tabElements = document.getElementsByClassName("utbot-form__tab");
+ const currentTabElement = tabElements[tabIndex];
+
+ showElement(currentTabElement, true);
+ // Show previous button if necessary
+ showElement(prevButton, tabIndex === 0);
+
+ // Set nextButton title according to tab number
+ if (tabIndex === tabElements.length - 1) {
+ nextButton.innerHTML = "Finish";
+ } else {
+ nextButton.innerHTML = "Next";
+ }
+ fixStepIndicator(tabIndex);
+}
+
+function nextStep() {
+ let res = nextPrev(1);
+ if (isConnectionTab()) {
+ restartCheckingConnection(GRPC_PREFIX, 0);
+ restartCheckingConnection(SFTP_PREFIX, 0);
+ } else if (isStartTab()) {
+ restartCheckingPlugin(0);
+ }
+ return res;
+}
+
+function prevStep() {
+ return nextPrev(-1);
+}
+
+function showConnectionSuccessStatus(prefix, clientVersion, serverVersion) {
+ showProgress(prefix, false);
+ if (clientVersion !== serverVersion) {
+ const connectionWarning = $(prefix + "connection_warning");
+ if (connectionWarning.getAttribute("format") !== null) {
+ connectionWarning.innerText =
+ connectionWarning.getAttribute("format").toString()
+ + " "
+ + `Server: ${serverVersion}, Client: ${clientVersion}`;
+ }
+ showElement($(prefix + "connection_success"), false);
+ showElement(connectionWarning, true);
+ }
+ else {
+ showElement($(prefix + "connection_success"), true);
+ showElement($(prefix + "connection_warning"), false);
+ }
+ showElement($(prefix + "connection_failure"), false);
+}
+
+function showConnectionFailureStatus(prefix) {
+ showProgress(prefix, false);
+ showElement($(prefix + "connection_success"), false);
+ showElement($(prefix + "connection_warning"), false);
+ showElement($(prefix + "connection_failure"), true);
+ // just ping if failed, maybe server down
+ //restartCheckingConnection(prefix, 1500);
+}
+
+function showPluginStatus(prefix, installed) {
+ showElement($(prefix + "installed"), installed);
+ showElement($(prefix + "not_installed"), !installed);
+ if (!installed) {
+ restartCheckingPlugin(1000);
+ }
+}
+
+function isPluginInstalledAndMarkValid(prefix) {
+ let active = isActive($(prefix + "installed"));
+ setValid($(prefix + "ref"), active);
+ return active;
+}
+
+function nextPrev(tabShift) {
+ if (tabShift !== 1 && tabShift !== -1) {
+ return false;
+ }
+ let tabElements = document.getElementsByClassName("utbot-form__tab");
+ let currentTabElement = tabElements[currentTabIndex];
+ if (tabShift === 1 && !validateForm()) {
+ return false;
+ }
+ let actionToPerform = currentTabElement.getAttribute("vs-message-callback");
+ if (tabShift === 1 && actionToPerform) {
+ // make setup action only on the way forward
+ eval(actionToPerform)
+ }
+ currentTabElement.classList.remove('active');
+
+ currentTabIndex = currentTabIndex + tabShift;
+ if (currentTabIndex >= tabElements.length) {
+ closeWizard();
+ return false;
+ }
+
+ restoreOriginalStateOfSomeElements();
+ showTab(currentTabIndex);
+ return true;
+}
+
+function setValid(el, valid) {
+ if (!el)
+ return;
+
+ if (!valid) {
+ el.classList.add("invalid");
+ } else {
+ el.classList.remove("invalid");
+ }
+}
+
+function checkInputValidAsNotEmpty(el, syncValidStatus) {
+ if (!el)
+ return;
+
+ let valid = !!el.value;
+ if (syncValidStatus) {
+ setValid(el, valid);
+ }
+ return valid;
+}
+
+function defaultValidateForEmptyValue() {
+ let valid = true;
+ let tabElements = document.getElementsByClassName("utbot-form__tab");
+ let tabInputs = tabElements[currentTabIndex].getElementsByTagName("input");
+ for (let i = 0; i < tabInputs.length; i++) {
+ valid &= checkInputValidAsNotEmpty(tabInputs[i], true);
+ }
+ return valid;
+}
+
+function validateForm() {
+ let valid = true;
+ if (isStartTab()) {
+ // call them all - we need to mark all invalid input
+ valid &= isPluginInstalledAndMarkValid("SFTP_")
+ valid &= isPluginInstalledAndMarkValid("SARIF_");
+ } else if (isConnectionTab()) {
+ // call them all - we need to mark all invalid input
+ valid &= isConnectionPortValid($("portGRPCInput"), GRPC_PREFIX);
+ valid &= isConnectionPortValid($("portSFTPInput"), SFTP_PREFIX);
+ valid &= checkInputValidAsNotEmpty($("hostInput"), true);
+ valid &= checkInputValidAsNotEmpty($("serverPath"), true);
+ } else {
+ valid = this.defaultValidateForEmptyValue();
+ }
+
+ if (valid) {
+ document.getElementsByClassName("utbot-form__steps_step")[currentTabIndex].classList.add("finish");
+ }
+ return valid;
+}
+
+function fixStepIndicator(tabIndex) {
+ let steps = document.getElementsByClassName("utbot-form__steps_step");
+ for (let i = 0; i < steps.length; i++) {
+ steps[i].classList.remove("active");
+ if (i > tabIndex) {
+ steps[tabIndex].classList.remove('finish');
+ }
+ }
+ steps[tabIndex].classList.add("active");
+}
+
+function restoreOriginalStateOfSomeElements() {
+ const button = $("runInstallerBtn");
+ const messageBlock = document.getElementsByClassName("utbot-form__tab_installer_message")[0];
+ if (button !== undefined && button !== null) {
+ button.disabled = false;
+ }
+ if (messageBlock !== undefined && messageBlock !== null) {
+ messageBlock.classList.remove("active");
+ }
+}
+
+function getVarValue(name) {
+ //DbgMessage(name + " = " + document.getElementsByClassName("utbot-vars")[0].getAttribute(name));
+ return document.getElementsByClassName("utbot-vars")[0].getAttribute(name);
+}
+
+function removeElementByClassName(className) {
+ const removableElements = document.getElementsByClassName(className);
+ for (let i = 0; i < removableElements.length; i++) {
+ const parentNode = removableElements[i].parentNode;
+ if (parentNode !== undefined || parentNode !== null) {
+ parentNode.removeChild(removableElements[i]);
+ }
+ }
+}
+
+function handleOnOffDefaultConfigurationOnLocalhost() {
+ const serverPath = $('serverPath');
+ const hostInput = $('hostInput');
+ const portGRPCInput = $('portGRPCInput');
+ const portSFTPInput = $('portSFTPInput');
+ const useLocalhost = $('useLocalHost').checked;
+ if (useLocalhost) {
+ DbgMessage("Local host is used!");
+
+ nonLocalHost = hostInput.value;
+ hostInput.value = "localhost";
+
+ nonLocalGRPCPort = portGRPCInput.value;
+ portGRPCInput.value = getVarValue("defaultGRPCPort");
+
+ nonLocalSFTPPort = portSFTPInput.value;
+ portSFTPInput.value = ""; // Not Used
+
+ nonLocalRemoteDir = serverPath.value;
+ serverPath.value = getVarValue("projectDir");
+ }
+ else {
+ DbgMessage("Local host is not used!");
+ hostInput.value = nonLocalHost;
+ portGRPCInput.value = nonLocalGRPCPort;
+ portSFTPInput.value = nonLocalSFTPPort;
+ serverPath.value = nonLocalRemoteDir;
+ }
+ serverPath.disabled= useLocalhost;
+ hostInput.disabled = useLocalhost;
+ portGRPCInput.disabled = useLocalhost;
+ portSFTPInput.disabled = useLocalhost;
+
+ restartCheckingConnection(GRPC_PREFIX, 0);
+ restartCheckingConnection(SFTP_PREFIX, 0);
+}
+
+// user from eval
+function sendServerSetup() {
+ vscode.postMessage({
+ command: 'set_server_setup',
+ host: $('hostInput').value,
+ portGRPC: parseInt($('portGRPCInput').value),
+ portSFTP: parseInt($('portSFTPInput').value),
+ serverPath: $('serverPath').value,
+ });
+}
+
+// used from eval call
+function sendBuildInfo() {
+ const buildDirInputElement = $('buildDirectory');
+ const cmakeOptionsInputElement = $('cmakeOptions');
+ vscode.postMessage({
+ command: 'set_build_info',
+ buildDirectory: buildDirInputElement.value,
+ cmakeOptions: cmakeOptionsInputElement.value
+ });
+}
+
+
+/**
+ * Request to test the connection with host
+ */
+function testConnection(prefix) {
+ //DbgMessage(">>>>> testConnection " + prefix)
+ let port = "";
+ switch (prefix) {
+ case GRPC_PREFIX:
+ port = $('portGRPCInput').value;
+ break;
+ case SFTP_PREFIX:
+ let el = $('portSFTPInput');
+ if (!checkInputValidAsNotEmpty(el, false)) {
+ // show `Not Used` connection status
+ showProgress(prefix, true);
+ showConnectionSuccessStatus(prefix, 1, -1);
+ return;
+ }
+ port = el.value;
+ break;
+ }
+
+ let letHostEl = $('hostInput');
+ if (!checkInputValidAsNotEmpty(letHostEl, false)) {
+ // show `Failed` connection status
+ showProgress(prefix, true);
+ showConnectionFailureStatus(prefix);
+ return;
+ }
+
+ showProgress(prefix, true);
+ vscode.postMessage({
+ command: prefix + 'test_connection',
+ host: letHostEl.value,
+ port: parseInt(port)
+ });
+}
+
+/**
+ * Request to run installation script.
+ */
+function runInstaller() {
+ const button = $("runInstallerBtn");
+ const messageBlock = document.getElementsByClassName("utbot-form__tab_installer_message")[0]
+ button.disabled = true;
+ messageBlock.classList.add("active");
+ vscode.postMessage({
+ command: 'run_installer'
+ });
+}
+
+function closeWizard() {
+ vscode.postMessage({ command: 'close_wizard' });
+}
+
+function openSFTPSettings(paramKey) {
+ //DbgMessage("openSFTPSettings");
+ vscode.postMessage({
+ command: 'openSFTPSettings',
+ key: paramKey
+ });
+}
\ No newline at end of file
diff --git a/vscode-plugin/package.json b/vscode-plugin/package.json
index 6cad3071a..e04ed1c0d 100644
--- a/vscode-plugin/package.json
+++ b/vscode-plugin/package.json
@@ -560,25 +560,29 @@
"@types/mocha": "9.1.0",
"@typescript-eslint/eslint-plugin": "2.34.0",
"@typescript-eslint/parser": "2.34.0",
+ "@vscode/test-electron": "2.1.2",
"eslint": "6.8.0",
"glob": "7.2.0",
- "mocha": "9.2.0",
- "@vscode/test-electron": "2.1.2"
+ "mocha": "9.2.0"
},
"dependencies": {
"@types/google-protobuf": "3.15.5",
"@types/node": "15.6.0",
"@types/randomstring": "1.1.8",
+ "@types/ssh2": "1.11.6",
"@types/vscode": "1.64.0",
+ "@types/ssh2-streams": "0.1.9",
"emittery": "0.10.1",
"filepath": "1.1.0",
"google-protobuf": "3.12.4",
"grpc": "npm:@grpc/grpc-js@1.5.5",
- "grpc-tools": "1.11.2",
"grpc_tools_node_protoc_ts": "5.3.2",
+ "grpc-tools": "1.11.2",
"log4js": "6.5.2",
"randomstring": "1.2.2",
+ "ssh2-streams": "0.4.10",
"source-map-support": "0.5.21",
- "typescript": "3.9.4"
+ "typescript": "3.9.4",
+ "node-ssh": "^13.0.0"
}
}
diff --git a/vscode-plugin/src/client/client.ts b/vscode-plugin/src/client/client.ts
index 7bec9ac1a..82e1ef5f2 100644
--- a/vscode-plugin/src/client/client.ts
+++ b/vscode-plugin/src/client/client.ts
@@ -101,7 +101,7 @@ export class Client {
}
this.host = Prefs.getHost();
- this.port = +Prefs.getPort();
+ this.port = parseInt(Prefs.getGRPCPort());
this.logLevel = this.DEFAULT_LOG_LEVEL;
@@ -395,7 +395,7 @@ export class Client {
const response = this.testsService.configureProject(projectConfigRequest, this.metadata);
await this.handleServerResponse(response, progressKey, token, resolve, reject, responseHandler);
} catch (err) {
- messages.showErrorMessage(err.message);
+ messages.showErrorMessage(err);
utbotUI.channels().outputServerLogChannel.show(true);
reject(err);
}
diff --git a/vscode-plugin/src/config/defaultValues.ts b/vscode-plugin/src/config/defaultValues.ts
index bb4f2cd71..1d03768ea 100644
--- a/vscode-plugin/src/config/defaultValues.ts
+++ b/vscode-plugin/src/config/defaultValues.ts
@@ -8,7 +8,8 @@ import {isWin32} from "../utils/utils";
export class DefaultConfigValues {
public static readonly DEFAULT_HOST = "localhost";
- public static readonly DEFAULT_PORT = 2121;
+ public static readonly DEFAULT_GRPC_PORT = 2121;
+ public static readonly DEFAULT_SFTP_PORT = 2020;
public static readonly POSSIBLE_BUILD_DIR_NAMES = ['out', 'build'];
public static readonly POSSIBLE_TEST_DIR_NAMES = ['test'];
@@ -39,8 +40,16 @@ export class DefaultConfigValues {
return host;
}
- public static getDefaultPort(): number {
- return parseInt(Prefs.getGlobalPort());
+ public static getDefaultGRPCPort(): number {
+ return parseInt(Prefs.getGlobalGRPCPort());
+ }
+
+ public static getDefaultSFTPPort(): number {
+ const sftpPort = vsUtils.getFromSftpConfig("port");
+ if (sftpPort !== undefined) {
+ return parseInt(sftpPort);
+ }
+ return DefaultConfigValues.DEFAULT_SFTP_PORT;
}
public static getDefaultRemotePath(): string {
diff --git a/vscode-plugin/src/config/notificationMessages.ts b/vscode-plugin/src/config/notificationMessages.ts
index 7b012d404..f54097ad9 100644
--- a/vscode-plugin/src/config/notificationMessages.ts
+++ b/vscode-plugin/src/config/notificationMessages.ts
@@ -11,9 +11,14 @@ export const serverIsDeadError = "UTBot server doesn't respond. Check the connec
export const grpcConnectionLostError = "No connection established";
export const targetNotUsed = "There is no used target. Use any in UTBot Targets window, please.";
-// {SARIF
+// {SFTP
+export const defaultSFTP = "Natizyskunk.sftp";
+export const installSFTP = "Please, install Natizyskunk SFTP from https://marketplace.visualstudio.com/items?itemName=" + defaultSFTP;
+// }SFTP
+
+// {SARIF
export const defaultSARIFViewer = "MS-SarifVSCode.sarif-viewer";
-export const intstallSARIFViewer = "Please, install MS Sarif Viewer from https://marketplace.visualstudio.com/items?itemName=" + defaultSARIFViewer;
+export const installSARIFViewer = "Please, install MS Sarif Viewer from https://marketplace.visualstudio.com/items?itemName=" + defaultSARIFViewer;
// }SARIF
diff --git a/vscode-plugin/src/config/prefs.ts b/vscode-plugin/src/config/prefs.ts
index b3fed36e0..6c168e505 100644
--- a/vscode-plugin/src/config/prefs.ts
+++ b/vscode-plugin/src/config/prefs.ts
@@ -116,24 +116,6 @@ export class Prefs {
return !this.isInitialized(context);
}
- public static async setPredictedSettings(): Promise
{
- logger.debug("Setting default settings");
- await this.setPredictedHost();
- await this.setPredictedPort();
- }
-
- public static async setPredictedHost(): Promise {
- const predictedHost = defcfg.DefaultConfigValues.getDefaultHost();
- await Prefs.setHost(predictedHost);
- logger.debug(`Host is automatically set to '${predictedHost}'`);
- }
-
- public static async setPredictedPort(): Promise {
- const predictedPort = defcfg.DefaultConfigValues.getDefaultPort();
- await Prefs.setPort(predictedPort);
- logger.debug(`Port is automatically set to '${predictedPort}'`);
- }
-
/**
* Marks current workspace as unconfigured for UTBot.
* @param context extension's context
@@ -334,15 +316,15 @@ export class Prefs {
return this.getAsset(Prefs.HOST_PREF);
}
- public static async setPort(port: number): Promise {
+ public static async setGRPCPort(port: number): Promise {
await this.setGlobalAsset(Prefs.PORT_PREF, port, false);
}
- public static getGlobalPort(): string {
- return this.getGlobalAsset(Prefs.PORT_PREF, `${defcfg.DefaultConfigValues.DEFAULT_PORT}`);
+ public static getGlobalGRPCPort(): string {
+ return this.getGlobalAsset(Prefs.PORT_PREF, `${defcfg.DefaultConfigValues.DEFAULT_GRPC_PORT}`);
}
- public static getPort(): string {
+ public static getGRPCPort(): string {
return this.getAsset(Prefs.PORT_PREF);
}
diff --git a/vscode-plugin/src/emitter/UTBotEventEmitter.ts b/vscode-plugin/src/emitter/UTBotEventEmitter.ts
index 32ad34ed8..71af2f345 100644
--- a/vscode-plugin/src/emitter/UTBotEventEmitter.ts
+++ b/vscode-plugin/src/emitter/UTBotEventEmitter.ts
@@ -1,4 +1,4 @@
-import * as Emittery from "emittery";
+import Emittery from "emittery";
export class UTBotEventEmitter {
private emittery: Emittery> = new Emittery();
diff --git a/vscode-plugin/src/responses/responseHandler.ts b/vscode-plugin/src/responses/responseHandler.ts
index 32f599077..47f9e55c9 100644
--- a/vscode-plugin/src/responses/responseHandler.ts
+++ b/vscode-plugin/src/responses/responseHandler.ts
@@ -93,7 +93,7 @@ export class TestsResponseHandler implements ResponseHandler {
const sarifExt = vs.extensions.getExtension(messages.defaultSARIFViewer);
// eslint-disable-next-line eqeqeq
if (sarifExt == null) {
- messages.showWarningMessage(messages.intstallSARIFViewer);
+ messages.showWarningMessage(messages.installSARIFViewer);
} else {
if (!sarifExt.isActive) {
await sarifExt.activate();
diff --git a/vscode-plugin/src/test/suite/index.ts b/vscode-plugin/src/test/suite/index.ts
index 3a577d8c1..2d5a3502a 100644
--- a/vscode-plugin/src/test/suite/index.ts
+++ b/vscode-plugin/src/test/suite/index.ts
@@ -1,5 +1,5 @@
-import * as glob from 'glob';
-import * as Mocha from 'mocha';
+import glob from 'glob';
+import Mocha from 'mocha';
import * as path from 'path';
export function run(): Promise {
diff --git a/vscode-plugin/src/wizard/wizard.ts b/vscode-plugin/src/wizard/wizard.ts
index 30d4e9c9f..e055562f5 100644
--- a/vscode-plugin/src/wizard/wizard.ts
+++ b/vscode-plugin/src/wizard/wizard.ts
@@ -12,6 +12,7 @@ import * as pathUtils from '../utils/pathUtils';
import {WizardEventsEmitter} from './wizardEventsEmitter';
import * as fs from "fs";
import * as vsUtils from "../utils/vscodeUtils";
+import {NodeSSH} from "node-ssh";
const { logger } = ExtensionLogger;
@@ -55,71 +56,59 @@ export class UtbotWizardPanel {
constructor(private readonly panel: vs.WebviewPanel, private readonly context: vs.ExtensionContext) {
void this.update();
this.panel.onDidDispose(() => this.dispose(), null, this.disposables);
-
- this.panel.onDidChangeViewState(
- _event => {
- if (this.panel.visible) {
- void this.update();
- }
- },
- null,
- this.disposables
- );
-
this.panel.webview.onDidReceiveMessage(
async message => {
switch (message.command) {
- case 'openSFTPSettings':
- if (message.key !== undefined) {
- const keyName = message.key;
- //await vs.commands.executeCommand('workbench.action.openSettings', 'Natizyskunk.sftp.remotePath');
- await vs.commands.getCommands(true).then(
- async (commands: string[]) => {
- if (commands.includes("sftp.config")) {
- await vs.commands.executeCommand("sftp.config").then(
- async () => {
- // TODO: positioning at keyname/value line
- // await vs.commands.executeCommand('actions.find', `${keyName}`).then(
- // () => messages.showErrorMessage(`query: @${keyName}`)
- // );
- }
- );
- } else {
- messages.showErrorMessage("SFTP plugin isn't installed!");
- }
- }
- );
- }
- break;
case 'run_installer':
this.runInstallationScript();
break;
case 'set_server_setup':
await Prefs.setHost(message.host);
- await Prefs.setPort(message.port);
- await Prefs.setRemotePath(message.mappingPath);
+ await Prefs.setGRPCPort(message.portGRPC);
+ await Prefs.setRemotePath(message.serverPath);
+ await this.setupSFTP(
+ !!message.portSFTP,
+ message.host,
+ message.portSFTP,
+ message.serverPath);
break;
case 'set_build_info':
await Prefs.setBuildDirectory(message.buildDirectory);
await Prefs.setCmakeOptions(message.cmakeOptions);
break;
- case 'check_connection':
- case 'test_connection':
- this.pingAction(
- message.host,
- message.port,
- message.command + '_success',
- message.command + '_failure');
- break;
case 'close_wizard':
this.panel.dispose();
break;
case 'dbg_message':
logger.info(`dbg_message: ${message.message}`);
break;
- default:
+ case 'check_plugins':
+ //logger.info(`check_plugins`);
+ this.checkPlugins();
+ break;
+ default: {
+ if (message.command.endsWith('test_connection')) {
+ //messages.showErrorMessage(`!!!!!! message (${message.command}) from WizardWebView: ${message}`);
+ if (message.command.startsWith(`GRPC_`)) {
+ this.pingAction(
+ message.host,
+ message.port,
+ message.command + '_success',
+ message.command + '_failure');
+ break;
+ }
+ else if (message.command.startsWith(`SFTP_`)) {
+ this.pingSFTPAction(
+ message.host,
+ message.port,
+ message.command + '_success',
+ message.command + '_failure');
+ break;
+ }
+ }
messages.showErrorMessage(`Unknown message (${message.command}) from WizardWebView: ${message}`);
break;
+ }
}
},
null,
@@ -127,6 +116,89 @@ export class UtbotWizardPanel {
);
}
+ private checkPlugins(): void {
+ void this.panel.webview.postMessage({
+ command: "checkPlugins",
+ sftpPluginInstalled: !!vs.extensions.getExtension(messages.defaultSFTP),
+ sarifPluginInstalled: !!vs.extensions.getExtension(messages.defaultSARIFViewer)
+ });
+ }
+
+ private async setupSFTP(
+ activate: boolean,
+ host: string,
+ portSFTP: string,
+ remotePath: string
+ ): Promise {
+ const sftpExt = vs.extensions.getExtension(messages.defaultSFTP);
+ if (!sftpExt) {
+ messages.showWarningMessage(messages.installSFTP);
+ } else {
+ if (!sftpExt.isActive) {
+ await sftpExt.activate();
+ }
+ const workspaceFolderUrl = vs.workspace.workspaceFolders?.[0].uri;
+ if (workspaceFolderUrl) {
+ const workspaceFolder = workspaceFolderUrl.fsPath;
+ const sftpConfigPath = pathUtils.fsJoin(workspaceFolder, '.vscode', 'sftp.json');
+ try {
+ if (activate) {
+ const configContent =
+`{
+ "name": "UTBot Server",
+ "host": "${host}",
+ "protocol": "sftp",
+ "port": ${portSFTP},
+ "username": "utbot",
+ "password": "utbot",
+ "remotePath": "${remotePath}",
+ "uploadOnSave": true,
+ "useTempFile": false,
+ "openSsh": false
+}`;
+ if (!fs.existsSync(sftpConfigPath)) {
+ fs.writeFileSync(sftpConfigPath, ' ');
+ }
+ const doc = await vs.workspace.openTextDocument(sftpConfigPath);
+ const editor = await vs.window.showTextDocument(doc, {preview: true, preserveFocus: false});
+ // we need to generate the `onDidSaveTextDocument` event
+ // it is the only event that is processed by SFTP pluging to change the preload configuration
+ void editor.edit( builder => {
+ builder.delete(new vs.Range(0, 0, 10000, 10000));
+ builder.insert(new vs.Position(0, 0), configContent);
+ })
+ .then( () => {
+ void editor.document.save().then( saved => {
+ if (saved) {
+ messages.showWarningMessage(`New configuration ".vscode/sftp.json" was saved!`);
+ }
+ void vs.commands.executeCommand('workbench.action.closeActiveEditor');
+ const postponedSync = (): void => {
+ void vs.commands.executeCommand("sftp.sync.localToRemote", workspaceFolderUrl).then(
+ () => messages.showWarningMessage(`Project copy was created on UTBot Server at "${remotePath}"`),
+ (err) => messages.showWarningMessage(`Project copy was not created on UTBot Server at "${remotePath}" with error ` + err)
+ );
+ };
+ setTimeout(postponedSync, 300);
+ });
+ });
+ } else {
+ fs.unlink(sftpConfigPath, function (err) {
+ if (err) {
+ console.error(err);
+ console.log('File ".vscode/sftp.json" not found');
+ }else{
+ console.log('File ".vscode/sftp.json" was deleted successfully');
+ }
+ });
+ }
+ } catch (error) {
+ messages.showWarningMessage("Error while SFTP configuration: " + error);
+ }
+ }
+ }
+ }
+
private runInstallationScript(): void {
const onDiskPath = vs.Uri.file(pathUtils.fsJoin(this.context.extensionPath, 'scripts', 'utbot_installer.sh'));
const terminal = vs.window.createTerminal('UTBot Server Installation');
@@ -134,7 +206,7 @@ export class UtbotWizardPanel {
terminal.sendText(onDiskPath.fsPath, true);
}
- private lastRequest: Promise | null = null;
+ private lastRequest: Promise | null = null;
private pingAction(host: string, port: number, successCmd: string, failureCmd: string): void {
const servicePing = new GrpcServicePing(
this.context.extension.packageJSON.version,
@@ -156,10 +228,10 @@ export class UtbotWizardPanel {
command: successCmd,
clientVersion: this.context.extension.packageJSON.version,
serverVersion: (serverVer.length === 0
- ? "undefined"
- : serverVer)});
+ ? "undefined"
+ : serverVer)});
} else {
- await this.panel.webview.postMessage({ command: failureCmd });
+ await this.panel.webview.postMessage({ command: failureCmd});
}
}).catch(async err => {
logger.error(`Error! ${err}`);
@@ -170,6 +242,34 @@ export class UtbotWizardPanel {
return;
}
+ private lastSFTPRequest: Promise | null = null;
+ private pingSFTPAction(host: string, port: number, successCmd: string, failureCmd: string): void {
+ const ssh = new NodeSSH();
+ const capturedPingPromiseForLambda = ssh.connect({
+ host: host,
+ port: port,
+ username: 'utbot',
+ password: 'utbot'
+ });
+ this.lastSFTPRequest = capturedPingPromiseForLambda;
+ capturedPingPromiseForLambda.then( async () => {
+ ssh.dispose();
+ if (this.lastSFTPRequest !== capturedPingPromiseForLambda) {
+ return;
+ }
+ await this.panel.webview.postMessage({
+ command: successCmd,
+ clientVersion: "1",
+ serverVersion: "1"});
+ }, async (error) => {
+ ssh.dispose();
+ if (this.lastSFTPRequest === capturedPingPromiseForLambda) {
+ await this.panel.webview.postMessage({ command: failureCmd});
+ }
+ });
+ return;
+ }
+
public async update(): Promise {
this.panel.webview.html = await this.getHtmlForWebview(this.panel.webview);
}
@@ -223,7 +323,7 @@ export class UtbotWizardPanel {
const predictedBuildDirectory = await defcfg.DefaultConfigValues.getDefaultBuildDirectoryPath();
const initVars: {param: string; value: string|undefined}[] = [
// UI javascript
- {param: 'scriptUri', value: mediaPath('wizard.js').toString()},
+ {param: 'scriptUri', value: mediaPath('wizardHTML.js').toString()},
// Security (switched off)
//{param: 'wvscriptUri', value: webview.cspSource},
@@ -231,18 +331,20 @@ export class UtbotWizardPanel {
// CSS in header
{param: 'vscodeUri', value: mediaPath('vscode.css').toString()},
- {param: 'stylesUri', value: mediaPath('wizard.css').toString()},
+ {param: 'stylesUri', value: mediaPath('wizardHTML.css').toString()},
// vars
{param: 'os', value: os.platform()},
{param: 'projectDir', value: defcfg.DefaultConfigValues.toWSLPathOnWindows(vsUtils.getProjectDirByOpenedFile().fsPath)},
- {param: 'defaultPort', value: defcfg.DefaultConfigValues.DEFAULT_PORT.toString()},
- {param: 'sftpHost', value: vsUtils.getFromSftpConfig("host")},
- {param: 'sftpDir', value: vsUtils.getFromSftpConfig("remotePath")},
+ {param: 'defaultGRPCPort', value: defcfg.DefaultConfigValues.DEFAULT_GRPC_PORT.toString()},
+ {param: 'defaultSFTPPort', value: defcfg.DefaultConfigValues.DEFAULT_SFTP_PORT.toString()},
+ {param: 'serverHost', value: vsUtils.getFromSftpConfig("host")},
+ {param: 'serverDir', value: vsUtils.getFromSftpConfig("remotePath")},
// connection tab
{param: 'predictedHost', value: defcfg.DefaultConfigValues.getDefaultHost()},
- {param: 'predictedPort', value: Prefs.getGlobalPort()},
+ {param: 'predictedGRPCPort', value: Prefs.getGlobalGRPCPort()},
+ {param: 'predictedSFTPPort', value: defcfg.DefaultConfigValues.getDefaultSFTPPort().toString()},
{param: 'predictedRemotePath', value: defcfg.DefaultConfigValues.getDefaultRemotePath()},
// project tab
@@ -257,8 +359,8 @@ export class UtbotWizardPanel {
// @ts-ignore
content = content.replaceAll(`{{${p2v.param}}}`,
`${p2v.value === undefined
- ? ''
- : p2v.value}`);
+ ? ''
+ : p2v.value}`);
}
const uninitVars = UtbotWizardPanel.checkNonInitializedVars.exec(content);
diff --git a/vscode-plugin/tsconfig.json b/vscode-plugin/tsconfig.json
index 833903d44..8ad8f4cb0 100644
--- a/vscode-plugin/tsconfig.json
+++ b/vscode-plugin/tsconfig.json
@@ -9,6 +9,7 @@
],
"sourceMap": true,
"rootDir": "src",
+ "esModuleInterop": true,
"strict": true /* enable all strict type-checking options */
/* Additional Checks */
// "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */