diff --git a/app/Http/Controllers/PluginController.php b/app/Http/Controllers/PluginController.php index 422c73eb..8579095c 100644 --- a/app/Http/Controllers/PluginController.php +++ b/app/Http/Controllers/PluginController.php @@ -5,6 +5,7 @@ namespace App\Http\Controllers; use View; use Datatables; use App\Events; +use App\Services\Plugin; use Illuminate\Http\Request; use App\Services\PluginManager; @@ -46,10 +47,32 @@ class PluginController extends Controller switch ($request->get('action')) { case 'enable': + if (! $plugins->isRequirementsSatisfied($name)) { + $msg = ''; + + foreach ($plugins->getUnsatisfiedRequirements($name) as $name => $detail) { + if (! $detail['version']) { + $msg .= '
  • '.trans('admin.plugins.operations.unsatisfied.disabled', [ + 'name' => "$name" + ]).'
  • '; + } else { + $msg .= '
  • '.trans('admin.plugins.operations.unsatisfied.version', [ + 'name' => "$name", + 'constraint' => "{$detail['constraint']}" + ]).'
  • '; + } + } + + return json('

    '.trans('admin.plugins.operations.unsatisfied.notice')."

    ", 1); + } + $plugins->enable($name); return json(trans('admin.plugins.operations.enabled', ['plugin' => $plugin->title]), 0); + case 'requirements': + return json($this->getPluginDependencies($plugin)); + case 'disable': $plugins->disable($name); @@ -83,6 +106,9 @@ class PluginController extends Controller ->editColumn('author', function ($plugin) { return ['author' => trans($plugin->author ?: 'EMPTY'), 'url' => $plugin->url]; }) + ->addColumn('dependencies', function ($plugin) { + return $this->getPluginDependencies($plugin); + }) ->addColumn('status', function ($plugin) { return trans('admin.plugins.status.'.($plugin->isEnabled() ? 'enabled' : 'disabled')); }) @@ -91,4 +117,15 @@ class PluginController extends Controller }) ->make(true); } + + protected function getPluginDependencies(Plugin $plugin) + { + $plugins = app('plugins'); + + return [ + 'isRequirementsSatisfied' => $plugins->isRequirementsSatisfied($plugin->name), + 'requirements' => $plugin->getRequirements(), + 'unsatisfiedRequirements' => $plugins->getUnsatisfiedRequirements($plugin->name) + ]; + } } diff --git a/resources/assets/src/js/admin/plugins.js b/resources/assets/src/js/admin/plugins.js index 9346d9fe..361b65c3 100644 --- a/resources/assets/src/js/admin/plugins.js +++ b/resources/assets/src/js/admin/plugins.js @@ -20,6 +20,7 @@ const pluginsTableColumnDefs = [ { targets: 1, data: 'description', + orderable: false, width: '35%' }, { @@ -29,14 +30,37 @@ const pluginsTableColumnDefs = [ }, { targets: 3, - data: 'version' + data: 'version', + orderable: false }, { targets: 4, - data: 'status' + data: 'dependencies', + searchable: false, + orderable: false, + render: data => { + if (data.requirements.length === 0) { + return `${trans('admin.noDependencies')}`; + } + + let result = data.isRequirementsSatisfied ? '' : `${trans('admin.whyDependencies')}
    `; + + for (const name in data.requirements) { + const constraint = data.requirements[name]; + const color = (name in data.unsatisfiedRequirements) ? 'red' : 'green'; + + result += `${name}: ${constraint}
    `; + } + + return result; + } }, { targets: 5, + data: 'status' + }, + { + targets: 6, data: 'operations', searchable: false, orderable: false, @@ -64,6 +88,20 @@ const pluginsTableColumnDefs = [ async function enablePlugin(name) { try { + const { requirements } = await fetch({ + type: 'POST', + url: url(`admin/plugins/manage?action=requirements&name=${name}`), + dataType: 'json' + }); + + if (requirements.length === 0) { + await swal({ + text: trans('admin.noDependenciesNotice'), + type: 'warning', + showCancelButton: true + }); + } + const { errno, msg } = await fetch({ type: 'POST', url: url(`admin/plugins/manage?action=enable&name=${name}`), @@ -74,7 +112,7 @@ async function enablePlugin(name) { $.pluginsTable.ajax.reload(null, false); } else { - toastr.warning(msg); + swal({ type: 'warning', html: msg }); } } catch (error) { showAjaxError(error); @@ -93,7 +131,7 @@ async function disablePlugin(name) { $.pluginsTable.ajax.reload(null, false); } else { - toastr.warning(msg); + swal({ type: 'warning', html: msg }); } } catch (error) { showAjaxError(error); @@ -122,7 +160,7 @@ async function deletePlugin(name) { $.pluginsTable.ajax.reload(null, false); } else { - toastr.warning(msg); + swal({ type: 'warning', html: msg }); } } catch (error) { showAjaxError(error); diff --git a/resources/lang/en/admin.yml b/resources/lang/en/admin.yml index 8f5ad45f..ae555b39 100644 --- a/resources/lang/en/admin.yml +++ b/resources/lang/en/admin.yml @@ -98,6 +98,7 @@ plugins: description: Description author: Author version: Version + dependencies: Dependencies status: title: Status @@ -107,6 +108,10 @@ plugins: operations: title: Operations enabled: :plugin has been enabled. + unsatisfied: + notice: There are unsatisfied dependencies in the plugin, therefore we can't enable it. Please install or update the plugins listed below. + disabled: The :name plugin is not enabled. + version: The version of :name does not satisfies the constraint :constraint disabled: :plugin has been disabled. deleted: The plugin was deleted successfully. no-config-notice: The plugin is not installed or doesn't provide configuration page. diff --git a/resources/lang/en/locale.js b/resources/lang/en/locale.js index e65121d8..a5dd9e3c 100644 --- a/resources/lang/en/locale.js +++ b/resources/lang/en/locale.js @@ -171,11 +171,14 @@ configurePlugin: 'Configure', noPluginConfigNotice: 'The plugin has been disabled or no configuration is provided.', deletePlugin: 'Delete', + noDependencies: 'No Dependencies', + whyDependencies: 'What\'s this?', statusEnabled: 'Enabled', statusDisabled: 'Disabled', enablePlugin: 'Enable', disablePlugin: 'Disable', confirmDeletion: 'Are you sure to delete this plugin?', + noDependenciesNotice: 'There is no dependency definition in the plugin. It means that the plugin may be not compatible with the current version of Blessing Skin, and enabling it may cause unexpected problems. Do you really want to enable the plugin?', // Update preparing: 'Preparing', diff --git a/resources/lang/zh_CN/admin.yml b/resources/lang/zh_CN/admin.yml index 6177b08c..2c7e0836 100644 --- a/resources/lang/zh_CN/admin.yml +++ b/resources/lang/zh_CN/admin.yml @@ -98,6 +98,7 @@ plugins: description: 描述 author: 作者 version: 版本 + dependencies: 依赖关系 status: title: 状态 @@ -107,6 +108,10 @@ plugins: operations: title: 操作 enabled: :plugin 已启用 + unsatisfied: + notice: 无法启用此插件,因为其仍有未满足的依赖关系。请检查以下插件的版本,更新或安装它们: + disabled: :name 插件未启用 + version: :name 的版本不符合要求 :constraint disabled: :plugin 已禁用 deleted: 插件已被成功删除 no-config-notice: 插件未安装或未提供配置页面 diff --git a/resources/lang/zh_CN/locale.js b/resources/lang/zh_CN/locale.js index d987e22d..9c1edef4 100644 --- a/resources/lang/zh_CN/locale.js +++ b/resources/lang/zh_CN/locale.js @@ -173,11 +173,14 @@ configurePlugin: '插件配置', noPluginConfigNotice: '插件已被禁用或无配置页', deletePlugin: '删除插件', + noDependencies: '无要求', + whyDependencies: '为什么会这样?', statusEnabled: '已启用', statusDisabled: '已禁用', enablePlugin: '启用插件', disablePlugin: '禁用插件', confirmDeletion: '真的要删除这个插件吗?', + noDependenciesNotice: '此插件没有声明任何依赖关系,这代表它有可能并不兼容此版本的 Blessing Skin,请将此插件升级至可能的最新版本。强行启用可能导致无法预料的后果。你确定要启用此插件吗?', // Update preparing: '正在准备', diff --git a/resources/views/admin/plugins.tpl b/resources/views/admin/plugins.tpl index 8b5e4304..55f9b11a 100644 --- a/resources/views/admin/plugins.tpl +++ b/resources/views/admin/plugins.tpl @@ -35,6 +35,7 @@ {{ trans('admin.plugins.description') }} {{ trans('admin.plugins.author') }} {{ trans('admin.plugins.version') }} + {{ trans('admin.plugins.dependencies') }} {{ trans('admin.plugins.status.title') }} {{ trans('admin.plugins.operations.title') }}