diff --git a/_build/data/transport.core.system_settings.php b/_build/data/transport.core.system_settings.php index 47ffc186c76..2cb4c9225f4 100644 --- a/_build/data/transport.core.system_settings.php +++ b/_build/data/transport.core.system_settings.php @@ -425,6 +425,15 @@ 'area' => 'manager', 'editedon' => null, ], '', true, true); +$settings['default_provider'] = $xpdo->newObject(modSystemSetting::class); +$settings['default_provider']->fromArray([ + 'key' => 'default_provider', + 'value' => 1, + 'xtype' => 'modx-combo-provider', + 'namespace' => 'core', + 'area' => 'manager', + 'editedon' => null, +], '', true, true); $settings['default_media_source_type'] = $xpdo->newObject(modSystemSetting::class); $settings['default_media_source_type']->fromArray([ 'key' => 'default_media_source_type', diff --git a/core/lexicon/en/setting.inc.php b/core/lexicon/en/setting.inc.php index b98e375f93d..c4941004aae 100644 --- a/core/lexicon/en/setting.inc.php +++ b/core/lexicon/en/setting.inc.php @@ -240,6 +240,9 @@ $_lang['setting_default_media_source_type'] = 'Default Media Source Type'; $_lang['setting_default_media_source_type_desc'] = 'The default selected Media Source Type when creating a new Media Source.'; +$_lang['setting_default_provider'] = 'Default Package Provider'; +$_lang['setting_default_provider_desc'] = 'The default Provider selected in Package Management when downloading extras.'; + $_lang['setting_photo_profile_source'] = 'User Profile Photo Source'; $_lang['setting_photo_profile_source_desc'] = 'Specifies the Media Source to use for storing and retrieving profile photos/avatars. If not specified, the default Media Source will be used.'; diff --git a/core/lexicon/en/workspace.inc.php b/core/lexicon/en/workspace.inc.php index 96a314c9489..aa91a8dea5a 100644 --- a/core/lexicon/en/workspace.inc.php +++ b/core/lexicon/en/workspace.inc.php @@ -185,13 +185,14 @@ $_lang['provider_err_ns_url'] = 'Please provide a valid URL for the Provider.'; $_lang['provider_err_remove'] = 'An error occurred while trying to delete the Provider.'; $_lang['provider_err_save'] = 'An error occurred while trying to save the Provider.'; -$_lang['provider_home_msg'] = 'Choose a Category from the left to begin browsing this Provider.'; +$_lang['provider_home_msg'] = 'Choose a Category from the left to begin browsing [[+name]].'; $_lang['provider_home_title'] = 'Download Extras'; $_lang['provider_select'] = 'Select a Provider'; $_lang['provider_select_desc'] = 'Please select the provider from which you will retrieve packages.'; $_lang['provider_total_downloads'] = 'Total Downloads for this Provider'; $_lang['provider_total_packages'] = 'Total Packages in this Provider'; $_lang['provider_url'] = 'Service URL'; +$_lang['provider_with_name'] = 'Provider: [[+name]]'; $_lang['providers'] = 'Providers'; $_lang['providers_desc'] = 'Providers are repositories for MODX component packages. They are remote URLs that contain lists of MODX packages that you can download and install components from.'; $_lang['provisioner'] = 'Provisioner'; diff --git a/core/src/Revolution/Processors/Workspace/Providers/SetDefault.php b/core/src/Revolution/Processors/Workspace/Providers/SetDefault.php new file mode 100644 index 00000000000..d7c8eebad6d --- /dev/null +++ b/core/src/Revolution/Processors/Workspace/Providers/SetDefault.php @@ -0,0 +1,78 @@ +getProperty('id'); + if ($id < 1) { + return $this->failure($this->modx->lexicon('provider_err_ns')); + } + + /** @var modTransportProvider|null $provider */ + $provider = $this->modx->getObject(modTransportProvider::class, $id); + if (!$provider) { + return $this->failure($this->modx->lexicon('provider_err_nfs', ['id' => $id])); + } + + /** @var modSystemSetting|null $setting */ + $setting = $this->modx->getObject(modSystemSetting::class, ['key' => 'default_provider']); + if (!$setting) { + $setting = $this->modx->newObject(modSystemSetting::class); + $setting->fromArray([ + 'key' => 'default_provider', + 'xtype' => 'modx-combo-provider', + 'namespace' => 'core', + 'area' => 'manager', + ], '', true); + } + + $setting->set('value', (string)$id); + if ($setting->save() === false) { + return $this->failure($this->modx->lexicon('setting_err_save')); + } + + $this->modx->setOption('default_provider', (string)$id); + $this->modx->reloadConfig(); + + return $this->success('', [ + 'id' => (int)$provider->get('id'), + 'name' => $provider->get('name'), + ]); + } +} diff --git a/manager/assets/modext/workspace/combos.js b/manager/assets/modext/workspace/combos.js index f43d8f2f6eb..9302b607406 100644 --- a/manager/assets/modext/workspace/combos.js +++ b/manager/assets/modext/workspace/combos.js @@ -1,6 +1,6 @@ /** * Displays a dropdown list of modTransportProviders - * + * * @class MODx.combo.Provider * @extends MODx.combo.ComboBox * @param {Object} config An object of options. @@ -23,3 +23,90 @@ MODx.combo.Provider = function(config) { }; Ext.extend(MODx.combo.Provider,MODx.combo.ComboBox); Ext.reg('modx-combo-provider',MODx.combo.Provider); + +/** + * Format a lexicon string that uses [[+name]] for the active provider. + * + * @param {String} key + * @param {String} name + * @returns {String} + */ +MODx.formatProviderLexicon = (key, name) => _(key).split('[[+name]]').join(name || ''); + +/** + * Refresh chrome that displays the active provider name. + */ +MODx.updateProviderUI = () => { + const btn = Ext.getCmp('modx-package-provider-btn'); + if (btn) { + btn.setText(MODx.formatProviderLexicon('provider_with_name', MODx.providerName)); + } +}; + +/** + * Set the active package provider. When persisting, writes default_provider first, + * then updates in-memory state and UI so a failed save leaves the previous provider. + * + * @param {String|Number} id + * @param {String} name + * @param {Object} options + * @param {Boolean} [options.persist=true] + * @param {Function} [options.callback] + * @param {Object} [options.scope] + */ +MODx.setActiveProvider = (id, name, options = {}) => { + const providerId = String(id); + const providerName = name || ''; + const scope = options.scope || window; + + const applyLocal = () => { + MODx.provider = providerId; + MODx.providerName = providerName; + MODx.defaultProvider = providerId; + if (MODx.config) { + MODx.config.default_provider = providerId; + } + + const tree = Ext.getCmp('modx-package-browser-tree'); + if (tree && tree.setProvider) { + tree.setProvider(providerId); + } + + MODx.updateProviderUI(); + }; + + const finish = () => { + if (typeof options.callback === 'function') { + options.callback.call(scope); + } + }; + + if (options.persist === false) { + applyLocal(); + finish(); + return; + } + + MODx.Ajax.request({ + url: MODx.config.connector_url + ,params: { + action: 'Workspace/Providers/SetDefault' + ,id: providerId + } + ,listeners: { + success: { + fn: () => { + applyLocal(); + finish(); + } + ,scope: scope + } + ,failure: { + fn: (r) => { + MODx.msg.alert(_('error'), (r && r.message) ? r.message : _('provider_err_save')); + } + ,scope: scope + } + } + }); +}; diff --git a/manager/assets/modext/workspace/package.browser.panels.js b/manager/assets/modext/workspace/package.browser.panels.js index a9476386e77..87200d535de 100644 --- a/manager/assets/modext/workspace/package.browser.panels.js +++ b/manager/assets/modext/workspace/package.browser.panels.js @@ -634,7 +634,7 @@ Ext.extend(MODx.PackageBrowserThumbsView,MODx.DataView,{ ,params: { action: 'Workspace/Packages/Rest/Download' ,info: data.location+'::'+data.signature - ,provider: MODx.provider || MODx.config.default_provider + ,provider: MODx.provider } ,scope: this ,listeners: { @@ -816,7 +816,7 @@ Ext.extend(MODx.panel.PackageBrowserView,MODx.Panel,{ ,params: { action: 'Workspace/Packages/Rest/Download' ,info: record.location+'::'+record.signature - ,provider: MODx.provider || MODx.config.default_provider + ,provider: MODx.provider } ,scope: this ,listeners: { diff --git a/manager/assets/modext/workspace/package.browser.tree.js b/manager/assets/modext/workspace/package.browser.tree.js index 77c5e7e2d39..2c18fe5a522 100644 --- a/manager/assets/modext/workspace/package.browser.tree.js +++ b/manager/assets/modext/workspace/package.browser.tree.js @@ -67,9 +67,6 @@ Ext.extend(MODx.tree.PackageBrowserTree,MODx.tree.Tree,{ } } - ,changeGProvider: false - ,changePProvider: false - ,getProviderInfos: function(pv){ MODx.Ajax.request({ url: this.config.url @@ -91,8 +88,15 @@ Ext.extend(MODx.tree.PackageBrowserTree,MODx.tree.Tree,{ if (Ext.isEmpty(pv) || pv == undefined) { pv = MODx.defaultProvider; } this.getLoader().baseParams.provider = pv; this.getProviderInfos(pv); - this.changeGProvider = true; - this.changePProvider = true; + + const grid = Ext.getCmp('modx-package-browser-grid'); + if (grid && grid.getStore) { + grid.getStore().setBaseParam('provider', pv); + } + const thumbs = Ext.getCmp('modx-package-browser-thumbs-view'); + if (thumbs && thumbs.store) { + thumbs.store.baseParams.provider = pv; + } } ,onNodeClick: function(n,e) { @@ -107,21 +111,14 @@ Ext.extend(MODx.tree.PackageBrowserTree,MODx.tree.Tree,{ if (tp && tp.attributes.data.templated == 1) { var p = Ext.getCmp('modx-package-browser-thumbs-view'); p.store.baseParams.tag = n.attributes.data.id; - if(this.changePProvider){ - p.store.baseParams.provider = MODx.provider; - this.changePProvider = false; - } + p.store.baseParams.provider = MODx.provider; p.run(); Ext.getCmp('modx-package-browser-view').activate(n.attributes.data.name); } else { var grid = Ext.getCmp('modx-package-browser-grid'); grid.getStore().setBaseParam('tag', n.attributes.data.id); grid.getStore().setBaseParam('query', ''); - if(this.changeGProvider){ - grid.getStore().setBaseParam('provider', MODx.provider); - grid.getStore().removeAll(); - this.changeGProvider = false; - } + grid.getStore().setBaseParam('provider', MODx.provider); grid.getStore().load(); grid.activate(n.attributes.data.name); } diff --git a/manager/assets/modext/workspace/package.containers.js b/manager/assets/modext/workspace/package.containers.js index 12aab289468..666147028bb 100644 --- a/manager/assets/modext/workspace/package.containers.js +++ b/manager/assets/modext/workspace/package.containers.js @@ -222,14 +222,17 @@ Ext.extend(MODx.panel.PackagesBrowser,MODx.Panel,{ Ext.getCmp('modx-layout').hideLeftbar(true, false); Ext.getCmp('card-container').getLayout().setActiveItem(this.id); Ext.getCmp('modx-package-browser-home').activate(); - this.updateBreadcrumbs(_('provider_home_msg')); + this.updateBreadcrumbs(MODx.formatProviderLexicon('provider_home_msg', MODx.providerName)); } ,updateBreadcrumbs: function(msg, highlight){ - var bd = { text: msg }; + const bd = { text: msg }; if(highlight){ bd.className = 'highlight'; } - bd.trail = [{ text : _('package_browser') }]; + bd.trail = [ + { text : _('package_browser') } + ,{ text : MODx.providerName || _('provider') } + ]; Ext.getCmp('packages-breadcrumbs').updateDetail(bd); } diff --git a/manager/assets/modext/workspace/package.grid.js b/manager/assets/modext/workspace/package.grid.js index ea37f629cd3..fc56377ae22 100644 --- a/manager/assets/modext/workspace/package.grid.js +++ b/manager/assets/modext/workspace/package.grid.js @@ -71,6 +71,13 @@ MODx.grid.Package = function(config = {}) { }; } + const providerButton = MODx.curlEnabled ? { + text: MODx.formatProviderLexicon('provider_with_name', MODx.providerName), + id: 'modx-package-provider-btn', + handler: this.changeProvider, + scope: this + } : null; + Ext.applyIf(config, { title: _('packages'), // Deprecate id, change to modx-grid-package in future release @@ -140,6 +147,7 @@ MODx.grid.Package = function(config = {}) { autosave: true, tbar: [ downloadButton, + providerButton, { text: _('packages_purge'), handler: this.purgePackages @@ -147,7 +155,7 @@ MODx.grid.Package = function(config = {}) { '->', this.getQueryFilterField(), this.getClearFiltersButton() - ] + ].filter(Boolean) }); MODx.grid.Package.superclass.constructor.call(this, config); this.on('render', function() { @@ -323,7 +331,6 @@ Ext.extend(MODx.grid.Package, MODx.grid.Grid, { /* Launch Package Browser */ onDownloadMoreExtra: function(btn, e) { - MODx.provider = MODx.defaultProvider; Ext.getCmp('modx-panel-packages-browser').activate(); }, diff --git a/manager/assets/modext/workspace/package.windows.js b/manager/assets/modext/workspace/package.windows.js index 1c5eeb7e520..313635d3c12 100644 --- a/manager/assets/modext/workspace/package.windows.js +++ b/manager/assets/modext/workspace/package.windows.js @@ -305,26 +305,26 @@ MODx.window.ChangeProvider = function(config) { }); }; Ext.extend(MODx.window.ChangeProvider,Ext.Window,{ //Using MODx.Window would create an empty unused form (It's not a bug)) - submit: function(o) { - var fm = Ext.getCmp('change-provider-form'); - if (fm.getForm().isValid()) { - var vs = fm.getForm().getValues(); - MODx.provider = vs.provider; - MODx.providerName = fm.getForm().findField('provider').getRawValue(); - var tree = Ext.getCmp('modx-package-browser-tree'); - tree.setProvider(vs.provider); - if (tree.rendered) { - var loader = tree.getLoader(); - loader.baseParams = { - action: 'Workspace/Packages/Rest/GetNodes' - ,provider: vs.provider - }; - loader.load(tree.root); - } - MODx.debug('Switching to: '+MODx.provider); - this.hide(); - Ext.getCmp('modx-panel-packages-browser').activate(); + submit: function() { + const fm = Ext.getCmp('change-provider-form'); + if (!fm.getForm().isValid()) { + return; } + const vs = fm.getForm().getValues(); + const name = fm.getForm().findField('provider').getRawValue(); + const win = this; + MODx.setActiveProvider(vs.provider, name, { + scope: this + ,callback: () => { + const tree = Ext.getCmp('modx-package-browser-tree'); + if (tree && tree.rendered) { + tree.getLoader().load(tree.root); + } + MODx.debug('Switching to: ' + MODx.provider); + win.hide(); + Ext.getCmp('modx-panel-packages-browser').activate(); + } + }); } }); Ext.reg('modx-package-changeprovider', MODx.window.ChangeProvider); diff --git a/manager/controllers/default/workspaces/index.class.php b/manager/controllers/default/workspaces/index.class.php index 3281cf46313..aa9aa136354 100644 --- a/manager/controllers/default/workspaces/index.class.php +++ b/manager/controllers/default/workspaces/index.class.php @@ -68,7 +68,12 @@ public function loadCustomCssJs() { $this->addHtml(""); $this->addJavascript($mgrUrl.'assets/modext/workspace/index.js');