/*! meta-admin/modules/notifications */
/*jslint
browser, long
*/
/*global
L
*/
import {} from "leaflet";
import {} from "leaflet.markercluster";
import Logger from "js-logger";
import ko from "knockout";
import protocol from "meta-core/modules/protocol";
import _ from "underscore";
import dates from "util-web/modules/dates";
import i18next from "util-web/modules/i18next";
import keyval from "util-web/modules/keyval";
import nav from "util-web/modules/nav";
import ui from "util-web/modules/ui";
import template from "./notifications.html";
const LOG = Logger.get("meta-admin/notifications");
const DEFAULT_CHANNELS = [protocol.CLIENT_STATE_CHANNEL, protocol.WATCHDOG_STATUS_CHANNEL];
const SUBSCRIBE_CHANNELS_KEY = "admin-sub-chan";
/**
* notifications component.
*
* @module meta-admin/modules/component/notifications
*/
export default Object.freeze({
template,
viewModel: {
createViewModel: function ({
sizeLimit = 250,
viewmodel
}) {
const sanitizeArray = function (inputString) {
if (_.isEmpty(inputString) === false) {
return inputString.split(",");
}
};
const spliceNotificationsToSizeLimit = function (notifications) {
const length = notifications.length;
if (sizeLimit < length) {
LOG.debug(`spliceNotificationsToSizeLimit, length=${length}, sizeLimit=${sizeLimit}`);
notifications.splice(sizeLimit, length - sizeLimit);
}
};
const vm = {};
vm.viewmodel = viewmodel;
vm.activeTab = ko.observable();
vm.errorReply = ko.observable();
vm.copyClientId = (clientNotification) => navigator.clipboard.writeText(clientNotification.clientId);
vm.copyMetaId = (metaNotification) => navigator.clipboard.writeText(metaNotification.log.metaId);
vm.limit = ko.observable(50);
const configDefaultChannels = vm.viewmodel.config?.notifications?.defaultChannels;
const defaultChannels = (
_.isEmpty(configDefaultChannels)
? DEFAULT_CHANNELS
: configDefaultChannels
);
vm.channels = ko.observable(defaultChannels.join(","));
vm.fromTimestamp = ko.observable();
vm.toTimestamp = ko.observable();
vm.fromTimestampSub = dates.insertDateTimes({
fromDateObservable: vm.fromTimestamp,
toDateObservable: vm.toTimestamp
});
vm.isLoading = ko.observable();
vm.subscribeClient = ko.observable(true);
vm.subscribeMeta = ko.observable(true);
vm.subscribeMetas = ko.observable();
vm.subscribeMetaTypeIds = ko.observable();
vm.subscribeMetaChanges = ko.observable();
vm.subscribeMetaDistanceFrom = ko.observable();
vm.subscribeMetaDistanceMeters = ko.observable(500);
vm.subscribeMetaDistanceCircle = L.circle([0, 0], {
color: "#008B8B",
radius: vm.subscribeMetaDistanceMeters()
});
vm.subscribeMetaDistanceComputed = ko.computed(function () {
const from = vm.subscribeMetaDistanceFrom();
const meters = vm.subscribeMetaDistanceMeters();
if (from) {
vm.subscribeMetaDistanceCircle.setLatLng(from);
vm.subscribeMetaDistanceCircle.setRadius(Number(meters));
} else {
vm.subscribeMetaDistanceCircle.setLatLng([0, 0]);
}
}).extend({rateLimit: 500});
vm.subscribeChannels = ko.observable(DEFAULT_CHANNELS.join(","));
vm.isSubscribeActive = ko.observable();
vm.activateSubscribe = function () {
vm.isSubscribeActive(true);
};
vm.pickSubscribeDistanceFrom = function () {
const mapApi = vm.viewmodel.mapApiProvider();
if (Boolean(mapApi) === false) {
return Promise.resolve(undefined);
}
vm.isSubscribeActive(false);
return mapApi.pickPosition().then(function (position) {
vm.subscribeMetaDistanceFrom(position);
vm.isSubscribeActive(true);
});
};
vm.clearSubscribeDistanceFrom = () => vm.subscribeMetaDistanceFrom(undefined);
vm.subscribe = function (form) {
const typeIds = sanitizeArray(vm.subscribeMetaTypeIds());
const changes = sanitizeArray(vm.subscribeMetaChanges());
const distanceFrom = vm.subscribeMetaDistanceFrom();
if (ui.validateForm(form) === false) {
return;
}
let metaCriteria;
if (typeIds || changes || distanceFrom) {
metaCriteria = protocol.subscriptionRequestMetaCriteria({
change: changes,
distanceFrom,
distanceMeters: Number(vm.subscribeMetaDistanceMeters()),
typeId: typeIds
});
}
const channels = sanitizeArray(vm.subscribeChannels());
LOG.debug("subscribe");
return vm.viewmodel.client.subscribe(protocol.subscriptionRequest({
channels,
client: vm.subscribeClient(),
meta: vm.subscribeMeta(),
metaCriteria
})).then(function () {
vm.errorReply(undefined);
vm.isSubscribeActive(false);
ui.resetForm(form);
return keyval.set(SUBSCRIBE_CHANNELS_KEY, vm.subscribeChannels() || "");
}, function (exc) {
vm.errorReply(JSON.stringify(exc, undefined, 4));
});
};
vm.isClientNotificationActive = ko.observable();
vm.clientNotificationChannel = ko.observable("");
vm.clientNotificationAction = ko.observable("");
vm.clientNotificationMessage = ko.observable();
vm.clientNotificationData = ko.observable();
vm.isClientNotificationDataValid = ko.observable(true);
vm.clientNotificationDataString = vm.viewmodel.newComputedJsonField(vm.clientNotificationData, undefined, vm.isClientNotificationDataValid);
vm.activateClientNotification = () => vm.isClientNotificationActive(true);
vm.sendClientNotification = function (form) {
if (ui.validateForm(form) === false) {
return;
}
const channel = vm.clientNotificationChannel();
LOG.debug(`sendClientNotification, channel=${channel}`);
vm.viewmodel.client.postClientNotification(protocol.clientNotification({
action: vm.clientNotificationAction(),
channel,
data: vm.clientNotificationData(),
message: vm.clientNotificationMessage(),
timestamp: dates.nowDateTimeString()
}));
vm.clientNotificationChannel("");
vm.clientNotificationAction("");
vm.clientNotificationMessage(undefined);
vm.clientNotificationDataString(undefined);
ui.resetForm(form);
};
vm.clientNotifications = ko.observableArray();
vm.metaNotifications = ko.observableArray();
vm.onClientNotification = function (clientNotification) {
vm.clientNotifications.unshift(clientNotification);
};
vm[protocol.CLIENT_NOTIFICATION] = vm.onClientNotification;
vm.onMetaNotification = function (metaNotification) {
vm.metaNotifications.unshift(metaNotification);
};
vm[protocol.META_NOTIFICATION] = vm.onMetaNotification;
const eventHandle = vm.viewmodel.client.registerOnEvent(vm);
vm.cleanup = function () {
spliceNotificationsToSizeLimit(vm.clientNotifications());
spliceNotificationsToSizeLimit(vm.metaNotifications());
};
const cleanupIntervalHandle = setInterval(vm.cleanup, 10000);
vm.navigateToTab = vm.viewmodel.navigateToTab.bind(undefined, vm.viewmodel.COMPONENTS.NOTIFICATIONS);
vm.onNavUpdate = function (tab) {
const activeTab = (
_.isEmpty(tab)
? vm.viewmodel.NOTIFICATIONS_TABS.CLIENT
: tab
);
LOG.debug(`onNavUpdate, tab=${tab}, activeTab=${activeTab}`);
vm.activeTab(activeTab);
};
nav.register({
id: vm.viewmodel.COMPONENTS.NOTIFICATIONS,
onUpdate: vm.onNavUpdate
});
vm.dispose = function () {
LOG.debug("dispose");
vm.viewmodel.client.unregisterOnEvent(eventHandle);
vm.fromTimestampSub.dispose();
clearInterval(cleanupIntervalHandle);
};
ko.when(function () {
return _.isObject(vm.viewmodel.mapApiProvider());
}).then(function () {
vm.viewmodel.mapApiProvider().addOverlay(vm.subscribeMetaDistanceCircle, i18next.t("subscribe_distance"));
});
ko.when(function () {
return vm.viewmodel.client.isAuth() && vm.viewmodel.isAdmin();
}).then(function () {
return keyval.get(SUBSCRIBE_CHANNELS_KEY);
}).then(function (channels) {
if (_.isEmpty(channels) === false) {
vm.subscribeChannels(channels);
}
return vm.subscribe();
});
return Object.freeze(vm);
}
}
});