<commit_before>/*global define,IPython*/
/*jslint white: true*/
/**
* @author <NAME> <<EMAIL>>
* @public
*/
define(['jquery',
        'underscore',
        'narrativeConfig',
        'Util/String',
        'Util/Display',
        'kbase-client-api',
        'jquery-nearest',
        'kbwidget',
        'kbaseAuthenticatedWidget',
        'kbaseNarrativeDownloadPanel'],
function ($, _, Config, StringUtil, DisplayUtil) {
    'use strict';
    $.KBWidget({
        name: 'kbaseNarrativeDataList',
        parent: 'kbaseAuthenticatedWidget',
        version: '1.0.0',
        options: {
            ws_name: null, // must be the WS name, not the WS Numeric ID

            ws_url: Config.url('workspace'),
            landing_page_url: "/functional-site/#/", // !! always include trailing slash
            lp_url: Config.url('landing_pages'),
            profile_page_url: Config.url('profile_page'),

            user_name_fetch_url: "https://kbase.us/services/genome_comparison/users?usernames=",
            loadingImage: Config.get('loading_gif'),
            methodStoreURL: Config.url('narrative_method_store'), 

            ws_chunk_size: 10000, // this is the limit of the number of objects to retrieve from the ws on each pass
            ws_max_objs_to_fetch: 75000, // this is the total limit of the number of objects before we stop trying to get more
            // note that if there are more objects than this, then sorts/search filters may
            // not show accurate results

            objs_to_render_to_start: 40, // initial number of rows to display
            objs_to_render_on_scroll: 5, // number of rows to add when the user scrolls to the bottom, should be <=5, much more and
            // the addition of new rows becomes jerky

            max_objs_to_prevent_filter_as_you_type_in_search: 50000, //if there are more than this # of objs, user must click search
            //instead of updating as you type

            max_objs_to_prevent_initial_sort: 10000, // initial sort makes loading slower, so we can turn it off if
            // there are more than this number of objects

            max_name_length: 33,
            refresh_interval: 30000,
            parentControlPanel: null
        },
        // private variables
        mainListPanelHeight: '340px',
        refreshTimer: null,
        ws_name: null,
        ws: null,
        ws_last_update_timestamp: null,
        ws_obj_count: null,
        n_objs_rendered: 0,
        real_name_lookup: {},
        $searchInput: null,
        $filterTypeSelect: null,
        availableTypes: {},
        $searchDiv: null,
        $sortByDiv: null,
        $filterTypeDiv: null,
        $addDataButton: null,
        $controllerDiv: null,
        $mainListDiv: null,
        mainListId: null,
        $loadingDiv: null,
        methClient: null,
        obj_list: [],
        obj_data: {}, // old style - type_name : info

        my_user_id: null,
        /**
         * @method init
         * Builds the DOM structure for the widget.
         * Includes the tables and panel.
         * If any data was passed in (options.data), that gets shoved into the datatable.
         * @param {Object} - the options set.
         * @returns {Object} this shiny new widget.
         * @private
         */
        init: function (options) {
            this._super(options);
            var self = this;

            this.$controllerDiv = $('<div>');
            this.$elem.append(this.$controllerDiv);
            this.renderController();
            this.$loadingDiv = $('<div>').addClass('kb-data-loading')
                .append('<img src="' + this.options.loadingImage + '">')
                .hide();
            this.$elem.append(this.$loadingDiv);
            this.mainListId = StringUtil.uuid();
            this.$mainListDiv = $('<div id=' + this.mainListId + '>')
                .css({'overflow-x': 'hidden', 'overflow-y': 'auto', 'height': this.mainListPanelHeight})
                .on('scroll', function () {
                    if ($(this).scrollTop() + $(this).innerHeight() >= this.scrollHeight) {
                        self.renderMore();
                    }
                });

            this.$addDataButton = $('<span>').addClass('kb-data-list-add-data-button fa fa-plus fa-2x')
                .css({'position': 'absolute', bottom: '15px', right: '25px', 'z-index': '5'})
                .click(function () {
                    self.trigger('hideGalleryPanelOverlay.Narrative');
                    self.trigger('toggleSidePanelOverlay.Narrative', self.options.parentControlPanel.$overlayPanel);
                });
            var $mainListDivContainer = $('<div>').css({'position': 'relative'})
                .append(this.$mainListDiv)
                .append(this.$addDataButton.hide());
            this.$elem.append($mainListDivContainer);

            if (this._attributes.auth) {
                this.ws = new Workspace(this.options.ws_url, this._attributes.auth);
            }

            // listener for refresh
            $(document).on('updateDataList.Narrative', function () {
                self.refresh();
            })

            this.showLoading();
            if (this.options.ws_name) {
                this.ws_name = this.options.ws_name;
                // this.setWorkspace(this.options.ws_name);
            }

            this.methClient = new NarrativeMethodStore(this.options.methodStoreURL);

            return this;
        },
        setWorkspace: function (ws_name) {
            this.ws_name = ws_name;
            // this.ws_name = "janakacore"; // for testing a bigish workspace
            //this.ws_name = "KBasePublicGenomesV4"; // for testing a very big workspace
            this.refresh();
        },
        refresh: function (showError) {
            var self = this;

            // Set the refresh timer on the first refresh. From  here, it'll refresh itself
            // every this.options.refresh_interval (30000) ms
            if (self.refreshTimer === null) {
                self.refreshTimer = setInterval(function () {
                    self.refresh();
                }, this.options.refresh_interval); // check if there is new data every X ms
            }
            if (self.ws_name && self.ws) {
                self.ws.get_workspace_info({
                    workspace: this.ws_name
                },
                    function (workspace_info) {
                        //[0] ws_id id, [1] ws_name workspace, [2] username owner, [3] timestamp moddate,
                        //[4] int object, [5] permission user_permission, [6] permission globalread,
                        //[7] lock_status lockstat, [8] usermeta metadata
                        //console.log('I have: '+self.ws_last_update_timestamp+ " remote has: "+workspace_info[3]);

                        // Update RO or RW mode
                        self.trigger("updateReadOnlyMode.Narrative",
                            [self.ws, self.ws_name]);

                        if (self.ws_last_update_timestamp) {
                            if (self.ws_last_update_timestamp !== workspace_info[3]) {
                                self.ws_last_update_timestamp = workspace_info[3];
                                self.ws_obj_count = workspace_info[4];
                                self.reloadWsData();
                            } else {
                                //console.log('updating times');
                                self.refreshTimeStrings();
                            }
                        } else {
                            self.ws_last_update_timestamp = workspace_info[3];
                            self.ws_obj_count = workspace_info[4];
                            self.reloadWsData();
                        }
                    },
                    function (error) {
                        console.error('DataList: when checking for updates:', error);
                        if (showError) {
                            self.$mainListDiv.show();
                            self.$mainListDiv.empty();
                            self.$mainListDiv.append($('<div>').css({'color': '#F44336', 'margin': '10px'})
                                .append('Error: Unable to connect to KBase data.'));
                            self.hideLoading();
                        }
                    });
            } else {
                /*Not really an error yet because we don't know what order things are being called
                 var where = "kbaseNarrativeDataList.refresh";
                 if (!self.ws) {
                 console.error(where, "Workspace not connected");
                 }
                 else {
                 console.error(where, "Workspace name is empty");
                 }*/
            }
        },
        refreshSpecificObject: function () {

        },
        refreshTimeStrings: function () {
            var self = this;
            var newTime;
            var oldTime;
            if (self.objectList) {
                for (var i = 0; i < self.objectList.length; i++) {
                    if (self.objectList[i].$div) {
                        newTime = self.getTimeStampStr(self.objectList[i].info[3]);
                        oldTime = self.objectList[i].$div.find('.kb-data-list-date').text();
                        if (newTime !== oldTime) {
                            self.objectList[i].$div.find('.kb-data-list-date').text(newTime);
                        }
                    }
                }
            }
        },<commit_msg>Added some more explicit errors in data list.<commit_after>/*global define,IPython*/
/*jslint white: true*/
/**
* @author <NAME> <<EMAIL>>
* @public
*/
define(['jquery',
        'underscore',
        'narrativeConfig',
        'Util/String',
        'Util/Display',
        'kbase-client-api',
        'jquery-nearest',
        'kbwidget',
        'kbaseAuthenticatedWidget',
        'kbaseNarrativeDownloadPanel'],
function ($, _, Config, StringUtil, DisplayUtil) {
    'use strict';
    $.KBWidget({
        name: 'kbaseNarrativeDataList',
        parent: 'kbaseAuthenticatedWidget',
        version: '1.0.0',
        options: {
            ws_name: null, // must be the WS name, not the WS Numeric ID

            ws_url: Config.url('workspace'),
            landing_page_url: "/functional-site/#/", // !! always include trailing slash
            lp_url: Config.url('landing_pages'),
            profile_page_url: Config.url('profile_page'),

            user_name_fetch_url: "https://kbase.us/services/genome_comparison/users?usernames=",
            loadingImage: Config.get('loading_gif'),
            methodStoreURL: Config.url('narrative_method_store'), 

            ws_chunk_size: 10000, // this is the limit of the number of objects to retrieve from the ws on each pass
            ws_max_objs_to_fetch: 75000, // this is the total limit of the number of objects before we stop trying to get more
            // note that if there are more objects than this, then sorts/search filters may
            // not show accurate results

            objs_to_render_to_start: 40, // initial number of rows to display
            objs_to_render_on_scroll: 5, // number of rows to add when the user scrolls to the bottom, should be <=5, much more and
            // the addition of new rows becomes jerky

            max_objs_to_prevent_filter_as_you_type_in_search: 50000, //if there are more than this # of objs, user must click search
            //instead of updating as you type

            max_objs_to_prevent_initial_sort: 10000, // initial sort makes loading slower, so we can turn it off if
            // there are more than this number of objects

            max_name_length: 33,
            refresh_interval: 30000,
            parentControlPanel: null
        },
        // private variables
        mainListPanelHeight: '340px',
        refreshTimer: null,
        ws_name: null,
        ws: null,
        ws_last_update_timestamp: null,
        ws_obj_count: null,
        n_objs_rendered: 0,
        real_name_lookup: {},
        $searchInput: null,
        $filterTypeSelect: null,
        availableTypes: {},
        $searchDiv: null,
        $sortByDiv: null,
        $filterTypeDiv: null,
        $addDataButton: null,
        $controllerDiv: null,
        $mainListDiv: null,
        mainListId: null,
        $loadingDiv: null,
        methClient: null,
        obj_list: [],
        obj_data: {}, // old style - type_name : info

        my_user_id: null,
        /**
         * @method init
         * Builds the DOM structure for the widget.
         * Includes the tables and panel.
         * If any data was passed in (options.data), that gets shoved into the datatable.
         * @param {Object} - the options set.
         * @returns {Object} this shiny new widget.
         * @private
         */
        init: function (options) {
            this._super(options);
            var self = this;

            this.$controllerDiv = $('<div>');
            this.$elem.append(this.$controllerDiv);
            this.renderController();
            this.$loadingDiv = $('<div>').addClass('kb-data-loading')
                .append('<img src="' + this.options.loadingImage + '">')
                .hide();
            this.$elem.append(this.$loadingDiv);
            this.mainListId = StringUtil.uuid();
            this.$mainListDiv = $('<div id=' + this.mainListId + '>')
                .css({'overflow-x': 'hidden', 'overflow-y': 'auto', 'height': this.mainListPanelHeight})
                .on('scroll', function () {
                    if ($(this).scrollTop() + $(this).innerHeight() >= this.scrollHeight) {
                        self.renderMore();
                    }
                });

            this.$addDataButton = $('<span>').addClass('kb-data-list-add-data-button fa fa-plus fa-2x')
                .css({'position': 'absolute', bottom: '15px', right: '25px', 'z-index': '5'})
                .click(function () {
                    self.trigger('hideGalleryPanelOverlay.Narrative');
                    self.trigger('toggleSidePanelOverlay.Narrative', self.options.parentControlPanel.$overlayPanel);
                });
            var $mainListDivContainer = $('<div>').css({'position': 'relative'})
                .append(this.$mainListDiv)
                .append(this.$addDataButton.hide());
            this.$elem.append($mainListDivContainer);

            if (this._attributes.auth) {
                this.ws = new Workspace(this.options.ws_url, this._attributes.auth);
            }

            // listener for refresh
            $(document).on('updateDataList.Narrative', function () {
                self.refresh();
            })

            this.showLoading();
            if (this.options.ws_name) {
                this.ws_name = this.options.ws_name;
                // this.setWorkspace(this.options.ws_name);
            }

            this.methClient = new NarrativeMethodStore(this.options.methodStoreURL);

            return this;
        },
        setWorkspace: function (ws_name) {
            this.ws_name = ws_name;
            // this.ws_name = "janakacore"; // for testing a bigish workspace
            //this.ws_name = "KBasePublicGenomesV4"; // for testing a very big workspace
            this.refresh();
        },
        refresh: function (showError) {
            var self = this;

            // Set the refresh timer on the first refresh. From  here, it'll refresh itself
            // every this.options.refresh_interval (30000) ms
            if (self.refreshTimer === null) {
                self.refreshTimer = setInterval(function () {
                    self.refresh();
                }, this.options.refresh_interval); // check if there is new data every X ms
            }
            if (self.ws_name && self.ws) {
                self.ws.get_workspace_info({
                    workspace: this.ws_name
                },
                    function (workspace_info) {
                        //[0] ws_id id, [1] ws_name workspace, [2] username owner, [3] timestamp moddate,
                        //[4] int object, [5] permission user_permission, [6] permission globalread,
                        //[7] lock_status lockstat, [8] usermeta metadata
                        //console.log('I have: '+self.ws_last_update_timestamp+ " remote has: "+workspace_info[3]);

                        // Update RO or RW mode
                        self.trigger("updateReadOnlyMode.Narrative",
                            [self.ws, self.ws_name]);

                        if (self.ws_last_update_timestamp) {
                            if (self.ws_last_update_timestamp !== workspace_info[3]) {
                                self.ws_last_update_timestamp = workspace_info[3];
                                self.ws_obj_count = workspace_info[4];
                                self.reloadWsData();
                            } else {
                                //console.log('updating times');
                                self.refreshTimeStrings();
                            }
                        } else {
                            self.ws_last_update_timestamp = workspace_info[3];
                            self.ws_obj_count = workspace_info[4];
                            self.reloadWsData();
                        }
                    },
                    function (error) {
                        console.error('DataList: when checking for updates:', error);
                        if (showError) {
                            self.$mainListDiv.show();
                            self.$mainListDiv.empty();
                            self.$mainListDiv.append($('<div>').css({'color': '#F44336', 'margin': '10px'})
                                .append('Error: Unable to connect to KBase data.'));
                        }
                        self.hideLoading();
                    });
            } else {
                console.error('DataList: missing variable(s)');
                console.error('ws_name: ' + self.ws_name);
                console.error('ws: ' + self.ws);
                self.hideLoading();
                /*Not really an error yet because we don't know what order things are being called
                 var where = "kbaseNarrativeDataList.refresh";
                 if (!self.ws) {
                 console.error(where, "Workspace not connected");
                 }
                 else {
                 console.error(where, "Workspace name is empty");
                 }*/
            }
        },
        refreshSpecificObject: function () {

        },
        refreshTimeStrings: function () {
            var self = this;
            var newTime;
            var oldTime;
            if (self.objectList) {
                for (var i = 0; i < self.objectList.length; i++) {
                    if (self.objectList[i].$div) {
                        newTime = self.getTimeStampStr(self.objectList[i].info[3]);
                        oldTime = self.objectList[i].$div.find('.kb-data-list-date').text();
                        if (newTime !== oldTime) {
                            self.objectList[i].$div.find('.kb-data-list-date').text(newTime);
                        }
                    }
                }
            }
        },
{'fraction_non_alphanumeric': 0.11282843894899536, 'fraction_numerical': 0.0076249356002060795, 'mean_word_length': 1.4965916398713826, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 25, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5015418', 'n_tokens_mistral': 5224, 'n_tokens_neox': 4940, 'n_words': 1187}