define([ 'require' , 'jquery' , 'nbextensions/visualpython/src/common/vpCommon' , 'nbextensions/visualpython/src/common/constant' , 'nbextensions/visualpython/src/common/StringBuilder' , 'nbextensions/visualpython/src/common/vpFuncJS' , 'nbextensions/visualpython/src/common/component/vpSuggestInputText' ], function (requirejs, $, vpCommon, vpConst, sb, vpFuncJS, vpSuggestInputText) { // ìµì ìì± const funcOptProp = { stepCount : 1 , funcName : "pip" , funcID : "com_pip" , funcArgs : [ ] } /** * html load ì½ë°±. ê³ ì id ìì±íì¬ ë¶ê³¼íë©° js ê°ì²´ í´ëì¤ ìì±íì¬ ì»¨í ì´ëë¡ ì ë¬ * @param {function} callback í¸ì¶ì(컨í ì´ë) ì ì½ë°±í¨ì * @param {JSON} meta ë©í ë°ì´í° */ var optionLoadCallback = function(callback, meta) { // document.getElementsByTagName("head")[0].appendChild(link); // 컨í ì´ëìì ì ë¬ë callback í¨ìê° ì¡´ì¬íë©´ ì¤í. if (typeof(callback) === 'function') { var uuid = vpCommon.getUUID(); // ìµë 10í ì¤ë³µëì§ ìëë¡ ì²´í¬ for (var idx = 0; idx < 10; idx++) { // ì´ë¯¸ ì¬ì©ì¤ì¸ uuid ì¸ ê²½ì° ë¤ì ìì± if ($(vpConst.VP_CONTAINER_ID).find("." + uuid).length > 0) { uuid = vpCommon.getUUID(); } } $(vpCommon.wrapSelector(vpCommon.formatString("#{0}", vpConst.OPTION_GREEN_ROOM))).find(vpCommon.formatString(".{0}", vpConst.API_OPTION_PAGE)).addClass(uuid); // ìµì ê°ì²´ ìì± var pipPackage = new PipPackage(uuid); pipPackage.metadata = meta; // ìµì ìì± í ë¹. pipPackage.setOptionProp(funcOptProp); // html ì¤ì . pipPackage.initHtml(); callback(pipPackage); // ê³µíµ ê°ì²´ë¥¼ callback ì¸ìë¡ ì ë¬ } } /** * html ë¡ë. * @param {function} callback í¸ì¶ì(컨í ì´ë) ì ì½ë°±í¨ì * @param {JSON} meta ë©í ë°ì´í° */ var initOption = function(callback, meta) { vpCommon.loadHtml(vpCommon.wrapSelector(vpCommon.formatString("#{0}", vpConst.OPTION_GREEN_ROOM)), "file_io/pip.html", optionLoadCallback, callback, meta); } /** * 본 ìµì ì²ë¦¬ ìí í´ëì¤ * @param {String} uuid ê³ ì id */ var PipPackage = function(uuid) { this.uuid = uuid; // Load html ììì uuid. this.package = { input: [ { name: 'vp_pipMeta' } ] }; // alert on changing --yes option with uninstall this.alertOnOption = true; this.loading = false; this.listupPkgDetails = { 'numpy': { 'description': 'Data Analysis', 'version': 'test' }, 'scipy': { 'description': 'Data Analysis', 'version': 'test' }, 'pandas': { 'description': 'Data Analysis', 'version': 'test' }, 'sympy': { 'description': 'Data Analysis', 'version': 'test' }, 'pgmpy': { 'description': 'Data Analysis', 'version': 'test' }, 'statsmodels': { 'description': 'Data Analysis', 'version': 'test' }, 'matplotlib': { 'description': 'Visualization', 'version': 'test' }, 'seaborn': { 'description': 'Visualization', 'version': 'test' }, 'scikit-learn': { 'description': 'Machine Learning', 'version': 'test' }, 'nltk': { 'description': 'Natural Language Processing', 'version': 'test' }, 'konlpy': { 'description': 'Korean Language Processing', 'version': 'test' }, 'soynlp': { 'description': 'Korean Language Processing', 'version': 'test' }, 'opencv-python': { 'description': 'Image Processing', 'version': 'test' }, 'geopandas': { 'description': 'Geographical Information', 'version': 'test' }, 'surprise': { 'description': 'Recommended', 'version': 'test' }, 'Keras': { 'description': 'Deep Learning', 'version': 'test' }, 'tensorflow': { 'description': 'Deep Learning', 'version': 'test' } } this.listupPkgList = Object.keys(this.listupPkgDetails); } /** * vpFuncJS ìì ìì */ PipPackage.prototype = Object.create(vpFuncJS.VpFuncJS.prototype); /** * ì í¨ì± ê²ì¬ * @returns ì í¨ì± ê²ì¬ ê²°ê³¼. ì í©ì true */ PipPackage.prototype.optionValidation = function() { return true; // ë¶ëª¨ í´ëì¤ ì í¨ì± ê²ì¬ í¸ì¶. // vpFuncJS.VpFuncJS.prototype.optionValidation.apply(this); } PipPackage.prototype.getMetadata = function(id) { if (this.metadata == undefined) return ""; var len = this.metadata.options.length; for (var i = 0; i < len; i++) { var obj = this.metadata.options[i]; if (obj.id == id) return obj.value; } return ""; } /** * html ë´ë¶ binding ì²ë¦¬ */ PipPackage.prototype.initHtml = function() { var that = this; // load css this.loadCss(Jupyter.notebook.base_url + vpConst.BASE_PATH + vpConst.STYLE_PATH + "file_io/pip.css"); this.loadInstallPage(); this.loadInstalledPage(); this.loadCmdLinePage(); this.loadPackagePages(); this.showPage('install'); // E1. event for page selection $(this.wrapSelector('#vp_pipSelectPage')).change(function() { var value = $(this).val(); that.showPage(value); }); // E2. click packages $(document).on('click', this.wrapSelector('.vp-pip-package-table tr:not(:first)'), function() { $(that.wrapSelector('.vp-pip-package-table tr')).removeClass('selected'); $(this).addClass('selected'); }); // E3. install package $(document).on('click', this.wrapSelector('#vp_pipInstall'), function() { if (that.loading == true) { return; } var pkgName = $(that.wrapSelector('#vp_pipInstallPage .vp-pip-package-table tr.selected td:nth(0)')).text(); if (pkgName == undefined) { vpCommon.renderAlertModal('Nothing selected.'); return; } // check installing that.showLoadingBox('Installing ' + pkgName + '...'); var code = new sb.StringBuilder(); code.appendFormat('!pip install {0} -q', pkgName); that.kernelExecute(code.toString(), function(result) { that.hideLoadingBox(); if (result != undefined && result.includes('ERROR')) { that.openMultiBtnModal(result, ["Ok"], function(clickIndex) { }); } else { vpCommon.renderSuccessMessage(pkgName + ' installed!'); that.loadPackagePages(); } }); }); // E4. upgrade package $(document).on('click', this.wrapSelector('#vp_pipUpgrade'), function() { if (that.loading == true) { return; } var pkgName = $(that.wrapSelector('#vp_pipInstalledPage .vp-pip-package-table tr.selected td:nth(0)')).text(); if (pkgName == undefined) { vpCommon.renderAlertModal('Nothing selected.'); return; } // check upgrading that.showLoadingBox('Upgrading ' + pkgName + '...'); var code = new sb.StringBuilder(); code.appendFormat('!pip install {0} --upgrade', pkgName); that.kernelExecute(code.toString(), function(result) { that.hideLoadingBox(); if (result != undefined && result.includes('ERROR')) { that.openMultiBtnModal(result, ["Ok"], function(clickIndex) { }); } else { vpCommon.renderSuccessMessage(pkgName + ' upgraded!'); that.loadPackagePages(); } }); }); // E5. uninstall package $(document).on('click', this.wrapSelector('#vp_pipUninstall'), function() { if (that.loading == true) { return; } var pkgName = $(that.wrapSelector('#vp_pipInstalledPage .vp-pip-package-table tr.selected td:nth(0)')).text(); if (pkgName == undefined) { vpCommon.renderAlertModal('Nothing selected.'); return; } that.openMultiBtnModal("Are you sure you want to uninstall " + pkgName + "?", ["Yes", "No"], function(clickIndex) { // if yes if (clickIndex == 0) { // check uninstall that.showLoadingBox('Uninstalling ' + pkgName + '...'); var code = new sb.StringBuilder(); code.appendFormat('!pip uninstall {0} --yes', pkgName); that.kernelExecute(code.toString(), function(result) { that.hideLoadingBox(); if (result != undefined && result.includes('ERROR')) { // show error logs that.openMultiBtnModal(result, ["Ok"], function(clickIndex) { }); } else { vpCommon.renderSuccessMessage(pkgName + ' uninstalled!'); that.loadPackagePages(); } }); } }); }); } /** * load package pages (Install/Installed Packages) */ PipPackage.prototype.loadPackagePages = function() { var that = this; this.showLoadingBox(); // search packages this.getPackageList(function(pkgList) { // [ {name: _, version: _, 'latest_version': _, 'latest_filetype': _ }] // installed package list [['name', 'version', 'latest', 'type']] var installedPackages = pkgList.filter(o => that.listupPkgList.includes(o.name)); // install package list ['key', ... ] var installedPackageList = installedPackages.map(o => o.name); var installPackages = that.listupPkgList.filter(o => !installedPackageList.includes(o)); // install page setting that.renderPkgSearchBox('vp_pipInstallSearch', installPackages); that.renderInstallPkgTbl(installPackages); // installed page setting that.renderPkgSearchBox('vp_pipInstalledSearch', installedPackageList); that.renderInstalledPkgTbl(installedPackages); // load finished that.hideLoadingBox(); var selectedPage = $(that.wrapSelector('#vp_pipSelectPage')).val(); that.showPage(selectedPage); }); } /** * Get package list on kernel * @param {function} callback run after result loaded */ PipPackage.prototype.getPackageList = function(callback) { var that = this; // í¨í¤ì§ ì¡°í ì½ë var code = new sb.StringBuilder(); code.append(`!pip list -o --format json`); this.kernelExecute(code.toString(), function(result) { // outdated packages var pkgList1 = JSON.parse(result); var code2 = new sb.StringBuilder(); code2.append(`!pip list -u --format json`); that.kernelExecute(code2.toString(), function(result2) { // up to date packages var pkgList2 = JSON.parse(result2); var pkgList = [... pkgList1, ...pkgList2]; // load callback callback(pkgList); }); }); } PipPackage.prototype.showLoadingBox = function(msg = '') { this.loading = true; $(this.wrapSelector('#vp_pipInstallPage .vp-pip-package-table tr:not(:first)')).hide(); $(this.wrapSelector('#vp_pipInstalledPage .vp-pip-package-table tr:not(:first)')).hide(); $(this.wrapSelector('.vp-pip-loading-box')).text(msg == ''? 'Collecting packages...': msg); $(this.wrapSelector('.vp-pip-loading-box')).show(); } PipPackage.prototype.hideLoadingBox = function() { this.loading = false; $(this.wrapSelector('#vp_pipInstallPage .vp-pip-package-table tr')).show(); $(this.wrapSelector('#vp_pipInstalledPage .vp-pip-package-table tr')).show(); $(this.wrapSelector('.vp-pip-loading-box')).hide(); } /** * show selected page * @param {String} pageType pageType : 'install', 'installed', 'command' * if pageType == '', hide all */ PipPackage.prototype.showPage = function(pageType = '') { // hide all $(this.wrapSelector('.vp-pip-inner-box')).hide(); switch(pageType) { case 'install': $(this.wrapSelector('#vp_pipInstallPage')).show(); break; case 'installed': $(this.wrapSelector('#vp_pipInstalledPage')).show(); break; case 'command': $(this.wrapSelector('#vp_pipCommandPage')).show(); break; default: break; } } PipPackage.prototype.renderPkgSearchBox = function(id, suggestList) { var that = this; // search box var suggestInput = new vpSuggestInputText.vpSuggestInputText(); suggestInput.setComponentID(id); suggestInput.setPlaceholder("Search packages"); suggestInput.addClass('vp-pip-search'); suggestInput.setSuggestList(function() { return suggestList; }); suggestInput.setSelectEvent(function(selectedValue) { $(that.wrapSelector('#' + id)).parent().find('.vp-pip-package-table tr:not(:first)').each(function(idx, tag) { var name = $(tag).find('td:first').text(); if (selectedValue == name) { $(that.wrapSelector('#' + id)).parent().find('.vp-pip-package-table tr:not(:first)').removeClass('selected'); $(tag).addClass('selected'); return; } }); }); $(this.wrapSelector('#' + id)).replaceWith(function() { return suggestInput.toTagString(); }); } /** * render install package table * @param {Array} installPackages install packages ['key', ... ] */ PipPackage.prototype.renderInstallPkgTbl = function(installPackages) { // package table var tblLayoutRequire = this.createHORIZSimpleLayout(); tblLayoutRequire.addClass('vp-pip-package-table'); tblLayoutRequire.setMergeCellClass(vpConst.TABLE_LAYOUT_CELL_CENTER_ALIGN); // tblLayoutRequire.setColWidth(["30%", "30%", "30%"]); // tblLayoutRequire.setHeader(["Package", "Description", "Lastest Version"]); tblLayoutRequire.setColWidth(["30%", "*"]); tblLayoutRequire.setHeader(["Package", "Description"]); // package add installPackages.sort(function(a, b) { var name1 = a.toUpperCase(); // ignore case var name2 = b.toUpperCase(); // ignore case if (name1 < name2) { return -1; } if (name1 > name2) { return 1; } // equal return 0; }); installPackages.forEach(key => { var obj = this.listupPkgDetails[key]; // tblLayoutRequire.addRow([key, obj.description, obj.version]); tblLayoutRequire.addRow([key, obj.description]); }); $(this.wrapSelector('#vp_pipInstallPage .vp-pip-package-box')).html(tblLayoutRequire.toTagString()); } /** * render installed package table * @param {Array} installedPackages installed package list [['name', 'version', 'latest', 'type']] */ PipPackage.prototype.renderInstalledPkgTbl = function(installedPackages) { // package table var tblLayoutRequire = this.createHORIZSimpleLayout(); tblLayoutRequire.addClass('vp-pip-package-table'); tblLayoutRequire.setMergeCellClass(vpConst.TABLE_LAYOUT_CELL_CENTER_ALIGN); tblLayoutRequire.setColWidth(["30%", "30%", "30%"]); tblLayoutRequire.setHeader(["Package", "Current Version", "Lastest Version"]); // package add installedPackages.sort(function(a, b) { var name1 = a.name.toUpperCase(); // ignore case var name2 = b.name.toUpperCase(); // ignore case if (name1 < name2) { return -1; } if (name1 > name2) { return 1; } // equal return 0; }); installedPackages.forEach(obj => { tblLayoutRequire.addRow([obj.name, obj.version, (obj.latest_version == undefined? 'up to date': obj.latest_version)]); }); $(this.wrapSelector('#vp_pipInstalledPage .vp-pip-package-box')).html(tblLayoutRequire.toTagString()); } /** * load install package page */ PipPackage.prototype.loadInstallPage = function() { var sbPageContent = new sb.StringBuilder(); var sbTagString = new sb.StringBuilder(); // search box var suggestInput = new vpSuggestInputText.vpSuggestInputText(); suggestInput.setComponentID('vp_pipInstallSearch'); suggestInput.setPlaceholder("Search packages"); suggestInput.addClass('vp-pip-search'); sbPageContent.appendLine(suggestInput.toTagString()); sbPageContent.appendFormatLine('