<commit_before>export default ['workflowData', 'workflowResultsService', 'workflowDataOptions',
    'jobLabels', 'workflowNodes', '$scope', 'ParseTypeChange',
    'ParseVariableString', 'WorkflowService', 'count', '$state', 'i18n',
    'moment', function(workflowData, workflowResultsService,
    workflowDataOptions, jobLabels, workflowNodes, $scope, ParseTypeChange,
    ParseVariableString, WorkflowService, count, $state, i18n, moment) {
        var runTimeElapsedTimer = null;

        var getLinks = function() {
            var getLink = function(key) {
                if(key === 'schedule') {
                    if($scope.workflow.related.schedule) {
                        return '/#/templates/workflow_job_template/' + $scope.workflow.workflow_job_template + '/schedules' + $scope.workflow.related.schedule.split(/api\/v\d+\/schedules/)[1];
                    }
                    else {
                        return null;
                    }
                }
                else {
                    if ($scope.workflow.related[key]) {
                        return '/#/' + $scope.workflow.related[key]
                            .split(/api\/v\d+\//)[1];
                    } else {
                        return null;
                    }
                }
            };

            $scope.workflow_template_link = '/#/templates/workflow_job_template/'+$scope.workflow.workflow_job_template;
            $scope.created_by_link = getLink('created_by');
            $scope.scheduled_by_link = getLink('schedule');
            $scope.cloud_credential_link = getLink('cloud_credential');
            $scope.network_credential_link = getLink('network_credential');
        };

        var getLabels = function() {
            var getLabel = function(key) {
                if ($scope.workflowOptions && $scope.workflowOptions[key]) {
                    return $scope.workflowOptions[key].choices
                        .filter(val => val[0] === $scope.workflow[key])
                        .map(val => val[1])[0];
                } else {
                    return null;
                }
            };

            $scope.status_label = getLabel('status');
            $scope.type_label = getLabel('job_type');
            $scope.verbosity_label = getLabel('verbosity');
        };

        var updateWorkflowJobElapsedTimer = function(time) {
            $scope.workflow.elapsed = time;
        };

        function init() {
            // put initially resolved request data on scope
            $scope.workflow = workflowData;
            $scope.workflow_nodes = workflowNodes;
            $scope.workflowOptions = workflowDataOptions.actions.GET;
            $scope.labels = jobLabels;
            $scope.count = count.val;
            $scope.showManualControls = false;

            // Start elapsed time updater for job known to be running
            if ($scope.workflow.started !== null && $scope.workflow.status === 'running') {
                runTimeElapsedTimer = workflowResultsService.createOneSecondTimer($scope.workflow.started, updateWorkflowJobElapsedTimer);
            }

            if(workflowData.summary_fields && workflowData.summary_fields.workflow_job_template &&
                workflowData.summary_fields.workflow_job_template.id){
                    $scope.workflow_job_template_link = `/#/templates/workflow_job_template/${$scope.workflow.summary_fields.workflow_job_template.id}`;
            }

            // stdout full screen toggle tooltip text
            $scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output");

            // turn related api browser routes into front end routes
            getLinks();

            // use options labels to manipulate display of details
            getLabels();

            // set up a read only code mirror for extra vars
            $scope.variables = ParseVariableString($scope.workflow.extra_vars);
            $scope.parseType = 'yaml';
            ParseTypeChange({ scope: $scope,
                field_id: 'pre-formatted-variables',
                readOnly: true });

            // Click binding for the expand/collapse button on the standard out log
            $scope.stdoutFullScreen = false;

            WorkflowService.buildTree({
                workflowNodes: workflowNodes
            }).then(function(data){
                $scope.treeData = data;

                // TODO: I think that the workflow chart directive (and eventually d3) is meddling with
                // this treeData object and removing the children object for some reason (?)
                // This happens on occasion and I think is a race condition (?)
                if(!$scope.treeData.data.children) {
                    $scope.treeData.data.children = [];
                }

                $scope.canAddWorkflowJobTemplate = false;
            });

        }

        $scope.toggleStdoutFullscreen = function() {

            $scope.$broadcast('workflowDetailsResized');

            $scope.stdoutFullScreen = !$scope.stdoutFullScreen;

            if ($scope.stdoutFullScreen === true) {
                $scope.toggleStdoutFullscreenTooltip = i18n._("Collapse Output");
            } else if ($scope.stdoutFullScreen === false) {
                $scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output");
            }
        };

        $scope.deleteJob = function() {
            workflowResultsService.deleteJob($scope.workflow);
        };

        $scope.cancelJob = function() {
            workflowResultsService.cancelJob($scope.workflow);
        };

        $scope.relaunchJob = function() {
            workflowResultsService.relaunchJob($scope);
        };

        $scope.toggleManualControls = function() {
            $scope.showManualControls = !$scope.showManualControls;
        };

        $scope.lessLabels = false;
        $scope.toggleLessLabels = function() {
            if (!$scope.lessLabels) {
                $('#workflow-results-labels').slideUp(200);
                $scope.lessLabels = true;
            }
            else {
                $('#workflow-results-labels').slideDown(200);
                $scope.lessLabels = false;
            }
        };

        $scope.panChart = function(direction) {
            $scope.$broadcast('panWorkflowChart', {
                direction: direction
            });
        };

        $scope.zoomChart = function(zoom) {
            $scope.$broadcast('zoomWorkflowChart', {
                zoom: zoom
            });
        };

        $scope.resetChart = function() {
            $scope.$broadcast('resetWorkflowChart');
        };

        $scope.zoomToFitChart = function() {
            $scope.$broadcast('zoomToFitChart');
        };

        $scope.workflowZoomed = function(zoom) {
            $scope.$broadcast('workflowZoomed', {
                zoom: zoom
            });
        };

        init();

        // Processing of job-status messages from the websocket
        $scope.$on(`ws-jobs`, function(e, data) {
            // Update the workflow job's unified job:
            if (parseInt(data.unified_job_id, 10) === parseInt($scope.workflow.id,10)) {
                    $scope.workflow.status = data.status;
                    // start internval counter for job that transitioned to running
                    if ($scope.workflow.status === 'running') {
                        runTimeElapsedTimer = workflowResultsService.createOneSecondTimer(moment(), updateWorkflowJobElapsedTimer);
                    }

                    if(data.status === "successful" || data.status === "failed" || data.status === "error"){
                        $state.go('.', null, { reload: true });
                    }
            }
            // Update the jobs spawned by the workflow:
            if(data.hasOwnProperty('workflow_job_id') &&
                parseInt(data.workflow_job_id, 10) === parseInt($scope.workflow.id,10)){

                    WorkflowService.updateStatusOfNode({
                        treeData: $scope.treeData,
                        nodeId: data.workflow_node_id,<commit_msg>Handle race condition where workflow job status might appear stuck in waiting if we miss the socket event indicating that it got moved to running<commit_after>export default ['workflowData', 'workflowResultsService', 'workflowDataOptions',
    'jobLabels', 'workflowNodes', '$scope', 'ParseTypeChange',
    'ParseVariableString', 'WorkflowService', 'count', '$state', 'i18n',
    'moment', function(workflowData, workflowResultsService,
    workflowDataOptions, jobLabels, workflowNodes, $scope, ParseTypeChange,
    ParseVariableString, WorkflowService, count, $state, i18n, moment) {
        var runTimeElapsedTimer = null;

        var getLinks = function() {
            var getLink = function(key) {
                if(key === 'schedule') {
                    if($scope.workflow.related.schedule) {
                        return '/#/templates/workflow_job_template/' + $scope.workflow.workflow_job_template + '/schedules' + $scope.workflow.related.schedule.split(/api\/v\d+\/schedules/)[1];
                    }
                    else {
                        return null;
                    }
                }
                else {
                    if ($scope.workflow.related[key]) {
                        return '/#/' + $scope.workflow.related[key]
                            .split(/api\/v\d+\//)[1];
                    } else {
                        return null;
                    }
                }
            };

            $scope.workflow_template_link = '/#/templates/workflow_job_template/'+$scope.workflow.workflow_job_template;
            $scope.created_by_link = getLink('created_by');
            $scope.scheduled_by_link = getLink('schedule');
            $scope.cloud_credential_link = getLink('cloud_credential');
            $scope.network_credential_link = getLink('network_credential');
        };

        var getLabels = function() {
            var getLabel = function(key) {
                if ($scope.workflowOptions && $scope.workflowOptions[key]) {
                    return $scope.workflowOptions[key].choices
                        .filter(val => val[0] === $scope.workflow[key])
                        .map(val => val[1])[0];
                } else {
                    return null;
                }
            };

            $scope.status_label = getLabel('status');
            $scope.type_label = getLabel('job_type');
            $scope.verbosity_label = getLabel('verbosity');
        };

        var updateWorkflowJobElapsedTimer = function(time) {
            $scope.workflow.elapsed = time;
        };

        function init() {
            // put initially resolved request data on scope
            $scope.workflow = workflowData;
            $scope.workflow_nodes = workflowNodes;
            $scope.workflowOptions = workflowDataOptions.actions.GET;
            $scope.labels = jobLabels;
            $scope.count = count.val;
            $scope.showManualControls = false;

            // Start elapsed time updater for job known to be running
            if ($scope.workflow.started !== null && $scope.workflow.status === 'running') {
                runTimeElapsedTimer = workflowResultsService.createOneSecondTimer($scope.workflow.started, updateWorkflowJobElapsedTimer);
            }

            if(workflowData.summary_fields && workflowData.summary_fields.workflow_job_template &&
                workflowData.summary_fields.workflow_job_template.id){
                    $scope.workflow_job_template_link = `/#/templates/workflow_job_template/${$scope.workflow.summary_fields.workflow_job_template.id}`;
            }

            // stdout full screen toggle tooltip text
            $scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output");

            // turn related api browser routes into front end routes
            getLinks();

            // use options labels to manipulate display of details
            getLabels();

            // set up a read only code mirror for extra vars
            $scope.variables = ParseVariableString($scope.workflow.extra_vars);
            $scope.parseType = 'yaml';
            ParseTypeChange({ scope: $scope,
                field_id: 'pre-formatted-variables',
                readOnly: true });

            // Click binding for the expand/collapse button on the standard out log
            $scope.stdoutFullScreen = false;

            WorkflowService.buildTree({
                workflowNodes: workflowNodes
            }).then(function(data){
                $scope.treeData = data;

                // TODO: I think that the workflow chart directive (and eventually d3) is meddling with
                // this treeData object and removing the children object for some reason (?)
                // This happens on occasion and I think is a race condition (?)
                if(!$scope.treeData.data.children) {
                    $scope.treeData.data.children = [];
                }

                $scope.canAddWorkflowJobTemplate = false;
            });

        }

        $scope.toggleStdoutFullscreen = function() {

            $scope.$broadcast('workflowDetailsResized');

            $scope.stdoutFullScreen = !$scope.stdoutFullScreen;

            if ($scope.stdoutFullScreen === true) {
                $scope.toggleStdoutFullscreenTooltip = i18n._("Collapse Output");
            } else if ($scope.stdoutFullScreen === false) {
                $scope.toggleStdoutFullscreenTooltip = i18n._("Expand Output");
            }
        };

        $scope.deleteJob = function() {
            workflowResultsService.deleteJob($scope.workflow);
        };

        $scope.cancelJob = function() {
            workflowResultsService.cancelJob($scope.workflow);
        };

        $scope.relaunchJob = function() {
            workflowResultsService.relaunchJob($scope);
        };

        $scope.toggleManualControls = function() {
            $scope.showManualControls = !$scope.showManualControls;
        };

        $scope.lessLabels = false;
        $scope.toggleLessLabels = function() {
            if (!$scope.lessLabels) {
                $('#workflow-results-labels').slideUp(200);
                $scope.lessLabels = true;
            }
            else {
                $('#workflow-results-labels').slideDown(200);
                $scope.lessLabels = false;
            }
        };

        $scope.panChart = function(direction) {
            $scope.$broadcast('panWorkflowChart', {
                direction: direction
            });
        };

        $scope.zoomChart = function(zoom) {
            $scope.$broadcast('zoomWorkflowChart', {
                zoom: zoom
            });
        };

        $scope.resetChart = function() {
            $scope.$broadcast('resetWorkflowChart');
        };

        $scope.zoomToFitChart = function() {
            $scope.$broadcast('zoomToFitChart');
        };

        $scope.workflowZoomed = function(zoom) {
            $scope.$broadcast('workflowZoomed', {
                zoom: zoom
            });
        };

        init();

        // Processing of job-status messages from the websocket
        $scope.$on(`ws-jobs`, function(e, data) {
            // Update the workflow job's unified job:
            if (parseInt(data.unified_job_id, 10) === parseInt($scope.workflow.id,10)) {
                    $scope.workflow.status = data.status;
                    // start internval counter for job that transitioned to running
                    if ($scope.workflow.status === 'running') {
                        runTimeElapsedTimer = workflowResultsService.createOneSecondTimer(moment(), updateWorkflowJobElapsedTimer);
                    }

                    if(data.status === "successful" || data.status === "failed" || data.status === "error"){
                        $state.go('.', null, { reload: true });
                    }
            }
            // Update the jobs spawned by the workflow:
            if(data.hasOwnProperty('workflow_job_id') &&
                parseInt(data.workflow_job_id, 10) === parseInt($scope.workflow.id,10)){

                    // This check ensures that the workflow status icon doesn't get stuck in
                    // the waiting state due to the UI missing the initial socket message.  This
                    // can happen if the GET request on the workflow job returns "waiting" and
                    // the sockets aren't established yet so we miss the event that indicates
                    // the workflow job has moved into a running state.
                    if (!_.includes(['running', 'successful', 'failed', 'error'], $scope.workflow.status)){
                        $scope.workflow.status = 'running';
                        runTimeElapsedTimer = workflowResultsService.createOneSecondTimer(moment(), updateWorkflowJobElapsedTimer);
                    }

                    WorkflowService.updateStatusOfNode({
                        treeData: $scope.treeData,
                        nodeId: data.workflow_node_id,
{'fraction_non_alphanumeric': 0.11063134554790524, 'fraction_numerical': 0.00350099194771852, 'mean_word_length': 1.7400479616306954, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1462948', 'n_tokens_mistral': 4454, 'n_tokens_neox': 4194, 'n_words': 849}