Skip to content

Commit

Permalink
Explorer UI: improvements along with policy ui
Browse files Browse the repository at this point in the history
* Thing definition and template for example thing
* Validations for connections
* Small fixes and improvements

Signed-off-by: thfries <thomas.fries0@gmail.com>
  • Loading branch information
thfries committed Aug 5, 2022
1 parent c8a487b commit fbe2617
Show file tree
Hide file tree
Showing 14 changed files with 239 additions and 153 deletions.
7 changes: 4 additions & 3 deletions ui/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,11 @@ textarea {
left: 0;
}

h5 {
margin-bottom: 0;
h5, h6 {
margin-top: 0.25rem;
margin-bottom: 0.25rem;
}

hr {
margin-top: 0.1rem;
margin: 0.25rem;
}
2 changes: 1 addition & 1 deletion ui/modules/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ export async function callConnectionsAPI(operation, successCallback, connectionI
document.body.style.cursor = 'progress';
response.json().then((data) => {
if (data && data['?'] && data['?']['?'].status >= 400) {
const dittoErr = data['?']['?'];
const dittoErr = data['?']['?'].payload;
Utils.showError(dittoErr.description, dittoErr.message, dittoErr.status);
} else {
if (params.unwrapJsonPath) {
Expand Down
45 changes: 16 additions & 29 deletions ui/modules/connections/connections.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ <h5 data-bs-toggle="collapse" data-bs-target="#connectionsEdit">
Refresh
</button>
</div>
<div class="input-group has-validation">
<input class="form-control" id="tableValidationConnections" hidden="true"></input>
<div class="invalid-feedback"></div>
</div>
<div class="table-wrap">
<table class="table table-striped table-hover table-sm">
<thead>
Expand All @@ -42,8 +46,7 @@ <h6>Connection</h6>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text">Id</label>
<input type="text" class="form-control form-control-sm" disabled="true" id="inputConnectionId"></input>
<button class="btn btn-outline-secondary btn-sm" data-bs-toggle="modal"
data-bs-target="#create_connection_modal">
<button class="btn btn-outline-secondary btn-sm" id="buttonCreateConnection">
<i class="bi bi-plus-circle"></i>
</button>
<button class="btn btn-outline-secondary btn-sm" id="buttonSaveConnection" data-bs-toggle="tooltip"
Expand All @@ -57,7 +60,16 @@ <h6>Connection</h6>
</div>
<div class="input-group input-group-sm mb-1">
<label class="input-group-text">Template</label>
<select type="text" class="form-select form-select-sm" id="selectConnectionTemplate"></select>
<div class="btn-group dropend">
<button class="btn btn-outline-secondary btn-sm dropdown-toggle"
data-bs-toggle="dropdown"></button>
<ul id="ulConnectionTemplates" class="dropdown-menu" style="position: fixed; top: auto;"></ul>
</div>
<input type="text" class="form-control form-control-sm" id="inputConnectionTemplate" disabled="true"></input>
</div>
<div class="input-group has-validation">
<input class="form-control" id="editorValidationConnection" hidden="true"></input>
<div class="invalid-feedback"></div>
</div>
<div class="ace_container" style="flex-grow: 1;">
<div class="script_editor" id="connectionEditor"></div>
Expand All @@ -74,31 +86,6 @@ <h6>Outgoing JavaScript Mapping</h6>
</div>
</div>
</div>
<div class="modal fade" id="create_connection_modal" tabindex="-1">
<div class="modal-dialog dialog-sm">
<div class="modal-content">
<div class="modal-header">
Select Connection Template
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<div class="modal-body">
<fieldset class="form-group">
<div class="row">
<label class="col-form-label col-sm-2 pt-0">Type</label>
<div class="col-sm-10" id="connectionTemplateRadios"></div>
</div>
</fieldset>
Edit the template and click "Save" to finally create the connection
</div>
<div class="modal-footer">
<button class="btn btn-outline-secondary btn-sm" data-bs-dismiss="modal"
id="buttonCreateConnection">Select Template</button>
</div>
</div>
</div>
</div>
<!-- <div class="row" style="height:300px;">
</div> -->
</div>
<h5 data-bs-toggle="collapse" data-bs-target="#tabConnectionHelper">
Connection Status, Metrics and Logs
Expand Down Expand Up @@ -173,7 +160,7 @@ <h6>Connection Logs</h6>
<button class="btn btn-outline-secondary btn-sm button_round_left" id="buttonEnableConnectionLogs"
data-bs-toggle="tooltip" title="Click to enable connection logs for the selected connection">
<i class="bi bi-toggle-off"></i>
<span>Disabled</span>
<span>Enable</span>
</button>
<button class="btn btn-outline-secondary btn-sm button_round_right" id="buttonResetConnectionLogs"
data-bs-toggle="tooltip" title="Reset connection logs for the selected connection">
Expand Down
143 changes: 79 additions & 64 deletions ui/modules/connections/connections.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import * as API from '../api.js';
import * as Environments from '../environments/environments.js';

let dom = {
connectionTemplateRadios: null,
selectConnectionTemplate: null,
ulConnectionTemplates: null,
inputConnectionTemplate: null,
inputConnectionId: null,
tbodyConnections: null,
tbodyConnectionLogs: null,
Expand All @@ -38,6 +38,8 @@ let dom = {
buttonResetConnectionMetrics: null,
tabConnections: null,
collapseConnections: null,
editorValidationConnection: null,
tableValidationConnections: null,
};

let connectionEditor;
Expand All @@ -47,6 +49,7 @@ let connectionLogDetail;
let connectionStatusDetail;

let theConnection;
let selectedConnectionId;
let connectionLogs;

let connectionTemplates;
Expand All @@ -62,50 +65,38 @@ export function ready() {
connectionLogDetail = Utils.createAceEditor('connectionLogDetail', 'ace/mode/json', true);
connectionStatusDetail = Utils.createAceEditor('connectionStatusDetail', 'ace/mode/json', true);

Utils.addValidatorToTable(dom.tbodyConnections, dom.tableValidationConnections);

loadConnectionTemplates();

dom.buttonLoadConnections.onclick = loadConnections;
dom.tabConnections.onclick = onTabActivated;

dom.buttonCreateConnection.onclick = () => {
const templateConnection = {};
if (API.env() !== 'things') {
templateConnection.id = Math.random().toString(36).replace('0.', '');
dom.tbodyConnections.addEventListener('click', (event) => {
if (event.target && event.target.tagName === 'TD') {
if (selectedConnectionId === event.target.parentNode.id) {
selectedConnectionId = null;
setConnection(null);
} else {
selectedConnectionId = event.target.parentNode.id;
API.callConnectionsAPI('retrieveConnection', setConnection, selectedConnectionId);
}
}
const newConnection = JSON.parse(JSON.stringify(
connectionTemplates[document.querySelector('input[name=connectionTemplate]:checked').value]));

const mergedConnection = {...templateConnection, ...newConnection};
setConnection(mergedConnection);
};
});

dom.selectConnectionTemplate.onchange = () => {
dom.ulConnectionTemplates.addEventListener('click', (event) => {
dom.inputConnectionTemplate.value = event.target.textContent;
const templateConnection = {};
if (API.env() !== 'things') {
templateConnection.id = Math.random().toString(36).replace('0.', '');
}
const newConnection = JSON.parse(JSON.stringify(
connectionTemplates[dom.selectConnectionTemplate.value]));
connectionTemplates[dom.inputConnectionTemplate.value]));

const mergedConnection = {...templateConnection, ...newConnection};
setConnection(mergedConnection);
setConnection(mergedConnection, true);
dom.editorValidationConnection.classList.remove('is-invalid');
connectionEditor.session.getUndoManager().markClean();
};

connectionEditor.on('input', () => {
if (!connectionEditor.session.getUndoManager().isClean()) {
dom.selectConnectionTemplate.value = null;
}
});

dom.tbodyConnections.addEventListener('click', (event) => {
if (event.target && event.target.tagName === 'TD') {
API.callConnectionsAPI('retrieveConnection', setConnection, event.target.parentNode.id);
}
});

dom.tbodyConnectionLogs.addEventListener('click', (event) => {
connectionLogDetail.setValue(JSON.stringify(connectionLogs[event.target.parentNode.rowIndex - 1], null, 2), -1);
});

incomingEditor.on('blur', function() {
Expand All @@ -122,54 +113,75 @@ export function ready() {
theConnection = JSON.parse(connectionEditor.getValue());
});

dom.buttonSaveConnection.onclick = () => {
if (dom.inputConnectionId.value) {
API.callConnectionsAPI('modifyConnection', loadConnections, dom.inputConnectionId.value, theConnection);
connectionEditor.on('input', () => {
if (!connectionEditor.session.getUndoManager().isClean()) {
dom.inputConnectionTemplate.value = null;
dom.editorValidationConnection.classList.remove('is-invalid');
}
});

dom.buttonCreateConnection.onclick = () => {
Utils.assert(theConnection, 'Please enter a connection configuration (select a template as a basis)', dom.editorValidationConnection);
if (API.env() === 'things') {
delete theConnection.id;
} else {
if (API.env() === 'things') {
delete theConnection.id;
}
API.callConnectionsAPI('createConnection', loadConnections, null, theConnection);
selectedConnectionId = theConnection.id;
}
API.callConnectionsAPI('createConnection', loadConnections, null, theConnection);
};

dom.buttonSaveConnection.onclick = () => {
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
API.callConnectionsAPI('modifyConnection', loadConnections, selectedConnectionId, theConnection);
};

dom.buttonDeleteConnection.onclick = () => {
Utils.assert(dom.inputConnectionId.value, 'Please select a connection');
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
Utils.confirm(`Are you sure you want to delete connection<br>'${theConnection.name}'?`, 'Delete', () => {
API.callConnectionsAPI('deleteConnection', () => {
setConnection(null);
loadConnections();
},
dom.inputConnectionId.value);
selectedConnectionId);
});
};

// Status --------------

dom.buttonRetrieveConnectionStatus.onclick = retrieveConnectionStatus;
document.querySelector('a[data-bs-target="#tabConnectionStatus"]').onclick = retrieveConnectionStatus;
dom.buttonRetrieveConnectionMetrics.onclick = retrieveConnectionMetrics;
document.querySelector('a[data-bs-target="#tabConnectionMetrics"]').onclick = retrieveConnectionMetrics;

// Logs --------------

dom.buttonEnableConnectionLogs.onclick = () => {
Utils.assert(dom.inputConnectionId.value, 'Please select a connection');
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
API.callConnectionsAPI('connectionCommand', retrieveConnectionLogs, dom.inputConnectionId.value, null, 'connectivity.commands:enableConnectionLogs');
};

dom.buttonResetConnectionLogs.onclick = () => {
Utils.assert(dom.inputConnectionId.value, 'Please select a connection');
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
API.callConnectionsAPI('connectionCommand', retrieveConnectionLogs, dom.inputConnectionId.value, null, 'connectivity.commands:resetConnectionLogs');
};

dom.buttonRetrieveConnectionLogs.onclick = retrieveConnectionLogs;

dom.tbodyConnectionLogs.addEventListener('click', (event) => {
connectionLogDetail.setValue(JSON.stringify(connectionLogs[event.target.parentNode.rowIndex - 1], null, 2), -1);
});

// Metrics ---------------

dom.buttonRetrieveConnectionMetrics.onclick = retrieveConnectionMetrics;
document.querySelector('a[data-bs-target="#tabConnectionMetrics"]').onclick = retrieveConnectionMetrics;

dom.buttonResetConnectionMetrics.onclick = () => {
Utils.assert(dom.inputConnectionId.value, 'Please select a connection');
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
API.callConnectionsAPI('connectionCommand', null, dom.inputConnectionId.value, null, 'connectivity.commands:resetConnectionMetrics');
};
}

function retrieveConnectionMetrics() {
Utils.assert(dom.inputConnectionId.value, 'Please select a connection');
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
dom.tbodyConnectionMetrics.innerHTML = '';
API.callConnectionsAPI('retrieveConnectionMetrics', (response) => {
if (response.connectionMetrics.outbound) {
Expand All @@ -184,15 +196,15 @@ function retrieveConnectionMetrics() {
}

function retrieveConnectionStatus() {
Utils.assert(dom.inputConnectionId.value, 'Please select a connection');
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
API.callConnectionsAPI('retrieveStatus', (connectionStatus) => {
connectionStatusDetail.setValue(JSON.stringify(connectionStatus, null, 2), -1);
},
dom.inputConnectionId.value);
}

function retrieveConnectionLogs() {
Utils.assert(dom.inputConnectionId.value, 'Please select a connection');
Utils.assert(selectedConnectionId, 'Please select a connection', dom.tableValidationConnections);
dom.tbodyConnectionLogs.innerHTML = '';
connectionLogDetail.setValue('');
API.callConnectionsAPI('retrieveConnectionLogs', (response) => {
Expand All @@ -208,32 +220,34 @@ function retrieveConnectionLogs() {
function adjustEnableButton(response) {
if (response.enabledUntil) {
dom.buttonEnableConnectionLogs.querySelector('i').classList.replace('bi-toggle-off', 'bi-toggle-on');
dom.buttonEnableConnectionLogs.querySelector('span').innerText = 'Enabled';
dom.buttonEnableConnectionLogs.setAttribute('title', `Enabled until ${Utils.formatDate(response.enabledUntil)}`);
} else {
dom.buttonEnableConnectionLogs.querySelector('i').classList.replace('bi-toggle-on', 'bi-toggle-off');
dom.buttonEnableConnectionLogs.querySelector('span').innerText = 'Disabled';
dom.buttonEnableConnectionLogs.setAttribute('title', 'Click to enable connection logs for the selected connection');
}
}
}

function setConnection(connection) {
function setConnection(connection, isNewConnection) {
theConnection = connection;
dom.inputConnectionId.value = (theConnection && theConnection.id) ? theConnection.id : null;
connectionEditor.setValue(theConnection ? JSON.stringify(theConnection, null, 2) : '', -1);
const withJavaScript = theConnection && theConnection.mappingDefinitions && theConnection.mappingDefinitions.javascript;
incomingEditor.setValue(withJavaScript ?
theConnection.mappingDefinitions.javascript.options.incomingScript :
'', -1);
outgoingEditor.setValue(withJavaScript ?
theConnection.mappingDefinitions.javascript.options.outgoingScript :
'', -1);
incomingEditor.setValue('');
outgoingEditor.setValue('');
if (theConnection) {
dom.inputConnectionId.value = theConnection.id ? theConnection.id : null;
connectionEditor.setValue(JSON.stringify(theConnection, null, 2), -1);
if (theConnection.mappingDefinitions && theConnection.mappingDefinitions.javascript) {
incomingEditor.setValue(theConnection.mappingDefinitions.javascript.options.incomingScript, -1);
outgoingEditor.setValue(theConnection.mappingDefinitions.javascript.options.outgoingScript, -1);
};
} else {
dom.inputConnectionId.value = null;
connectionEditor.setValue('');
}
connectionStatusDetail.setValue('');
connectionLogDetail.setValue('');
dom.tbodyConnectionMetrics.innerHTML = '';
dom.tbodyConnectionLogs.innerHTML = '';
if (theConnection && theConnection.id) {
if (!isNewConnection && theConnection && theConnection.id) {
retrieveConnectionLogs();
}
}
Expand All @@ -259,12 +273,13 @@ function loadConnections() {
row.insertCell(-1).innerHTML = status.recoveryStatus;
},
id);
if (theConnection && id === theConnection.id) {
if (id === selectedConnectionId) {
row.classList.add('table-active');
connectionSelected = true;
}
});
if (!connectionSelected) {
selectedConnectionId = null;
setConnection(null);
}
});
Expand All @@ -275,8 +290,7 @@ function loadConnectionTemplates() {
.then((response) => {
response.json().then((loadedTemplates) => {
connectionTemplates = loadedTemplates;
Utils.setOptions(dom.selectConnectionTemplate, Object.keys(connectionTemplates));
dom.selectConnectionTemplate.value = null;
Utils.addDropDownEntries(dom.ulConnectionTemplates, Object.keys(connectionTemplates));
});
});
}
Expand All @@ -302,6 +316,7 @@ function initializeMappings(connection) {
if (!connection['mappingDefinitions']) {
connection.mappingDefinitions = {
javascript: {
mappingEngine: 'JavaScript',
options: {
incomingScript: '',
outgoingScript: '',
Expand Down
2 changes: 1 addition & 1 deletion ui/modules/environments/environments.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ <h5>Environments</h5>
<div class="tab-pane container active no-margin" id="tabEnvDetails">
<div class="input-group input-group-sm mb-1 mt-1">
<label class="input-group-text">Name</label>
<input type="text" class="form-control" id="inputEnvironmentName">
<input type="text" class="form-control" id="inputEnvironmentName" spellcheck="false">
<button class="btn btn-outline-secondary btn-sm" id="buttonCreateEnvironment">
<i class="bi bi-plus-circle"></i>
</button>
Expand Down
Loading

0 comments on commit fbe2617

Please sign in to comment.