function()

in source/html/js/app/ui/event_alert_indicators.js [5:251]


    function($, _, model, event_alerts, diagrams) {

        /**
         * Retrieve all edges originating from the given arn.
         */

        const getEdges = (arn, reverse) => {
            const edges = model.edges.get({
                // filter: (item) => 
                // {
                //     return item.id.endsWith(`:${arn}`) || item.id.startsWith(`${arn}:`);
                // }
                filter: (item) => {
                    // first arn in the edge id is the source
                    return item.id.startsWith(`${arn}:`);
                }
            });
            return _.isArray(edges) ? edges : [edges];
        };

        /**
         * Retrieve all edges with the given arn and belonging to the given pipeline.
         */

        const getEdgesByPipeline = (arn, pipeline, bidi = true) => {
            // console.log(arn, pipeline);
            let options;
            if (bidi) {
                options = {
                    filter: (item) => {
                        // the arn as the source or target and the pipeline number at the end
                        return ((item.id.includes(`:${arn}:`) || item.id.startsWith(`${arn}:`)) &&
                            item.id.endsWith(`:${pipeline}`));
                    }
                };
            } else {
                options = {
                    filter: (item) => {
                        return item.id.startsWith(`${arn}:`) && item.id.endsWith(`:${pipeline}`);
                    }
                };
            }
            const edges = model.edges.get(options);
            return _.isArray(edges) ? edges : [edges];
        };

        /**
         * Update the node on all containing diagrams
         * @param {DataSet} node The DataSet node provided by the model.
         * @param {Boolean} alertState If true, alert setting call, or false for alert clearing
         * @param {String} dataSet Default to 'nodes. Only other possible option is 'edges'.
         */
        const updateUIHandler = (node, alertState = true, dataSet = 'nodes') => {
            let matches = [];
            if (dataSet === 'nodes') {
                matches = diagrams.have_all([node.id]);
            } else if (dataSet === 'edges') {
                // both nodes of an edge need to be on a diagram for the edge to be there
                matches = diagrams.have_all([node.from, node.to]);
            }

            for (let diagram of matches) {
                // update the diagrams state
                diagram[dataSet].update(node);
                diagram.alert(alertState);
            }
        };

        const updateAlertHandler = (node, active_alert = true, alert_details = {}) => {
            let selected = null;
            let unselected = null;
            let newState = 'normal';

            if (node.degraded) {
                newState = 'degraded';
                selected = node.render.degraded_selected();
                unselected = node.render.degraded_unselected();
            } else if (node.alerting) {
                newState = 'alerting';
                selected = node.render.alert_selected();
                unselected = node.render.alert_unselected();
            } else {
                selected = node.render.normal_selected();
                unselected = node.render.normal_unselected();
            }

            if (selected != node.image.selected || unselected != node.image.unselected) {
                /** Update the node */
                node.image.selected = selected;
                node.image.unselected = unselected;
                model.nodes.update(node);
                updateUIHandler(node, active_alert);
            }

            const newEdgeOpts = {
                color: { color: (active_alert === true && newState !== 'normal') ? 'red' : 'black' },
                dashes: (active_alert === true && newState !== 'normal'),
                hoverWidth: 1
            };

            let edges;
            if (node.id.includes(":medialive:") && node.id.includes(":channel:")) {
                // get edges in both directions if possible
                edges = getEdgesByPipeline(node.id, parseInt(alert_details.pipeline));
            }
            // else 
            // if (_.has(alert_details, "pipeline")) {
            //     // get outbound edges by pipeline
            //     edges = getEdgesByPipeline(node.id, parseInt(alert_details.pipeline), false);
            // } 
            else {
                // get outbound edges
                edges = getEdges(node.id);
            }

            // console.log("edges: " + JSON.stringify(edges));

            /** Update the edges */
            edges.forEach((edge) => {
                // console.log(JSON.stringify(edge));
                // console.log(`edge: ${edge.id}`);

                if (edge.color.color !== newEdgeOpts.color.color || edge.dashes !== newEdgeOpts.dashes) {
                    // console.log("edge needs update");
                    edge.color = newEdgeOpts.color;
                    edge.dashes = newEdgeOpts.dashes;
                    edge.hoverWidth = newEdgeOpts.hoverWidth;
                    model.edges.update(edge);
                    updateUIHandler(edge, active_alert, 'edges');
                } else {
                    // console.log("edge is correct");
                }
            });
        };

        const updateEventAlertState = (current_alerts, previous_alerts) => {
            /** iterate through current 'set' alerts */
            let alerting_nodes = new Set();

            // console.log(`current alerts: ${current_alerts.length}`);
            // console.log(`previous alerts: ${previous_alerts.length}`);

            // we only need one unique alert per arn/pipeline
            // filter out multiple alerts for either: same arn/pipeline or same arn (if no pipeline)

            let uniq_current_alerts = _.uniqBy(current_alerts, (item) => {
                if (_.has(item, "detail") && _.has(item.detail, "pipeline")) {
                    return `${item.resource_arn}:${item.detail.pipeline}`;
                } else {
                    return `${item.resource_arn}`;
                }
            });

            let uniq_previous_alerts = _.uniqBy(previous_alerts, (item) => {
                if (_.has(item, "detail") && _.has(item.detail, "pipeline")) {
                    return `${item.resource_arn}:${item.detail.pipeline}`;
                } else {
                    return `${item.resource_arn}`;
                }
            });

            // console.log(`unique current alerts: ${uniq_current_alerts.length}`);
            // console.log(`unique previous alerts: ${uniq_previous_alerts.length}`);

            // use the filtered lists
            current_alerts = uniq_current_alerts;
            previous_alerts = uniq_previous_alerts;

            for (let item of current_alerts) {
                const node = model.nodes.get(item.resource_arn);
                if (node) {
                    node.alerting = true;
                    alerting_nodes.add(node.id);
                    // track which pipelines are down on the model item
                    if (_.has(item, "detail") && _.has(item.detail, "pipeline")) {
                        // create the attribute if its not there
                        if (!_.isArray(node.running_pipelines)) {
                            if (_.has(node.data, "ChannelClass") && node.data.ChannelClass === "SINGLE_PIPELINE") {
                                node.running_pipelines = new Array(1);
                            } else if (_.has(node.data, "ChannelClass") && node.data.ChannelClass === "STANDARD") {
                                node.running_pipelines = new Array(2);
                            } else if (_.has(node.data, "PipelinesRunningCount")) {
                                let count = Number.parseInt(node.data.PipelinesRunningCount);
                                node.running_pipelines = new Array(count);
                            } else {
                                node.running_pipelines = new Array(1);
                            }
                            node.running_pipelines.fill(1);
                        }
                        let index = Number.parseInt(item.detail.pipeline);
                        node.running_pipelines[index] = 0;
                        node.degraded = (_.sum(node.running_pipelines) > 0) && (_.sum(node.running_pipelines) < node.running_pipelines.length);
                    } else {
                        node.degraded = false;
                    }
                    updateAlertHandler(node, true, item.detail);
                }
            }

            // filter out multiple alerts for either: same arn/pipeline or same arn (if no pipeline)
            // cleared alerts are present in the previous list and not in the current list

            let uniq_cleared_alerts = _.differenceBy(previous_alerts, current_alerts, (item) => {
                if (_.has(item, "detail") && _.has(item.detail, "pipeline")) {
                    return `${item.resource_arn}:${item.detail.pipeline}`;
                } else {
                    return `${item.resource_arn}`;
                }
            });

            console.log(`unique cleared alerts: ${uniq_cleared_alerts.length}`);

            for (let cleared of uniq_cleared_alerts) {
                let node = model.nodes.get(cleared.resource_arn);
                if (node) {
                    if (!alerting_nodes.has(node.id)) {
                        node.alerting = false;
                    }
                    // track which pipelines are up on the model item
                    if (_.has(cleared, "detail") && _.has(cleared.detail, "pipeline")) {
                        // create the attribute if its not there
                        if (!_.isArray(node.running_pipelines)) {
                            if (_.has(node.data, "ChannelClass") && node.data.ChannelClass === "SINGLE_PIPELINE") {
                                node.running_pipelines = new Array(1);
                            } else if (_.has(node.data, "ChannelClass") && node.data.ChannelClass === "STANDARD") {
                                node.running_pipelines = new Array(2);
                            } else if (_.has(node.data, "PipelinesRunningCount")) {
                                let count = Number.parseInt(node.data.PipelinesRunningCount);
                                node.running_pipelines = new Array(count);
                            } else {
                                node.running_pipelines = new Array(1);
                            }
                            node.running_pipelines.fill(1);
                        }
                        let index = Number.parseInt(cleared.detail.pipeline);
                        node.running_pipelines[index] = 1;
                        node.degraded = (_.sum(node.running_pipelines) > 0) && (_.sum(node.running_pipelines) < node.running_pipelines.length);
                    } else {
                        node.degraded = false;
                    }
                    updateAlertHandler(node, false, cleared.detail);
                }
            }
        };

        event_alerts.add_callback(updateEventAlertState);
    });