<commit_before>/**
 * @author <NAME> <<EMAIL>>
 * @public
 * This is a generalized class for an input cell that sits in an IPython markdown cell.
 * It handles all of its rendering here (no longer in HTML in markdown), and invokes
 * an input widget passed to it.
 *
 * This expects a method object passed to it, and expects that object to have the new
 * format from the narrative_method_store service.
 */

(function( $, undefined ) {
    $.KBWidget({
        name: "kbaseNarrativeAppCell",
        parent: "kbaseWidget",
        version: "1.0.0",
        options: {
            app: null,
            cellId: null,
            loadingImage: 'static/kbase/images/ajax-loader.gif',
            methodStoreURL: 'https://kbase.us/services/narrative_method_store',
            
            appHelpLink: '/functional-site/#/narrativestore/app/',
            methodHelpLink: '/functional-site/#/narrativestore/method/',
        },
        IGNORE_VERSION: true,
        defaultInputWidget: 'kbaseNarrativeMethodInput',
        defaultOutputWidget: 'kbaseDefaultNarrativeOutput',

        appSpec: null,
        methodSpecs: null,
        inputSteps: null,
        inputStepLookup: null,
        
        $runButton: null,
        $stopButton: null,
        
        
        /**
         * @private
         * @method
         * Initialization is done by the KBase widget architecture itself.
         * This requires and assumes that an app spec and cellId are both present.
         * TODO: add checks and failures for this.
         *
         * This renders by calling fetchMethodInfo, which grabs all the specs
         * for the intermediate steps, then renders the whole mess and 
         * refreshes to update with jobs and results and such.
         *
         */
        init: function(options) {
            this._super(options);

            if (window.kbconfig && window.kbconfig.urls) {
                this.options.methodStoreURL = window.kbconfig.urls.narrative_method_store;
            }
            this.methClient = new NarrativeMethodStore(this.options.methodStoreURL);

            this.options.appSpec = this.options.appSpec.replace(/\n/g, '');
            this.appSpec = JSON.parse(this.options.appSpec);
            this.cellId = this.options.cellId;

            this.$elem.append($('<img src="' + this.options.loadingImage + '">'))
                      .append($('<div>Loading App...</div>'));

            this.fetchMethodInfo();
            
            return this;
        },

        fetchMethodInfo: function() {
            if (!this.appSpec.steps || this.appSpec.steps.length === 0) {
                this.showError('App "' + this.appSpec.info.name + '" has no steps!');
            }
            // get the list of method ids
            var methodIds = [];
            for (var i=0; i<this.appSpec.steps.length; i++) {
                methodIds.push(this.appSpec.steps[i].method_id);
            }
            this.methClient.get_method_spec({'ids' : methodIds},
                $.proxy(function(specs) {
                    this.methodSpecs = specs;
                    this.render(specs);
                }, this),
                $.proxy(function(error) {
                    this.showError(error);
                }, this)
            );
        },

        showError: function(error) {
            console.error(error);
            var $errorHeader = $('<div>')
                               .addClass('alert alert-danger')
                               .append('<b>Sorry, an error occurred while loading your KBase App.</b><br>Please contact the KBase team at <a href="mailto:<EMAIL>?subject=Narrative%App%20loading%20error"><EMAIL></a> with the information below.');
            var $errorPanel = $('<div>')
                                .addClass('panel kb-app-panel');
            $errorPanel.append($errorHeader);

            // If it's a string, just dump the string.
            if (typeof error === 'string') {
                $errorPanel.append($('<div>').append(error));
            }

            // If it's an object, expect an error object as returned by the execute_reply callback from the IPython kernel.
            else if (typeof error === 'object') {
                var $details = $('<div>');
                $details.append($('<div>')
                                .append('<b>Error:</b> ' + error.error.message+ '<br><br>'));

                var $tracebackDiv = $('<div>')
                                    .addClass('kb-function-error-traceback');
                if (error.error) {
                    error.error.error.replace(/\n/g, "<br>");
                    $tracebackDiv.append(error.error.error + "<br>");
                }

                var $tracebackPanel = $('<div>');
                var tracebackAccordion = [{'title' : 'Detailed Error Trace', 'body' : $tracebackDiv}];

                $errorPanel.append($details)
                           .append($tracebackPanel);
                $tracebackPanel.kbaseAccordion({ elements : tracebackAccordion });
            }
            this.$elem.empty().append($errorPanel);
        },

        /* temp hack to deal with current state of NJS */
        getSpecAndParameterInfo: function() {
            return {
                appSpec : this.appSpec,
                methodSpecs : this.methodSpecs,
                parameterValues: this.getAllParameterValues()
            };
        },
        
        /**
         * Renders this cell and its contained input widget.
         */
        render: function(stepSpecs) {
            this.methodSpecs = {};

            var self = this;
            this.$runButton = $('<button>')
                              .attr('type', 'button')
                              .attr('value', 'Run')
                              .addClass('btn btn-success btn-sm')
                              .append('Run')
                              .click(
                                  $.proxy(function(event) {
                                      self.startAppRun();
                                      event.preventDefault();
                                      this.trigger('runApp.Narrative', { 
                                          cell: IPython.notebook.get_selected_cell(),
                                          appSpec: this.appSpec,
                                          methodSpecs: this.methodSpecs,
                                          parameters: this.getParameters()
                                      });
                                  }, this)
                              );
            this.$stopButton = $('<button>')
                              .attr('type', 'button')
                              .attr('value', 'Stop')
                              .addClass('btn btn-warning btn-sm')
                              .append('Stop')
                              .click(
                                  $.proxy(function(event) {
                                      self.stopAppRun();
                                  }, this)
                              )
                              .hide();
                            

            var $appInfo = this.appSpec.info.name;
            this.$methodPanel = $('<div>')
                                .addClass('kb-app-steps');
            var stepHeaderText = "Step ";
            this.inputSteps = [];
            this.inputStepLookup = {};
            var inputStep = {};
            for (var i=0; i<stepSpecs.length; i++) {
                var $stepPanel = this.renderStepDiv(this.appSpec.steps[i].step_id, stepSpecs[i], stepHeaderText + (i+1)+": ");
                this.$methodPanel.append($stepPanel);
                this.methodSpecs[stepSpecs[i].info.id] = stepSpecs[i];
            }

            var $buttons = $('<div>')
                           .addClass('buttons pull-right')
                           .append(this.$runButton)
                           .append(this.$stopButton);

            var $appSubtitleDiv = $("<div>")
                                        .addClass('kb-app-panel-description')
                                        .append(this.appSpec.info.subtitle);
            
            var $appHeaderDiv = $("<div>")
                                        .addClass('kb-app-panel-header')
                                        .append(this.appSpec.info.header);
            
            var $cellPanel = $('<div>')
                             .addClass('panel kb-app-panel kb-cell-run')
                             .append($('<div>')
                                     .addClass('panel-heading app-panel-heading')
                                     .append("<h1><b>"+$appInfo+"</b></h1>")
                                     .append($appSubtitleDiv))
                             .append($('<div>')<commit_msg>minor hack to clean app header text of html quotes<commit_after>/**
 * @author <NAME> <<EMAIL>>
 * @public
 * This is a generalized class for an input cell that sits in an IPython markdown cell.
 * It handles all of its rendering here (no longer in HTML in markdown), and invokes
 * an input widget passed to it.
 *
 * This expects a method object passed to it, and expects that object to have the new
 * format from the narrative_method_store service.
 */

(function( $, undefined ) {
    $.KBWidget({
        name: "kbaseNarrativeAppCell",
        parent: "kbaseWidget",
        version: "1.0.0",
        options: {
            app: null,
            cellId: null,
            loadingImage: 'static/kbase/images/ajax-loader.gif',
            methodStoreURL: 'https://kbase.us/services/narrative_method_store',
            
            appHelpLink: '/functional-site/#/narrativestore/app/',
            methodHelpLink: '/functional-site/#/narrativestore/method/',
        },
        IGNORE_VERSION: true,
        defaultInputWidget: 'kbaseNarrativeMethodInput',
        defaultOutputWidget: 'kbaseDefaultNarrativeOutput',

        appSpec: null,
        methodSpecs: null,
        inputSteps: null,
        inputStepLookup: null,
        
        $runButton: null,
        $stopButton: null,
        
        
        /**
         * @private
         * @method
         * Initialization is done by the KBase widget architecture itself.
         * This requires and assumes that an app spec and cellId are both present.
         * TODO: add checks and failures for this.
         *
         * This renders by calling fetchMethodInfo, which grabs all the specs
         * for the intermediate steps, then renders the whole mess and 
         * refreshes to update with jobs and results and such.
         *
         */
        init: function(options) {
            this._super(options);

            if (window.kbconfig && window.kbconfig.urls) {
                this.options.methodStoreURL = window.kbconfig.urls.narrative_method_store;
            }
            this.methClient = new NarrativeMethodStore(this.options.methodStoreURL);

            this.options.appSpec = this.options.appSpec.replace(/\n/g, '');
            this.appSpec = JSON.parse(this.options.appSpec);
            this.cellId = this.options.cellId;

            this.$elem.append($('<img src="' + this.options.loadingImage + '">'))
                      .append($('<div>Loading App...</div>'));

            this.fetchMethodInfo();
            
            return this;
        },

        fetchMethodInfo: function() {
            if (!this.appSpec.steps || this.appSpec.steps.length === 0) {
                this.showError('App "' + this.appSpec.info.name + '" has no steps!');
            }
            // get the list of method ids
            var methodIds = [];
            for (var i=0; i<this.appSpec.steps.length; i++) {
                methodIds.push(this.appSpec.steps[i].method_id);
            }
            this.methClient.get_method_spec({'ids' : methodIds},
                $.proxy(function(specs) {
                    this.methodSpecs = specs;
                    this.render(specs);
                }, this),
                $.proxy(function(error) {
                    this.showError(error);
                }, this)
            );
        },

        showError: function(error) {
            console.error(error);
            var $errorHeader = $('<div>')
                               .addClass('alert alert-danger')
                               .append('<b>Sorry, an error occurred while loading your KBase App.</b><br>Please contact the KBase team at <a href="mailto:<EMAIL>?subject=Narrative%App%20loading%20error"><EMAIL></a> with the information below.');
            var $errorPanel = $('<div>')
                                .addClass('panel kb-app-panel');
            $errorPanel.append($errorHeader);

            // If it's a string, just dump the string.
            if (typeof error === 'string') {
                $errorPanel.append($('<div>').append(error));
            }

            // If it's an object, expect an error object as returned by the execute_reply callback from the IPython kernel.
            else if (typeof error === 'object') {
                var $details = $('<div>');
                $details.append($('<div>')
                                .append('<b>Error:</b> ' + error.error.message+ '<br><br>'));

                var $tracebackDiv = $('<div>')
                                    .addClass('kb-function-error-traceback');
                if (error.error) {
                    error.error.error.replace(/\n/g, "<br>");
                    $tracebackDiv.append(error.error.error + "<br>");
                }

                var $tracebackPanel = $('<div>');
                var tracebackAccordion = [{'title' : 'Detailed Error Trace', 'body' : $tracebackDiv}];

                $errorPanel.append($details)
                           .append($tracebackPanel);
                $tracebackPanel.kbaseAccordion({ elements : tracebackAccordion });
            }
            this.$elem.empty().append($errorPanel);
        },

        /* temp hack to deal with current state of NJS */
        getSpecAndParameterInfo: function() {
            return {
                appSpec : this.appSpec,
                methodSpecs : this.methodSpecs,
                parameterValues: this.getAllParameterValues()
            };
        },
        
        /**
         * Renders this cell and its contained input widget.
         */
        render: function(stepSpecs) {
            this.methodSpecs = {};

            var self = this;
            this.$runButton = $('<button>')
                              .attr('type', 'button')
                              .attr('value', 'Run')
                              .addClass('btn btn-success btn-sm')
                              .append('Run')
                              .click(
                                  $.proxy(function(event) {
                                      self.startAppRun();
                                      event.preventDefault();
                                      this.trigger('runApp.Narrative', { 
                                          cell: IPython.notebook.get_selected_cell(),
                                          appSpec: this.appSpec,
                                          methodSpecs: this.methodSpecs,
                                          parameters: this.getParameters()
                                      });
                                  }, this)
                              );
            this.$stopButton = $('<button>')
                              .attr('type', 'button')
                              .attr('value', 'Stop')
                              .addClass('btn btn-warning btn-sm')
                              .append('Stop')
                              .click(
                                  $.proxy(function(event) {
                                      self.stopAppRun();
                                  }, this)
                              )
                              .hide();
                            

            var $appInfo = this.appSpec.info.name;
            this.$methodPanel = $('<div>')
                                .addClass('kb-app-steps');
            var stepHeaderText = "Step ";
            this.inputSteps = [];
            this.inputStepLookup = {};
            var inputStep = {};
            for (var i=0; i<stepSpecs.length; i++) {
                var $stepPanel = this.renderStepDiv(this.appSpec.steps[i].step_id, stepSpecs[i], stepHeaderText + (i+1)+": ");
                this.$methodPanel.append($stepPanel);
                this.methodSpecs[stepSpecs[i].info.id] = stepSpecs[i];
            }

            var $buttons = $('<div>')
                           .addClass('buttons pull-right')
                           .append(this.$runButton)
                           .append(this.$stopButton);

            var $appSubtitleDiv = $("<div>")
                                        .addClass('kb-app-panel-description')
                                        .append(this.appSpec.info.subtitle);
            
            var headerCleaned = this.appSpec.info.header.replace(/&quot;/g, "")
            var $appHeaderDiv = $("<div>")
                                        .addClass('kb-app-panel-header')
                                        .append(headerCleaned);
            
            var $cellPanel = $('<div>')
                             .addClass('panel kb-app-panel kb-cell-run')
                             .append($('<div>')
                                     .addClass('panel-heading app-panel-heading')
                                     .append("<h1><b>"+$appInfo+"</b></h1>")
                                     .append($appSubtitleDiv))
                             .append($('<div>')
{'fraction_non_alphanumeric': 0.11923250056268288, 'fraction_numerical': 0.0014629754670267836, 'mean_word_length': 1.2316675037669513, 'pattern_counts': {'":': 2, '<': 85, '<?xml version=': 0, '>': 81, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 50, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5147746', 'n_tokens_mistral': 4422, 'n_tokens_neox': 4262, 'n_words': 919}