';
- cancelledExecs.forEach(function(execution) {
+ cancelledExecs.forEach(function (execution) {
const isAbandoned = execution.is_running;
html += '
';
@@ -863,13 +860,9 @@ class Dashboard {
// Call backend API to cancel the task
$.ajax({
- url: '/cancel_task_execution',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
+ url: '/cancel_task_execution', type: 'POST', contentType: 'application/json', data: JSON.stringify({
task_id: executionData.task_id
- }),
- success: function(response) {
+ }), success: function (response) {
console.log('Cancel task response:', response);
if (response.status === 'error') {
@@ -882,7 +875,7 @@ class Dashboard {
if (response.was_cancelled) {
console.log('Task ' + executionData.task_id + ' was successfully cancelled');
// Add to cancelled list (only managed in JS, not persisted)
- const alreadyCancelled = self.cancelledExecutions.some(function(exec) {
+ const alreadyCancelled = self.cancelledExecutions.some(function (exec) {
return exec.task_id === executionData.task_id;
});
if (!alreadyCancelled) {
@@ -893,7 +886,7 @@ class Dashboard {
console.log('Execution already in cancelled list');
}
} else {
- console.log('Task ' + executionData.task_id + ' could not be cancelled (may have already completed). ' + response.message );
+ console.log('Task ' + executionData.task_id + ' could not be cancelled (may have already completed). ' + response.message);
}
// Refresh display regardless
self.loadQueuedExecutions();
@@ -901,8 +894,7 @@ class Dashboard {
console.error('Unexpected response status:', response.status);
alert('Unexpected response from server');
}
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('AJAX error cancelling task:');
console.error(' Status:', status);
console.error(' Error:', error);
@@ -930,12 +922,7 @@ class Dashboard {
if (typeof text !== 'string') return text;
const patterns = {
- '<': '<',
- '>': '>',
- '&': '&',
- '"': '"',
- "'": ''',
- '`': '`'
+ '<': '<', '>': '>', '&': '&', '"': '"', "'": ''', '`': '`'
};
return text.replace(/[<>&"'`]/g, match => patterns[match]);
@@ -950,13 +937,10 @@ class Dashboard {
loadToolNames() {
let self = this;
return $.ajax({
- url: '/get_tool_names',
- type: 'GET',
- success: function(response) {
+ url: '/get_tool_names', type: 'GET', success: function (response) {
self.toolNames = response.tool_names || [];
console.log('Loaded tool names:', self.toolNames);
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error loading tool names:', error);
}
});
@@ -998,13 +982,9 @@ class Dashboard {
// Make API call
$.ajax({
- url: '/get_log_messages',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
+ url: '/get_log_messages', type: 'POST', contentType: 'application/json', data: JSON.stringify({
start_idx: 0
- }),
- success: function(response) {
+ }), success: function (response) {
// Clear existing logs
self.$logContainer.empty();
@@ -1013,7 +993,7 @@ class Dashboard {
// Display each log message
if (response.messages && response.messages.length > 0) {
- response.messages.forEach(function(message) {
+ response.messages.forEach(function (message) {
self.displayLogMessage(message);
});
@@ -1028,11 +1008,9 @@ class Dashboard {
// Start periodic polling for new logs
self.startPeriodicPolling();
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error loading logs:', error);
- self.$errorContainer.html('
Error loading logs: ' +
- (xhr.responseJSON ? xhr.responseJSON.detail : error) + '
');
+ self.$errorContainer.html('
Error loading logs: ' + (xhr.responseJSON ? xhr.responseJSON.detail : error) + '
');
}
});
}
@@ -1041,13 +1019,9 @@ class Dashboard {
let self = this;
console.log("Polling logs", this.currentMaxIdx);
$.ajax({
- url: '/get_log_messages',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
+ url: '/get_log_messages', type: 'POST', contentType: 'application/json', data: JSON.stringify({
start_idx: self.currentMaxIdx + 1
- }),
- success: function(response) {
+ }), success: function (response) {
self.failureCount = 0;
// Only append new messages if we have any
if (response.messages && response.messages.length > 0) {
@@ -1060,7 +1034,7 @@ class Dashboard {
}
// Append new messages
- response.messages.forEach(function(message) {
+ response.messages.forEach(function (message) {
self.displayLogMessage(message);
});
@@ -1078,8 +1052,7 @@ class Dashboard {
// Update window title with active project
self.updateTitle(response.active_project);
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error polling for new logs:', error);
self.failureCount++;
if (self.failureCount >= 3) {
@@ -1104,14 +1077,14 @@ class Dashboard {
loadStats() {
let self = this;
- $.when(
- $.ajax({ url: '/get_tool_stats', type: 'GET' }),
- $.ajax({ url: '/get_token_count_estimator_name', type: 'GET' })
- ).done(function(statsResp, estimatorResp) {
+ $.when($.ajax({url: '/get_tool_stats', type: 'GET'}), $.ajax({
+ url: '/get_token_count_estimator_name',
+ type: 'GET'
+ })).done(function (statsResp, estimatorResp) {
const stats = statsResp[0].stats;
const tokenCountEstimatorName = estimatorResp[0].token_count_estimator_name;
self.displayStats(stats, tokenCountEstimatorName);
- }).fail(function() {
+ }).fail(function () {
console.error('Error loading stats or estimator name');
});
}
@@ -1119,12 +1092,9 @@ class Dashboard {
clearStats() {
let self = this;
$.ajax({
- url: '/clear_tool_stats',
- type: 'POST',
- success: function() {
+ url: '/clear_tool_stats', type: 'POST', success: function () {
self.loadStats();
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error clearing stats:', error);
}
});
@@ -1132,7 +1102,7 @@ class Dashboard {
displayStats(stats, tokenCountEstimatorName) {
const names = Object.keys(stats);
- // If no stats collected
+ // If no stats collected
if (names.length === 0) {
// hide summary, charts, estimator name
$('#stats-summary').hide();
@@ -1187,27 +1157,18 @@ class Dashboard {
// Tool calls pie chart
this.countChart = new Chart(countCtx, {
- type: 'pie',
- data: {
- labels: names,
- datasets: [{
- data: counts,
- backgroundColor: colors
+ type: 'pie', data: {
+ labels: names, datasets: [{
+ data: counts, backgroundColor: colors
}]
- },
- options: {
+ }, options: {
plugins: {
legend: {
- display: true,
- labels: {
+ display: true, labels: {
color: textColor
}
- },
- datalabels: {
- display: true,
- color: 'white',
- font: { weight: 'bold' },
- formatter: (value) => value
+ }, datalabels: {
+ display: true, color: 'white', font: {weight: 'bold'}, formatter: (value) => value
}
}
}
@@ -1215,27 +1176,18 @@ class Dashboard {
// Input tokens pie chart
this.inputChart = new Chart(inputCtx, {
- type: 'pie',
- data: {
- labels: names,
- datasets: [{
- data: inputTokens,
- backgroundColor: colors
+ type: 'pie', data: {
+ labels: names, datasets: [{
+ data: inputTokens, backgroundColor: colors
}]
- },
- options: {
+ }, options: {
plugins: {
legend: {
- display: true,
- labels: {
+ display: true, labels: {
color: textColor
}
- },
- datalabels: {
- display: true,
- color: 'white',
- font: { weight: 'bold' },
- formatter: (value) => value
+ }, datalabels: {
+ display: true, color: 'white', font: {weight: 'bold'}, formatter: (value) => value
}
}
}
@@ -1243,27 +1195,18 @@ class Dashboard {
// Output tokens pie chart
this.outputChart = new Chart(outputCtx, {
- type: 'pie',
- data: {
- labels: names,
- datasets: [{
- data: outputTokens,
- backgroundColor: colors
+ type: 'pie', data: {
+ labels: names, datasets: [{
+ data: outputTokens, backgroundColor: colors
}]
- },
- options: {
+ }, options: {
plugins: {
legend: {
- display: true,
- labels: {
+ display: true, labels: {
color: textColor
}
- },
- datalabels: {
- display: true,
- color: 'white',
- font: { weight: 'bold' },
- formatter: (value) => value
+ }, datalabels: {
+ display: true, color: 'white', font: {weight: 'bold'}, formatter: (value) => value
}
}
}
@@ -1271,78 +1214,42 @@ class Dashboard {
// Combined input/output tokens bar chart
this.tokensChart = new Chart(tokensCtx, {
- type: 'bar',
- data: {
- labels: names,
- datasets: [
- {
- label: 'Input Tokens',
- data: inputTokens,
- backgroundColor: colors.map(color => color + '80'), // Semi-transparent
- borderColor: colors,
- borderWidth: 2,
- borderSkipped: false,
- yAxisID: 'y'
- },
- {
- label: 'Output Tokens',
- data: outputTokens,
- backgroundColor: colors,
- yAxisID: 'y1'
- }
- ]
- },
- options: {
- responsive: true,
- plugins: {
+ type: 'bar', data: {
+ labels: names, datasets: [{
+ label: 'Input Tokens', data: inputTokens, backgroundColor: colors.map(color => color + '80'), // Semi-transparent
+ borderColor: colors, borderWidth: 2, borderSkipped: false, yAxisID: 'y'
+ }, {
+ label: 'Output Tokens', data: outputTokens, backgroundColor: colors, yAxisID: 'y1'
+ }]
+ }, options: {
+ responsive: true, plugins: {
legend: {
labels: {
color: textColor
}
}
- },
- scales: {
+ }, scales: {
x: {
ticks: {
color: textColor
- },
- grid: {
+ }, grid: {
color: gridColor
}
- },
- y: {
- type: 'linear',
- display: true,
- position: 'left',
- beginAtZero: true,
- title: {
- display: true,
- text: 'Input Tokens',
+ }, y: {
+ type: 'linear', display: true, position: 'left', beginAtZero: true, title: {
+ display: true, text: 'Input Tokens', color: textColor
+ }, ticks: {
color: textColor
- },
- ticks: {
- color: textColor
- },
- grid: {
+ }, grid: {
color: gridColor
}
- },
- y1: {
- type: 'linear',
- display: true,
- position: 'right',
- beginAtZero: true,
- title: {
- display: true,
- text: 'Output Tokens',
+ }, y1: {
+ type: 'linear', display: true, position: 'right', beginAtZero: true, title: {
+ display: true, text: 'Output Tokens', color: textColor
+ }, ticks: {
color: textColor
- },
- ticks: {
- color: textColor
- },
- grid: {
- drawOnChartArea: false,
- color: gridColor
+ }, grid: {
+ drawOnChartArea: false, color: gridColor
}
}
}
@@ -1351,10 +1258,7 @@ class Dashboard {
}
generateColors(count) {
- const colors = [
- '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF',
- '#FF9F40', '#FF6384', '#C9CBCF', '#4BC0C0', '#FF6384'
- ];
+ const colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40', '#FF6384', '#C9CBCF', '#4BC0C0', '#FF6384'];
return Array.from({length: count}, (_, i) => colors[i % colors.length]);
}
@@ -1533,21 +1437,16 @@ class Dashboard {
const self = this;
$.ajax({
- url: '/remove_language',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
+ url: '/remove_language', type: 'POST', contentType: 'application/json', data: JSON.stringify({
language: language
- }),
- success: function(response) {
+ }), success: function (response) {
if (response.status === 'success') {
// Reload config to show updated language list
self.loadConfigOverview();
} else {
alert('Error removing language ' + language + ": " + response.message);
}
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error removing language:', error);
alert('Error removing language: ' + (xhr.responseJSON ? xhr.responseJSON.message : error));
}
@@ -1574,9 +1473,7 @@ class Dashboard {
loadAvailableLanguages() {
let self = this;
$.ajax({
- url: '/get_available_languages',
- type: 'GET',
- success: function(response) {
+ url: '/get_available_languages', type: 'GET', success: function (response) {
const languages = response.languages || [];
// Clear all existing options
self.$modalLanguageSelect.empty();
@@ -1587,13 +1484,12 @@ class Dashboard {
self.$modalAddBtn.prop('disabled', true);
} else {
// Add language options
- languages.forEach(function(language) {
+ languages.forEach(function (language) {
self.$modalLanguageSelect.append($('
').val(language).text(language));
});
self.$modalAddBtn.prop('disabled', false);
}
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error loading available languages:', error);
}
});
@@ -1617,13 +1513,9 @@ class Dashboard {
self.isAddingLanguage = true;
$.ajax({
- url: '/add_language',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
+ url: '/add_language', type: 'POST', contentType: 'application/json', data: JSON.stringify({
language: selectedLanguage
- }),
- success: function(response) {
+ }), success: function (response) {
if (response.status === 'success') {
console.log("Language added successfully");
} else {
@@ -1632,15 +1524,13 @@ class Dashboard {
$('#add-language-btn').show();
$('#add-language-spinner').hide();
}
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error adding language:', error);
alert('Error adding language: ' + (xhr.responseJSON ? xhr.responseJSON.message : error));
// Restore button visibility on error
$('#add-language-btn').show();
$('#add-language-spinner').hide();
- },
- complete: function() {
+ }, complete: function () {
self.isAddingLanguage = false;
self.loadConfigOverview();
}
@@ -1659,13 +1549,9 @@ class Dashboard {
// Load memory content
$.ajax({
- url: '/get_memory',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
+ url: '/get_memory', type: 'POST', contentType: 'application/json', data: JSON.stringify({
memory_name: memoryName
- }),
- success: function(response) {
+ }), success: function (response) {
if (response.status === 'error') {
alert('Error: ' + response.message);
return;
@@ -1674,8 +1560,7 @@ class Dashboard {
self.$editMemoryContent.val(response.content);
self.memoryContentDirty = false;
self.$editMemoryModal.fadeIn(200);
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error loading memory:', error);
alert('Error loading memory: ' + (xhr.responseJSON ? xhr.responseJSON.message : error));
}
@@ -1715,14 +1600,9 @@ class Dashboard {
self.$editMemorySaveBtn.prop('disabled', true).text('Saving...');
$.ajax({
- url: '/save_memory',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
- memory_name: memoryName,
- content: content
- }),
- success: function(response) {
+ url: '/save_memory', type: 'POST', contentType: 'application/json', data: JSON.stringify({
+ memory_name: memoryName, content: content
+ }), success: function (response) {
if (response.status === 'success') {
// Update original content and reset dirty flag
self.originalMemoryContent = content;
@@ -1733,12 +1613,10 @@ class Dashboard {
} else {
alert('Error: ' + response.message);
}
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error saving memory:', error);
alert('Error saving memory: ' + (xhr.responseJSON ? xhr.responseJSON.message : error));
- },
- complete: function() {
+ }, complete: function () {
// Re-enable button
self.$editMemorySaveBtn.prop('disabled', false).text('Save');
}
@@ -1772,21 +1650,16 @@ class Dashboard {
const self = this;
$.ajax({
- url: '/delete_memory',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
+ url: '/delete_memory', type: 'POST', contentType: 'application/json', data: JSON.stringify({
memory_name: memoryName
- }),
- success: function(response) {
+ }), success: function (response) {
if (response.status === 'success') {
// Reload config to show updated memory list
self.loadConfigOverview();
} else {
alert('Error: ' + response.message);
}
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error deleting memory:', error);
alert('Error deleting memory: ' + (xhr.responseJSON ? xhr.responseJSON.message : error));
}
@@ -1835,14 +1708,9 @@ class Dashboard {
self.$createMemoryCreateBtn.prop('disabled', true).text('Creating...');
$.ajax({
- url: '/save_memory',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
- memory_name: memoryName,
- content: ''
- }),
- success: function(response) {
+ url: '/save_memory', type: 'POST', contentType: 'application/json', data: JSON.stringify({
+ memory_name: memoryName, content: ''
+ }), success: function (response) {
if (response.status === 'success') {
// Close the create modal
self.closeCreateMemoryModal();
@@ -1856,8 +1724,7 @@ class Dashboard {
alert('Error: ' + response.message);
self.$createMemoryCreateBtn.prop('disabled', false).text('Create');
}
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error creating memory:', error);
alert('Error creating memory: ' + (xhr.responseJSON ? xhr.responseJSON.message : error));
self.$createMemoryCreateBtn.prop('disabled', false).text('Create');
@@ -1873,9 +1740,7 @@ class Dashboard {
// Load serena config content
$.ajax({
- url: '/get_serena_config',
- type: 'GET',
- success: function(response) {
+ url: '/get_serena_config', type: 'GET', success: function (response) {
if (response.status === 'error') {
alert('Error: ' + response.message);
return;
@@ -1884,15 +1749,14 @@ class Dashboard {
self.$editSerenaConfigContent.val(response.content);
self.serenaConfigContentDirty = false;
self.$editSerenaConfigModal.fadeIn(200);
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error loading serena config:', error);
alert('Error loading serena config: ' + (xhr.responseJSON ? xhr.responseJSON.message : error));
}
});
// Track changes to config content
- this.$editSerenaConfigContent.off('input').on('input', function() {
+ this.$editSerenaConfigContent.off('input').on('input', function () {
const currentContent = self.$editSerenaConfigContent.val();
self.serenaConfigContentDirty = (currentContent !== self.originalSerenaConfigContent);
});
@@ -1919,13 +1783,9 @@ class Dashboard {
self.$editSerenaConfigSaveBtn.prop('disabled', true).text('Saving...');
$.ajax({
- url: '/save_serena_config',
- type: 'POST',
- contentType: 'application/json',
- data: JSON.stringify({
+ url: '/save_serena_config', type: 'POST', contentType: 'application/json', data: JSON.stringify({
content: content
- }),
- success: function(response) {
+ }), success: function (response) {
if (response.status === 'success') {
// Update original content and reset dirty flag
self.originalSerenaConfigContent = content;
@@ -1936,12 +1796,10 @@ class Dashboard {
} else {
alert('Error: ' + response.message);
}
- },
- error: function(xhr, status, error) {
+ }, error: function (xhr, status, error) {
console.error('Error saving serena config:', error);
alert('Error saving serena config: ' + (xhr.responseJSON ? xhr.responseJSON.message : error));
- },
- complete: function() {
+ }, complete: function () {
// Re-enable button
self.$editSerenaConfigSaveBtn.prop('disabled', false).text('Save');
}
@@ -1955,12 +1813,10 @@ class Dashboard {
const _shutdown = function () {
console.log("Triggering shutdown");
$.ajax({
- url: '/shutdown',
- type: "PUT",
- contentType: 'application/json',
+ url: '/shutdown', type: "PUT", contentType: 'application/json',
});
self.$errorContainer.html('Shutting down ...
')
- setTimeout(function() {
+ setTimeout(function () {
window.close();
}, 1000);
}
diff --git a/src/serena/resources/dashboard/index.html b/src/serena/resources/dashboard/index.html
index d9220cba..3da2ec6f 100644
--- a/src/serena/resources/dashboard/index.html
+++ b/src/serena/resources/dashboard/index.html
@@ -298,7 +298,7 @@
×
-
Serena Configuration
+
Global Serena Configuration
Note: Changes to the configuration will only take effect after Serena is restarted.