Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions debian/wb-mqtt-homeui.postinst
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,19 @@ else
fi
BOARD_CONF="/usr/share/wb-mqtt-homeui/config.${CONF_SUFFIX}.json"
CONFFILE="/etc/wb-webui.conf"
TEMPLATES_CONF="/usr/share/wb-mqtt-homeui/templatesConfig.default.json"
TEMPLATES_CONFFILE="/etc/wb-templates.conf"

function install_default_config()
{
ucf --debconf-ok $BOARD_CONF $CONFFILE
}

function install_default_templates_config()
{
ucf --debconf-ok $TEMPLATES_CONF $TEMPLATES_CONFFILE
}

function is_config_untouched()
{
for fname in $(ls /usr/share/wb-mqtt-homeui/config.*.json); do
Expand All @@ -53,6 +60,10 @@ case "$1" in
install_default_config
fi
fi

if [ ! -e "$TEMPLATES_CONFFILE" ]; then
install_default_templates_config
fi
;;
esac

Expand Down
2 changes: 2 additions & 0 deletions frontend/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ configs:
minify configs/$$wb.svg > dist/configs/$$wb.svg; \
j2 configs/config.$$wb.json.jinja > dist/configs/config.$$wb.json; \
done
cp -a configs/templatesConfig.default.json dist/configs

install: configs
install -d -m 0777 $(DESTDIR)/var/www/css
Expand All @@ -46,6 +47,7 @@ install: configs

install -Dm0644 dist/configs/*.json -t $(DESTDIR)/usr/share/wb-mqtt-homeui
install -Dm0644 webui.schema.json -t $(DESTDIR)/usr/share/wb-mqtt-confed/schemas
install -Dm0644 templates.schema.json -t $(DESTDIR)/usr/share/wb-mqtt-confed/schemas
install -Dm0644 wb-configs.rules $(DESTDIR)/etc/wb-configs.d/20wb-mqtt-homeui

uninstall:
Expand Down
60 changes: 57 additions & 3 deletions frontend/app/scripts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import dumbTemplateModule from './services/dumbtemplate';
import pageStateService from './services/pagestate';
import deviceDataService from './services/devicedata';
import uiConfigService from './services/uiconfig';
import templatesConfigService from './services/templatesConfig';
import hiliteService from './services/hilite';
import userAgentFactory from './services/userAgent.factory';
import rolesFactoryService from './services/roles.factory';
Expand Down Expand Up @@ -141,7 +142,8 @@ const module = angular
.value('historyMaxPoints', 1000)
.value('logsMaxRows', 50)
.value('webuiConfigPath', '/etc/wb-webui.conf')
.value('configSaveDebounceMs', 300);
.value('configSaveDebounceMs', 300)
.value('templatesConfigPath', '/etc/wb-templates.conf');

// Register services
module
Expand Down Expand Up @@ -174,6 +176,7 @@ module
// make sure DeviceData is loaded at the startup so no MQTT messages are missed
})
.factory('uiConfig', uiConfigService)
.factory('templatesConfig', templatesConfigService)
.filter('hilite', hiliteService);

// Register controllers
Expand Down Expand Up @@ -381,9 +384,11 @@ const realApp = angular
mqttClient,
ConfigEditorProxy,
webuiConfigPath,
templatesConfigPath,
errors,
whenMqttReady,
uiConfig,
templatesConfig,
$timeout,
configSaveDebounceMs,
ngToast,
Expand Down Expand Up @@ -417,9 +422,11 @@ const realApp = angular
mqttClient,
ConfigEditorProxy,
webuiConfigPath,
templatesConfigPath,
errors,
whenMqttReady,
uiConfig
uiConfig,
templatesConfig
) {
return function (loginData) {
if (loginData.url) {
Expand All @@ -443,6 +450,17 @@ const realApp = angular
})
.catch(errors.catch('app.errors.load'));

// Try to obtain Templates configs
whenMqttReady()
.then(() => {
return ConfigEditorProxy.Load({ path: templatesConfigPath });
})
.then(result => {
console.log('LOAD TEMPLATES CONF: %o', result.content);
templatesConfig.ready(result.content);
})
.catch(errors.catch('app.errors.load'));

return true;

//.....................................................................
Expand All @@ -461,9 +479,11 @@ const realApp = angular
mqttClient,
ConfigEditorProxy,
webuiConfigPath,
templatesConfigPath,
errors,
whenMqttReady,
uiConfig
uiConfig,
templatesConfig
);

//.........................................................................
Expand Down Expand Up @@ -492,6 +512,7 @@ const realApp = angular

// TBD: the following should be handled by config sync service
var configSaveDebounce = null;
var templatesConfigSaveDebounce = null;
var firstBootstrap = true;

// Watch for WebUI config changes
Expand Down Expand Up @@ -527,6 +548,39 @@ const realApp = angular
true
);

// Watch for templates config changes
$rootScope.$watch(
() => templatesConfig.data,
(newData, oldData) => {
if (angular.equals(newData, oldData)) {
return;
}
if (firstBootstrap) {
firstBootstrap = false;
return;
}
console.log('new templates data: %o', newData);
if (templatesConfigSaveDebounce) {
$timeout.cancel(templatesConfigSaveDebounce);
}
templatesConfigSaveDebounce = $timeout(() => {
errors.hideError();
ConfigEditorProxy.Save({ path: templatesConfigPath, content: newData })
.then(() => {
console.log('templates config saved');
})
.catch(err => {
if (err.name === 'QuotaExceededError') {
errors.showError('app.errors.overflow');
} else {
errors.showError('app.errors.save', err);
}
});
}, configSaveDebounceMs);
},
true
);

whenMqttReady()
.then(() => {
if (rolesFactory.checkRights(rolesFactory.ROLE_THREE)) {
Expand Down
91 changes: 91 additions & 0 deletions frontend/app/scripts/controllers/historyController.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
var errors = $injector.get('errors');
var historyMaxPoints = $injector.get('historyMaxPoints');
var uiConfig = $injector.get('uiConfig');
this.templatesConfig = $injector.get('templatesConfig');
this.orderByFilter = $injector.get('orderByFilter');
this.$timeout = $injector.get('$timeout');
this.$state = $injector.get('$state');
Expand Down Expand Up @@ -184,6 +185,11 @@

this.dataPointsMultiple = [];

// Templates props
this.templates = [];
this.selectedTemplate = null;
this.newTemplateName = "";

// 4. Setup
this.updateTranslations()
.then(() => uiConfig.whenReady())
Expand All @@ -192,6 +198,13 @@
this.setSelectedControlsAndStartLoading(stateFromUrl.c);
});

this.updateTranslations()
.then(() => this.templatesConfig.whenReady())
.then(data => {
this.templates = data.templates;
console.log("[LOG]: Templates are set up: %o", this.templates);
});

this.plotlyEvents = graph => {
// !!!!! метод обязательно должен быть в конструкторе иначе контекст будет непонятно чей
graph.on('plotly_relayout', event => {
Expand Down Expand Up @@ -978,6 +991,84 @@

downloadLink.click();
}

saveTemplate() {
if (!this.newTemplateName || !this.selectedControls.length) return;
if (this.templates.find(elem => elem.name === this.newTemplateName)) {
alert(this.$translate.instant('history.errors.template_exists'))
return;
}

// NOTE: Probably should add more fields of the control
// because (deviceId, controlId) can duplicate?
const newTemplate = {
name: this.newTemplateName,
data: this.selectedControls.map(control => ({
deviceId: control.deviceId,
controlId: control.controlId
}))
};
console.log(`[LOG]: New template was created: ${newTemplate.name}`);
console.log('[LOG]: New template data: %o', newTemplate.data);

// Save the template locally and globally
// (because this.templates are linked to data from templatesConfig)
this.templates.push(newTemplate);
this.newTemplateName = "";
console.log("[LOG]: New template was saved");
}

applyTemplate() {
if (!this.selectedTemplate) return;
console.log("[LOG]: selectedTemplate: %o", this.selectedTemplate);
const template = this.templates.find((element) => element.name === this.selectedTemplate.name);
this.selectedControls = template.data.map(
data => {
const control = this.controls.find(
c =>
c.deviceId === data.deviceId &&
c.controlId === data.controlId
);
return control || null;
}
)
.filter(c => c)

console.log("[LOG]: Template was successfully applied");
}

updateTemplate() {
if (!this.selectedTemplate || !this.selectedControls.length) return;
const updatedTemplate = {
name: this.selectedTemplate.name,
data: this.selectedControls.map(control => ({
deviceId: control.deviceId,
controlId: control.controlId,
})),
};

console.log("[LOG]: Obtained updated template");
console.log(`[LOG]: New template name: ${updatedTemplate.name}`);

// Updating the template by index
const index = this.templates.findIndex(t => t.name === this.selectedTemplate.name);
console.log(`[LOG]: Existing template found with index ${index}`);
if (index !== -1) {
this.templates[index] = updatedTemplate;

Check warning on line 1057 in frontend/app/scripts/controllers/historyController.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

frontend/app/scripts/controllers/historyController.js#L1057

Generic Object Injection Sink
console.log("[LOG]: Template was updated");
}
}

deleteTemplate() {
if (!this.selectedTemplate) return;

const index = this.templates.findIndex((element) => element.name === this.selectedTemplate.name);
this.templates.splice(index, 1);
this.selectedTemplate = null;
this.selectedControls = [null];

console.log("[LOG]: Template was deleted");
}
} // class HistoryCtrl

//-----------------------------------------------------------------------------
Expand Down
15 changes: 11 additions & 4 deletions frontend/app/scripts/i18n/history/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,30 @@
"nothing": "No data points to display",
"date": "Date and time",
"all_channels": "All channels: ",
"widget_channels": "Channels used in widgets: "
"widget_channels": "Channels used in widgets: ",
"choose_template": "- Choose template -",
"new_template": "- Name for a new template -"
},
"buttons": {
"delete": "delete",
"add": "Add channel",
"load": "Load data",
"reset": "Reset",
"stop": "Stop loading",
"download": "Download history as CSV"
"download": "Download history as CSV",
"apply_template": "Apply template",
"delete_template": "Delete template",
"update_template": "Update template",
"save_template": "Save template"
},
"errors": {
"dates": "Date range is invalid. Change one of dates",
"load": "Error getting history",
"warning": "Warning"
"warning": "Warning",
"template_exists": "This template already exists"
},
"format": {
"date_with_ms": "MMM d, yyyy h:mm:ss:sss a"
}
}
}
}
15 changes: 11 additions & 4 deletions frontend/app/scripts/i18n/history/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,30 @@
"nothing": "Нет записей для отображения",
"date": "Дата и время",
"all_channels": "Все каналы: ",
"widget_channels": "Каналы из виджетов: "
"widget_channels": "Каналы из виджетов: ",
"choose_template": "- Выберите шаблон -",
"new_template": "- Имя шаблона -"
},
"buttons": {
"delete": "удалить",
"add": "Добавить канал",
"load": "Загрузить данные",
"reset": "Сбросить",
"stop": "Остановить загрузку",
"download": "Скачать данные в виде CSV"
"download": "Скачать данные в виде CSV",
"apply_template": "Применить шаблон",
"delete_template": "Удалить шаблон",
"update_template": "Изменить шаблон",
"save_template": "Сохранить шаблон"
},
"errors": {
"dates": "Некорректный временной интервал, измените одну из дат",
"load": "Ошибка получения данных",
"warning": "Предупреждение"
"warning": "Предупреждение",
"template_exists": "Такой шаблон уже существует"
},
"format": {
"date_with_ms": "d MMM yyyy г. H:mm:ss:sss"
}
}
}
}
29 changes: 29 additions & 0 deletions frontend/app/scripts/services/templatesConfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
'use strict';

// Service used to keep track of templates data
function templatesConfigService($q) {
'ngInject';

var data = {
templates: []
};

var deferReady = $q.defer();

return {
data,

whenReady() {
return deferReady.promise;
},

ready(changes) {
if (changes) {
angular.extend(data, changes);

Check warning on line 22 in frontend/app/scripts/services/templatesConfig.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

frontend/app/scripts/services/templatesConfig.js#L22

'angular' is not defined.
}
deferReady.resolve(data);
}
}
}

export default templatesConfigService;
Loading